Merge "power: pm8921-bms: adjust the pon ocv" into msm-3.0
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index cc94b69..3ee63c0 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -15,19 +15,21 @@
KERNEL_USE_OF ?= $(shell $(PERL) -e '$$of = "n"; while (<>) { if (/CONFIG_USE_OF=y/) { $$of = "y"; break; } } print $$of;' kernel/arch/arm/configs/$(KERNEL_DEFCONFIG))
ifeq "$(KERNEL_USE_OF)" "y"
+DTS_NAME ?= $(MSM_ARCH)
+DTS_FILES = $(wildcard $(TOP)/kernel/arch/arm/boot/dts/$(DTS_NAME)*.dts)
+DTS_FILE = $(lastword $(subst /, ,$(1)))
+DTB_FILE = $(addprefix $(KERNEL_OUT)/arch/arm/boot/,$(patsubst %.dts,%.dtb,$(call DTS_FILE,$(1))))
+ZIMG_FILE = $(addprefix $(KERNEL_OUT)/arch/arm/boot/,$(patsubst %.dts,%-zImage,$(call DTS_FILE,$(1))))
KERNEL_ZIMG = $(KERNEL_OUT)/arch/arm/boot/zImage
-DTB_FILE = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH).dtb
-DTS_FILE = $(TOP)/kernel/arch/arm/boot/dts/$(MSM_ARCH).dts
-FULL_KERNEL = $(KERNEL_OUT)/arch/arm/boot/$(MSM_ARCH)-zImage
DTC = $(KERNEL_OUT)/scripts/dtc/dtc
define append-dtb
-md $(KERNEL_OUT)/arch/arm/boot;\
-$(DTC) -p 1024 -O dtb -o $(DTB_FILE) $(DTS_FILE);\
-cat $(KERNEL_ZIMG) $(DTB_FILE) > $(FULL_KERNEL)
+mkdir -p $(KERNEL_OUT)/arch/arm/boot;\
+$(foreach d, $(DTS_FILES), \
+ $(DTC) -p 1024 -O dtb -o $(call DTB_FILE,$(d)) $(d); \
+ cat $(KERNEL_ZIMG) $(call DTB_FILE,$(d)) > $(call ZIMG_FILE,$(d));)
endef
else
-FULL_KERNEL = $(KERNEL_IMG)
define append-dtb
endef
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
new file mode 100644
index 0000000..eb3986e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -0,0 +1,23 @@
+* ARM architected timer
+
+ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
+provides a per-cpu local timer.
+
+The timer is attached to a GIC to deliver its two per-processor
+interrupts (one for the secure mode, one for the non-secure mode).
+
+** Timer node properties:
+
+- compatible : Should be "arm,armv7-timer"
+
+- interrupts : One or two interrupts for secure and non-secure mode
+
+- clock-frequency : The frequency of the main counter, in Hz. Optional.
+
+Example:
+
+ timer {
+ compatible = "arm,armv7-timer"";
+ interrupts = <1 13 0xf08 1 14 0xf08>;
+ clock-frequency = <100000000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
new file mode 100644
index 0000000..f50e021
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -0,0 +1,42 @@
+* ARM L2 Cache Controller
+
+ARM cores often have a separate level 2 cache controller. There are various
+implementations of the L2 cache controller with compatible programming models.
+The ARM L2 cache representation in the device tree should be done as follows:
+
+Required properties:
+
+- compatible : should be one of:
+ "arm,pl310-cache"
+ "arm,l220-cache"
+ "arm,l210-cache"
+- cache-unified : Specifies the cache is a unified cache.
+- cache-level : Should be set to 2 for a level 2 cache.
+- reg : Physical base address and size of cache controller's memory mapped
+ registers.
+
+Optional properties:
+
+- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of
+ read, write and setup latencies. Minimum valid values are 1. Controllers
+ without setup latency control should use a value of 0.
+- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of
+ read, write and setup latencies. Controllers without setup latency control
+ should use 0. Controllers without separate read and write Tag RAM latency
+ values should only use the first cell.
+- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell.
+- arm,filter-ranges : <start length> Starting address and length of window to
+ filter. Addresses in the filter window are directed to the M1 port. Other
+ addresses will go to the M0 port.
+
+Example:
+
+L2: cache-controller {
+ compatible = "arm,pl310-cache";
+ reg = <0xfff12000 0x1000>;
+ arm,data-latency = <1 1 1>;
+ arm,tag-latency = <2 2 2>;
+ arm,filter-latency = <0x80000000 0x8000000>;
+ cache-unified;
+ cache-level = <2>;
+};
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
new file mode 100644
index 0000000..9cf57fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -0,0 +1,29 @@
+Fixed Voltage regulators
+
+Required properties:
+- compatible: Must be "regulator-fixed";
+
+Optional properties:
+- gpio: gpio to use for enable control
+- startup-delay-us: startup time in microseconds
+- enable-active-high: Polarity of GPIO is Active high
+If this property is missing, the default assumed is Active low.
+
+Any property defined as part of the core regulator
+binding, defined in regulator.txt, can also be used.
+However a fixed voltage regulator is expected to have the
+regulator-min-microvolt and regulator-max-microvolt
+to be the same.
+
+Example:
+
+ abc: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-supply";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio1 16 0>;
+ startup-delay-us = <70000>;
+ enable-active-high;
+ regulator-boot-on
+ };
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
new file mode 100644
index 0000000..82bef20
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -0,0 +1,54 @@
+Voltage/Current Regulators
+
+Optional properties:
+- regulator-name: A string used as a descriptive name for regulator outputs
+- regulator-min-microvolt: smallest voltage consumers may set
+- regulator-max-microvolt: largest voltage consumers may set
+- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops
+- regulator-min-microamp: smallest current consumers may set
+- regulator-max-microamp: largest current consumers may set
+- regulator-always-on: boolean, regulator should never be disabled
+- regulator-boot-on: bootloader/firmware enabled regulator
+- <name>-supply: phandle to the parent supply/regulator node
+
+Example:
+
+ xyzreg: regulator@0 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ vin-supply = <&vin>;
+ };
+
+Regulator Consumers:
+Consumer nodes can reference one or more of its supplies/
+regulators using the below bindings.
+
+- <name>-supply: phandle to the regulator node
+
+These are the same bindings that a regulator in the above
+example used to reference its own supply, in which case
+its just seen as a special case of a regulator being a
+consumer itself.
+
+Example of a consumer device node (mmc) referencing two
+regulators (twl-reg1 and twl-reg2),
+
+ twl-reg1: regulator@0 {
+ ...
+ ...
+ ...
+ };
+
+ twl-reg2: regulator@1 {
+ ...
+ ...
+ ...
+ };
+
+ mmc: mmc@0x0 {
+ ...
+ ...
+ vmmc-supply = <&twl-reg1>;
+ vmmcaux-supply = <&twl-reg2>;
+ };
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
new file mode 100644
index 0000000..cf727d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -0,0 +1,38 @@
+Qualcomm SLIMBUS controller
+
+Required properties:
+
+ - reg : Offset and length of the register region(s) for the device
+ - reg-names : Register region name(s) referenced in reg above
+ Required register resource entries are:
+ "slimbus_physical": Physical adderss of controller register blocks
+ "slimbus_bam_physical": Physical address of Bus Access Module (BAM)
+ for this controller
+ - compatible : should be "qcom,slim-msm"
+ - cell-index : SLIMBUS number used for this controller
+ - interrupts : Interrupt numbers used by this controller
+ - interrupt-names : Required interrupt resource entries are:
+ "slimbus_irq" : Interrupt for SLIMBUS core
+ "slimbus_bam_irq" : Interrupt for controller core's BAM
+
+Optional property:
+ - reg entry for slew rate : If slew rate control register is provided, this
+ entry should be used.
+ - reg-name for slew rate: "slimbus_slew_reg"
+ - qcom,min-clk-gear : Minimum clock gear at which this controller can be run
+ (range: 1-10)
+ Default value will be 1 if this entry is not specified
+ - qcom,max-clk-gear: Maximum clock gear at which this controller can be run
+ (range: 1-10)
+ Default value will be 10 if this entry is not specified
+Example:
+ slim@fe12f000 {
+ cell-index = <1>;
+ compatible = "qcom,slim-msm";
+ reg = <0xfe12f000 0x35000>,
+ <0xfe104000 0x20000>;
+ reg-names = "slimbus_physical", "slimbus_bam_physical";
+ interrupts = <0 163 0 0 164 0>;
+ interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+ qcom,min-clk-gear = <10>;
+ };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 308f984..a4c90bc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1167,7 +1167,7 @@
capabilities of the processor.
config PL310_ERRATA_588369
- bool "Clean & Invalidate maintenance operations do not invalidate clean lines"
+ bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines"
depends on CACHE_L2X0
help
The PL310 L2 cache controller implements three types of Clean &
@@ -1192,7 +1192,7 @@
entries regardless of the ASID.
config PL310_ERRATA_727915
- bool "Background Clean & Invalidate by Way operation can cause data corruption"
+ bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption"
depends on CACHE_L2X0
help
PL310 implements the Clean & Invalidate by Way L2 cache maintenance
@@ -1225,8 +1225,8 @@
operation is received by a CPU before the ICIALLUIS has completed,
potentially leading to corrupted entries in the cache or TLB.
-config ARM_ERRATA_753970
- bool "ARM errata: cache sync operation may be faulty"
+config PL310_ERRATA_753970
+ bool "PL310 errata: cache sync operation may be faulty"
depends on CACHE_PL310
help
This option enables the workaround for the 753970 PL310 (r3p0) erratum.
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
new file mode 100644
index 0000000..bb53ff8
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -0,0 +1,60 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msmcopper.dtsi"
+
+/ {
+ model = "Qualcomm MSM Copper RUMI";
+ compatible = "qcom,msmcopper-rumi", "qcom,msmcopper";
+
+ timer {
+ clock-frequency = <5000000>;
+ };
+
+ serial@f991f000 {
+ status = "disable";
+ };
+
+ usb@f9a55000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f980b000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f984b000 {
+ status = "disable";
+ };
+
+ qcom,sps@f998000 {
+ status = "disable";
+ };
+
+ spi@f9924000 {
+ status = "disable";
+ };
+
+ slim@fe12f000 {
+ status = "disable";
+ };
+
+ qcom,spmi@fc4c0000 {
+ status = "disable";
+ };
+
+ i2c@f9966000 {
+ status = "disable";
+ };
+};
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
new file mode 100644
index 0000000..ab6b8ba
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -0,0 +1,20 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msmcopper.dtsi"
+
+/ {
+ model = "Qualcomm MSM Copper Simulator";
+ compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+};
diff --git a/arch/arm/boot/dts/msmcopper.dts b/arch/arm/boot/dts/msmcopper.dtsi
similarity index 83%
rename from arch/arm/boot/dts/msmcopper.dts
rename to arch/arm/boot/dts/msmcopper.dtsi
index a0ea117..314748c 100644
--- a/arch/arm/boot/dts/msmcopper.dts
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -1,10 +1,20 @@
-/dts-v1/;
+/* Copyright (c) 2012, Code Aurora Forum. 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/ "skeleton.dtsi"
/ {
model = "Qualcomm MSM Copper";
- compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+ compatible = "qcom,msmcopper";
interrupt-parent = <&intc>;
intc: interrupt-controller@F9000000 {
@@ -23,8 +33,9 @@
};
timer {
- compatible = "qcom,msm-qtimer";
+ compatible = "qcom,msm-qtimer", "arm,armv7-timer";
interrupts = <1 2 0>;
+ clock-frequency = <19200000>;
};
serial@f991f000 {
@@ -33,6 +44,12 @@
interrupts = <0 109 0>;
};
+ serial@f995e000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf995e000 0x1000>;
+ interrupts = <0 114 0>;
+ };
+
usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
@@ -85,6 +102,17 @@
spi-max-frequency = <24000000>;
};
+ slim@fe12f000 {
+ cell-index = <1>;
+ compatible = "qcom,slim-msm";
+ reg = <0xfe12f000 0x35000>,
+ <0xfe104000 0x20000>;
+ reg-names = "slimbus_physical", "slimbus_bam_physical";
+ interrupts = <0 163 0 0 164 0>;
+ interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+ qcom,min-clk-gear = <10>;
+ };
+
qcom,spmi@fc4c0000 {
cell-index = <0>;
compatible = "qcom,spmi-pmic-arb";
@@ -198,4 +226,8 @@
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <24000000>;
};
+
+ qcom,acpuclk@0xf900000 {
+ compatible = "qcom,acpuclk-copper";
+ };
};
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index c671d32..1d0584e 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -8,6 +8,7 @@
CONFIG_IKCONFIG_PROC=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
# CONFIG_PERF_EVENTS is not set
@@ -34,7 +35,7 @@
# CONFIG_MSM_HW3D is not set
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
-CONFIG_MSM_JTAG=y
+CONFIG_MSM_WATCHDOG=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index 80252d8..b3e5b87 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -8,6 +8,7 @@
CONFIG_IKCONFIG_PROC=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
@@ -33,6 +34,7 @@
# CONFIG_MSM_HW3D is not set
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
+CONFIG_MSM_WATCHDOG=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index d1c607e..dcd2be6 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -56,6 +56,11 @@
CONFIG_USE_OF=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_FREQ=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_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -97,13 +102,18 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_DCC_TTY=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
CONFIG_SPMI=y
CONFIG_SPMI_MSM_PMIC_ARB=y
CONFIG_MSM_QPNP=y
CONFIG_MSM_QPNP_INT=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_QUP=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_CTRL=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
CONFIG_POWER_SUPPLY=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
deleted file mode 100644
index 82fc695..0000000
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ /dev/null
@@ -1,307 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-perf"
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=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_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_ASHMEM=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X27=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM7X00A_USE_DG_TIMER=y
-# CONFIG_MSM_FIQ_SUPPORT is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_MSM_HW3D is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=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_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_WAKELOCK=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=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_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_LOG=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_SIP=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_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_OWNER=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=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_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_LOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_CLS_U32=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_BT_MSM_SLEEP=y
-CONFIG_MSM_BT_POWER=y
-# CONFIG_WIRELESS_EXT_SYSFS is not set
-CONFIG_RFKILL=y
-# CONFIG_RFKILL_PM is not set
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_LIBRA_SDIOIF=m
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM_LEGACY=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_KEYCHORD=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-# CONFIG_HWMON is not set
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
-# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP30=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM_SOC=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA12_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA12"
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_PARTITION_ADVANCED=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_SCHED_DEBUG is not set
-CONFIG_TIMER_STATS=y
-# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
deleted file mode 100644
index c6dfdc4..0000000
--- a/arch/arm/configs/msm7627_defconfig
+++ /dev/null
@@ -1,312 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=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_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_ASHMEM=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_MSM=y
-CONFIG_ARCH_MSM7X27=y
-# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_MSM7X00A_USE_DG_TIMER=y
-# CONFIG_MSM_FIQ_SUPPORT is not set
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_ONCRPCROUTER=y
-CONFIG_MSM_RMT_STORAGE_CLIENT=y
-# CONFIG_MSM_HW3D is not set
-CONFIG_STRICT_MEMORY_RWX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=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_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_WAKELOCK=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=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_IPV6_SUBTREES=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_LOG=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_SIP=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_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_OWNER=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=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_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_LOG=y
-CONFIG_NF_NAT=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NET_CLS_U32=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_IBS=y
-CONFIG_BT_MSM_SLEEP=y
-CONFIG_MSM_BT_POWER=y
-# CONFIG_WIRELESS_EXT_SYSFS is not set
-CONFIG_RFKILL=y
-# CONFIG_RFKILL_PM is not set
-CONFIG_GENLOCK=y
-CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_MTD=y
-CONFIG_MTD_TESTS=m
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=8
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_CHR_DEV_SCH=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_DM_CRYPT=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_LIBRA_SDIOIF=m
-CONFIG_SLIP=y
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_MODE_SLIP6=y
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=m
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_MSM_LEGACY=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_KEYCHORD=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_INPUT_GPIO=y
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM_HS=y
-CONFIG_DIAG_CHAR=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_BATTERY_MSM=y
-# CONFIG_HWMON is not set
-CONFIG_MSM_KGSL=y
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_MSM=y
-# CONFIG_FB_MSM_BACKLIGHT is not set
-CONFIG_FB_MSM_TRIPLE_BUFFER=y
-CONFIG_FB_MSM_MDP30=y
-CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MSM_SOC=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_SUSPEND=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_EHSET=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM_72K=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
-CONFIG_USB_EHSET_TEST_FIXTURE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_MSM_72K=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_RMNET_SMD_CTL_CHANNEL="DATA12_CNTL"
-CONFIG_RMNET_SMD_DATA_CHANNEL="DATA12"
-CONFIG_MMC=y
-CONFIG_MMC_PERF_PROFILING=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_MMC_CLKGATE=y
-CONFIG_MMC_PARANOID_SD_INIT=y
-CONFIG_MMC_BLOCK_MINORS=32
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_TEST=m
-CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
-CONFIG_SWITCH=y
-CONFIG_SWITCH_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DEBUG=y
-CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_YAFFS_FS=y
-CONFIG_YAFFS_DISABLE_TAGS_ECC=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_PARTITION_ADVANCED=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_LOCKUP_DETECTOR=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_LATENCYTOP=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 6a5497d..1cf5df3 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -1,4 +1,3 @@
-CONFIG_CFG80211=m
CONFIG_EXPERIMENTAL=y
CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)-perf"
# CONFIG_SWAP is not set
@@ -170,6 +169,7 @@
CONFIG_BT_HCIUART_IBS=y
CONFIG_BT_MSM_SLEEP=y
CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=m
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
@@ -303,7 +303,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
CONFIG_MMC_MSM_SDC3_SUPPORT=y
CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 11c4224..8d31ee6 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -1,4 +1,3 @@
-CONFIG_CFG80211=m
CONFIG_EXPERIMENTAL=y
CONFIG_LOCALVERSION="$(KERNEL_LOCAL_VERSION)"
# CONFIG_SWAP is not set
@@ -170,6 +169,7 @@
CONFIG_BT_HCIUART_IBS=y
CONFIG_BT_MSM_SLEEP=y
CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=m
# CONFIG_CFG80211_WEXT is not set
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
@@ -304,7 +304,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
CONFIG_MMC_MSM_SDC3_SUPPORT=y
CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 3ee4132..736f2bb 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -334,7 +334,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 1e037ea..bc464b4 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -333,7 +333,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
# CONFIG_MMC_MSM_SDC1_SUPPORT is not set
CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 2375654..e7f1a67 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -65,6 +65,7 @@
CONFIG_MSM_PIL_MODEM=y
CONFIG_MSM_PIL_QDSP6V3=y
CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
@@ -387,7 +388,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 23cd17e..c8dfd7a 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -64,6 +64,7 @@
CONFIG_MSM_PIL_MODEM=y
CONFIG_MSM_PIL_QDSP6V3=y
CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
@@ -388,7 +389,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 68870b6..7fa8099 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -9,7 +9,6 @@
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
CONFIG_RT_GROUP_SCHED=y
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
@@ -53,6 +52,7 @@
CONFIG_MACH_APQ8064_CDP=y
CONFIG_MACH_APQ8064_MTP=y
CONFIG_MACH_APQ8064_LIQUID=y
+CONFIG_MACH_MPQ8064_CDP=y
CONFIG_MACH_MPQ8064_HRD=y
CONFIG_MACH_MPQ8064_DTV=y
# CONFIG_MSM_STACKED_MEMORY is not set
@@ -69,6 +69,8 @@
CONFIG_MSM_PIL_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
+CONFIG_MSM_PIL_VIDC=y
CONFIG_MSM_PIL_GSS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_MODEM_8960=y
@@ -85,9 +87,9 @@
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_QDSS=y
CONFIG_MSM_SLEEP_STATS=y
-CONFIG_MSM_DCVS=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_DCVS=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -300,6 +302,7 @@
CONFIG_PM8921_CHARGER=y
CONFIG_PM8921_BMS=y
CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_SENSORS_EPM_ADC=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_THERMAL_PM8XXX=y
@@ -327,9 +330,9 @@
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
-CONFIG_IMX091=y
CONFIG_MSM_GEMINI=y
CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index ccf448d..262aaac 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -8,7 +8,6 @@
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
CONFIG_RT_GROUP_SCHED=y
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
@@ -52,6 +51,7 @@
CONFIG_MACH_APQ8064_CDP=y
CONFIG_MACH_APQ8064_MTP=y
CONFIG_MACH_APQ8064_LIQUID=y
+CONFIG_MACH_MPQ8064_CDP=y
CONFIG_MACH_MPQ8064_HRD=y
CONFIG_MACH_MPQ8064_DTV=y
# CONFIG_MSM_STACKED_MEMORY is not set
@@ -68,6 +68,8 @@
CONFIG_MSM_PIL_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_PIL_DSPS=y
+CONFIG_MSM_PIL_VIDC=y
CONFIG_MSM_PIL_GSS=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_MODEM_8960=y
@@ -85,13 +87,15 @@
CONFIG_MSM_QDSS=y
CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y
CONFIG_MSM_SLEEP_STATS=y
-CONFIG_MSM_DCVS=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
CONFIG_MSM_L2_ERP_1BIT_PANIC=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_DCVS=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -304,6 +308,7 @@
CONFIG_PM8921_CHARGER=y
CONFIG_PM8921_BMS=y
CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_SENSORS_EPM_ADC=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_THERMAL_PM8XXX=y
@@ -331,9 +336,9 @@
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
-CONFIG_IMX091=y
CONFIG_MSM_GEMINI=y
CONFIG_S5K3L1YX=y
+CONFIG_IMX091=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index c9ce881..601f235 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -43,7 +43,6 @@
# CONFIG_MSM_RESET_MODEM is not set
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
-CONFIG_MSM_PIL_QDSP6V4=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
# CONFIG_MSM_SYSMON_COMM is not set
CONFIG_MSM_MODEM_8960=y
@@ -192,7 +191,6 @@
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
-CONFIG_SLIMBUS=y
CONFIG_SLIMBUS_MSM_CTRL=y
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
@@ -201,10 +199,13 @@
CONFIG_SENSORS_PM8XXX_ADC=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
+CONFIG_THERMAL_PM8XXX=y
CONFIG_MFD_PM8018_CORE=y
CONFIG_WCD9310_CODEC=y
CONFIG_REGULATOR_PM8XXX=y
CONFIG_REGULATOR_GPIO=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
@@ -230,7 +231,8 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
-CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_CI13XXX_MSM=m
+CONFIG_USB_CI13XXX_MSM_HSIC=m
CONFIG_USB_G_ANDROID=y
CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
@@ -243,7 +245,6 @@
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
-CONFIG_MMC_MSM_SDIO_SUPPORT=y
CONFIG_MMC_MSM_CARD_HW_DETECTION=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_NEW_LEDS=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 827305d..2098288 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -9,11 +9,17 @@
#ifdef CONFIG_ARM_ARCH_TIMER
int arch_timer_register(struct arch_timer *);
+int arch_timer_of_register(void);
#else
static inline int arch_timer_register(struct arch_timer *at)
{
return -ENXIO;
}
+
+static inline int arch_timer_of_register(void)
+{
+ return -ENXIO;
+}
#endif
#endif
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 49106e1..c582364 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -45,8 +45,15 @@
#define L2X0_CLEAN_INV_LINE_PA 0x7F0
#define L2X0_CLEAN_INV_LINE_IDX 0x7F8
#define L2X0_CLEAN_INV_WAY 0x7FC
-#define L2X0_LOCKDOWN_WAY_D 0x900
-#define L2X0_LOCKDOWN_WAY_I 0x904
+/*
+ * The lockdown registers repeat 8 times for L310, the L210 has only one
+ * D and one I lockdown register at 0x0900 and 0x0904.
+ */
+#define L2X0_LOCKDOWN_WAY_D_BASE 0x900
+#define L2X0_LOCKDOWN_WAY_I_BASE 0x904
+#define L2X0_LOCKDOWN_STRIDE 0x08
+#define L2X0_ADDR_FILTER_START 0xC00
+#define L2X0_ADDR_FILTER_END 0xC04
#define L2X0_TEST_OPERATION 0xF00
#define L2X0_LINE_DATA 0xF10
#define L2X0_LINE_TAG 0xF30
@@ -62,8 +69,23 @@
#define L2X0_CACHE_ID_PART_L210 (1 << 6)
#define L2X0_CACHE_ID_PART_L220 (2 << 6)
#define L2X0_CACHE_ID_PART_L310 (3 << 6)
+#define L2X0_CACHE_ID_RTL_MASK 0x3f
+#define L2X0_CACHE_ID_RTL_R0P0 0x0
+#define L2X0_CACHE_ID_RTL_R1P0 0x2
+#define L2X0_CACHE_ID_RTL_R2P0 0x4
+#define L2X0_CACHE_ID_RTL_R3P0 0x5
+#define L2X0_CACHE_ID_RTL_R3P1 0x6
+#define L2X0_CACHE_ID_RTL_R3P2 0x8
#define L2X0_AUX_CTRL_MASK 0xc0000fff
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0
+#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3
+#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3)
+#define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6
+#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6)
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9
+#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9)
#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
@@ -75,13 +97,43 @@
#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
#define L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT 20
-#define REV_PL310_R2P0 4
+#define L2X0_LATENCY_CTRL_SETUP_SHIFT 0
+#define L2X0_LATENCY_CTRL_RD_SHIFT 4
+#define L2X0_LATENCY_CTRL_WR_SHIFT 8
+
+#define L2X0_ADDR_FILTER_EN 1
#ifndef __ASSEMBLY__
-extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
extern void l2x0_suspend(void);
extern void l2x0_resume(int collapsed);
extern void l2x0_cache_sync(void);
+extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
+#if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
+extern int l2x0_of_init(u32 aux_val, u32 aux_mask);
+#else
+static inline int l2x0_of_init(u32 aux_val, u32 aux_mask)
+{
+ return -ENODEV;
+}
+#endif
+
+struct l2x0_regs {
+ unsigned long phy_base;
+ unsigned long aux_ctrl;
+ /*
+ * Whether the following registers need to be saved/restored
+ * depends on platform
+ */
+ unsigned long tag_latency;
+ unsigned long data_latency;
+ unsigned long filter_start;
+ unsigned long filter_end;
+ unsigned long prefetch_ctrl;
+ unsigned long pwr_ctrl;
+};
+
+extern struct l2x0_regs l2x0_saved_regs;
+
#endif
#endif
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 5bb5139..5668e75 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -50,8 +50,11 @@
void gic_enable_ppi(unsigned int);
bool gic_is_spi_pending(unsigned int irq);
void gic_clear_spi_pending(unsigned int irq);
+#ifdef CONFIG_ARM_GIC
void gic_set_irq_secure(unsigned int irq);
-
+#else
+static inline void gic_set_irq_secure(unsigned int irq) { }
+#endif
static inline void gic_init(unsigned int nr, int start,
void __iomem *dist , void __iomem *cpu)
{
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index d838743..53426c6 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -34,6 +34,7 @@
void (*sync)(void);
#endif
void (*set_debug)(unsigned long);
+ void (*resume)(void);
};
#ifdef CONFIG_OUTER_CACHE
@@ -74,6 +75,12 @@
outer_cache.disable();
}
+static inline void outer_resume(void)
+{
+ if (outer_cache.resume)
+ outer_cache.resume();
+}
+
#else
static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 4dccb04..31c5f5f 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -92,7 +92,6 @@
#define xchg(ptr,x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-extern asmlinkage void __backtrace(void);
extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
struct mm_struct;
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index c6ff17c..8c5b581 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -18,6 +18,7 @@
#include <linux/jiffies.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
+#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -272,13 +273,10 @@
.stop = arch_timer_stop,
};
-int __init arch_timer_register(struct arch_timer *at)
+static int __init arch_timer_common_register(void)
{
int err;
- if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ))
- return -EINVAL;
-
err = arch_timer_available();
if (err)
return err;
@@ -296,7 +294,6 @@
set_delay_fn(read_current_timer_delay_loop);
#endif
- arch_timer_ppi = at->res[0].start;
err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
"arch_timer", arch_timer_evt);
if (err) {
@@ -305,8 +302,7 @@
goto out_free;
}
- if (at->res[1].start > 0 && (at->res[1].flags & IORESOURCE_IRQ)) {
- arch_timer_ppi2 = at->res[1].start;
+ if (arch_timer_ppi2) {
err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
"arch_timer", arch_timer_evt);
if (err) {
@@ -334,3 +330,54 @@
return err;
}
+
+int __init arch_timer_register(struct arch_timer *at)
+{
+ if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ))
+ return -EINVAL;
+
+ arch_timer_ppi = at->res[0].start;
+
+ if (at->res[1].start > 0 && (at->res[1].flags & IORESOURCE_IRQ))
+ arch_timer_ppi2 = at->res[1].start;
+
+ return arch_timer_common_register();
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+ { .compatible = "arm,armv7-timer", },
+ {},
+};
+
+int __init arch_timer_of_register(void)
+{
+ struct device_node *np;
+ u32 freq;
+ int ret;
+
+ np = of_find_matching_node(NULL, arch_timer_of_match);
+ if (!np) {
+ pr_err("arch_timer: can't find DT node\n");
+ return -ENODEV;
+ }
+
+ /* Try to determine the frequency from the device tree or CNTFRQ */
+ if (!of_property_read_u32(np, "clock-frequency", &freq))
+ arch_timer_rate = freq;
+
+ ret = irq_of_parse_and_map(np, 0);
+ if (ret <= 0) {
+ pr_err("arch_timer: interrupt not specified in timer node\n");
+ return -ENODEV;
+ }
+ arch_timer_ppi = ret;
+ ret = irq_of_parse_and_map(np, 1);
+ if (ret > 0)
+ arch_timer_ppi2 = ret;
+ pr_info("arch_timer: found %s irqs %d %d\n",
+ np->name, arch_timer_ppi, arch_timer_ppi2);
+
+ return arch_timer_common_register();
+}
+#endif
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 263eaaf..c035a96 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -49,9 +49,6 @@
extern void fpundefinstr(void);
-
-EXPORT_SYMBOL(__backtrace);
-
/* networking */
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_from_user);
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 927522c..69391bf 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -20,6 +20,7 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/procinfo.h>
+#include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h>
/*
@@ -89,6 +90,17 @@
DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
BLANK();
+#ifdef CONFIG_CACHE_L2X0
+ DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base));
+ DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl));
+ DEFINE(L2X0_R_TAG_LATENCY, offsetof(struct l2x0_regs, tag_latency));
+ DEFINE(L2X0_R_DATA_LATENCY, offsetof(struct l2x0_regs, data_latency));
+ DEFINE(L2X0_R_FILTER_START, offsetof(struct l2x0_regs, filter_start));
+ DEFINE(L2X0_R_FILTER_END, offsetof(struct l2x0_regs, filter_end));
+ DEFINE(L2X0_R_PREFETCH_CTRL, offsetof(struct l2x0_regs, prefetch_ctrl));
+ DEFINE(L2X0_R_PWR_CTRL, offsetof(struct l2x0_regs, pwr_ctrl));
+ BLANK();
+#endif
#ifdef CONFIG_CPU_HAS_ASID
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id));
BLANK();
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 32ab699..bd99bbb 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -437,7 +437,7 @@
printk("\n");
printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
__show_regs(regs);
- __backtrace();
+ dump_stack();
}
ATOMIC_NOTIFIER_HEAD(thread_notify_head);
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index a673297..cd07b58 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -22,15 +22,10 @@
#define mask r7
#define offset r8
-ENTRY(__backtrace)
- mov r1, #0x10
- mov r0, fp
-
ENTRY(c_backtrace)
#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
mov pc, lr
-ENDPROC(__backtrace)
ENDPROC(c_backtrace)
#else
stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location...
@@ -107,7 +102,6 @@
mov r1, frame
bl printk
no_frame: ldmfd sp!, {r4 - r8, pc}
-ENDPROC(__backtrace)
ENDPROC(c_backtrace)
.pushsection __ex_table,"a"
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
index faa7748..e55c484 100644
--- a/arch/arm/lib/div64.S
+++ b/arch/arm/lib/div64.S
@@ -13,6 +13,7 @@
*/
#include <linux/linkage.h>
+#include <asm/unwind.h>
#ifdef __ARMEB__
#define xh r0
@@ -44,6 +45,7 @@
*/
ENTRY(__do_div64)
+UNWIND(.fnstart)
@ Test for easy paths first.
subs ip, r4, #1
@@ -189,7 +191,12 @@
moveq yh, xh
moveq xh, #0
moveq pc, lr
+UNWIND(.fnend)
+UNWIND(.fnstart)
+UNWIND(.pad #4)
+UNWIND(.save {lr})
+Ldiv0_64:
@ Division by 0:
str lr, [sp, #-8]!
bl __div0
@@ -200,4 +207,5 @@
mov xh, #0
ldr pc, [sp], #8
+UNWIND(.fnend)
ENDPROC(__do_div64)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 67ba2b1..ae69ad4 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -263,8 +263,10 @@
select MULTI_IRQ_HANDLER
select MSM_PM8X60 if PM
select MSM_XO
+ select MSM_MULTIMEDIA_USE_ION
select MSM_QDSP6_APR
select MSM_AUDIO_QDSP6 if SND_SOC
+ select FIQ
config ARCH_MSM8625
bool "MSM8625"
@@ -780,6 +782,12 @@
help
Support for the Qualcomm APQ8064 LIQUID device.
+config MACH_MPQ8064_CDP
+ depends on ARCH_APQ8064
+ bool "MPQ8064 CDP"
+ help
+ Support for the Qualcomm MPQ8064 CDP device.
+
config MACH_MPQ8064_HRD
depends on ARCH_APQ8064
bool "MPQ8064 HRD"
@@ -818,7 +826,7 @@
default "0x80200000" if ARCH_APQ8064
default "0x80200000" if ARCH_MSM8960
default "0x80200000" if ARCH_MSM8930
- default "0x80200000" if ARCH_MSMCOPPER
+ default "0x20200000" if ARCH_MSMCOPPER
default "0x10000000" if ARCH_FSM9XXX
default "0x00200000" if !MSM_STACKED_MEMORY
default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
@@ -1771,6 +1779,21 @@
used to decrypt data and perform secure operations on the behalf of
the kernel.
+config MSM_PIL_DSPS
+ tristate "DSPS Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down ARM7 DSPS processors.
+
+ DSPS is a sensors offloading processor used for applications such
+ as rotation detection, temperature, etc.
+
+config MSM_PIL_VIDC
+ tristate "Video Core Secure Boot Support"
+ depends on MSM_PIL
+ help
+ Support for authenticating the video core image.
+
config MSM_PIL_GSS
tristate "GSS (Coretx A5) Boot Support"
depends on MSM_PIL
@@ -1957,7 +1980,7 @@
config MSM_WATCHDOG
bool "MSM Watchdog Support"
- depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615 || ARCH_FSM9XXX
help
This enables the watchdog as is present on 8x60. Currently we use
core 0's watchdog, and reset the entire SoC if it times out. It does
@@ -2212,4 +2235,21 @@
config HAVE_ARCH_HAS_CURRENT_TIMER
bool
+
+config MSM_CACHE_DUMP
+ bool "Cache dumping support"
+ help
+ Add infrastructure to dump the L1 and L2 caches to an allocated buffer.
+ This allows for analysis of the caches in case cache corruption is
+ suspected.
+
+config MSM_CACHE_DUMP_ON_PANIC
+ bool "Dump caches on panic"
+ depends on MSM_CACHE_DUMP
+ help
+ By default, the caches are flushed on panic. This means that trying to
+ look at them in a RAM dump will give useless data. Select this if you
+ want to dump the L1 and L2 caches on panic before any flush occurs.
+ If unsure, say N
+
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e93993c..0cef857 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -67,15 +67,13 @@
obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
obj-$(CONFIG_MSM_PIL) += scm-pas.o
-ifdef CONFIG_MSM_PIL
-obj-$(CONFIG_ARCH_MSM8X60) += peripheral-reset.o
-obj-$(CONFIG_ARCH_MSM8960) += peripheral-reset-8960.o
-endif
obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
+obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
+obj-$(CONFIG_MSM_PIL_DSPS) += pil-dsps.o
obj-$(CONFIG_MSM_PIL_GSS) += pil-gss.o
obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
@@ -201,12 +199,16 @@
obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
endif
+ifdef CONFIG_MSM_CAMERA_V4L2
+ obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-camera.o
+endif
obj-$(CONFIG_ARCH_FSM9XXX) += devices-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
+obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
obj-$(CONFIG_MACH_MSM8X60_RUMI3) += board-msm8x60.o
obj-$(CONFIG_MACH_MSM8X60_SIM) += board-msm8x60.o
obj-$(CONFIG_MACH_MSM8X60_SURF) += board-msm8x60.o
@@ -223,7 +225,7 @@
obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
board-7627a-all-objs += board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
-board-7627a-all-objs += board-msm7627a-display.o board-msm7627a-wlan.o
+board-7627a-all-objs += board-msm7627a-display.o board-msm7627a-wlan.o board-msm7627a-io.o
obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-7627a-all.o
@@ -260,9 +262,15 @@
obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o
obj-$(CONFIG_MACH_APQ8064_SIM) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
-obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o
+obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_MPQ8064_HRD) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_MACH_MPQ8064_DTV) += board-8064-all.o board-8064-regulator.o
+obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -334,3 +342,4 @@
obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
obj-$(CONFIG_MSM_RTB) += msm_rtb.o
obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
+obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 7ac2d9f..58c630e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -46,7 +46,7 @@
zreladdr-$(CONFIG_ARCH_APQ8064) := 0x80208000
# MSMCOPPER
- zreladdr-$(CONFIG_ARCH_MSMCOPPER) := 0x80208000
+ zreladdr-$(CONFIG_ARCH_MSMCOPPER) := 0x20208000
# MSM9615
zreladdr-$(CONFIG_ARCH_MSM9615) := 0x40808000
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 35e8eba..b6c0b26 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -171,7 +171,7 @@
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -186,7 +186,7 @@
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 120000 },
{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 120000 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -200,8 +200,8 @@
{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -215,8 +215,8 @@
{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -229,8 +229,8 @@
{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3, 61440 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
- { 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+ { 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -243,8 +243,8 @@
{ 1, 196608, ACPU_PLL_1, 1, 0, 24576, 3, 3, 98304 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
- { 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
+ { 0, 604800, ACPU_PLL_4, 6, 1, 75600, 3, 6, 160000 },
{ 1, 1209600, ACPU_PLL_4, 6, 0, 151200, 3, 7, 200000},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -273,7 +273,7 @@
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -288,7 +288,7 @@
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 120000 },
{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 120000 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -302,8 +302,8 @@
{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -317,8 +317,8 @@
{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 122880 },
{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
- { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
- { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
+ { 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 160000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 160000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
@@ -468,6 +468,10 @@
reg_clksel ^= 1;
writel_relaxed(reg_clksel, A11S_CLK_SEL_ADDR);
+ /* Wait for the clock switch to complete */
+ mb();
+ udelay(50);
+
/*
* If the new clock divider is lower than the previous, then
* program the divider after switching the clock
@@ -619,8 +623,6 @@
/* Adjust the global one */
loops_per_jiffy = cur_s->lpj;
- mb();
- udelay(50);
}
/* Nothing else to do for SWFI. */
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 54d2aa9..29b0065 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -461,6 +461,14 @@
BUG_ON(IS_ERR(acpuclk_sources[PLL_2]));
acpuclk_sources[PLL_3] = clk_get_sys("acpu", "pll3_clk");
BUG_ON(IS_ERR(acpuclk_sources[PLL_3]));
+ /*
+ * Prepare all the PLLs because we enable/disable them
+ * from atomic context and can't always ensure they're
+ * all prepared in non-atomic context.
+ */
+ BUG_ON(clk_prepare(acpuclk_sources[PLL_1]));
+ BUG_ON(clk_prepare(acpuclk_sources[PLL_2]));
+ BUG_ON(clk_prepare(acpuclk_sources[PLL_3]));
}
static struct acpuclk_data acpuclk_7x30_data = {
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index cbeac3f..051e165 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -36,6 +36,7 @@
#include <mach/rpm-regulator.h>
#include "acpuclock.h"
+#include "pm.h"
/*
* Source IDs.
@@ -377,10 +378,11 @@
},
};
-static struct scalable *scalable;
static struct l2_level *l2_freq_tbl;
static struct acpu_level *acpu_freq_tbl;
static int l2_freq_tbl_size;
+static struct scalable *scalable;
+#define SCALABLE_TO_CPU(sc) ((sc) - scalable)
/* Instantaneous bandwidth requests in MB/s. */
#define BW_MBPS(_bw) \
@@ -912,28 +914,37 @@
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
/*
- * If responding to CPU_DEAD we must be running on another
- * CPU. Therefore, we can't access the downed CPU's CP15
- * clock MUX registers from here and can't change clock sources.
- * Just turn off the PLL- since the CPU is down already, halting
- * its clock should be safe.
+ * If responding to CPU_DEAD we must be running on another CPU.
+ * Therefore, we can't access the downed CPU's clock MUX CP15
+ * registers from here and can't change clock sources. If the
+ * CPU is collapsed, however, it is still safe to turn off the
+ * PLL without switching the MUX away from it.
*/
if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
set_sec_clk_src(sc, tgt_s->sec_src_sel);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
+ hfpll_disable(sc, 0);
+ } else if (reason == SETRATE_HOTPLUG
+ && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
+ hfpll_disable(sc, 0);
}
- hfpll_disable(sc, 0);
} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
- hfpll_set_rate(sc, tgt_s);
- hfpll_enable(sc, 0);
/*
* If responding to CPU_UP_PREPARE, we can't change CP15
* registers for the CPU that's coming up since we're not
* running on that CPU. That's okay though, since the MUX
* source was not changed on the way down, either.
*/
- if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
+ if (reason != SETRATE_HOTPLUG || sc == &scalable[L2]) {
+ hfpll_set_rate(sc, tgt_s);
+ hfpll_enable(sc, 0);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
+ } else if (reason == SETRATE_HOTPLUG
+ && msm_pm_verify_cpu_pc(SCALABLE_TO_CPU(sc))) {
+ /* PLL was disabled during hot-unplug. Re-enable it. */
+ hfpll_set_rate(sc, tgt_s);
+ hfpll_enable(sc, 0);
+ }
} else {
if (reason != SETRATE_HOTPLUG || sc == &scalable[L2])
set_sec_clk_src(sc, tgt_s->sec_src_sel);
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 7339a4c..787483b 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -40,13 +40,12 @@
#define COMPLEX_SLEW 7
/* PLL calibration limits.
- * The PLL hardware is capable of 384MHz to 1536MHz. The L_VALs
- * used for calibration should respect these limits. */
+ * The PLL hardware has a minimum frequency of 384MHz.
+ * Calibration should respect this limit. */
#define L_VAL_SCPLL_CAL_MIN 0x08 /* = 432 MHz with 27MHz source */
-#define L_VAL_SCPLL_CAL_MAX 0x1C /* = 1512 MHz with 27MHz source */
-#define MAX_VDD_SC 1250000 /* uV */
-#define MAX_VDD_MEM 1250000 /* uV */
+#define MAX_VDD_SC 1325000 /* uV */
+#define MAX_VDD_MEM 1325000 /* uV */
#define MAX_VDD_DIG 1200000 /* uV */
#define MAX_AXI 310500 /* KHz */
#define SCPLL_LOW_VDD_FMAX 594000 /* KHz */
@@ -72,7 +71,7 @@
#define SCPLL_STATUS_OFFSET 0x10
#define SCPLL_CFG_OFFSET 0x1C
#define SCPLL_FSM_CTL_EXT_OFFSET 0x24
-#define SCPLL_LUT_A_HW_MAX (0x38 + ((L_VAL_SCPLL_CAL_MAX / 4) * 4))
+#define SCPLL_LUT_OFFSET(l_val) (0x38 + (((l_val) / 4) * 4))
/* Clock registers. */
#define SPSS0_CLK_CTL_ADDR (MSM_ACC0_BASE + 0x04)
@@ -218,6 +217,72 @@
};
/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_slowest[] = {
+ { {1, 1}, 192000, ACPU_PLL_8, 3, 1, 0, 0, L2(1), 800000, 0x03006000},
+ /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+ { {0, 0}, MAX_AXI, ACPU_AFAB, 1, 0, 0, 0, L2(0), 825000, 0x03006000},
+ { {1, 1}, 384000, ACPU_PLL_8, 3, 0, 0, 0, L2(1), 825000, 0x03006000},
+ { {1, 1}, 432000, ACPU_SCPLL, 0, 0, 1, 0x08, L2(1), 850000, 0x03006000},
+ { {1, 1}, 486000, ACPU_SCPLL, 0, 0, 1, 0x09, L2(2), 850000, 0x03006000},
+ { {1, 1}, 540000, ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3), 875000, 0x03006000},
+ { {1, 1}, 594000, ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4), 875000, 0x03006000},
+ { {1, 1}, 648000, ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5), 900000, 0x03006000},
+ { {1, 1}, 702000, ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6), 900000, 0x03006000},
+ { {1, 1}, 756000, ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7), 925000, 0x03006000},
+ { {1, 1}, 810000, ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8), 975000, 0x03006000},
+ { {1, 1}, 864000, ACPU_SCPLL, 0, 0, 1, 0x10, L2(9), 975000, 0x03006000},
+ { {1, 1}, 918000, ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
+ { {1, 1}, 972000, ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
+ { {1, 1}, 1026000, ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
+ { {1, 1}, 1080000, ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
+ { {1, 1}, 1134000, ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
+ { {1, 1}, 1188000, ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
+ { {1, 1}, 1242000, ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
+ { {1, 1}, 1296000, ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
+ { {1, 1}, 1350000, ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1175000, 0x03006000},
+ { {1, 1}, 1404000, ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1200000, 0x03006000},
+ { {1, 1}, 1458000, ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1225000, 0x03006000},
+ { {1, 1}, 1512000, ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1250000, 0x03006000},
+ { {1, 1}, 1566000, ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1275000, 0x03006000},
+ { {1, 1}, 1620000, ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1300000, 0x03006000},
+ { {1, 1}, 1674000, ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1325000, 0x03006000},
+ { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
+static struct clkctl_acpu_speed acpu_freq_tbl_slower[] = {
+ { {1, 1}, 192000, ACPU_PLL_8, 3, 1, 0, 0, L2(1), 800000, 0x03006000},
+ /* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
+ { {0, 0}, MAX_AXI, ACPU_AFAB, 1, 0, 0, 0, L2(0), 825000, 0x03006000},
+ { {1, 1}, 384000, ACPU_PLL_8, 3, 0, 0, 0, L2(1), 825000, 0x03006000},
+ { {1, 1}, 432000, ACPU_SCPLL, 0, 0, 1, 0x08, L2(1), 850000, 0x03006000},
+ { {1, 1}, 486000, ACPU_SCPLL, 0, 0, 1, 0x09, L2(2), 850000, 0x03006000},
+ { {1, 1}, 540000, ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3), 875000, 0x03006000},
+ { {1, 1}, 594000, ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4), 875000, 0x03006000},
+ { {1, 1}, 648000, ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5), 900000, 0x03006000},
+ { {1, 1}, 702000, ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6), 900000, 0x03006000},
+ { {1, 1}, 756000, ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7), 925000, 0x03006000},
+ { {1, 1}, 810000, ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8), 975000, 0x03006000},
+ { {1, 1}, 864000, ACPU_SCPLL, 0, 0, 1, 0x10, L2(9), 975000, 0x03006000},
+ { {1, 1}, 918000, ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1000000, 0x03006000},
+ { {1, 1}, 972000, ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1025000, 0x03006000},
+ { {1, 1}, 1026000, ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1025000, 0x03006000},
+ { {1, 1}, 1080000, ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1050000, 0x03006000},
+ { {1, 1}, 1134000, ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1075000, 0x03006000},
+ { {1, 1}, 1188000, ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1100000, 0x03006000},
+ { {1, 1}, 1242000, ACPU_SCPLL, 0, 0, 1, 0x17, L2(16), 1125000, 0x03006000},
+ { {1, 1}, 1296000, ACPU_SCPLL, 0, 0, 1, 0x18, L2(17), 1150000, 0x03006000},
+ { {1, 1}, 1350000, ACPU_SCPLL, 0, 0, 1, 0x19, L2(18), 1150000, 0x03006000},
+ { {1, 1}, 1404000, ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
+ { {1, 1}, 1458000, ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
+ { {1, 1}, 1512000, ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
+ { {1, 1}, 1566000, ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1250000, 0x03006000},
+ { {1, 1}, 1620000, ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1275000, 0x03006000},
+ { {1, 1}, 1674000, ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1300000, 0x03006000},
+ { {0, 0}, 0 },
+};
+
+/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
static struct clkctl_acpu_speed acpu_freq_tbl_slow[] = {
{ {1, 1}, 192000, ACPU_PLL_8, 3, 1, 0, 0, L2(1), 800000, 0x03006000},
/* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
@@ -244,6 +309,9 @@
{ {1, 1}, 1404000, ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1175000, 0x03006000},
{ {1, 1}, 1458000, ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1200000, 0x03006000},
{ {1, 1}, 1512000, ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1225000, 0x03006000},
+ { {1, 1}, 1566000, ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1225000, 0x03006000},
+ { {1, 1}, 1620000, ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1225000, 0x03006000},
+ { {1, 1}, 1674000, ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1250000, 0x03006000},
{ {0, 0}, 0 },
};
@@ -274,6 +342,9 @@
{ {1, 1}, 1404000, ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1150000, 0x03006000},
{ {1, 1}, 1458000, ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1150000, 0x03006000},
{ {1, 1}, 1512000, ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1175000, 0x03006000},
+ { {1, 1}, 1566000, ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1175000, 0x03006000},
+ { {1, 1}, 1620000, ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1200000, 0x03006000},
+ { {1, 1}, 1674000, ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1200000, 0x03006000},
{ {0, 0}, 0 },
};
@@ -304,6 +375,9 @@
{ {1, 1}, 1404000, ACPU_SCPLL, 0, 0, 1, 0x1A, L2(19), 1100000, 0x03006000},
{ {1, 1}, 1458000, ACPU_SCPLL, 0, 0, 1, 0x1B, L2(19), 1100000, 0x03006000},
{ {1, 1}, 1512000, ACPU_SCPLL, 0, 0, 1, 0x1C, L2(19), 1125000, 0x03006000},
+ { {1, 1}, 1566000, ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1125000, 0x03006000},
+ { {1, 1}, 1620000, ACPU_SCPLL, 0, 0, 1, 0x1E, L2(19), 1125000, 0x03006000},
+ { {1, 1}, 1674000, ACPU_SCPLL, 0, 0, 1, 0x1F, L2(19), 1150000, 0x03006000},
{ {0, 0}, 0 },
};
@@ -669,34 +743,29 @@
return rc;
}
-static void __init scpll_init(int sc_pll)
+static void __init scpll_init(int pll, unsigned int max_l_val)
{
uint32_t regval;
- pr_debug("Initializing SCPLL%d\n", sc_pll);
+ pr_debug("Initializing SCPLL%d\n", pll);
/* Clear calibration LUT registers containing max frequency entry.
* LUT registers are only writeable in debug mode. */
- writel_relaxed(SCPLL_DEBUG_FULL,
- sc_pll_base[sc_pll] + SCPLL_DEBUG_OFFSET);
- writel_relaxed(0x0, sc_pll_base[sc_pll] + SCPLL_LUT_A_HW_MAX);
- writel_relaxed(SCPLL_DEBUG_NONE,
- sc_pll_base[sc_pll] + SCPLL_DEBUG_OFFSET);
+ writel_relaxed(SCPLL_DEBUG_FULL, sc_pll_base[pll] + SCPLL_DEBUG_OFFSET);
+ writel_relaxed(0x0, sc_pll_base[pll] + SCPLL_LUT_OFFSET(max_l_val));
+ writel_relaxed(SCPLL_DEBUG_NONE, sc_pll_base[pll] + SCPLL_DEBUG_OFFSET);
/* Power-up SCPLL into standby mode. */
- writel_relaxed(SCPLL_STANDBY, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+ writel_relaxed(SCPLL_STANDBY, sc_pll_base[pll] + SCPLL_CTL_OFFSET);
mb();
udelay(10);
- /* Calibrate the SCPLL to the maximum range supported by the h/w. We
- * might not use the full range of calibrated frequencies, but this
- * simplifies changes required for future increases in max CPU freq.
- */
- regval = (L_VAL_SCPLL_CAL_MAX << 24) | (L_VAL_SCPLL_CAL_MIN << 16);
- writel_relaxed(regval, sc_pll_base[sc_pll] + SCPLL_CAL_OFFSET);
+ /* Calibrate the SCPLL for the frequency range needed. */
+ regval = (max_l_val << 24) | (L_VAL_SCPLL_CAL_MIN << 16);
+ writel_relaxed(regval, sc_pll_base[pll] + SCPLL_CAL_OFFSET);
/* Start calibration */
- writel_relaxed(SCPLL_FULL_CAL, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
+ writel_relaxed(SCPLL_FULL_CAL, sc_pll_base[pll] + SCPLL_CTL_OFFSET);
/* Wait for proof that calibration has started before checking the
* 'calibration done' bit in the status register. Waiting for the
@@ -704,15 +773,15 @@
* This is required since the 'calibration done' bit takes time to
* transition from 'done' to 'not done' when starting a calibration.
*/
- while (readl_relaxed(sc_pll_base[sc_pll] + SCPLL_LUT_A_HW_MAX) == 0)
+ while (!readl_relaxed(sc_pll_base[pll] + SCPLL_LUT_OFFSET(max_l_val)))
cpu_relax();
/* Wait for calibration to complete. */
- while (readl_relaxed(sc_pll_base[sc_pll] + SCPLL_STATUS_OFFSET) & 0x2)
+ while (readl_relaxed(sc_pll_base[pll] + SCPLL_STATUS_OFFSET) & 0x2)
cpu_relax();
/* Power-down SCPLL. */
- scpll_disable(sc_pll);
+ scpll_disable(pll);
}
/* Force ACPU core and L2 cache clocks to rates that don't require SCPLLs. */
@@ -859,7 +928,7 @@
.notifier_call = acpuclock_cpu_callback,
};
-static unsigned int __init select_freq_plan(void)
+static __init struct clkctl_acpu_speed *select_freq_plan(void)
{
uint32_t pte_efuse, speed_bin, pvs, max_khz;
struct clkctl_acpu_speed *f;
@@ -870,12 +939,41 @@
if (speed_bin == 0xF)
speed_bin = (pte_efuse >> 4) & 0xF;
- if (speed_bin == 0x1) {
- max_khz = 1512000;
- pvs = (pte_efuse >> 10) & 0x7;
- if (pvs == 0x7)
- pvs = (pte_efuse >> 13) & 0x7;
+ pvs = (pte_efuse >> 10) & 0x7;
+ if (pvs == 0x7)
+ pvs = (pte_efuse >> 13) & 0x7;
+ if (speed_bin == 0x2) {
+ max_khz = 1674000;
+ switch (pvs) {
+ case 0x7:
+ case 0x5:
+ acpu_freq_tbl = acpu_freq_tbl_slowest;
+ pr_info("ACPU PVS: Slowest\n");
+ break;
+ case 0x4:
+ acpu_freq_tbl = acpu_freq_tbl_slower;
+ pr_info("ACPU PVS: Slower\n");
+ break;
+ case 0x0:
+ acpu_freq_tbl = acpu_freq_tbl_slow;
+ pr_info("ACPU PVS: Slow\n");
+ break;
+ case 0x1:
+ acpu_freq_tbl = acpu_freq_tbl_nom;
+ pr_info("ACPU PVS: Nominal\n");
+ break;
+ case 0x3:
+ acpu_freq_tbl = acpu_freq_tbl_fast;
+ pr_info("ACPU PVS: Fast\n");
+ break;
+ default:
+ acpu_freq_tbl = acpu_freq_tbl_slowest;
+ pr_warn("ACPU PVS: Unknown. Defaulting to slowest.\n");
+ break;
+ }
+ } else if (speed_bin == 0x1) {
+ max_khz = 1512000;
switch (pvs) {
case 0x0:
case 0x7:
@@ -910,7 +1008,7 @@
f--;
pr_info("Max ACPU freq: %u KHz\n", f->acpuclk_khz);
- return f->acpuclk_khz;
+ return f;
}
static struct acpuclk_data acpuclk_8x60_data = {
@@ -922,25 +1020,25 @@
static int __init acpuclk_8x60_init(struct acpuclk_soc_data *soc_data)
{
- unsigned int max_cpu_khz;
+ struct clkctl_acpu_speed *max_freq;
int cpu;
mutex_init(&drv_state.lock);
spin_lock_init(&drv_state.l2_lock);
/* Configure hardware. */
- max_cpu_khz = select_freq_plan();
+ max_freq = select_freq_plan();
unselect_scplls();
scpll_set_refs();
for_each_possible_cpu(cpu)
- scpll_init(cpu);
- scpll_init(L2);
+ scpll_init(cpu, max_freq->l_val);
+ scpll_init(L2, max_freq->l2_level->l_val);
regulator_init();
bus_init();
/* Improve boot time by ramping up CPUs immediately. */
for_each_online_cpu(cpu)
- acpuclk_8x60_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
+ acpuclk_8x60_set_rate(cpu, max_freq->acpuclk_khz, SETRATE_INIT);
acpuclk_register(&acpuclk_8x60_data);
cpufreq_table_init();
diff --git a/arch/arm/mach-msm/acpuclock-copper.c b/arch/arm/mach-msm/acpuclock-copper.c
new file mode 100644
index 0000000..1a02c06
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-copper.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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/platform_device.h>
+#include <linux/of.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include <mach/socinfo.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* Corner type vreg VDD values */
+#define LVL_NONE RPM_VREG_CORNER_NONE
+#define LVL_LOW RPM_VREG_CORNER_LOW
+#define LVL_NOM RPM_VREG_CORNER_NOMINAL
+#define LVL_HIGH RPM_VREG_CORNER_HIGH
+
+static struct hfpll_data hfpll_data_cpu = {
+ .mode_offset = 0x00,
+ .l_offset = 0x04,
+ .m_offset = 0x08,
+ .n_offset = 0x0C,
+ .config_offset = 0x14,
+ /* TODO: Verify magic number for copper when available. */
+ .config_val = 0x7845C665,
+ .low_vdd_l_max = 52,
+ .vdd[HFPLL_VDD_NONE] = 0,
+ .vdd[HFPLL_VDD_LOW] = 810000,
+ .vdd[HFPLL_VDD_NOM] = 900000,
+};
+
+static struct hfpll_data hfpll_data_l2 = {
+ .mode_offset = 0x00,
+ .l_offset = 0x04,
+ .m_offset = 0x08,
+ .n_offset = 0x0C,
+ .config_offset = 0x14,
+ /* TODO: Verify magic number for copper when available. */
+ .config_val = 0x7845C665,
+ .low_vdd_l_max = 52,
+ .vdd[HFPLL_VDD_NONE] = LVL_NONE,
+ .vdd[HFPLL_VDD_LOW] = LVL_LOW,
+ .vdd[HFPLL_VDD_NOM] = LVL_NOM,
+};
+
+static struct scalable scalable[] = {
+ [CPU0] = {
+ .hfpll_phys_base = 0xF908A000,
+ .hfpll_data = &hfpll_data_cpu,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1050000, 3200000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1050000, 0,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8941_S1 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1050000, 0,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8941_S2 },
+ .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+ RPM_VREG_VOTER1,
+ RPM_VREG_ID_PM8941_L12 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0xF909A000,
+ .hfpll_data = &hfpll_data_cpu,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1050000, 3200000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1050000, 0,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8941_S1 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1050000, 0,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8941_S2 },
+ .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+ RPM_VREG_VOTER2,
+ RPM_VREG_ID_PM8941_L12 },
+ },
+ [CPU2] = {
+ .hfpll_phys_base = 0xF90AA000,
+ .hfpll_data = &hfpll_data_cpu,
+ .l2cpmr_iaddr = 0x6501,
+ .vreg[VREG_CORE] = { "krait2", 1050000, 3200000 },
+ .vreg[VREG_MEM] = { "krait2_mem", 1050000, 0,
+ RPM_VREG_VOTER4,
+ RPM_VREG_ID_PM8921_S1 },
+ .vreg[VREG_DIG] = { "krait2_dig", 1050000, 0,
+ RPM_VREG_VOTER4,
+ RPM_VREG_ID_PM8921_S2 },
+ .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+ RPM_VREG_VOTER4,
+ RPM_VREG_ID_PM8941_L12 },
+ },
+ [CPU3] = {
+ .hfpll_phys_base = 0xF90BA000,
+ .hfpll_data = &hfpll_data_cpu,
+ .l2cpmr_iaddr = 0x7501,
+ .vreg[VREG_CORE] = { "krait3", 1050000, 3200000 },
+ .vreg[VREG_MEM] = { "krait3_mem", 1050000, 0,
+ RPM_VREG_VOTER5,
+ RPM_VREG_ID_PM8941_S1 },
+ .vreg[VREG_DIG] = { "krait3_dig", 1050000, 0,
+ RPM_VREG_VOTER5,
+ RPM_VREG_ID_PM8941_S2 },
+ .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+ RPM_VREG_VOTER5,
+ RPM_VREG_ID_PM8941_L12 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0xF9016000,
+ .hfpll_data = &hfpll_data_l2,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "hfpll", 1800000, 0,
+ RPM_VREG_VOTER6,
+ RPM_VREG_ID_PM8941_L12 },
+ },
+};
+
+static struct msm_bus_paths bw_level_tbl[] = {
+ [0] = BW_MBPS(400), /* At least 50 MHz on bus. */
+ [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
+ [2] = BW_MBPS(1334), /* At least 167 MHz on bus. */
+ [3] = BW_MBPS(2666), /* At least 200 MHz on bus. */
+ [4] = BW_MBPS(3200), /* At least 333 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclk-copper",
+};
+
+#define L2(x) (&l2_freq_tbl[(x)])
+static struct l2_level l2_freq_tbl[] = {
+ [0] = { {STBY_KHZ, QSB, 0, 0, 0 }, LVL_NOM, 1050000, 0 },
+ [1] = { { 300000, PLL_0, 0, 2, 0 }, LVL_NOM, 1050000, 2 },
+ [2] = { { 384000, HFPLL, 2, 0, 40 }, LVL_NOM, 1050000, 2 },
+ [3] = { { 460800, HFPLL, 2, 0, 48 }, LVL_NOM, 1050000, 2 },
+ [4] = { { 537600, HFPLL, 1, 0, 28 }, LVL_NOM, 1050000, 2 },
+ [5] = { { 576000, HFPLL, 1, 0, 30 }, LVL_NOM, 1050000, 3 },
+ [6] = { { 652800, HFPLL, 1, 0, 34 }, LVL_NOM, 1050000, 3 },
+ [7] = { { 729600, HFPLL, 1, 0, 38 }, LVL_NOM, 1050000, 3 },
+ [8] = { { 806400, HFPLL, 1, 0, 42 }, LVL_NOM, 1050000, 3 },
+ [9] = { { 883200, HFPLL, 1, 0, 46 }, LVL_NOM, 1050000, 4 },
+ [10] = { { 960000, HFPLL, 1, 0, 50 }, LVL_NOM, 1050000, 4 },
+ [11] = { { 1036800, HFPLL, 1, 0, 54 }, LVL_NOM, 1050000, 4 },
+};
+
+static struct acpu_level acpu_freq_tbl[] = {
+ { 0, {STBY_KHZ, QSB, 0, 0, 0 }, L2(0), 1050000 },
+ { 1, { 300000, PLL_0, 0, 2, 0 }, L2(1), 1050000 },
+ { 1, { 384000, HFPLL, 2, 0, 40 }, L2(2), 1050000 },
+ { 1, { 460800, HFPLL, 2, 0, 48 }, L2(3), 1050000 },
+ { 1, { 537600, HFPLL, 1, 0, 28 }, L2(4), 1050000 },
+ { 1, { 576000, HFPLL, 1, 0, 30 }, L2(5), 1050000 },
+ { 1, { 652800, HFPLL, 1, 0, 34 }, L2(6), 1050000 },
+ { 1, { 729600, HFPLL, 1, 0, 38 }, L2(7), 1050000 },
+ { 1, { 806400, HFPLL, 1, 0, 42 }, L2(8), 1050000 },
+ { 1, { 883200, HFPLL, 1, 0, 46 }, L2(9), 1050000 },
+ { 1, { 960000, HFPLL, 1, 0, 50 }, L2(10), 1050000 },
+ { 1, { 1036800, HFPLL, 1, 0, 54 }, L2(11), 1050000 },
+ { 0, { 0 } }
+};
+
+static struct acpuclk_krait_params acpuclk_copper_params = {
+ .scalable = scalable,
+ .pvs_acpu_freq_tbl[PVS_SLOW] = acpu_freq_tbl,
+ .pvs_acpu_freq_tbl[PVS_NOMINAL] = acpu_freq_tbl,
+ .pvs_acpu_freq_tbl[PVS_FAST] = acpu_freq_tbl,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl),
+ .bus_scale_data = &bus_scale_data,
+ .qfprom_phys_base = 0xFC4A8000,
+};
+
+static int __init acpuclk_copper_probe(struct platform_device *pdev)
+{
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_copper_params);
+}
+
+static struct of_device_id acpuclk_copper_match_table[] = {
+ { .compatible = "qcom,acpuclk-copper" },
+ {}
+};
+
+static struct platform_driver acpuclk_copper_driver = {
+ .driver = {
+ .name = "acpuclk-copper",
+ .of_match_table = acpuclk_copper_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acpuclk_8960_init(void)
+{
+ return platform_driver_probe(&acpuclk_copper_driver,
+ acpuclk_copper_probe);
+}
+device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
new file mode 100644
index 0000000..5682ac3
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+#include <asm/cpu.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+/* MUX source selects. */
+#define PRI_SRC_SEL_SEC_SRC 0
+#define PRI_SRC_SEL_HFPLL 1
+#define PRI_SRC_SEL_HFPLL_DIV2 2
+#define SEC_SRC_SEL_QSB 0
+#define SEC_SRC_SEL_L2PLL 1
+#define SEC_SRC_SEL_AUX 2
+
+/* PTE EFUSE register offset. */
+#define PTE_EFUSE 0xC0
+
+static DEFINE_MUTEX(driver_lock);
+static DEFINE_SPINLOCK(l2_lock);
+
+static struct drv_data {
+ const struct acpu_level *acpu_freq_tbl;
+ const struct l2_level *l2_freq_tbl;
+ struct scalable *scalable;
+ u32 bus_perf_client;
+ struct device *dev;
+} drv;
+
+static unsigned long acpuclk_krait_get_rate(int cpu)
+{
+ return drv.scalable[cpu].cur_speed->khz;
+}
+
+/* Select a source on the primary MUX. */
+static void set_pri_clk_src(struct scalable *sc, u32 pri_src_sel)
+{
+ u32 regval;
+
+ regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+ regval &= ~0x3;
+ regval |= (pri_src_sel & 0x3);
+ set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+ /* Wait for switch to complete. */
+ mb();
+ udelay(1);
+}
+
+/* Select a source on the secondary MUX. */
+static void set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
+{
+ u32 regval;
+
+ regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+ regval &= ~(0x3 << 2);
+ regval |= ((sec_src_sel & 0x3) << 2);
+ set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+ /* Wait for switch to complete. */
+ mb();
+ udelay(1);
+}
+
+/* Enable an already-configured HFPLL. */
+static void hfpll_enable(struct scalable *sc, bool skip_regulators)
+{
+ int rc;
+
+ if (!skip_regulators) {
+ /* Enable regulators required by the HFPLL. */
+ if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
+ rc = rpm_vreg_set_voltage(
+ sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+ sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+ sc->vreg[VREG_HFPLL_A].cur_vdd,
+ sc->vreg[VREG_HFPLL_A].max_vdd, 0);
+ if (rc)
+ dev_err(drv.dev,
+ "%s regulator enable failed (%d)\n",
+ sc->vreg[VREG_HFPLL_A].name, rc);
+ }
+ if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
+ rc = rpm_vreg_set_voltage(
+ sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+ sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
+ sc->vreg[VREG_HFPLL_B].cur_vdd,
+ sc->vreg[VREG_HFPLL_B].max_vdd, 0);
+ if (rc)
+ dev_err(drv.dev,
+ "%s regulator enable failed (%d)\n",
+ sc->vreg[VREG_HFPLL_B].name, rc);
+ }
+ }
+
+ /* Disable PLL bypass mode. */
+ writel_relaxed(0x2, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ mb();
+ udelay(10);
+
+ /* De-assert active-low PLL reset. */
+ writel_relaxed(0x6, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+ /* Wait for PLL to lock. */
+ mb();
+ udelay(60);
+
+ /* Enable PLL output. */
+ writel_relaxed(0x7, sc->hfpll_base + sc->hfpll_data->mode_offset);
+}
+
+/* Disable a HFPLL for power-savings or while it's being reprogrammed. */
+static void hfpll_disable(struct scalable *sc, bool skip_regulators)
+{
+ int rc;
+
+ /*
+ * Disable the PLL output, disable test mode, enable the bypass mode,
+ * and assert the reset.
+ */
+ writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->mode_offset);
+
+ if (!skip_regulators) {
+ /* Remove voltage votes required by the HFPLL. */
+ if (sc->vreg[VREG_HFPLL_B].rpm_vreg_id) {
+ rc = rpm_vreg_set_voltage(
+ sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
+ sc->vreg[VREG_HFPLL_B].rpm_vreg_voter,
+ 0, 0, 0);
+ if (rc)
+ dev_err(drv.dev,
+ "%s regulator enable failed (%d)\n",
+ sc->vreg[VREG_HFPLL_B].name, rc);
+ }
+ if (sc->vreg[VREG_HFPLL_A].rpm_vreg_id) {
+ rc = rpm_vreg_set_voltage(
+ sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+ sc->vreg[VREG_HFPLL_A].rpm_vreg_voter,
+ 0, 0, 0);
+ if (rc)
+ dev_err(drv.dev,
+ "%s regulator enable failed (%d)\n",
+ sc->vreg[VREG_HFPLL_A].name, rc);
+ }
+ }
+}
+
+/* Program the HFPLL rate. Assumes HFPLL is already disabled. */
+static void hfpll_set_rate(struct scalable *sc, const struct core_speed *tgt_s)
+{
+ writel_relaxed(tgt_s->pll_l_val,
+ sc->hfpll_base + sc->hfpll_data->l_offset);
+}
+
+/* Return the L2 speed that should be applied. */
+static const struct l2_level *compute_l2_level(struct scalable *sc,
+ const struct l2_level *vote_l)
+{
+ const struct l2_level *new_l;
+ int cpu;
+
+ /* Find max L2 speed vote. */
+ sc->l2_vote = vote_l;
+ new_l = drv.l2_freq_tbl;
+ for_each_present_cpu(cpu)
+ new_l = max(new_l, drv.scalable[cpu].l2_vote);
+
+ return new_l;
+}
+
+/* Update the bus bandwidth request. */
+static void set_bus_bw(unsigned int bw)
+{
+ int ret;
+
+ /* Update bandwidth if request has changed. This may sleep. */
+ ret = msm_bus_scale_client_update_request(drv.bus_perf_client, bw);
+ if (ret)
+ dev_err(drv.dev, "bandwidth request failed (%d)\n", ret);
+}
+
+/* Set the CPU or L2 clock speed. */
+static void set_speed(struct scalable *sc, const struct core_speed *tgt_s)
+{
+ const struct core_speed *strt_s = sc->cur_speed;
+
+ if (strt_s->src == HFPLL && tgt_s->src == HFPLL) {
+ /*
+ * Move to an always-on source running at a frequency
+ * that does not require an elevated CPU voltage.
+ */
+ set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+ set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+
+ /* Re-program HFPLL. */
+ hfpll_disable(sc, 1);
+ hfpll_set_rate(sc, tgt_s);
+ hfpll_enable(sc, 1);
+
+ /* Move to HFPLL. */
+ set_pri_clk_src(sc, tgt_s->pri_src_sel);
+ } else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
+ set_sec_clk_src(sc, tgt_s->sec_src_sel);
+ set_pri_clk_src(sc, tgt_s->pri_src_sel);
+ hfpll_disable(sc, 0);
+ } else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
+ hfpll_set_rate(sc, tgt_s);
+ hfpll_enable(sc, 0);
+ set_pri_clk_src(sc, tgt_s->pri_src_sel);
+ } else {
+ set_sec_clk_src(sc, tgt_s->sec_src_sel);
+ }
+
+ sc->cur_speed = tgt_s;
+}
+
+/* Apply any per-cpu voltage increases. */
+static int increase_vdd(int cpu, int vdd_core, int vdd_mem, int vdd_dig,
+ enum setrate_reason reason)
+{
+ struct scalable *sc = &drv.scalable[cpu];
+ int rc = 0;
+
+ /*
+ * Increase vdd_mem active-set before vdd_dig.
+ * vdd_mem should be >= vdd_dig.
+ */
+ if (vdd_mem > sc->vreg[VREG_MEM].cur_vdd) {
+ rc = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+ sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+ sc->vreg[VREG_MEM].max_vdd, 0);
+ if (rc) {
+ dev_err(drv.dev,
+ "vdd_mem (cpu%d) increase failed (%d)\n",
+ cpu, rc);
+ return rc;
+ }
+ sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+ }
+
+ /* Increase vdd_dig active-set vote. */
+ if (vdd_dig > sc->vreg[VREG_DIG].cur_vdd) {
+ rc = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+ sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+ sc->vreg[VREG_DIG].max_vdd, 0);
+ if (rc) {
+ dev_err(drv.dev,
+ "vdd_dig (cpu%d) increase failed (%d)\n",
+ cpu, rc);
+ return rc;
+ }
+ sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+ }
+
+ /*
+ * Update per-CPU core voltage. Don't do this for the hotplug path for
+ * which it should already be correct. Attempting to set it is bad
+ * because we don't know what CPU we are running on at this point, but
+ * the CPU regulator API requires we call it from the affected CPU.
+ */
+ if (vdd_core > sc->vreg[VREG_CORE].cur_vdd
+ && reason != SETRATE_HOTPLUG) {
+ rc = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+ sc->vreg[VREG_CORE].max_vdd);
+ if (rc) {
+ dev_err(drv.dev,
+ "vdd_core (cpu%d) increase failed (%d)\n",
+ cpu, rc);
+ return rc;
+ }
+ sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+ }
+
+ return rc;
+}
+
+/* Apply any per-cpu voltage decreases. */
+static void decrease_vdd(int cpu, int vdd_core, int vdd_mem, int vdd_dig,
+ enum setrate_reason reason)
+{
+ struct scalable *sc = &drv.scalable[cpu];
+ int ret;
+
+ /*
+ * Update per-CPU core voltage. This must be called on the CPU
+ * that's being affected. Don't do this in the hotplug remove path,
+ * where the rail is off and we're executing on the other CPU.
+ */
+ if (vdd_core < sc->vreg[VREG_CORE].cur_vdd
+ && reason != SETRATE_HOTPLUG) {
+ ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+ sc->vreg[VREG_CORE].max_vdd);
+ if (ret) {
+ dev_err(drv.dev,
+ "vdd_core (cpu%d) decrease failed (%d)\n",
+ cpu, ret);
+ return;
+ }
+ sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+ }
+
+ /* Decrease vdd_dig active-set vote. */
+ if (vdd_dig < sc->vreg[VREG_DIG].cur_vdd) {
+ ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+ sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+ sc->vreg[VREG_DIG].max_vdd, 0);
+ if (ret) {
+ dev_err(drv.dev,
+ "vdd_dig (cpu%d) decrease failed (%d)\n",
+ cpu, ret);
+ return;
+ }
+ sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+ }
+
+ /*
+ * Decrease vdd_mem active-set after vdd_dig.
+ * vdd_mem should be >= vdd_dig.
+ */
+ if (vdd_mem < sc->vreg[VREG_MEM].cur_vdd) {
+ ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+ sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+ sc->vreg[VREG_MEM].max_vdd, 0);
+ if (ret) {
+ dev_err(drv.dev,
+ "vdd_mem (cpu%d) decrease failed (%d)\n",
+ cpu, ret);
+ return;
+ }
+ sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+ }
+}
+
+static int calculate_vdd_mem(const struct acpu_level *tgt)
+{
+ return tgt->l2_level->vdd_mem;
+}
+
+static int calculate_vdd_dig(const struct acpu_level *tgt)
+{
+ int pll_vdd_dig;
+ const int *hfpll_vdd = drv.scalable[L2].hfpll_data->vdd;
+ const u32 low_vdd_l_max = drv.scalable[L2].hfpll_data->low_vdd_l_max;
+
+ if (tgt->l2_level->speed.src != HFPLL)
+ pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NONE];
+ else if (tgt->l2_level->speed.pll_l_val > low_vdd_l_max)
+ pll_vdd_dig = hfpll_vdd[HFPLL_VDD_NOM];
+ else
+ pll_vdd_dig = hfpll_vdd[HFPLL_VDD_LOW];
+
+ return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
+}
+
+static int calculate_vdd_core(const struct acpu_level *tgt)
+{
+ return tgt->vdd_core;
+}
+
+/* Set the CPU's clock rate and adjust the L2 rate, voltage and BW requests. */
+static int acpuclk_krait_set_rate(int cpu, unsigned long rate,
+ enum setrate_reason reason)
+{
+ const struct core_speed *strt_acpu_s, *tgt_acpu_s;
+ const struct l2_level *tgt_l2_l;
+ const struct acpu_level *tgt;
+ int vdd_mem, vdd_dig, vdd_core;
+ unsigned long flags;
+ int rc = 0;
+
+ if (cpu > num_possible_cpus()) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+ mutex_lock(&driver_lock);
+
+ strt_acpu_s = drv.scalable[cpu].cur_speed;
+
+ /* Return early if rate didn't change. */
+ if (rate == strt_acpu_s->khz)
+ goto out;
+
+ /* Find target frequency. */
+ for (tgt = drv.acpu_freq_tbl; tgt->speed.khz != 0; tgt++) {
+ if (tgt->speed.khz == rate) {
+ tgt_acpu_s = &tgt->speed;
+ break;
+ }
+ }
+ if (tgt->speed.khz == 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Calculate voltage requirements for the current CPU. */
+ vdd_mem = calculate_vdd_mem(tgt);
+ vdd_dig = calculate_vdd_dig(tgt);
+ vdd_core = calculate_vdd_core(tgt);
+
+ /* Increase VDD levels if needed. */
+ if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG) {
+ rc = increase_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+ if (rc)
+ goto out;
+ }
+
+ pr_debug("Switching from ACPU%d rate %lu KHz -> %lu KHz\n",
+ cpu, strt_acpu_s->khz, tgt_acpu_s->khz);
+
+ /* Set the new CPU speed. */
+ set_speed(&drv.scalable[cpu], tgt_acpu_s);
+
+ /*
+ * Update the L2 vote and apply the rate change. A spinlock is
+ * necessary to ensure L2 rate is calculated and set atomically
+ * with the CPU frequency, even if acpuclk_krait_set_rate() is
+ * called from an atomic context and the driver_lock mutex is not
+ * acquired.
+ */
+ spin_lock_irqsave(&l2_lock, flags);
+ tgt_l2_l = compute_l2_level(&drv.scalable[cpu], tgt->l2_level);
+ set_speed(&drv.scalable[L2], &tgt_l2_l->speed);
+ spin_unlock_irqrestore(&l2_lock, flags);
+
+ /* Nothing else to do for power collapse or SWFI. */
+ if (reason == SETRATE_PC || reason == SETRATE_SWFI)
+ goto out;
+
+ /* Update bus bandwith request. */
+ set_bus_bw(tgt_l2_l->bw_level);
+
+ /* Drop VDD levels if we can. */
+ decrease_vdd(cpu, vdd_core, vdd_mem, vdd_dig, reason);
+
+ pr_debug("ACPU%d speed change complete\n", cpu);
+
+out:
+ if (reason == SETRATE_CPUFREQ || reason == SETRATE_HOTPLUG)
+ mutex_unlock(&driver_lock);
+ return rc;
+}
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __init hfpll_init(struct scalable *sc,
+ const struct core_speed *tgt_s)
+{
+ pr_debug("Initializing HFPLL%d\n", sc - drv.scalable);
+
+ /* Disable the PLL for re-programming. */
+ hfpll_disable(sc, 1);
+
+ /* Configure PLL parameters for integer mode. */
+ writel_relaxed(sc->hfpll_data->config_val,
+ sc->hfpll_base + sc->hfpll_data->config_offset);
+ writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
+ writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+
+ /* Set an initial rate and enable the PLL. */
+ hfpll_set_rate(sc, tgt_s);
+ hfpll_enable(sc, 0);
+}
+
+/* Voltage regulator initialization. */
+static void __init regulator_init(const struct acpu_level *lvl)
+{
+ int cpu, ret;
+ struct scalable *sc;
+ int vdd_mem, vdd_dig, vdd_core;
+
+ vdd_mem = calculate_vdd_mem(lvl);
+ vdd_dig = calculate_vdd_dig(lvl);
+
+ for_each_possible_cpu(cpu) {
+ sc = &drv.scalable[cpu];
+
+ /* Set initial vdd_mem vote. */
+ ret = rpm_vreg_set_voltage(sc->vreg[VREG_MEM].rpm_vreg_id,
+ sc->vreg[VREG_MEM].rpm_vreg_voter, vdd_mem,
+ sc->vreg[VREG_MEM].max_vdd, 0);
+ if (ret) {
+ dev_err(drv.dev, "%s initialization failed (%d)\n",
+ sc->vreg[VREG_MEM].name, ret);
+ BUG();
+ }
+ sc->vreg[VREG_MEM].cur_vdd = vdd_mem;
+
+ /* Set initial vdd_dig vote. */
+ ret = rpm_vreg_set_voltage(sc->vreg[VREG_DIG].rpm_vreg_id,
+ sc->vreg[VREG_DIG].rpm_vreg_voter, vdd_dig,
+ sc->vreg[VREG_DIG].max_vdd, 0);
+ if (ret) {
+ dev_err(drv.dev, "%s initialization failed (%d)\n",
+ sc->vreg[VREG_DIG].name, ret);
+ BUG();
+ }
+ sc->vreg[VREG_DIG].cur_vdd = vdd_dig;
+
+ /* Setup Krait CPU regulators and initial core voltage. */
+ sc->vreg[VREG_CORE].reg = regulator_get(NULL,
+ sc->vreg[VREG_CORE].name);
+ if (IS_ERR(sc->vreg[VREG_CORE].reg)) {
+ dev_err(drv.dev, "regulator_get(%s) failed (%ld)\n",
+ sc->vreg[VREG_CORE].name,
+ PTR_ERR(sc->vreg[VREG_CORE].reg));
+ BUG();
+ }
+ vdd_core = calculate_vdd_core(lvl);
+ ret = regulator_set_voltage(sc->vreg[VREG_CORE].reg, vdd_core,
+ sc->vreg[VREG_CORE].max_vdd);
+ if (ret) {
+ dev_err(drv.dev, "regulator_set_voltage(%s) (%d)\n",
+ sc->vreg[VREG_CORE].name, ret);
+ BUG();
+ }
+ sc->vreg[VREG_CORE].cur_vdd = vdd_core;
+ ret = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+ sc->vreg[VREG_CORE].peak_ua);
+ if (ret < 0) {
+ dev_err(drv.dev, "regulator_set_optimum_mode(%s) failed"
+ " (%d)\n", sc->vreg[VREG_CORE].name, ret);
+ BUG();
+ }
+ ret = regulator_enable(sc->vreg[VREG_CORE].reg);
+ if (ret) {
+ dev_err(drv.dev, "regulator_enable(%s) failed (%d)\n",
+ sc->vreg[VREG_CORE].name, ret);
+ BUG();
+ }
+ }
+}
+
+/* Set initial rate for a given core. */
+static void __init init_clock_sources(struct scalable *sc,
+ const struct core_speed *tgt_s)
+{
+ u32 regval;
+
+ /* Program AUX source input to the secondary MUX. */
+ if (sc->aux_clk_sel_addr)
+ writel_relaxed(sc->aux_clk_sel, sc->aux_clk_sel_addr);
+
+ /* Switch away from the HFPLL while it's re-initialized. */
+ set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+ set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
+ hfpll_init(sc, tgt_s);
+
+ /* Set PRI_SRC_SEL_HFPLL_DIV2 divider to div-2. */
+ regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+ regval &= ~(0x3 << 6);
+ set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+ /* Switch to the target clock source. */
+ set_sec_clk_src(sc, tgt_s->sec_src_sel);
+ set_pri_clk_src(sc, tgt_s->pri_src_sel);
+ sc->cur_speed = tgt_s;
+}
+
+static void __init per_cpu_init(int cpu, const struct acpu_level *max_level)
+{
+ drv.scalable[cpu].hfpll_base =
+ ioremap(drv.scalable[cpu].hfpll_phys_base, SZ_32);
+ BUG_ON(!drv.scalable[cpu].hfpll_base);
+
+ init_clock_sources(&drv.scalable[cpu], &max_level->speed);
+ drv.scalable[cpu].l2_vote = max_level->l2_level;
+}
+
+/* Register with bus driver. */
+static void __init bus_init(struct msm_bus_scale_pdata *bus_scale_data,
+ unsigned int init_bw)
+{
+ int ret;
+
+ drv.bus_perf_client = msm_bus_scale_register_client(bus_scale_data);
+ if (!drv.bus_perf_client) {
+ dev_err(drv.dev, "unable to register bus client\n");
+ BUG();
+ }
+
+ ret = msm_bus_scale_client_update_request(drv.bus_perf_client, init_bw);
+ if (ret)
+ dev_err(drv.dev, "initial bandwidth req failed (%d)\n", ret);
+}
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[NR_CPUS][35];
+
+static void __init cpufreq_table_init(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ int i, freq_cnt = 0;
+ /* Construct the freq_table tables from acpu_freq_tbl. */
+ for (i = 0; drv.acpu_freq_tbl[i].speed.khz != 0
+ && freq_cnt < ARRAY_SIZE(*freq_table); i++) {
+ if (drv.acpu_freq_tbl[i].use_for_scaling) {
+ freq_table[cpu][freq_cnt].index = freq_cnt;
+ freq_table[cpu][freq_cnt].frequency
+ = drv.acpu_freq_tbl[i].speed.khz;
+ freq_cnt++;
+ }
+ }
+ /* freq_table not big enough to store all usable freqs. */
+ BUG_ON(drv.acpu_freq_tbl[i].speed.khz != 0);
+
+ freq_table[cpu][freq_cnt].index = freq_cnt;
+ freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+ dev_info(drv.dev, "CPU%d: %d frequencies supported\n",
+ cpu, freq_cnt);
+
+ /* Register table with CPUFreq. */
+ cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
+ }
+}
+#else
+static void __init cpufreq_table_init(void) {}
+#endif
+
+#define HOT_UNPLUG_KHZ STBY_KHZ
+static int __cpuinit acpuclk_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ static int prev_khz[NR_CPUS];
+ int rc, cpu = (int)hcpu;
+ struct scalable *sc = &drv.scalable[cpu];
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DEAD:
+ prev_khz[cpu] = acpuclk_krait_get_rate(cpu);
+ /* Fall through. */
+ case CPU_UP_CANCELED:
+ acpuclk_krait_set_rate(cpu, HOT_UNPLUG_KHZ, SETRATE_HOTPLUG);
+ regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg, 0);
+ break;
+ case CPU_UP_PREPARE:
+ if (WARN_ON(!prev_khz[cpu]))
+ return NOTIFY_BAD;
+ rc = regulator_set_optimum_mode(sc->vreg[VREG_CORE].reg,
+ sc->vreg[VREG_CORE].peak_ua);
+ if (rc < 0)
+ return NOTIFY_BAD;
+ acpuclk_krait_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata acpuclk_cpu_notifier = {
+ .notifier_call = acpuclk_cpu_callback,
+};
+
+static const struct acpu_level __init *select_freq_plan(
+ const struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
+{
+ const struct acpu_level *l, *max_acpu_level = NULL;
+ void __iomem *qfprom_base;
+ u32 pte_efuse, pvs, tbl_idx;
+ char *pvs_names[] = { "Slow", "Nominal", "Fast", "Unknown" };
+
+ qfprom_base = ioremap(qfprom_phys, SZ_256);
+ /* Select frequency tables. */
+ if (qfprom_base) {
+ pte_efuse = readl_relaxed(qfprom_base + PTE_EFUSE);
+ pvs = (pte_efuse >> 10) & 0x7;
+ iounmap(qfprom_base);
+ if (pvs == 0x7)
+ pvs = (pte_efuse >> 13) & 0x7;
+
+ switch (pvs) {
+ case 0x0:
+ case 0x7:
+ tbl_idx = PVS_SLOW;
+ break;
+ case 0x1:
+ tbl_idx = PVS_NOMINAL;
+ break;
+ case 0x3:
+ tbl_idx = PVS_FAST;
+ break;
+ default:
+ tbl_idx = PVS_UNKNOWN;
+ break;
+ }
+ } else {
+ tbl_idx = PVS_UNKNOWN;
+ dev_err(drv.dev, "Unable to map QFPROM base\n");
+ }
+ dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
+ if (tbl_idx == PVS_UNKNOWN) {
+ tbl_idx = PVS_SLOW;
+ dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
+ pvs_names[tbl_idx]);
+ }
+ drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
+
+ /* Find the max supported scaling frequency. */
+ for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
+ if (l->use_for_scaling)
+ max_acpu_level = l;
+ BUG_ON(!max_acpu_level);
+ dev_info(drv.dev, "Max ACPU freq: %lu KHz\n",
+ max_acpu_level->speed.khz);
+
+ return max_acpu_level;
+}
+
+static struct acpuclk_data acpuclk_krait_data = {
+ .set_rate = acpuclk_krait_set_rate,
+ .get_rate = acpuclk_krait_get_rate,
+ .power_collapse_khz = STBY_KHZ,
+ .wait_for_irq_khz = STBY_KHZ,
+};
+
+int __init acpuclk_krait_init(struct device *dev,
+ const struct acpuclk_krait_params *params)
+{
+ const struct acpu_level *max_acpu_level;
+ int cpu;
+
+ drv.scalable = params->scalable;
+ drv.l2_freq_tbl = params->l2_freq_tbl;
+ drv.dev = dev;
+
+ drv.scalable[L2].hfpll_base =
+ ioremap(drv.scalable[L2].hfpll_phys_base, SZ_32);
+ BUG_ON(!drv.scalable[L2].hfpll_base);
+
+ max_acpu_level = select_freq_plan(params->pvs_acpu_freq_tbl,
+ params->qfprom_phys_base);
+ regulator_init(max_acpu_level);
+ bus_init(params->bus_scale_data, max_acpu_level->l2_level->bw_level);
+ init_clock_sources(&drv.scalable[L2], &max_acpu_level->l2_level->speed);
+ for_each_online_cpu(cpu)
+ per_cpu_init(cpu, max_acpu_level);
+
+ cpufreq_table_init();
+
+ acpuclk_register(&acpuclk_krait_data);
+ register_hotcpu_notifier(&acpuclk_cpu_notifier);
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
new file mode 100644
index 0000000..fbf1f5f
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
+#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_KRAIT_H
+
+#define STBY_KHZ 1
+
+#define BW_MBPS(_bw) \
+ { \
+ .vectors = (struct msm_bus_vectors[]){ \
+ {\
+ .src = MSM_BUS_MASTER_AMPSS_M0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ib = (_bw) * 1000000UL, \
+ }, \
+ { \
+ .src = MSM_BUS_MASTER_AMPSS_M1, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ib = (_bw) * 1000000UL, \
+ }, \
+ }, \
+ .num_paths = 2, \
+ }
+
+/**
+ * src_id - Clock source IDs.
+ */
+enum src_id {
+ PLL_0 = 0,
+ HFPLL,
+ QSB,
+};
+
+/**
+ * enum pvs - IDs to distinguish between CPU frequency tables.
+ */
+enum pvs {
+ PVS_SLOW = 0,
+ PVS_NOMINAL,
+ PVS_FAST,
+ PVS_UNKNOWN,
+ NUM_PVS
+};
+
+/**
+ * enum scalables - IDs of frequency scalable hardware blocks.
+ */
+enum scalables {
+ CPU0 = 0,
+ CPU1,
+ CPU2,
+ CPU3,
+ L2,
+};
+
+
+/**
+ * enum hfpll_vdd_level - IDs of HFPLL voltage levels.
+ */
+enum hfpll_vdd_levels {
+ HFPLL_VDD_NONE,
+ HFPLL_VDD_LOW,
+ HFPLL_VDD_NOM,
+ NUM_HFPLL_VDD
+};
+
+/**
+ * enum vregs - IDs of voltage regulators.
+ */
+enum vregs {
+ VREG_CORE,
+ VREG_MEM,
+ VREG_DIG,
+ VREG_HFPLL_A,
+ VREG_HFPLL_B,
+ NUM_VREG
+};
+
+/**
+ * struct vreg - Voltage regulator data.
+ * @name: Name of requlator.
+ * @max_vdd: Limit the maximum-settable voltage.
+ * @rpm_vreg_id: ID to use with rpm_vreg_*() APIs.
+ * @reg: Regulator handle.
+ * @cur_vdd: Last-set voltage in uV.
+ * @peak_ua: Maximum current draw expected in uA.
+ */
+struct vreg {
+ const char name[15];
+ const int max_vdd;
+ const int peak_ua;
+ const int rpm_vreg_voter;
+ const int rpm_vreg_id;
+ struct regulator *reg;
+ int cur_vdd;
+};
+
+/**
+ * struct core_speed - Clock tree and configuration parameters.
+ * @khz: Clock rate in KHz.
+ * @src: Clock source ID.
+ * @pri_src_sel: Input to select on the primary MUX.
+ * @sec_src_sel: Input to select on the secondary MUX.
+ * @pll_l_val: HFPLL "L" value to be applied when an HFPLL source is selected.
+ */
+struct core_speed {
+ const unsigned long khz;
+ const int src;
+ const u32 pri_src_sel;
+ const u32 sec_src_sel;
+ const u32 pll_l_val;
+};
+
+/**
+ * struct l2_level - L2 clock rate and associated voltage and b/w requirements.
+ * @speed: L2 clock configuration.
+ * @vdd_dig: vdd_dig voltage in uV.
+ * @vdd_mem: vdd_mem voltage in uV.
+ * @bw_level: Bandwidth performance level number.
+ */
+struct l2_level {
+ const struct core_speed speed;
+ const int vdd_dig;
+ const int vdd_mem;
+ const unsigned int bw_level;
+};
+
+/**
+ * struct acpu_level - CPU clock rate and L2 rate and voltage requirements.
+ * @use_for_scaling: Flag indicating whether or not the level should be used.
+ * @speed: CPU clock configuration.
+ * @l2_level: L2 configuration to use.
+ * @vdd_core: CPU core voltage in uV.
+ */
+struct acpu_level {
+ const int use_for_scaling;
+ const struct core_speed speed;
+ const struct l2_level *l2_level;
+ const int vdd_core;
+};
+
+/**
+ * struct hfpll_data - Descriptive data of HFPLL hardware.
+ * @mode_offset: Mode register offset from base address.
+ * @l_offset: "L" value register offset from base address.
+ * @m_offset: "M" value register offset from base address.
+ * @n_offset: "N" value register offset from base address.
+ * @config_offset: Configuration register offset from base address.
+ * @config_val: Value to initialize the @config_offset register to.
+ * @vdd: voltage requirements for each VDD level.
+ */
+struct hfpll_data {
+ const u32 mode_offset;
+ const u32 l_offset;
+ const u32 m_offset;
+ const u32 n_offset;
+ const u32 config_offset;
+ const u32 config_val;
+ const u32 low_vdd_l_max;
+ const int vdd[NUM_HFPLL_VDD];
+};
+
+/**
+ * struct scalable - Register locations and state associated with a scalable HW.
+ * @hfpll_phys_base: Physical base address of HFPLL register.
+ * @hfpll_base: Virtual base address of HFPLL registers.
+ * @aux_clk_sel_addr: Virtual address of auxiliary MUX.
+ * @aux_clk_sel: Auxiliary mux input to select at boot.
+ * @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
+ * @hfpll_data: Descriptive data of HFPLL hardware.
+ * @cur_speed: Pointer to currently-set speed.
+ * @l2_vote: L2 performance level vote associate with the current CPU speed.
+ * @vreg: Array of voltage regulators needed by the scalable.
+ */
+struct scalable {
+ const u32 hfpll_phys_base;
+ void __iomem *hfpll_base;
+ void __iomem *aux_clk_sel_addr;
+ const u32 aux_clk_sel;
+ const u32 l2cpmr_iaddr;
+ const struct hfpll_data *hfpll_data;
+ const struct core_speed *cur_speed;
+ const struct l2_level *l2_vote;
+ struct vreg vreg[NUM_VREG];
+};
+
+/**
+ * struct acpuclk_krait_params - SoC specific driver parameters.
+ * @scalable: Array of scalables.
+ * @pvs_acpu_freq_tbl: Array of CPU frequency tables.
+ * @l2_freq_tbl: L2 frequency table.
+ * @l2_freq_tbl_size: Number of rows in @l2_freq_tbl.
+ * @qfprom_phys_base: Physical base address of QFPROM.
+ * @bus_scale_data: MSM bus driver parameters.
+ */
+struct acpuclk_krait_params {
+ struct scalable *scalable;
+ const struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
+ const struct l2_level *l2_freq_tbl;
+ const size_t l2_freq_tbl_size;
+ const u32 qfprom_phys_base;
+ struct msm_bus_scale_pdata *bus_scale_data;
+};
+
+/**
+ * acpuclk_krait_init - Initialize the Krait CPU clock driver give SoC params.
+ */
+extern int acpuclk_krait_init(struct device *dev,
+ const struct acpuclk_krait_params *params);
+
+#endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 4dac062..6361d6d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -982,11 +982,13 @@
int msm_bam_dmux_is_ch_low(uint32_t id)
{
+ unsigned long flags;
int ret;
if (id >= BAM_DMUX_NUM_CHANNELS)
return -EINVAL;
+ spin_lock_irqsave(&bam_ch[id].lock, flags);
bam_ch[id].use_wm = 1;
ret = bam_ch[id].num_tx_pkts <= LOW_WATERMARK;
DBG("%s: ch %d num tx pkts=%d, LWM=%d\n", __func__,
@@ -995,6 +997,7 @@
ret = -ENODEV;
pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status);
}
+ spin_unlock_irqrestore(&bam_ch[id].lock, flags);
return ret;
}
@@ -2036,6 +2039,7 @@
goto register_bam_failed;
}
a2_device_handle = h;
+ toggle_apps_ack();
return 0;
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 157c939..5d1f3e8 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -461,6 +461,7 @@
.sensor_platform_info = &sensor_board_info_imx074,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
.actuator_info = &imx074_actuator_info
};
static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
@@ -495,6 +496,42 @@
.sensor_platform_info = &sensor_board_info_imx091,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
+};
+
+static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
+ {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
+ {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
+ {"cam_vio", REG_VS, 0, 0, 0},
+ {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
+ .csi_lane_assign = 0xE4,
+ .csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
+ .mount_angle = 90,
+ .cam_vreg = apq_8064_s5k3l1yx_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_s5k3l1yx_vreg),
+ .gpio_conf = &apq8064_back_cam_gpio_conf,
+ .i2c_conf = &apq8064_back_cam_i2c_conf,
+ .csi_lane_params = &s5k3l1yx_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
+ .sensor_name = "s5k3l1yx",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_s5k3l1yx,
+ .sensor_platform_info = &sensor_board_info_s5k3l1yx,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
@@ -529,6 +566,7 @@
.sensor_platform_info = &sensor_board_info_mt9m114,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = YUV_SENSOR,
};
static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -556,6 +594,7 @@
.sensor_platform_info = &sensor_board_info_ov2720,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
void __init apq8064_init_cam(void)
@@ -563,9 +602,10 @@
msm_gpiomux_install(apq8064_cam_common_configs,
ARRAY_SIZE(apq8064_cam_common_configs));
- if (machine_is_apq8064_cdp())
+ if (machine_is_apq8064_cdp()) {
sensor_board_info_imx074.mount_angle = 0;
- else if (machine_is_apq8064_liquid())
+ sensor_board_info_mt9m114.mount_angle = 0;
+ } else if (machine_is_apq8064_liquid())
sensor_board_info_imx074.mount_angle = 180;
platform_device_register(&msm8960_device_i2c_mux_gsbi4);
@@ -599,6 +639,10 @@
I2C_BOARD_INFO("imx091", 0x34),
.platform_data = &msm_camera_sensor_imx091_data,
},
+ {
+ I2C_BOARD_INFO("s5k3l1yx", 0x20),
+ .platform_data = &msm_camera_sensor_s5k3l1yx_data,
+ },
};
struct msm_camera_board_info apq8064_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 433fb2e..19d7a9e 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -46,7 +46,16 @@
#define MSM_FB_EXT_BUF_SIZE 0
#endif
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+#define MSM_FB_WFD_BUF_SIZE \
+ (roundup((1280 * 736 * 2), 4096) * 1) /* 2 bpp x 1 page */
+#else
+#define MSM_FB_WFD_BUF_SIZE 0
+#endif
+
+#define MSM_FB_SIZE \
+ roundup(MSM_FB_PRIM_BUF_SIZE + \
+ MSM_FB_EXT_BUF_SIZE + MSM_FB_WFD_BUF_SIZE, 4096)
#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
@@ -73,6 +82,17 @@
#define HDMI_PANEL_NAME "hdmi_msm"
#define TVOUT_PANEL_NAME "tvout_msm"
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+static unsigned char hdmi_is_primary = 1;
+#else
+static unsigned char hdmi_is_primary;
+#endif
+
+unsigned char apq8064_hdmi_as_primary_selected(void)
+{
+ return hdmi_is_primary;
+}
+
static void set_mdp_clocks_for_wuxga(void);
static int msm_fb_detect_panel(const char *name)
@@ -107,7 +127,7 @@
if (!strncmp(name, HDMI_PANEL_NAME,
strnlen(HDMI_PANEL_NAME,
PANEL_NAME_MAX_LEN))) {
- if (hdmi_is_primary)
+ if (apq8064_hdmi_as_primary_selected())
set_mdp_clocks_for_wuxga();
return 0;
}
@@ -297,6 +317,19 @@
.dev.platform_data = &hdmi_msm_data,
};
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct platform_device wfd_panel_device = {
+ .name = "wfd_panel",
+ .id = 0,
+ .dev.platform_data = NULL,
+};
+
+static struct platform_device wfd_device = {
+ .name = "msm_wfd",
+ .id = -1,
+};
+#endif
+
/* HDMI related GPIOs */
#define HDMI_CEC_VAR_GPIO 69
#define HDMI_DDC_CLK_GPIO 70
@@ -897,6 +930,11 @@
platform_device_register(&msm_fb_device);
platform_device_register(&lvds_chimei_panel_device);
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+ platform_device_register(&wfd_panel_device);
+ platform_device_register(&wfd_device);
+#endif
+
if (machine_is_apq8064_liquid())
platform_device_register(&mipi_dsi2lvds_bridge_device);
if (machine_is_apq8064_mtp())
@@ -931,7 +969,7 @@
for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
mdp_core_clk_rate_table[i] = 200000000;
- if (hdmi_is_primary) {
+ if (apq8064_hdmi_as_primary_selected()) {
dtv_bus_def_vectors[0].ab = 2000000000;
dtv_bus_def_vectors[0].ib = 2000000000;
}
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index bf82e40..2f94069 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -53,6 +53,13 @@
.pull = GPIOMUX_PULL_UP,
};
+/* Chip selects for EPM SPI clients */
+static struct gpiomux_setting gpio_epm_spi_cs_config = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
struct msm_gpiomux_config apq8064_ethernet_configs[] = {
{
.gpio = 43,
@@ -371,7 +378,7 @@
{
.gpio = 32, /* EPM CS */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ [GPIOMUX_SUSPENDED] = &gpio_epm_spi_cs_config,
},
},
{
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 2708283..7b84a68 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -16,10 +16,36 @@
#include <linux/msm_kgsl.h>
#include <mach/msm_bus_board.h>
#include <mach/board.h>
+#include <mach/msm_dcvs.h>
#include "devices.h"
#include "board-8064.h"
+#ifdef CONFIG_MSM_DCVS
+static struct msm_dcvs_freq_entry grp3d_freq[] = {
+ {0, 0, 333932},
+ {0, 0, 497532},
+ {0, 0, 707610},
+ {0, 0, 844545},
+};
+
+static struct msm_dcvs_core_info grp3d_core_info = {
+ .freq_tbl = &grp3d_freq[0],
+ .core_param = {
+ .max_time_us = 100000,
+ .num_freq = ARRAY_SIZE(grp3d_freq),
+ },
+ .algo_param = {
+ .slack_time_us = 39000,
+ .disable_pc_threshold = 86000,
+ .ss_window_size = 1000000,
+ .ss_util_pct = 95,
+ .em_max_util_pct = 97,
+ .ss_iobusy_conv = 100,
+ },
+};
+#endif /* CONFIG_MSM_DCVS */
+
#ifdef CONFIG_MSM_BUS_SCALING
static struct msm_bus_vectors grp3d_init_vectors[] = {
{
@@ -155,12 +181,12 @@
.io_fraction = 0,
},
{
- .gpu_freq = 320000000,
+ .gpu_freq = 325000000,
.bus_freq = 2,
.io_fraction = 33,
},
{
- .gpu_freq = 192000000,
+ .gpu_freq = 200000000,
.bus_freq = 1,
.io_fraction = 100,
},
@@ -180,6 +206,9 @@
#endif
.iommu_data = kgsl_3d0_iommu_data,
.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+#ifdef CONFIG_MSM_DCVS
+ .core_info = &grp3d_core_info,
+#endif
};
struct platform_device device_kgsl_3d0 = {
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index df28390..f915657 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -142,8 +142,6 @@
/* Initial PM8XXX MPP configurations */
static struct pm8xxx_mpp_init pm8xxx_mpps[] __initdata = {
PM8921_MPP_INIT(3, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
- /* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
- PM8921_MPP_INIT(7, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
/*MPP9 is used to detect docking station connection/removal on Liquid*/
PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 025f065..ae2de20 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -62,6 +62,7 @@
REGULATOR_SUPPLY("cam_vana", "4-0048"),
REGULATOR_SUPPLY("cam_vana", "4-006c"),
REGULATOR_SUPPLY("cam_vana", "4-0034"),
+ REGULATOR_SUPPLY("cam_vana", "4-0020"),
};
VREG_CONSUMERS(L9) = {
REGULATOR_SUPPLY("8921_l9", NULL),
@@ -80,6 +81,7 @@
REGULATOR_SUPPLY("cam_vdig", "4-0048"),
REGULATOR_SUPPLY("cam_vdig", "4-006c"),
REGULATOR_SUPPLY("cam_vdig", "4-0034"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0020"),
REGULATOR_SUPPLY("8921_l12", NULL),
};
VREG_CONSUMERS(L14) = {
@@ -94,6 +96,7 @@
REGULATOR_SUPPLY("cam_vaf", "4-0048"),
REGULATOR_SUPPLY("cam_vaf", "4-006c"),
REGULATOR_SUPPLY("cam_vaf", "4-0034"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0020"),
};
VREG_CONSUMERS(L17) = {
REGULATOR_SUPPLY("8921_l17", NULL),
@@ -197,6 +200,7 @@
REGULATOR_SUPPLY("cam_vio", "4-0048"),
REGULATOR_SUPPLY("cam_vio", "4-006c"),
REGULATOR_SUPPLY("cam_vio", "4-0034"),
+ REGULATOR_SUPPLY("cam_vio", "4-0020"),
};
VREG_CONSUMERS(LVS6) = {
REGULATOR_SUPPLY("8921_lvs6", NULL),
@@ -229,6 +233,7 @@
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
+ REGULATOR_SUPPLY("ext_ddr3", NULL),
REGULATOR_SUPPLY("vbus", "msm_ehci_host.0"),
};
VREG_CONSUMERS(EXT_MPP8) = {
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index b062dde..df20d60 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -16,6 +16,7 @@
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/i2c/smb349.h>
+#include <linux/i2c/sx150x.h>
#include <linux/slimbus/slimbus.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/pdata.h>
@@ -30,6 +31,7 @@
#include <linux/cyttsp.h>
#include <linux/i2c/isa1200.h>
#include <linux/gpio_keys.h>
+#include <linux/epm_adc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -74,7 +76,7 @@
#include "devices-msm8x60.h"
#define MSM_PMEM_ADSP_SIZE 0x7800000
-#define MSM_PMEM_AUDIO_SIZE 0x2B4000
+#define MSM_PMEM_AUDIO_SIZE 0x4CF000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#else
@@ -82,7 +84,7 @@
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
@@ -167,7 +169,6 @@
.id = 2,
.dev = { .platform_data = &android_pmem_adsp_pdata },
};
-#endif
static struct android_pmem_platform_data android_pmem_audio_pdata = {
.name = "pmem_audio",
@@ -181,7 +182,8 @@
.id = 4,
.dev = { .platform_data = &android_pmem_audio_pdata },
};
-#endif
+#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
+#endif /* CONFIG_ANDROID_PMEM */
static struct memtype_reserve apq8064_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
@@ -233,15 +235,19 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_size;
-#endif
android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
}
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
{
apq8064_reserve_table[p->memory_type].size += p->size;
}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
static void __init reserve_pmem_memory(void)
{
@@ -249,10 +255,10 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
reserve_memory_for(&android_pmem_adsp_pdata);
reserve_memory_for(&android_pmem_pdata);
-#endif
reserve_memory_for(&android_pmem_audio_pdata);
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
+#endif /*CONFIG_ANDROID_PMEM*/
}
static int apq8064_paddr_to_memtype(unsigned int paddr)
@@ -582,6 +588,12 @@
.name = "usb",
};
+static int phy_init_seq[] = {
+ 0x38, 0x81, /* update DC voltage level */
+ 0x24, 0x82, /* set pre-emphasis and rise/fall time */
+ -1
+};
+
static struct msm_otg_platform_data msm_otg_pdata = {
.mode = USB_OTG,
.otg_control = OTG_PMIC_CONTROL,
@@ -589,6 +601,7 @@
.pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
.power_budget = 750,
.bus_scale_table = &usb_bus_scale_pdata,
+ .phy_init_seq = phy_init_seq,
};
static struct msm_usb_host_platform_data msm_ehci_host_pdata3 = {
@@ -630,7 +643,59 @@
},
};
-#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS)
+struct sx150x_platform_data apq8064_sx150x_data[] = {
+ [SX150X_EPM] = {
+ .gpio_base = GPIO_EPM_EXPANDER_BASE,
+ .oscio_is_gpo = false,
+ .io_pullup_ena = 0x0,
+ .io_pulldn_ena = 0x0,
+ .io_open_drain_ena = 0x0,
+ .io_polarity = 0,
+ .irq_summary = -1,
+ },
+};
+
+static struct epm_chan_properties ads_adc_channel_data[] = {
+ {10, 100}, {500, 50}, {1, 1}, {1, 1},
+ {20, 50}, {10, 100}, {1, 1}, {1, 1},
+ {10, 100}, {10, 100}, {100, 100}, {200, 100},
+ {100, 50}, {2000, 50}, {1000, 50}, {200, 50},
+ {200, 100}, {1, 1}, {20, 50}, {500, 50},
+ {50, 50}, {200, 100}, {500, 100}, {20, 50},
+ {200, 50}, {2000, 100}, {1000, 50}, {100, 50},
+ {200, 100}, {500, 50}, {1000, 100}, {200, 50},
+ {1000, 50}, {50, 50}, {100, 50}, {100, 50},
+ {1, 1}, {1, 1}, {20, 100}, {20, 50},
+ {500, 100}, {1000, 100}, {100, 50}, {1000, 50},
+ {100, 50}, {1000, 100}, {100, 50}, {100, 50},
+};
+
+static struct epm_adc_platform_data epm_adc_pdata = {
+ .channel = ads_adc_channel_data,
+ .bus_id = 0x0,
+ .epm_i2c_board_info = {
+ .type = "sx1509q",
+ .addr = 0x3e,
+ .platform_data = &apq8064_sx150x_data[SX150X_EPM],
+ },
+ .gpio_expander_base_addr = GPIO_EPM_EXPANDER_BASE,
+};
+
+static struct platform_device epm_adc_device = {
+ .name = "epm_adc",
+ .id = -1,
+ .dev = {
+ .platform_data = &epm_adc_pdata,
+ },
+};
+
+static void __init apq8064_epm_adc_init(void)
+{
+ epm_adc_pdata.num_channels = 32;
+ epm_adc_pdata.num_adc = 2;
+ epm_adc_pdata.chan_per_adc = 16;
+ epm_adc_pdata.chan_per_mux = 8;
+};
/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
* 4 micbiases are used to power various analog and digital
@@ -1745,9 +1810,9 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
&android_pmem_device,
&android_pmem_adsp_device,
-#endif
&android_pmem_audio_device,
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
#ifdef CONFIG_ION_MSM
&ion_dev,
#endif
@@ -1803,8 +1868,10 @@
&msm_bus_8064_sys_fpb,
&msm_bus_8064_cpss_fpb,
&apq8064_msm_device_vidc,
+ &msm_pil_dsps,
&msm_8960_riva,
&msm_8960_q6_lpass,
+ &msm_pil_vidc,
&msm_gss,
#ifdef CONFIG_MSM_RTB
&msm_rtb_device,
@@ -1812,6 +1879,12 @@
&apq8064_cpu_idle_device,
&apq8064_msm_gov_device,
&apq8064_device_cache_erp,
+ &epm_adc_device,
+ &apq8064_qdss_device,
+ &msm_etb_device,
+ &msm_tpiu_device,
+ &msm_funnel_device,
+ &apq8064_etm_device,
};
static struct platform_device *sim_devices[] __initdata = {
@@ -1851,6 +1924,13 @@
.chip_select = 2,
.mode = SPI_MODE_0,
},
+ {
+ .modalias = "epm_adc",
+ .max_speed_hz = 1100000,
+ .bus_num = 0,
+ .chip_select = 3,
+ .mode = SPI_MODE_0,
+ },
};
static struct slim_boardinfo apq8064_slim_devices[] = {
@@ -1896,6 +1976,8 @@
apq8064_i2c_qup_gsbi1_pdata.use_gsbi_shared_mode = 1;
apq8064_device_qup_i2c_gsbi3.dev.platform_data =
&apq8064_i2c_qup_gsbi3_pdata;
+ apq8064_device_qup_i2c_gsbi1.dev.platform_data =
+ &apq8064_i2c_qup_gsbi1_pdata;
apq8064_device_qup_i2c_gsbi4.dev.platform_data =
&apq8064_i2c_qup_gsbi4_pdata;
}
@@ -2133,6 +2215,20 @@
#endif
}
+static void enable_ddr3_regulator(void)
+{
+ static struct regulator *ext_ddr3;
+
+ /* Use MPP7 output state as a flag for PCDDR3 presence. */
+ if (gpio_get_value_cansleep(PM8921_MPP_PM_TO_SYS(7)) > 0) {
+ ext_ddr3 = regulator_get(NULL, "ext_ddr3");
+ if (IS_ERR(ext_ddr3) || ext_ddr3 == NULL)
+ pr_err("Could not get MPP7 regulator\n");
+ else
+ regulator_enable(ext_ddr3);
+ }
+}
+
static void __init apq8064_common_init(void)
{
if (socinfo_init() < 0)
@@ -2153,10 +2249,15 @@
apq8064_init_pmic();
if (machine_is_apq8064_liquid())
msm_otg_pdata.mhl_enable = true;
+
+ msm_otg_pdata.swfi_latency =
+ msm_rpmrs_levels[0].latency_us + 1;
+
apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
apq8064_ehci_host_init();
apq8064_init_buses();
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ enable_ddr3_regulator();
if (machine_is_apq8064_mtp()) {
apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
device_initialize(&apq8064_device_hsic_host.dev);
@@ -2180,6 +2281,7 @@
msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
msm_pm_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ apq8064_epm_adc_init();
}
static void __init apq8064_allocate_memory_regions(void)
@@ -2215,6 +2317,8 @@
apq8064_common_init();
ethernet_init();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
+ if (!machine_is_apq8064_mtp())
+ msm_rotator_update_bus_vectors(1376, 768);
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
apq8064_init_fb();
apq8064_init_gpu();
@@ -2280,6 +2384,17 @@
.init_very_early = apq8064_early_reserve,
MACHINE_END
+MACHINE_START(MPQ8064_CDP, "QCT MPQ8064 CDP")
+ .map_io = apq8064_map_io,
+ .reserve = apq8064_reserve,
+ .init_irq = apq8064_init_irq,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_timer,
+ .init_machine = apq8064_cdp_init,
+ .init_early = apq8064_allocate_memory_regions,
+ .init_very_early = apq8064_early_reserve,
+MACHINE_END
+
MACHINE_START(MPQ8064_HRD, "QCT MPQ8064 HRD")
.map_io = apq8064_map_io,
.reserve = apq8064_reserve,
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 938d2ea..23ca39f 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -31,6 +31,8 @@
#define PM8821_MPP_PM_TO_SYS(pm_mpp) (pm_mpp - 1 + PM8821_MPP_BASE)
#define PM8821_IRQ_BASE (PM8921_IRQ_BASE + PM8921_NR_IRQS)
+#define TABLA_INTERRUPT_BASE (PM8821_IRQ_BASE + PM8821_NR_IRQS)
+
extern struct pm8xxx_regulator_platform_data
msm8064_pm8921_regulator_pdata[] __devinitdata;
@@ -69,12 +71,12 @@
#define APQ_8064_GSBI3_QUP_I2C_BUS_ID 3
#define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
+unsigned char apq8064_hdmi_as_primary_selected(void);
void apq8064_init_fb(void);
void apq8064_allocate_fb_region(void);
void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
uint32_t apq8064_rpm_get_swfi_latency(void);
void __init apq8064_set_display_params(char *prim_panel, char *ext_panel);
-extern char hdmi_is_primary;
void apq8064_init_gpu(void);
void apq8064_pm8xxx_gpio_mpp_init(void);
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 315e8fc..92e88aa72 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -446,6 +446,7 @@
.sensor_platform_info = &sensor_board_info_imx074,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
.actuator_info = &imx074_actuator_info
};
@@ -480,6 +481,7 @@
.sensor_platform_info = &sensor_board_info_mt9m114,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = YUV_SENSOR,
};
static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -506,6 +508,7 @@
.sensor_platform_info = &sensor_board_info_ov2720,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
@@ -539,6 +542,7 @@
.sensor_platform_info = &sensor_board_info_s5k3l1yx,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
void __init msm8930_init_cam(void)
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index c8c631e..42b20b2 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -496,6 +496,7 @@
.fpga_ctrl_mode = FPGA_SPI_INTF,
.phy_ctrl_settings = &dsi_novatek_cmd_mode_phy_db,
.dlane_swap = 0x1,
+ .enable_wled_bl_ctrl = 0x1,
};
static struct platform_device mipi_dsi_novatek_panel_device = {
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 77d9c5f..854f318 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -171,26 +171,6 @@
},
};
#endif
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-static struct gpiomux_setting hsic_act_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_12MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting hsic_sus_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
- .dir = GPIOMUX_OUT_LOW,
-};
-
-static struct gpiomux_setting hsic_hub_act_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-#endif
static struct gpiomux_setting hap_lvl_shft_suspended_config = {
.func = GPIOMUX_FUNC_GPIO,
@@ -487,32 +467,6 @@
},
};
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-static struct msm_gpiomux_config msm8960_hsic_configs[] = {
- {
- .gpio = 150, /*HSIC_STROBE */
- .settings = {
- [GPIOMUX_ACTIVE] = &hsic_act_cfg,
- [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
- },
- },
- {
- .gpio = 151, /* HSIC_DATA */
- .settings = {
- [GPIOMUX_ACTIVE] = &hsic_act_cfg,
- [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
- },
- },
- {
- .gpio = 91, /* HSIC_HUB_RESET */
- .settings = {
- [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
- [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
- },
- },
-};
-#endif
-
static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
{
.gpio = 47,
@@ -611,7 +565,11 @@
};
#endif
-#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting haptics_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
static struct gpiomux_setting haptics_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
@@ -622,17 +580,18 @@
{
.gpio = 77,
.settings = {
+ [GPIOMUX_ACTIVE] = &haptics_active_cfg,
[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
},
},
{
.gpio = 78,
.settings = {
+ [GPIOMUX_ACTIVE] = &haptics_active_cfg,
[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
},
},
};
-#endif
int __init msm8930_init_gpiomux(void)
{
@@ -679,19 +638,10 @@
msm_gpiomux_install(mdm_configs,
ARRAY_SIZE(mdm_configs));
-#ifdef MSM8930_PHASE_2
- if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid())
+ if (machine_is_msm8930_cdp() || machine_is_msm8930_mtp()
+ || machine_is_msm8930_fluid())
msm_gpiomux_install(msm8930_haptics_configs,
ARRAY_SIZE(msm8930_haptics_configs));
-#endif
-
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
- if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
- !machine_is_msm8930_mtp() &&
- !machine_is_msm8930_fluid())
- msm_gpiomux_install(msm8960_hsic_configs,
- ARRAY_SIZE(msm8960_hsic_configs));
-#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
msm_gpiomux_install(msm8960_hdmi_configs,
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index a5157038..7c8c64f 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -53,7 +53,7 @@
.src = MSM_BUS_MASTER_GRAPHICS_3D,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 0,
- .ib = KGSL_CONVERT_TO_MBPS(3200),
+ .ib = KGSL_CONVERT_TO_MBPS(4264),
},
};
@@ -115,17 +115,17 @@
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
.pwrlevel = {
{
- .gpu_freq = 200000000,
+ .gpu_freq = 450000000,
.bus_freq = 3,
.io_fraction = 0,
},
{
- .gpu_freq = 200000000,
+ .gpu_freq = 320000000,
.bus_freq = 2,
.io_fraction = 33,
},
{
- .gpu_freq = 200000000,
+ .gpu_freq = 192000000,
.bus_freq = 1,
.io_fraction = 100,
},
@@ -137,8 +137,8 @@
.init_level = 0,
.num_levels = 4,
.set_grp_async = NULL,
- .idle_timeout = 0x1FFFFFFF,
- .nap_allowed = false,
+ .idle_timeout = HZ/12,
+ .nap_allowed = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE,
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &grp3d_bus_scale_pdata,
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 1ca1902..86c0438 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -93,6 +93,8 @@
PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_30),
PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_30),
+ /* haptics gpio */
+ PM8XXX_GPIO_OUTPUT_FUNC(7, 0, PM_GPIO_FUNC_1),
};
/* Initial pm8038 MPP configurations */
@@ -227,10 +229,24 @@
};
#define PM8038_WLED_MAX_CURRENT 25
+#define PM8XXX_LED_PWM_PERIOD 1000
+#define PM8XXX_LED_PWM_DUTY_MS 20
+#define PM8038_RGB_LED_MAX_CURRENT 12
static struct led_info pm8038_led_info[] = {
[0] = {
.name = "wled",
+ .default_trigger = "bkl_trigger",
+ },
+ [1] = {
+ .name = "led:rgb_red",
+ .default_trigger = "battery-charging",
+ },
+ [2] = {
+ .name = "led:rgb_green",
+ },
+ [3] = {
+ .name = "led:rgb_blue",
},
};
@@ -249,14 +265,54 @@
.num_strings = 1,
};
+static int pm8038_led0_pwm_duty_pcts[56] = {
+ 1, 4, 8, 12, 16, 20, 24, 28, 32, 36,
+ 40, 44, 46, 52, 56, 60, 64, 68, 72, 76,
+ 80, 84, 88, 92, 96, 100, 100, 100, 98, 95,
+ 92, 88, 84, 82, 78, 74, 70, 66, 62, 58,
+ 58, 54, 50, 48, 42, 38, 34, 30, 26, 22,
+ 14, 10, 6, 4, 1
+};
+
+static struct pm8xxx_pwm_duty_cycles pm8038_led0_pwm_duty_cycles = {
+ .duty_pcts = (int *)&pm8038_led0_pwm_duty_pcts,
+ .num_duty_pcts = ARRAY_SIZE(pm8038_led0_pwm_duty_pcts),
+ .duty_ms = PM8XXX_LED_PWM_DUTY_MS,
+ .start_idx = 0,
+};
+
static struct pm8xxx_led_config pm8038_led_configs[] = {
[0] = {
.id = PM8XXX_ID_WLED,
.mode = PM8XXX_LED_MODE_MANUAL,
.max_current = PM8038_WLED_MAX_CURRENT,
- .default_state = 1,
+ .default_state = 0,
.wled_cfg = &wled_cfg,
},
+ [1] = {
+ .id = PM8XXX_ID_RGB_LED_RED,
+ .mode = PM8XXX_LED_MODE_PWM1,
+ .max_current = PM8038_RGB_LED_MAX_CURRENT,
+ .pwm_channel = 5,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ .pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+ },
+ [2] = {
+ .id = PM8XXX_ID_RGB_LED_GREEN,
+ .mode = PM8XXX_LED_MODE_PWM1,
+ .max_current = PM8038_RGB_LED_MAX_CURRENT,
+ .pwm_channel = 4,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ .pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+ },
+ [3] = {
+ .id = PM8XXX_ID_RGB_LED_BLUE,
+ .mode = PM8XXX_LED_MODE_PWM1,
+ .max_current = PM8038_RGB_LED_MAX_CURRENT,
+ .pwm_channel = 3,
+ .pwm_period_us = PM8XXX_LED_PWM_PERIOD,
+ .pwm_duty_cycles = &pm8038_led0_pwm_duty_cycles,
+ },
};
static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index e8500dc..f760e7b 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -84,6 +84,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar-slim"),
+ REGULATOR_SUPPLY("vddp", "0-0048"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8038_l12", NULL),
@@ -179,7 +180,7 @@
REGULATOR_SUPPLY("8038_lvs2", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vddp", "12-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
};
VREG_CONSUMERS(EXT_5V) = {
REGULATOR_SUPPLY("ext_5v", NULL),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 26211bf..83fb5fd 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -245,6 +245,7 @@
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
#else
.wpswitch_gpio = 66,
+ .wpswitch_polarity = 1,
#endif
#endif
.vreg_data = &mmc_slot_vreg_data[SDCC3],
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 59651a7..98f1228 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1024,16 +1024,6 @@
};
#endif
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
-#define HSIC_HUB_RESET_GPIO 91
-static struct msm_hsic_host_platform_data msm_hsic_pdata = {
- .strobe = 150,
- .data = 151,
-};
-#else
-static struct msm_hsic_host_platform_data msm_hsic_pdata;
-#endif
-
#define PID_MAGIC_ID 0x71432909
#define SERIAL_NUM_MAGIC_ID 0x61945374
#define SERIAL_NUMBER_LENGTH 127
@@ -1218,127 +1208,25 @@
#/* TODO: Remove this once PM8038 physically becomes
* available.
*/
-#ifndef MSM8930_PHASE_2
-#define PM_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
-#define PM_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
-#else
#define ISA1200_HAP_EN_GPIO 77
#define ISA1200_HAP_LEN_GPIO 78
#define ISA1200_HAP_CLK PM8038_GPIO_PM_TO_SYS(7)
-#endif
-
-#ifndef MSM8930_PHASE_2
-static struct msm_xo_voter *xo_handle_d1;
-#endif
static int isa1200_power(int on)
{
-#ifndef MSM8930_PHASE_2
- int rc = 0;
-
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
-
- rc = on ? msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_ON) :
- msm_xo_mode_vote(xo_handle_d1, MSM_XO_MODE_OFF);
- if (rc < 0) {
- pr_err("%s: failed to %svote for TCXO D1 buffer%d\n",
- __func__, on ? "" : "de-", rc);
- goto err_xo_vote;
- }
-
- return 0;
-
-err_xo_vote:
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
- return rc;
-#else
gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
return 0;
-#endif
-
}
static int isa1200_dev_setup(bool enable)
{
int rc = 0;
-#ifndef MSM8930_PHASE_2
- struct pm_gpio hap_gpio_config = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .out_strength = PM_GPIO_STRENGTH_HIGH,
- .function = PM_GPIO_FUNC_NORMAL,
- .inv_int_pol = 0,
- .vin_sel = 2,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 0,
- };
-
- if (enable == true) {
- rc = pm8xxx_gpio_config(PM_HAP_EN_GPIO, &hap_gpio_config);
- if (rc) {
- pr_err("%s: pm8921 gpio %d config failed(%d)\n",
- __func__, PM_HAP_EN_GPIO, rc);
- return rc;
- }
-
- rc = pm8xxx_gpio_config(PM_HAP_LEN_GPIO, &hap_gpio_config);
- if (rc) {
- pr_err("%s: pm8921 gpio %d config failed(%d)\n",
- __func__, PM_HAP_LEN_GPIO, rc);
- return rc;
- }
-
- rc = gpio_request(HAP_SHIFT_LVL_OE_GPIO, "hap_shft_lvl_oe");
- if (rc) {
- pr_err("%s: unable to request gpio %d (%d)\n",
- __func__, HAP_SHIFT_LVL_OE_GPIO, rc);
- return rc;
- }
-
- rc = gpio_direction_output(HAP_SHIFT_LVL_OE_GPIO, 0);
- if (rc) {
- pr_err("%s: Unable to set direction\n", __func__);
- goto free_gpio;
- }
-
- xo_handle_d1 = msm_xo_get(MSM_XO_TCXO_D1, "isa1200");
- if (IS_ERR(xo_handle_d1)) {
- rc = PTR_ERR(xo_handle_d1);
- pr_err("%s: failed to get the handle for D1(%d)\n",
- __func__, rc);
- goto gpio_set_dir;
- }
- } else {
- gpio_free(HAP_SHIFT_LVL_OE_GPIO);
-
- msm_xo_put(xo_handle_d1);
- }
-
- return 0;
-
-gpio_set_dir:
- gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, 0);
-free_gpio:
- gpio_free(HAP_SHIFT_LVL_OE_GPIO);
- return rc;
-#else
- struct pm_gpio hap_clk_gpio_config = {
- .direction = PM_GPIO_DIR_OUT,
- .pull = PM_GPIO_PULL_NO,
- .out_strength = PM_GPIO_STRENGTH_HIGH,
- .function = PM_GPIO_FUNC_1,
- .inv_int_pol = 0,
- .vin_sel = PM_GPIO_VIN_S4,
- .output_buffer = PM_GPIO_OUT_BUF_CMOS,
- .output_value = 0,
- };
-
- rc = pm8xxx_gpio_config(ISA1200_HAP_CLK, &hap_clk_gpio_config);
+ rc = pm8xxx_aux_clk_control(CLK_MP3_1, XO_DIV_1, enable);
if (rc) {
- pr_err("%s: pm8038 gpio %d config failed(%d)\n",
- __func__, ISA1200_HAP_CLK, rc);
+ pr_err("%s: unable to write aux clock register(%d)\n",
+ __func__, rc);
return rc;
}
@@ -1363,38 +1251,29 @@
fail_gpio_req:
return rc;
-#endif
}
static struct isa1200_regulator isa1200_reg_data[] = {
-#ifndef MSM8930_PHASE_2
- {
- .name = "vcc_i2c",
- .min_uV = ISA_I2C_VTG_MIN_UV,
- .max_uV = ISA_I2C_VTG_MAX_UV,
- .load_uA = ISA_I2C_CURR_UA,
- },
-#else
{
.name = "vddp",
.min_uV = ISA_I2C_VTG_MIN_UV,
.max_uV = ISA_I2C_VTG_MAX_UV,
.load_uA = ISA_I2C_CURR_UA,
},
-#endif
+ {
+ .name = "vcc_i2c",
+ .min_uV = ISA_I2C_VTG_MIN_UV,
+ .max_uV = ISA_I2C_VTG_MAX_UV,
+ .load_uA = ISA_I2C_CURR_UA,
+ },
};
static struct isa1200_platform_data isa1200_1_pdata = {
.name = "vibrator",
.dev_setup = isa1200_dev_setup,
.power_on = isa1200_power,
-#ifndef MSM8930_PHASE_2
- .hap_en_gpio = PM_HAP_EN_GPIO,
- .hap_len_gpio = PM_HAP_LEN_GPIO,
-#else
.hap_en_gpio = ISA1200_HAP_EN_GPIO,
.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
-#endif
.max_timeout = 15000,
.mode_ctrl = PWM_GEN_MODE,
.pwm_fd = {
@@ -1758,6 +1637,7 @@
&msm_8960_q6_mss_sw,
&msm_8960_riva,
&msm_pil_tzapps,
+ &msm_pil_vidc,
&msm8960_device_qup_spi_gsbi1,
&msm8960_device_qup_i2c_gsbi3,
&msm8960_device_qup_i2c_gsbi4,
@@ -1804,6 +1684,7 @@
&msm_device_tz_log,
#ifdef CONFIG_MSM_QDSS
+ &msm_qdss_device,
&msm_etb_device,
&msm_tpiu_device,
&msm_funnel_device,
@@ -2052,24 +1933,6 @@
int len;
};
-static void __init msm8930_init_hsic(void)
-{
-#ifdef CONFIG_USB_EHCI_MSM_HSIC
- uint32_t version = socinfo_get_version();
-
- pr_info("%s: version:%d mtp:%d\n", __func__,
- SOCINFO_VERSION_MAJOR(version),
- machine_is_msm8930_mtp());
-
- if ((SOCINFO_VERSION_MAJOR(version) == 1) ||
- machine_is_msm8930_mtp() ||
- machine_is_msm8930_fluid())
- return;
-
- platform_device_register(&msm_device_hsic_host);
-#endif
-}
-
#ifdef CONFIG_ISL9519_CHARGER
static struct isl_platform_data isl_data __initdata = {
.valid_n_gpio = 0, /* Not required when notify-by-pmic */
@@ -2099,23 +1962,14 @@
ARRAY_SIZE(isl_charger_i2c_info),
},
#endif /* CONFIG_ISL9519_CHARGER */
-#ifndef MSM8930_PHASE_2
{
- I2C_LIQUID,
- MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_8930_GSBI9_QUP_I2C_BUS_ID,
msm_isa1200_board_info,
ARRAY_SIZE(msm_isa1200_board_info),
},
-#else
{
- I2C_FFA | I2C_FLUID,
- MSM_8930_GSBI10_QUP_I2C_BUS_ID,
- msm_isa1200_board_info,
- ARRAY_SIZE(msm_isa1200_board_info),
- },
-#endif
- {
- I2C_SURF,
+ I2C_SURF | I2C_FFA | I2C_FLUID,
MSM_8930_GSBI3_QUP_I2C_BUS_ID,
mxt_device_info_8930,
ARRAY_SIZE(mxt_device_info_8930),
@@ -2178,7 +2032,6 @@
platform_device_register(&msm8930_device_rpm_regulator);
msm_clock_init(&msm8930_clock_init_data);
msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
- msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
msm8930_init_gpiomux();
msm8960_device_qup_spi_gsbi1.dev.platform_data =
&msm8960_qup_spi_gsbi1_pdata;
@@ -2214,12 +2067,10 @@
msm8930_pm8038_gpio_mpp_init();
#endif
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
- msm8930_init_hsic();
msm8930_init_cam();
msm8930_init_mmc();
acpuclk_init(&acpuclk_8930_soc_data);
- if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
- mxt_init_vkeys_8930();
+ mxt_init_vkeys_8930();
register_i2c_devices();
msm8930_init_fb();
slim_register_board_info(msm_slim_devices,
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 45fe40f..a8fad72 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -133,6 +133,7 @@
(socinfo_get_platform_subtype() == 1) \
)
-#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
#define MSM_8930_GSBI3_QUP_I2C_BUS_ID 3
+#define MSM_8930_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8930_GSBI9_QUP_I2C_BUS_ID 0
#define MSM_8930_GSBI10_QUP_I2C_BUS_ID 10
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index d51a6d3..c2a378f 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -517,6 +517,7 @@
.sensor_platform_info = &sensor_board_info_imx074,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
.actuator_info = &imx074_actuator_info
};
@@ -551,6 +552,7 @@
.sensor_platform_info = &sensor_board_info_mt9m114,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = YUV_SENSOR,
};
static struct msm_camera_sensor_flash_data flash_ov2720 = {
@@ -577,6 +579,7 @@
.sensor_platform_info = &sensor_board_info_ov2720,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
@@ -610,6 +613,7 @@
.sensor_platform_info = &sensor_board_info_s5k3l1yx,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
@@ -643,6 +647,7 @@
.sensor_platform_info = &sensor_board_info_imx091,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
static struct pm8xxx_mpp_config_data privacy_light_on_config = {
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 2a29ad0..b715346 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -83,11 +83,16 @@
#define TVOUT_PANEL_NAME "tvout_msm"
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-unsigned char hdmi_is_primary = 1;
+static unsigned char hdmi_is_primary = 1;
#else
-unsigned char hdmi_is_primary;
+static unsigned char hdmi_is_primary;
#endif
+unsigned char msm8960_hdmi_as_primary_selected(void)
+{
+ return hdmi_is_primary;
+}
+
static struct resource msm_fb_resources[] = {
{
.flags = IORESOURCE_DMA,
@@ -162,8 +167,11 @@
if (!strncmp(name, HDMI_PANEL_NAME,
strnlen(HDMI_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
+ PANEL_NAME_MAX_LEN))) {
+ if (hdmi_is_primary)
+ set_mdp_clocks_for_wuxga();
return 0;
+ }
if (!strncmp(name, TVOUT_PANEL_NAME,
strnlen(TVOUT_PANEL_NAME,
@@ -492,80 +500,6 @@
};
#ifdef CONFIG_MSM_BUS_SCALING
-
-static struct msm_bus_vectors rotator_init_vectors[] = {
- {
- .src = MSM_BUS_MASTER_ROTATOR,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
-};
-
-static struct msm_bus_vectors rotator_ui_vectors[] = {
- {
- .src = MSM_BUS_MASTER_ROTATOR,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = (1024 * 600 * 4 * 2 * 60),
- .ib = (1024 * 600 * 4 * 2 * 60 * 1.5),
- },
-};
-
-static struct msm_bus_vectors rotator_vga_vectors[] = {
- {
- .src = MSM_BUS_MASTER_ROTATOR,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = (640 * 480 * 2 * 2 * 30),
- .ib = (640 * 480 * 2 * 2 * 30 * 1.5),
- },
-};
-static struct msm_bus_vectors rotator_720p_vectors[] = {
- {
- .src = MSM_BUS_MASTER_ROTATOR,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = (1280 * 736 * 2 * 2 * 30),
- .ib = (1280 * 736 * 2 * 2 * 30 * 1.5),
- },
-};
-
-static struct msm_bus_vectors rotator_1080p_vectors[] = {
- {
- .src = MSM_BUS_MASTER_ROTATOR,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = (1920 * 1088 * 2 * 2 * 30),
- .ib = (1920 * 1088 * 2 * 2 * 30 * 1.5),
- },
-};
-
-static struct msm_bus_paths rotator_bus_scale_usecases[] = {
- {
- ARRAY_SIZE(rotator_init_vectors),
- rotator_init_vectors,
- },
- {
- ARRAY_SIZE(rotator_ui_vectors),
- rotator_ui_vectors,
- },
- {
- ARRAY_SIZE(rotator_vga_vectors),
- rotator_vga_vectors,
- },
- {
- ARRAY_SIZE(rotator_720p_vectors),
- rotator_720p_vectors,
- },
- {
- ARRAY_SIZE(rotator_1080p_vectors),
- rotator_1080p_vectors,
- },
-};
-
-struct msm_bus_scale_pdata rotator_bus_scale_pdata = {
- rotator_bus_scale_usecases,
- ARRAY_SIZE(rotator_bus_scale_usecases),
- .name = "rotator",
-};
-
static struct msm_bus_vectors mdp_init_vectors[] = {
{
.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -575,43 +509,6 @@
},
};
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
- /* If HDMI is used as primary */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 2000000000,
- .ib = 2000000000,
- },
-};
-static struct msm_bus_paths mdp_bus_scale_usecases[] = {
- {
- ARRAY_SIZE(mdp_init_vectors),
- mdp_init_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
-};
-#else
static struct msm_bus_vectors mdp_ui_vectors[] = {
{
.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -677,7 +574,6 @@
mdp_1080p_vectors,
},
};
-#endif
static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
mdp_bus_scale_usecases,
@@ -711,30 +607,6 @@
.cont_splash_enabled = 0x01,
};
-/**
- * Set MDP clocks to high frequency to avoid DSI underflow
- * when using high resolution 1200x1920 WUXGA panels
- */
-static void set_mdp_clocks_for_wuxga(void)
-{
- int i;
-
- mdp_ui_vectors[0].ab = 2000000000;
- mdp_ui_vectors[0].ib = 2000000000;
- mdp_vga_vectors[0].ab = 2000000000;
- mdp_vga_vectors[0].ib = 2000000000;
- mdp_720p_vectors[0].ab = 2000000000;
- mdp_720p_vectors[0].ib = 2000000000;
- mdp_1080p_vectors[0].ab = 2000000000;
- mdp_1080p_vectors[0].ib = 2000000000;
-
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
-
-}
-
void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table)
{
mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
@@ -1156,6 +1028,34 @@
size, addr, __pa(addr));
}
+/**
+ * Set MDP clocks to high frequency to avoid DSI underflow
+ * when using high resolution 1200x1920 WUXGA panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+ int i;
+
+ mdp_ui_vectors[0].ab = 2000000000;
+ mdp_ui_vectors[0].ib = 2000000000;
+ mdp_vga_vectors[0].ab = 2000000000;
+ mdp_vga_vectors[0].ib = 2000000000;
+ mdp_720p_vectors[0].ab = 2000000000;
+ mdp_720p_vectors[0].ib = 2000000000;
+ mdp_1080p_vectors[0].ab = 2000000000;
+ mdp_1080p_vectors[0].ib = 2000000000;
+
+ mdp_pdata.mdp_core_clk_rate = 200000000;
+
+ for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+ mdp_core_clk_rate_table[i] = 200000000;
+
+ if (hdmi_is_primary) {
+ dtv_bus_def_vectors[0].ab = 2000000000;
+ dtv_bus_def_vectors[0].ib = 2000000000;
+ }
+}
+
void __init msm8960_set_display_params(char *prim_panel, char *ext_panel)
{
if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
@@ -1170,6 +1070,13 @@
pr_debug("HDMI is the primary display by"
" boot parameter\n");
hdmi_is_primary = 1;
+ set_mdp_clocks_for_wuxga();
+ }
+ if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+ MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+ strnlen(MIPI_VIDEO_TOSHIBA_WUXGA_PANEL_NAME,
+ PANEL_NAME_MAX_LEN))) {
+ set_mdp_clocks_for_wuxga();
}
}
if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 5b632bd..bfb8be3 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -55,7 +55,7 @@
.pull = GPIOMUX_PULL_NONE,
};
-static struct gpiomux_setting gsbi5 = {
+static struct gpiomux_setting gsbi_uart = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_8MA,
.pull = GPIOMUX_PULL_NONE,
@@ -327,30 +327,6 @@
},
},
{
- .gpio = 22, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 23, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 24, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
- .gpio = 25, /* GSBI5 UART2 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gsbi5,
- },
- },
- {
.gpio = 44, /* GSBI12 I2C QUP SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gsbi12,
@@ -376,6 +352,60 @@
},
};
+static struct msm_gpiomux_config msm8960_gsbi5_uart_configs[] __initdata = {
+ {
+ .gpio = 22, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+ {
+ .gpio = 23, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+ {
+ .gpio = 24, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+ {
+ .gpio = 25, /* GSBI5 UART2 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+};
+
+static struct msm_gpiomux_config msm8960_gsbi8_uart_configs[] __initdata = {
+ {
+ .gpio = 34, /* GSBI8 UART3 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+ {
+ .gpio = 35, /* GSBI8 UART3 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+ {
+ .gpio = 36, /* GSBI8 UART3 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+ {
+ .gpio = 37, /* GSBI8 UART3 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gsbi_uart,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm8960_slimbus_config[] __initdata = {
{
.gpio = 60, /* slimbus data */
@@ -686,5 +716,12 @@
msm_gpiomux_install(msm8960_mdp_vsync_configs,
ARRAY_SIZE(msm8960_mdp_vsync_configs));
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+ msm_gpiomux_install(msm8960_gsbi8_uart_configs,
+ ARRAY_SIZE(msm8960_gsbi8_uart_configs));
+ else
+ msm_gpiomux_install(msm8960_gsbi5_uart_configs,
+ ARRAY_SIZE(msm8960_gsbi5_uart_configs));
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index e8df203..29fc200 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -79,6 +79,8 @@
#include <mach/mdm2.h>
#include <mach/mdm-peripheral.h>
#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
+#include <mach/scm.h>
#include <linux/fmem.h>
@@ -130,20 +132,27 @@
#endif
#define MSM_PMEM_ADSP_SIZE 0x7800000
-#define MSM_PMEM_AUDIO_SIZE 0x2B4000
+#define MSM_PMEM_AUDIO_SIZE 0x4CF000
#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000
-#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE 0x3800000
+#define MSM_ION_SF_SIZE 0x0
+#define MSM_ION_HEAP_NUM 7
+#else
+#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
+#define MSM_ION_HEAP_NUM 8
+#endif
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
-#define MSM_ION_HEAP_NUM 8
+
#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
@@ -219,7 +228,6 @@
.id = 2,
.dev = { .platform_data = &android_pmem_adsp_pdata },
};
-#endif
static struct android_pmem_platform_data android_pmem_audio_pdata = {
.name = "pmem_audio",
@@ -233,7 +241,8 @@
.id = 4,
.dev = { .platform_data = &android_pmem_audio_pdata },
};
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
struct fmem_platform_data fmem_pdata = {
};
@@ -310,20 +319,24 @@
if (!pmem_param_set) {
if (machine_is_msm8960_liquid())
pmem_size = MSM_LIQUID_PMEM_SIZE;
- if (hdmi_is_primary)
+ if (msm8960_hdmi_as_primary_selected())
pmem_size = MSM_HDMI_PRIM_PMEM_SIZE;
}
android_pmem_pdata.size = pmem_size;
-#endif
android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
}
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
{
msm8960_reserve_table[p->memory_type].size += p->size;
}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
static void __init reserve_pmem_memory(void)
{
@@ -331,8 +344,8 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
reserve_memory_for(&android_pmem_adsp_pdata);
reserve_memory_for(&android_pmem_pdata);
-#endif
reserve_memory_for(&android_pmem_audio_pdata);
+#endif
msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
#endif
}
@@ -417,6 +430,7 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &cp_mfc_ion_pdata,
},
+#ifndef CONFIG_MSM_IOMMU
{
.id = ION_SF_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
@@ -425,6 +439,7 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &co_ion_pdata,
},
+#endif
{
.id = ION_IOMMU_HEAP_ID,
.type = ION_HEAP_TYPE_IOMMU,
@@ -471,10 +486,11 @@
if (machine_is_msm8960_liquid())
msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE;
- if (hdmi_is_primary)
+ if (msm8960_hdmi_as_primary_selected())
msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
- if (machine_is_msm8960_liquid() || hdmi_is_primary) {
+ if (machine_is_msm8960_liquid() ||
+ msm8960_hdmi_as_primary_selected()) {
for (i = 0; i < ion_pdata.nr; i++) {
if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
ion_pdata.heaps[i].size =
@@ -581,6 +597,52 @@
msm8960_mdp_writeback(msm8960_reserve_table);
}
+#if defined(CONFIG_MSM_CACHE_DUMP)
+static struct msm_cache_dump_platform_data msm_cache_dump_pdata = {
+ .l2_size = L2_BUFFER_SIZE,
+};
+
+static struct platform_device msm_cache_dump_device = {
+ .name = "msm_cache_dump",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_cache_dump_pdata,
+ },
+};
+
+#endif
+
+static void reserve_cache_dump_memory(void)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP
+ unsigned int spare;
+ unsigned int l1_size;
+ unsigned int l2_size;
+ unsigned int total;
+ int ret;
+
+ ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_GET_SIZE_COMMAND_ID, &spare,
+ sizeof(spare), &l1_size, sizeof(l1_size));
+
+ if (ret)
+ /* Fall back to something reasonable here */
+ l1_size = L1_BUFFER_SIZE;
+
+ ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_GET_SIZE_COMMAND_ID, &spare,
+ sizeof(spare), &l2_size, sizeof(l2_size));
+
+ if (ret)
+ /* Fall back to something reasonable here */
+ l2_size = L2_BUFFER_SIZE;
+
+ total = l1_size + l2_size;
+
+ msm8960_reserve_table[MEMTYPE_EBI1].size += total;
+ msm_cache_dump_pdata.l1_size = l1_size;
+ msm_cache_dump_pdata.l2_size = l2_size;
+#endif
+}
+
static void __init msm8960_calculate_reserve_sizes(void)
{
size_pmem_devices();
@@ -588,6 +650,7 @@
reserve_ion_memory();
reserve_mdp_memory();
reserve_rtb_memory();
+ reserve_cache_dump_memory();
}
static struct reserve_info msm8960_reserve_info __initdata = {
@@ -2129,7 +2192,6 @@
static struct platform_device *common_devices[] __initdata = {
&msm8960_device_dmov,
&msm_device_smd,
- &msm8960_device_uart_gsbi5,
&msm_device_uart_dm6,
&msm_device_saw_core0,
&msm_device_saw_core1,
@@ -2166,9 +2228,9 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
&android_pmem_device,
&android_pmem_adsp_device,
-#endif
&android_pmem_audio_device,
#endif
+#endif
&msm_device_vidc,
&msm_device_bam_dmux,
&msm_fm_platform_init,
@@ -2192,6 +2254,7 @@
&msm8960_rpm_stat_device,
&msm_device_tz_log,
#ifdef CONFIG_MSM_QDSS
+ &msm_qdss_device,
&msm_etb_device,
&msm_tpiu_device,
&msm_funnel_device,
@@ -2205,9 +2268,13 @@
&msm8960_cpu_idle_device,
&msm8960_msm_gov_device,
&msm8960_device_cache_erp,
+#ifdef CONFIG_MSM_CACHE_DUMP
+ &msm_cache_dump_device,
+#endif
};
static struct platform_device *sim_devices[] __initdata = {
+ &msm8960_device_uart_gsbi5,
&msm8960_device_otg,
&msm8960_device_gadget_peripheral,
&msm_device_hsusb_host,
@@ -2253,6 +2320,7 @@
};
static struct platform_device *rumi3_devices[] __initdata = {
+ &msm8960_device_uart_gsbi5,
&msm_kgsl_3d0,
&msm_kgsl_2d0,
&msm_kgsl_2d1,
@@ -2267,6 +2335,8 @@
&msm_8960_q6_mss_sw,
&msm_8960_riva,
&msm_pil_tzapps,
+ &msm_pil_dsps,
+ &msm_pil_vidc,
&msm8960_device_otg,
&msm8960_device_gadget_peripheral,
&msm_device_hsusb_host,
@@ -2832,6 +2902,12 @@
platform_device_register(&msm8960_device_ext_3p3v_vreg);
if (machine_is_msm8960_cdp())
platform_device_register(&msm8960_device_ext_l2_vreg);
+
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+ platform_device_register(&msm8960_device_uart_gsbi8);
+ else
+ platform_device_register(&msm8960_device_uart_gsbi5);
+
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8960_pm8921_gpio_mpp_init();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index dc63fee..dea957c 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -73,13 +73,13 @@
extern struct sx150x_platform_data msm8960_sx150x_data[];
extern struct msm_camera_board_info msm8960_camera_board_info;
-extern unsigned char hdmi_is_primary;
void msm8960_init_cam(void);
void msm8960_init_fb(void);
void msm8960_init_pmic(void);
void msm8960_init_mmc(void);
int msm8960_init_gpiomux(void);
+unsigned char msm8960_hdmi_as_primary_selected(void);
void msm8960_allocate_fb_region(void);
void msm8960_set_display_params(char *prim_panel, char *ext_panel);
void msm8960_pm8921_gpio_mpp_init(void);
diff --git a/arch/arm/mach-msm/board-9615-display.c b/arch/arm/mach-msm/board-9615-display.c
new file mode 100644
index 0000000..74bc984
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-display.c
@@ -0,0 +1,169 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/ion.h>
+#include <asm/mach-types.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <mach/ion.h>
+#include <mach/msm_bus_board.h>
+
+#include "devices.h"
+#include "board-9615.h"
+
+/* prim = 240 x 320 x 4(bpp) x 2(pages) */
+#define MSM_FB_PRIM_BUF_SIZE roundup(240 * 320 * 4 * 2, 0x10000)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
+
+#define GPIO_PIN_EBI2_LCD_A_D 21
+#define GPIO_PIN_EBI2_LCD_CS 22
+#define GPIO_PIN_EBI2_LCD_RS 24
+
+
+#ifdef CONFIG_FB_MSM
+
+static struct resource msm_fb_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+ return 0;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+ .detect_client = msm_fb_detect_panel,
+};
+
+static struct platform_device msm_fb_device = {
+ .name = "msm_fb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_fb_resources),
+ .resource = msm_fb_resources,
+ .dev.platform_data = &msm_fb_pdata,
+};
+
+void __init mdm9615_allocate_fb_region(void)
+{
+ void *addr;
+ unsigned long size;
+
+ size = MSM_FB_SIZE;
+ addr = alloc_bootmem_align(size, 0x1000);
+ msm_fb_resources[0].start = __pa(addr);
+ msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+ pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
+ size, addr, __pa(addr));
+}
+
+
+static bool ebi2_power_init;
+static int ebi2_panel_power(int on)
+{
+ static struct regulator *panel_power;
+ int rc;
+
+ pr_debug("%s: on=%d\n", __func__, on);
+
+ if (!ebi2_power_init) {
+ panel_power = regulator_get(&msm_ebi2_lcdc_device.dev,
+ "VDDI2");
+ if (IS_ERR_OR_NULL(panel_power)) {
+ pr_err("could not get L14, rc = %ld\n",
+ PTR_ERR(panel_power));
+ return -ENODEV;
+ }
+
+ rc = regulator_set_voltage(panel_power, 2800000, 3800000);
+ if (rc) {
+ pr_err("set_voltage L14 failed, rc=%d\n", rc);
+ return -EINVAL;
+ }
+
+ ebi2_power_init = true;
+ }
+
+ if (on) {
+ rc = regulator_enable(panel_power);
+ if (rc) {
+ pr_err("enable L14 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = gpio_request(GPIO_PIN_EBI2_LCD_A_D, "disp_a_d");
+ if (rc) {
+ pr_err("request gpio EBI2_LCD_A_D failed, rc=%d\n", rc);
+ goto error1;
+ }
+ rc = gpio_request(GPIO_PIN_EBI2_LCD_CS, "disp_cs");
+ if (rc) {
+ pr_err("request gpio EBI2_LCD_CS failed, rc=%d\n", rc);
+ goto error2;
+ }
+ rc = gpio_request(GPIO_PIN_EBI2_LCD_RS, "disp_rs");
+ if (rc) {
+ pr_err("request gpio EBI2_LCD_RS failed, rc=%d\n", rc);
+ goto error3;
+ }
+ } else {
+ gpio_free(GPIO_PIN_EBI2_LCD_RS);
+ gpio_free(GPIO_PIN_EBI2_LCD_CS);
+ gpio_free(GPIO_PIN_EBI2_LCD_A_D);
+
+ rc = regulator_disable(panel_power);
+ if (rc) {
+ pr_err("disable L14 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+error3:
+ gpio_free(GPIO_PIN_EBI2_LCD_CS);
+error2:
+ gpio_free(GPIO_PIN_EBI2_LCD_A_D);
+error1:
+ regulator_disable(panel_power);
+ return rc;
+
+}
+
+static struct lcdc_platform_data ebi2_lcdc_pdata = {
+ .lcdc_power_save = ebi2_panel_power,
+};
+
+static struct lvds_panel_platform_data ebi2_epson_s1d_pdata;
+
+static struct platform_device ebi2_epson_s1d_panel_device = {
+ .name = "ebi2_epson_s1d_qvga",
+ .id = 0,
+ .dev = {
+ .platform_data = &ebi2_epson_s1d_pdata,
+ }
+};
+
+void __init mdm9615_init_fb(void)
+{
+ platform_device_register(&msm_fb_device);
+ platform_device_register(&ebi2_epson_s1d_panel_device);
+
+ msm_fb_register_device("ebi2_lcd", &ebi2_lcdc_pdata);
+}
+#endif
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index e61f001..0e18918 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -85,6 +85,26 @@
.pull = GPIOMUX_PULL_NONE,
};
+#ifdef CONFIG_FB_MSM_EBI2
+static struct gpiomux_setting ebi2_lcdc_a_d = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting ebi2_lcdc_cs = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ebi2_lcdc_rs = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+#endif
+
static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
{
.gpio = 24,
@@ -263,6 +283,29 @@
},
};
+#ifdef CONFIG_FB_MSM_EBI2
+static struct msm_gpiomux_config msm9615_ebi2_lcdc_configs[] __initdata = {
+ {
+ .gpio = 21, /* a_d */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ebi2_lcdc_a_d,
+ },
+ },
+ {
+ .gpio = 22, /* cs */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ebi2_lcdc_cs,
+ },
+ },
+ {
+ .gpio = 24, /* rs */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ebi2_lcdc_rs,
+ },
+ },
+};
+#endif
+
int __init msm9615_init_gpiomux(void)
{
int rc;
@@ -289,5 +332,10 @@
msm_gpiomux_install(msm9615_audio_codec_configs,
ARRAY_SIZE(msm9615_audio_codec_configs));
+#ifdef CONFIG_FB_MSM_EBI2
+ msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
+ ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
+#endif
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index dd83d6f..8328501 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -65,6 +65,7 @@
};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8018_l14", NULL),
+ REGULATOR_SUPPLY("VDDI2", "ebi2_lcd.0"),
};
VREG_CONSUMERS(S1) = {
REGULATOR_SUPPLY("8018_s1", NULL),
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 5a795c0..c73e5a9 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -202,9 +202,7 @@
.sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
.pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC2],
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
-#endif
};
static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
#else
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 3438f9d..8a8e575 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -28,6 +28,8 @@
#include <linux/leds-pm8xxx.h>
#include <linux/power/ltc4088-charger.h>
#include <linux/msm_tsens.h>
+#include <linux/ion.h>
+#include <linux/memory.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -39,6 +41,8 @@
#include <mach/msm_bus_board.h>
#include <mach/msm_xo.h>
#include <mach/dma.h>
+#include <mach/ion.h>
+#include <mach/msm_memtypes.h>
#include "timer.h"
#include "devices.h"
#include "board-9615.h"
@@ -47,6 +51,80 @@
#include "acpuclock.h"
#include "pm-boot.h"
+#ifdef CONFIG_ION_MSM
+#define MSM_ION_AUDIO_SIZE 0xAF000
+#define MSM_ION_HEAP_NUM 3
+#define MSM_KERNEL_EBI_SIZE 0x51000
+
+static struct memtype_reserve msm9615_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static int msm9615_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+ .adjacent_mem_id = INVALID_HEAP_ID,
+ .align = PAGE_SIZE,
+};
+
+static struct ion_platform_data ion_pdata = {
+ .nr = MSM_ION_HEAP_NUM,
+ .heaps = {
+ {
+ .id = ION_SYSTEM_HEAP_ID,
+ .type = ION_HEAP_TYPE_SYSTEM,
+ .name = ION_VMALLOC_HEAP_NAME,
+ },
+ {
+ .id = ION_IOMMU_HEAP_ID,
+ .type = ION_HEAP_TYPE_IOMMU,
+ .name = ION_IOMMU_HEAP_NAME,
+ },
+ {
+ .id = ION_AUDIO_HEAP_ID,
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .name = ION_AUDIO_HEAP_NAME,
+ .size = MSM_ION_AUDIO_SIZE,
+ .memory_type = ION_EBI_TYPE,
+ .extra_data = (void *) &co_ion_pdata,
+ },
+ }
+};
+
+static struct platform_device ion_dev = {
+ .name = "ion-msm",
+ .id = 1,
+ .dev = { .platform_data = &ion_pdata },
+};
+
+static void reserve_ion_memory(void)
+{
+ msm9615_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+}
+
+static void __init msm9615_calculate_reserve_sizes(void)
+{
+ reserve_ion_memory();
+ msm9615_reserve_table[MEMTYPE_EBI1].size += MSM_KERNEL_EBI_SIZE;
+}
+
+static struct reserve_info msm9615_reserve_info __initdata = {
+ .memtype_reserve_table = msm9615_reserve_table,
+ .calculate_reserve_sizes = msm9615_calculate_reserve_sizes,
+ .paddr_to_memtype = msm9615_paddr_to_memtype,
+};
+#endif
+
static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
@@ -367,7 +445,7 @@
0x44, 0x80,/* set VBUS valid threshold and
disconnect valid threshold */
0x38, 0x81, /* update DC voltage level */
- 0x14, 0x82,/* set preemphasis and rise/fall time */
+ 0x24, 0x82,/* set preemphasis and rise/fall time */
0x13, 0x83,/* set source impedance adjustment */
-1};
@@ -634,6 +712,9 @@
#ifdef CONFIG_HW_RANDOM_MSM
&msm_device_rng,
#endif
+#ifdef CONFIG_ION_MSM
+ &ion_dev,
+#endif
&msm_pcm,
&msm_multi_ch_pcm,
@@ -679,7 +760,10 @@
static void __init msm9615_reserve(void)
{
- msm_pm_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
+#ifdef CONFIG_ION_MSM
+ reserve_info = &msm9615_reserve_info;
+ msm_reserve();
+#endif
}
static void __init msm9615_common_init(void)
@@ -715,6 +799,7 @@
msm_pm_set_rpm_wakeup_irq(RPM_APCC_CPU0_WAKE_UP_IRQ);
msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
msm_pm_data);
+ msm_pm_boot_pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
msm_tsens_early_init(&msm_tsens_pdata);
}
@@ -722,6 +807,9 @@
static void __init msm9615_cdp_init(void)
{
msm9615_common_init();
+#ifdef CONFIG_FB_MSM
+ mdm9615_init_fb();
+#endif
}
static void __init msm9615_mtp_init(void)
@@ -729,6 +817,13 @@
msm9615_common_init();
}
+#ifdef CONFIG_FB_MSM
+static void __init mdm9615_allocate_memory_regions(void)
+{
+ mdm9615_allocate_fb_region();
+}
+#endif
+
MACHINE_START(MSM9615_CDP, "QCT MSM9615 CDP")
.map_io = msm9615_map_io,
.init_irq = msm9615_init_irq,
@@ -736,6 +831,9 @@
.timer = &msm_timer,
.init_machine = msm9615_cdp_init,
.reserve = msm9615_reserve,
+#ifdef CONFIG_FB_MSM
+ .init_early = mdm9615_allocate_memory_regions,
+#endif
MACHINE_END
MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 27f5d81..239453f 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -40,4 +40,6 @@
int msm9615_init_gpiomux(void);
void msm9615_init_mmc(void);
+void mdm9615_allocate_fb_region(void);
+void mdm9615_init_fb(void);
#endif
diff --git a/arch/arm/mach-msm/board-copper-regulator.c b/arch/arm/mach-msm/board-copper-regulator.c
index 89878ce..9409936 100644
--- a/arch/arm/mach-msm/board-copper-regulator.c
+++ b/arch/arm/mach-msm/board-copper-regulator.c
@@ -138,6 +138,18 @@
VREG_CONSUMERS(LVS3) = {
REGULATOR_SUPPLY("8941_lvs3", NULL),
};
+VREG_CONSUMERS(K0) = {
+ REGULATOR_SUPPLY("krait0", NULL),
+};
+VREG_CONSUMERS(K1) = {
+ REGULATOR_SUPPLY("krait1", NULL),
+};
+VREG_CONSUMERS(K2) = {
+ REGULATOR_SUPPLY("krait2", NULL),
+};
+VREG_CONSUMERS(K3) = {
+ REGULATOR_SUPPLY("krait3", NULL),
+};
#define PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
_always_on, _supply_regulator, _hpm_min, _system_uA) \
@@ -189,6 +201,14 @@
PM8X41_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, \
_always_on, _supply_regulator, 0, 0)
+#define KRAIT_PWR(_id, _name, _always_on, _min_uV, _max_uV, \
+ _supply_regulator, _hpm_min, _system_uA) \
+ PM8X41_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+ | REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+ REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_DRMS, _always_on, \
+ _supply_regulator, _hpm_min, _system_uA)
+
/* PM8x41 regulator constraints */
/* ID name a_on min_uV max_uV supply hpm_min sys_uA */
@@ -233,6 +253,12 @@
PM8X41_VS(LVS2, "8941_lvs2", 0, "8941_s3");
PM8X41_VS(LVS3, "8941_lvs3", 0, "8941_s3");
+/* ID name a_on min_uV max_uV supply hpm_min sys_uA */
+KRAIT_PWR(K0, "krait0", 0, 850000, 1100000, NULL, 100000, 0);
+KRAIT_PWR(K1, "krait1", 0, 850000, 1100000, NULL, 100000, 0);
+KRAIT_PWR(K2, "krait2", 0, 850000, 1100000, NULL, 100000, 0);
+KRAIT_PWR(K3, "krait3", 0, 850000, 1100000, NULL, 100000, 0);
+
#define VREG_DEVICE(_name, _devid) \
vreg_device_##_name __devinitdata = \
{ \
@@ -279,6 +305,10 @@
static struct platform_device VREG_DEVICE(LVS1, 36);
static struct platform_device VREG_DEVICE(LVS2, 37);
static struct platform_device VREG_DEVICE(LVS3, 38);
+static struct platform_device VREG_DEVICE(K0, 39);
+static struct platform_device VREG_DEVICE(K1, 40);
+static struct platform_device VREG_DEVICE(K2, 41);
+static struct platform_device VREG_DEVICE(K3, 42);
struct platform_device *msm_copper_stub_regulator_devices[] __devinitdata = {
&vreg_device_S1B,
@@ -319,6 +349,10 @@
&vreg_device_LVS1,
&vreg_device_LVS2,
&vreg_device_LVS3,
+ &vreg_device_K0,
+ &vreg_device_K1,
+ &vreg_device_K2,
+ &vreg_device_K3,
};
int msm_copper_stub_regulator_devices_len __devinitdata =
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index b5ab440..b074809 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -369,6 +369,17 @@
msm_copper_stub_regulator_devices_len);
}
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msm_copper_add_drivers(void)
+{
+ regulator_stub_init();
+}
+
static struct of_device_id irq_match[] __initdata = {
{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
@@ -400,6 +411,7 @@
CLK_DUMMY("iface_clk", SPI_P_CLK, "spi_qsd.1", OFF),
CLK_DUMMY("core_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("iface_clk", NULL, "f9966000.i2c", 0),
+ CLK_DUMMY("core_clk", NULL, "fe12f000.slim", OFF),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 3fb6042..674df09 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -26,25 +26,7 @@
static void __init msm_dt_timer_init(void)
{
- struct device_node *node;
- struct arch_timer tmr;
- int rc;
-
- node = of_find_compatible_node(NULL, NULL, "qcom,msm-qtimer");
- if (!node) {
- pr_err("no matching timer node found\n");
- return;
- }
-
- tmr.res[0].start = 0;
- tmr.res[1].start = 0;
- rc = of_irq_to_resource(node, 0, tmr.res);
- if (rc < 0)
- pr_err("interrupt not specified in timer node\n");
- else
- arch_timer_register(&tmr);
-
- of_node_put(node);
+ arch_timer_of_register();
}
static struct sys_timer msm_dt_timer = {
@@ -73,11 +55,13 @@
msm_copper_init(&adata);
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
- if (machine_is_copper())
+ if (machine_is_copper()) {
msm_copper_add_devices();
+ msm_copper_add_drivers();
+ }
}
-static const char *msm_dt_match[] __initdata = {
+static const char *msm_dt_match[] __initconst = {
"qcom,msmcopper",
NULL
};
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 87fea3f..ce6bf35 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -835,6 +835,7 @@
&qcedev_device,
&ota_qcrypto_device,
&fsm_xo_device,
+ &fsm9xxx_device_watchdog,
};
static void __init fsm9xxx_init_irq(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index a8ab81a..81abbc0 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -20,6 +20,7 @@
#include <asm/gpio.h>
#include <asm/mach-types.h>
#include <mach/rpc_pmapp.h>
+#include <mach/socinfo.h>
#include "board-msm7627a.h"
#include "devices-msm7x2xa.h"
@@ -98,10 +99,19 @@
int gpio_bt_sys_rest_en = 133;
static void gpio_bt_config(void)
{
+ u32 socinfo = socinfo_get_platform_version();
if (machine_is_msm7627a_qrd1())
gpio_bt_sys_rest_en = 114;
if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
gpio_bt_sys_rest_en = 16;
+ if (machine_is_msm8625_qrd7())
+ gpio_bt_sys_rest_en = 88;
+ if (machine_is_msm7627a_qrd3()) {
+ if (socinfo == 0x70002)
+ gpio_bt_sys_rest_en = 88;
+ else
+ gpio_bt_sys_rest_en = 85;
+ }
}
static int bt_set_gpio(int on)
@@ -113,7 +123,7 @@
__func__, gpio_bt_sys_rest_en, on);
if (on) {
- if (machine_is_msm7627a_evb()) {
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_qrd7()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA),
@@ -128,7 +138,8 @@
if (!marimba_get_fm_status(&config) &&
!marimba_get_bt_status(&config)) {
- if (machine_is_msm7627a_evb()) {
+ if (machine_is_msm7627a_evb() ||
+ machine_is_msm8625_qrd7()) {
gpio_set_value(gpio_bt_sys_rest_en, 0);
rc = gpio_tlmm_config(GPIO_CFG(
gpio_bt_sys_rest_en, 0,
@@ -959,8 +970,6 @@
int i, rc = 0;
struct device *dev;
- if (machine_is_msm7627a_qrd3())
- return;
gpio_bt_config();
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 608eb1e..94b8710 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -149,6 +149,7 @@
.sensor_platform_info = &sensor_board_info_s5k4e1,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
#ifdef CONFIG_DW9712_ACT
.actuator_info = &s5k4e1_actuator_info
#endif
@@ -178,6 +179,7 @@
.sensor_platform_info = &sensor_board_info_ov7692,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = YUV_SENSOR,
};
#endif
@@ -204,9 +206,9 @@
};
static struct msm_camera_sensor_flash_src msm_flash_src_ov5647 = {
- .flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
- ._fsrc.led_src.led_name = "flashlight",
- ._fsrc.led_src.led_name_len = 10,
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_LED1,
+ ._fsrc.ext_driver_src.led_en = 13,
+ ._fsrc.ext_driver_src.led_flash_en = 32,
};
static struct msm_camera_sensor_flash_data flash_ov5647 = {
@@ -225,6 +227,7 @@
.sensor_platform_info = &sensor_board_info_ov5647,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
#ifdef CONFIG_AD5046_ACT
.actuator_info = &ad5046_actuator_info
@@ -254,6 +257,7 @@
.sensor_platform_info = &sensor_board_info_mt9e013,
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
#endif
@@ -279,6 +283,7 @@
.sensor_platform_info = &sensor_board_info_ov9726,
.csi_if = 1,
.camera_type = FRONT_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
};
#endif
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 86343f5..e2076f8 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -28,13 +28,19 @@
#include "board-msm7627a.h"
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_SIZE 0x261000
+#define MSM_FB_SIZE 0x2FD000
#define MSM7x25A_MSM_FB_SIZE 0xE1000
#else
#define MSM_FB_SIZE 0x196000
#define MSM7x25A_MSM_FB_SIZE 0x96000
#endif
+/*
+ * Reserve enough v4l2 space for a double buffered full screen
+ * res image (864x480x1.5x2)
+ */
+#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 1244160
+
static unsigned fb_size = MSM_FB_SIZE;
static int __init fb_size_setup(char *p)
{
@@ -459,6 +465,14 @@
}
};
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct resource msm_v4l2_video_overlay_resources[] = {
+ {
+ .flags = IORESOURCE_DMA,
+ }
+};
+#endif
+
#define LCDC_TOSHIBA_FWVGA_PANEL_NAME "lcdc_toshiba_fwvga_pt"
#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga"
@@ -522,6 +536,16 @@
}
};
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct platform_device msm_v4l2_video_overlay_device = {
+ .name = "msm_v4l2_overlay_pd",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_v4l2_video_overlay_resources),
+ .resource = msm_v4l2_video_overlay_resources,
+ };
+#endif
+
+
#ifdef CONFIG_FB_MSM_MIPI_DSI
static int mipi_renesas_set_bl(int level)
{
@@ -549,6 +573,93 @@
};
#endif
+static int evb_backlight_control(int level)
+{
+
+ int i = 0;
+ int remainder;
+ /* device address byte = 0x72 */
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+ gpio_set_value_cansleep(96, 0);
+ udelay(33);
+ gpio_set_value_cansleep(96, 1);
+ udelay(67);
+ gpio_set_value_cansleep(96, 0);
+ udelay(33);
+ gpio_set_value_cansleep(96, 1);
+ udelay(67);
+ gpio_set_value_cansleep(96, 0);
+ udelay(33);
+ gpio_set_value_cansleep(96, 1);
+ udelay(67);
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+ gpio_set_value_cansleep(96, 0);
+ udelay(33);
+ gpio_set_value_cansleep(96, 1);
+ udelay(67);
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+
+ /* t-EOS and t-start */
+ gpio_set_value_cansleep(96, 0);
+ ndelay(4200);
+ gpio_set_value_cansleep(96, 1);
+ ndelay(9000);
+
+ /* data byte */
+ /* RFA = 0 */
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+
+ /* Address bits */
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+
+ /* Data bits */
+ for (i = 0; i < 5; i++) {
+ remainder = (level) & (16);
+ if (remainder) {
+ gpio_set_value_cansleep(96, 0);
+ udelay(33);
+ gpio_set_value_cansleep(96, 1);
+ udelay(67);
+ } else {
+ gpio_set_value_cansleep(96, 0);
+ udelay(67);
+ gpio_set_value_cansleep(96, 1);
+ udelay(33);
+ }
+ level = level << 1;
+ }
+
+ /* t-EOS */
+ gpio_set_value_cansleep(96, 0);
+ ndelay(12000);
+ gpio_set_value_cansleep(96, 1);
+ return 0;
+}
+
+
static struct msm_panel_common_pdata mipi_truly_pdata = {
.pmic_backlight = mipi_truly_set_bl,
};
@@ -562,7 +673,7 @@
};
static struct msm_panel_common_pdata mipi_NT35510_pdata = {
- .pmic_backlight = NULL,/*mipi_NT35510_set_bl,*/
+ .pmic_backlight = evb_backlight_control,
};
static struct platform_device mipi_dsi_NT35510_panel_device = {
@@ -573,12 +684,27 @@
}
};
+static struct msm_panel_common_pdata mipi_NT35516_pdata = {
+ .pmic_backlight = NULL,
+};
+
+static struct platform_device mipi_dsi_NT35516_panel_device = {
+ .name = "mipi_truly_tft540960_1_e",
+ .id = 0,
+ .dev = {
+ .platform_data = &mipi_NT35516_pdata,
+ }
+};
+
static struct platform_device *msm_fb_devices[] __initdata = {
&msm_fb_device,
&lcdc_toshiba_panel_device,
#ifdef CONFIG_FB_MSM_MIPI_DSI
&mipi_dsi_renesas_panel_device,
#endif
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+ &msm_v4l2_video_overlay_device,
+#endif
};
static struct platform_device *qrd_fb_devices[] __initdata = {
@@ -594,6 +720,7 @@
static struct platform_device *evb_fb_devices[] __initdata = {
&msm_fb_device,
&mipi_dsi_NT35510_panel_device,
+ &mipi_dsi_NT35516_panel_device,
};
void __init msm_msm7627a_allocate_memory_regions(void)
@@ -610,6 +737,17 @@
msm_fb_resources[0].end = msm_fb_resources[0].start + fb_size - 1;
pr_info("allocating %lu bytes at %p (%lx physical) for fb\n", fb_size,
addr, __pa(addr));
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+ fb_size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE;
+ addr = alloc_bootmem_align(fb_size, 0x1000);
+ msm_v4l2_video_overlay_resources[0].start = __pa(addr);
+ msm_v4l2_video_overlay_resources[0].end =
+ msm_v4l2_video_overlay_resources[0].start + fb_size - 1;
+ pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n",
+ fb_size, addr, __pa(addr));
+#endif
+
}
static struct msm_panel_common_pdata mdp_pdata = {
@@ -990,7 +1128,7 @@
return rc;
rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
GPIO_CFG_ENABLE);
if (rc < 0) {
pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
@@ -1046,7 +1184,17 @@
qrd3_dsi_gpio_initialized = 1;
}
- gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, !!on);
+ if (on) {
+ gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+ udelay(190);
+ gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
+ udelay(286);
+ gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+ /* 1 wire mode starts from this low to high transition */
+ udelay(50);
+ } else
+ gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, !!on);
+
gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_2V85_EN, !!on);
gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_1V8_EN, !!on);
@@ -1104,15 +1252,36 @@
};
#endif
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+ if (strnlen(param, PANEL_NAME_MAX_LEN))
+ strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+ return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+void msm7x27a_set_display_params(char *prim_panel)
+{
+ if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+ strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+ PANEL_NAME_MAX_LEN);
+ pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+ msm_fb_pdata.prim_panel_name);
+ }
+}
+
void __init msm_fb_add_devices(void)
{
+ msm7x27a_set_display_params(prim_panel_name);
if (machine_is_msm7627a_qrd1())
platform_add_devices(qrd_fb_devices,
ARRAY_SIZE(qrd_fb_devices));
- else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ mipi_NT35510_pdata.bl_lock = 1;
platform_add_devices(evb_fb_devices,
ARRAY_SIZE(evb_fb_devices));
- else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+ } else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
sku3_lcdc_lcd_camera_power_init();
platform_add_devices(qrd3_fb_devices,
ARRAY_SIZE(qrd3_fb_devices));
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
new file mode 100644
index 0000000..8a2f53a
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -0,0 +1,756 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio_event.h>
+#include <linux/leds.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/i2c.h>
+#include <linux/input/rmi_platformdata.h>
+#include <linux/input/rmi_i2c.h>
+#include <linux/delay.h>
+#include <linux/atmel_maxtouch.h>
+#include <linux/input/ft5x06_ts.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_server_handset.h>
+
+#include "devices.h"
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+
+#define ATMEL_TS_I2C_NAME "maXTouch"
+#define ATMEL_X_OFFSET 13
+#define ATMEL_Y_OFFSET 0
+
+#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
+defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
+
+#ifndef CLEARPAD3000_ATTEN_GPIO
+#define CLEARPAD3000_ATTEN_GPIO (48)
+#endif
+
+#ifndef CLEARPAD3000_RESET_GPIO
+#define CLEARPAD3000_RESET_GPIO (26)
+#endif
+
+#define KP_INDEX(row, col) ((row)*ARRAY_SIZE(kp_col_gpios) + (col))
+
+static unsigned int kp_row_gpios[] = {31, 32, 33, 34, 35};
+static unsigned int kp_col_gpios[] = {36, 37, 38, 39, 40};
+
+static const unsigned short keymap[ARRAY_SIZE(kp_col_gpios) *
+ ARRAY_SIZE(kp_row_gpios)] = {
+ [KP_INDEX(0, 0)] = KEY_7,
+ [KP_INDEX(0, 1)] = KEY_DOWN,
+ [KP_INDEX(0, 2)] = KEY_UP,
+ [KP_INDEX(0, 3)] = KEY_RIGHT,
+ [KP_INDEX(0, 4)] = KEY_ENTER,
+
+ [KP_INDEX(1, 0)] = KEY_LEFT,
+ [KP_INDEX(1, 1)] = KEY_SEND,
+ [KP_INDEX(1, 2)] = KEY_1,
+ [KP_INDEX(1, 3)] = KEY_4,
+ [KP_INDEX(1, 4)] = KEY_CLEAR,
+
+ [KP_INDEX(2, 0)] = KEY_6,
+ [KP_INDEX(2, 1)] = KEY_5,
+ [KP_INDEX(2, 2)] = KEY_8,
+ [KP_INDEX(2, 3)] = KEY_3,
+ [KP_INDEX(2, 4)] = KEY_NUMERIC_STAR,
+
+ [KP_INDEX(3, 0)] = KEY_9,
+ [KP_INDEX(3, 1)] = KEY_NUMERIC_POUND,
+ [KP_INDEX(3, 2)] = KEY_0,
+ [KP_INDEX(3, 3)] = KEY_2,
+ [KP_INDEX(3, 4)] = KEY_SLEEP,
+
+ [KP_INDEX(4, 0)] = KEY_BACK,
+ [KP_INDEX(4, 1)] = KEY_HOME,
+ [KP_INDEX(4, 2)] = KEY_MENU,
+ [KP_INDEX(4, 3)] = KEY_VOLUMEUP,
+ [KP_INDEX(4, 4)] = KEY_VOLUMEDOWN,
+};
+
+/* SURF keypad platform device information */
+static struct gpio_event_matrix_info kp_matrix_info = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = keymap,
+ .output_gpios = kp_row_gpios,
+ .input_gpios = kp_col_gpios,
+ .noutputs = ARRAY_SIZE(kp_row_gpios),
+ .ninputs = ARRAY_SIZE(kp_col_gpios),
+ .settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+ .poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info[] = {
+ &kp_matrix_info.info
+};
+
+static struct gpio_event_platform_data kp_pdata = {
+ .name = "7x27a_kp",
+ .info = kp_info,
+ .info_count = ARRAY_SIZE(kp_info)
+};
+
+static struct platform_device kp_pdev = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &kp_pdata,
+ },
+};
+
+/* 8625 keypad device information */
+static unsigned int kp_row_gpios_8625[] = {31};
+static unsigned int kp_col_gpios_8625[] = {36, 37};
+
+static const unsigned short keymap_8625[] = {
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_8625 = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = keymap_8625,
+ .output_gpios = kp_row_gpios_8625,
+ .input_gpios = kp_col_gpios_8625,
+ .noutputs = ARRAY_SIZE(kp_row_gpios_8625),
+ .ninputs = ARRAY_SIZE(kp_col_gpios_8625),
+ .settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+ .poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_8625[] = {
+ &kp_matrix_info_8625.info,
+};
+
+static struct gpio_event_platform_data kp_pdata_8625 = {
+ .name = "7x27a_kp",
+ .info = kp_info_8625,
+ .info_count = ARRAY_SIZE(kp_info_8625)
+};
+
+static struct platform_device kp_pdev_8625 = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &kp_pdata_8625,
+ },
+};
+
+#define LED_GPIO_PDM 96
+#define LED_RED_GPIO_8625 49
+#define LED_GREEN_GPIO_8625 34
+
+static struct gpio_led gpio_leds_config_8625[] = {
+ {
+ .name = "green",
+ .gpio = LED_GREEN_GPIO_8625,
+ },
+ {
+ .name = "red",
+ .gpio = LED_RED_GPIO_8625,
+ },
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
+ .num_leds = ARRAY_SIZE(gpio_leds_config_8625),
+ .leds = gpio_leds_config_8625,
+};
+
+static struct platform_device gpio_leds_8625 = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_leds_pdata_8625,
+ },
+};
+
+#define MXT_TS_IRQ_GPIO 48
+#define MXT_TS_RESET_GPIO 26
+
+static const u8 mxt_config_data[] = {
+ /* T6 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T38 Object */
+ 16, 0, 0, 0, 0, 0, 0, 0,
+ /* T7 Object */
+ 32, 16, 50,
+ /* T8 Object */
+ 30, 0, 20, 20, 0, 0, 20, 0, 50, 0,
+ /* T9 Object */
+ 3, 0, 0, 18, 11, 0, 32, 75, 3, 3,
+ 0, 1, 1, 0, 10, 10, 10, 10, 31, 3,
+ 223, 1, 11, 11, 15, 15, 151, 43, 145, 80,
+ 100, 15, 0, 0, 0,
+ /* T15 Object */
+ 131, 0, 11, 11, 1, 1, 0, 45, 3, 0,
+ 0,
+ /* T18 Object */
+ 0, 0,
+ /* T19 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ /* T23 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* T25 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T40 Object */
+ 0, 0, 0, 0, 0,
+ /* T42 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T46 Object */
+ 0, 2, 32, 48, 0, 0, 0, 0, 0,
+ /* T47 Object */
+ 1, 20, 60, 5, 2, 50, 40, 0, 0, 40,
+ /* T48 Object */
+ 1, 12, 80, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
+ 10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
+ 0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+ 10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
+ 80, 100, 15, 3,
+};
+
+static struct mxt_config_info mxt_config_array[] = {
+ {
+ .config = mxt_config_data,
+ .config_length = ARRAY_SIZE(mxt_config_data),
+ .family_id = 0x81,
+ .variant_id = 0x01,
+ .version = 0x10,
+ .build = 0xAA,
+ },
+};
+
+static int mxt_key_codes[MXT_KEYARRAY_MAX_KEYS] = {
+ [0] = KEY_HOME,
+ [1] = KEY_MENU,
+ [9] = KEY_BACK,
+ [10] = KEY_SEARCH,
+};
+
+static struct mxt_platform_data mxt_platform_data = {
+ .config_array = mxt_config_array,
+ .config_array_size = ARRAY_SIZE(mxt_config_array),
+ .panel_minx = 0,
+ .panel_maxx = 479,
+ .panel_miny = 0,
+ .panel_maxy = 799,
+ .disp_minx = 0,
+ .disp_maxx = 479,
+ .disp_miny = 0,
+ .disp_maxy = 799,
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .i2c_pull_up = true,
+ .reset_gpio = MXT_TS_RESET_GPIO,
+ .irq_gpio = MXT_TS_IRQ_GPIO,
+ .key_codes = mxt_key_codes,
+};
+
+static struct i2c_board_info mxt_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+ .platform_data = &mxt_platform_data,
+ .irq = MSM_GPIO_TO_INT(MXT_TS_IRQ_GPIO),
+ },
+};
+
+static int synaptics_touchpad_setup(void);
+
+static struct msm_gpio clearpad3000_cfg_data[] = {
+ {GPIO_CFG(CLEARPAD3000_ATTEN_GPIO, 0, GPIO_CFG_INPUT,
+ GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "rmi4_attn"},
+ {GPIO_CFG(CLEARPAD3000_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_8MA), "rmi4_reset"},
+};
+
+static struct rmi_XY_pair rmi_offset = {.x = 0, .y = 0};
+static struct rmi_range rmi_clipx = {.min = 48, .max = 980};
+static struct rmi_range rmi_clipy = {.min = 7, .max = 1647};
+static struct rmi_f11_functiondata synaptics_f11_data = {
+ .swap_axes = false,
+ .flipX = false,
+ .flipY = false,
+ .offset = &rmi_offset,
+ .button_height = 113,
+ .clipX = &rmi_clipx,
+ .clipY = &rmi_clipy,
+};
+
+#define MAX_LEN 100
+
+static ssize_t clearpad3000_virtual_keys_register(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+ ":60:830:120:60" ":" __stringify(EV_KEY) \
+ ":" __stringify(KEY_HOME) ":180:830:120:60" \
+ ":" __stringify(EV_KEY) ":" \
+ __stringify(KEY_SEARCH) ":300:830:120:60" \
+ ":" __stringify(EV_KEY) ":" \
+ __stringify(KEY_BACK) ":420:830:120:60" "\n";
+
+ return snprintf(buf, strnlen(virtual_keys, MAX_LEN) + 1 , "%s",
+ virtual_keys);
+}
+
+static struct kobj_attribute clearpad3000_virtual_keys_attr = {
+ .attr = {
+ .name = "virtualkeys.sensor00fn11",
+ .mode = S_IRUGO,
+ },
+ .show = &clearpad3000_virtual_keys_register,
+};
+
+static struct attribute *virtual_key_properties_attrs[] = {
+ &clearpad3000_virtual_keys_attr.attr,
+ NULL
+};
+
+static struct attribute_group virtual_key_properties_attr_group = {
+ .attrs = virtual_key_properties_attrs,
+};
+
+struct kobject *virtual_key_properties_kobj;
+
+static struct rmi_functiondata synaptics_functiondata[] = {
+ {
+ .function_index = RMI_F11_INDEX,
+ .data = &synaptics_f11_data,
+ },
+};
+
+static struct rmi_functiondata_list synaptics_perfunctiondata = {
+ .count = ARRAY_SIZE(synaptics_functiondata),
+ .functiondata = synaptics_functiondata,
+};
+
+static struct rmi_sensordata synaptics_sensordata = {
+ .perfunctiondata = &synaptics_perfunctiondata,
+ .rmi_sensor_setup = synaptics_touchpad_setup,
+};
+
+static struct rmi_i2c_platformdata synaptics_platformdata = {
+ .i2c_address = 0x2c,
+ .irq_type = IORESOURCE_IRQ_LOWLEVEL,
+ .sensordata = &synaptics_sensordata,
+};
+
+static struct i2c_board_info synaptic_i2c_clearpad3k[] = {
+ {
+ I2C_BOARD_INFO("rmi4_ts", 0x2c),
+ .platform_data = &synaptics_platformdata,
+ },
+};
+
+static int synaptics_touchpad_setup(void)
+{
+ int retval = 0;
+
+ virtual_key_properties_kobj =
+ kobject_create_and_add("board_properties", NULL);
+ if (virtual_key_properties_kobj)
+ retval = sysfs_create_group(virtual_key_properties_kobj,
+ &virtual_key_properties_attr_group);
+ if (!virtual_key_properties_kobj || retval)
+ pr_err("failed to create ft5202 board_properties\n");
+
+ retval = msm_gpios_request_enable(clearpad3000_cfg_data,
+ sizeof(clearpad3000_cfg_data)/sizeof(struct msm_gpio));
+ if (retval) {
+ pr_err("%s:Failed to obtain touchpad GPIO %d. Code: %d.",
+ __func__, CLEARPAD3000_ATTEN_GPIO, retval);
+ retval = 0; /* ignore the err */
+ }
+ synaptics_platformdata.irq = gpio_to_irq(CLEARPAD3000_ATTEN_GPIO);
+
+ gpio_set_value(CLEARPAD3000_RESET_GPIO, 0);
+ usleep(10000);
+ gpio_set_value(CLEARPAD3000_RESET_GPIO, 1);
+ usleep(50000);
+
+ return retval;
+}
+#endif
+
+static struct regulator_bulk_data regs_atmel[] = {
+ { .supply = "ldo2", .min_uV = 2850000, .max_uV = 2850000 },
+ { .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+#define ATMEL_TS_GPIO_IRQ 82
+
+static int atmel_ts_power_on(bool on)
+{
+ int rc = on ?
+ regulator_bulk_enable(ARRAY_SIZE(regs_atmel), regs_atmel) :
+ regulator_bulk_disable(ARRAY_SIZE(regs_atmel), regs_atmel);
+
+ if (rc)
+ pr_err("%s: could not %sable regulators: %d\n",
+ __func__, on ? "en" : "dis", rc);
+ else
+ msleep(50);
+
+ return rc;
+}
+
+static int atmel_ts_platform_init(struct i2c_client *client)
+{
+ int rc;
+ struct device *dev = &client->dev;
+
+ rc = regulator_bulk_get(dev, ARRAY_SIZE(regs_atmel), regs_atmel);
+ if (rc) {
+ dev_err(dev, "%s: could not get regulators: %d\n",
+ __func__, rc);
+ goto out;
+ }
+
+ rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_atmel), regs_atmel);
+ if (rc) {
+ dev_err(dev, "%s: could not set voltages: %d\n",
+ __func__, rc);
+ goto reg_free;
+ }
+
+ rc = gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ dev_err(dev, "%s: gpio_tlmm_config for %d failed\n",
+ __func__, ATMEL_TS_GPIO_IRQ);
+ goto reg_free;
+ }
+
+ /* configure touchscreen interrupt gpio */
+ rc = gpio_request(ATMEL_TS_GPIO_IRQ, "atmel_maxtouch_gpio");
+ if (rc) {
+ dev_err(dev, "%s: unable to request gpio %d\n",
+ __func__, ATMEL_TS_GPIO_IRQ);
+ goto ts_gpio_tlmm_unconfig;
+ }
+
+ rc = gpio_direction_input(ATMEL_TS_GPIO_IRQ);
+ if (rc < 0) {
+ dev_err(dev, "%s: unable to set the direction of gpio %d\n",
+ __func__, ATMEL_TS_GPIO_IRQ);
+ goto free_ts_gpio;
+ }
+ return 0;
+
+free_ts_gpio:
+ gpio_free(ATMEL_TS_GPIO_IRQ);
+ts_gpio_tlmm_unconfig:
+ gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA), GPIO_CFG_DISABLE);
+reg_free:
+ regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
+out:
+ return rc;
+}
+
+static int atmel_ts_platform_exit(struct i2c_client *client)
+{
+ gpio_free(ATMEL_TS_GPIO_IRQ);
+ gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA), GPIO_CFG_DISABLE);
+ regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
+ return 0;
+}
+
+static u8 atmel_ts_read_chg(void)
+{
+ return gpio_get_value(ATMEL_TS_GPIO_IRQ);
+}
+
+static u8 atmel_ts_valid_interrupt(void)
+{
+ return !atmel_ts_read_chg();
+}
+
+
+static struct maxtouch_platform_data atmel_ts_pdata = {
+ .numtouch = 4,
+ .init_platform_hw = atmel_ts_platform_init,
+ .exit_platform_hw = atmel_ts_platform_exit,
+ .power_on = atmel_ts_power_on,
+ .display_res_x = 480,
+ .display_res_y = 864,
+ .min_x = ATMEL_X_OFFSET,
+ .max_x = (505 - ATMEL_X_OFFSET),
+ .min_y = ATMEL_Y_OFFSET,
+ .max_y = (863 - ATMEL_Y_OFFSET),
+ .valid_interrupt = atmel_ts_valid_interrupt,
+ .read_chg = atmel_ts_read_chg,
+};
+
+static struct i2c_board_info atmel_ts_i2c_info[] __initdata = {
+ {
+ I2C_BOARD_INFO(ATMEL_TS_I2C_NAME, 0x4a),
+ .platform_data = &atmel_ts_pdata,
+ .irq = MSM_GPIO_TO_INT(ATMEL_TS_GPIO_IRQ),
+ },
+};
+
+static struct msm_handset_platform_data hs_platform_data = {
+ .hs_name = "7k_handset",
+ .pwr_key_delay_ms = 500, /* 0 will disable end key */
+};
+
+static struct platform_device hs_pdev = {
+ .name = "msm-handset",
+ .id = -1,
+ .dev = {
+ .platform_data = &hs_platform_data,
+ },
+};
+
+#define FT5X06_IRQ_GPIO 48
+#define FT5X06_RESET_GPIO 26
+
+static ssize_t
+ft5x06_virtual_keys_register(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, 200,
+ __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":40:510:80:60"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":120:510:80:60"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":200:510:80:60"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":280:510:80:60"
+ "\n");
+}
+
+static struct kobj_attribute ft5x06_virtual_keys_attr = {
+ .attr = {
+ .name = "virtualkeys.ft5x06_ts",
+ .mode = S_IRUGO,
+ },
+ .show = &ft5x06_virtual_keys_register,
+};
+
+static struct attribute *ft5x06_virtual_key_properties_attrs[] = {
+ &ft5x06_virtual_keys_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ft5x06_virtual_key_properties_attr_group = {
+ .attrs = ft5x06_virtual_key_properties_attrs,
+};
+
+struct kobject *ft5x06_virtual_key_properties_kobj;
+
+static struct ft5x06_ts_platform_data ft5x06_platformdata = {
+ .x_max = 320,
+ .y_max = 480,
+ .reset_gpio = FT5X06_RESET_GPIO,
+ .irq_gpio = FT5X06_IRQ_GPIO,
+ .irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+};
+
+static struct i2c_board_info ft5x06_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("ft5x06_ts", 0x38),
+ .platform_data = &ft5x06_platformdata,
+ .irq = MSM_GPIO_TO_INT(FT5X06_IRQ_GPIO),
+ },
+};
+
+static void ft5x06_touchpad_setup(void)
+{
+ int rc;
+
+ rc = gpio_tlmm_config(GPIO_CFG(FT5X06_IRQ_GPIO, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+ if (rc)
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, FT5X06_IRQ_GPIO);
+
+ rc = gpio_tlmm_config(GPIO_CFG(FT5X06_RESET_GPIO, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+ GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+ if (rc)
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, FT5X06_RESET_GPIO);
+
+ ft5x06_virtual_key_properties_kobj =
+ kobject_create_and_add("board_properties", NULL);
+
+ if (ft5x06_virtual_key_properties_kobj)
+ rc = sysfs_create_group(ft5x06_virtual_key_properties_kobj,
+ &ft5x06_virtual_key_properties_attr_group);
+
+ if (!ft5x06_virtual_key_properties_kobj || rc)
+ pr_err("%s: failed to create board_properties\n", __func__);
+
+ i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+ ft5x06_device_info,
+ ARRAY_SIZE(ft5x06_device_info));
+}
+
+/* SKU3/SKU7 keypad device information */
+#define KP_INDEX_SKU3(row, col) ((row)*ARRAY_SIZE(kp_col_gpios_sku3) + (col))
+static unsigned int kp_row_gpios_sku3[] = {31, 32};
+static unsigned int kp_col_gpios_sku3[] = {36, 37};
+
+static const unsigned short keymap_sku3[] = {
+ [KP_INDEX_SKU3(0, 0)] = KEY_VOLUMEUP,
+ [KP_INDEX_SKU3(0, 1)] = KEY_VOLUMEDOWN,
+ [KP_INDEX_SKU3(1, 1)] = KEY_CAMERA,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_sku3 = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = keymap_sku3,
+ .output_gpios = kp_row_gpios_sku3,
+ .input_gpios = kp_col_gpios_sku3,
+ .noutputs = ARRAY_SIZE(kp_row_gpios_sku3),
+ .ninputs = ARRAY_SIZE(kp_col_gpios_sku3),
+ .settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+ .poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_sku3[] = {
+ &kp_matrix_info_sku3.info,
+};
+static struct gpio_event_platform_data kp_pdata_sku3 = {
+ .name = "7x27a_kp",
+ .info = kp_info_sku3,
+ .info_count = ARRAY_SIZE(kp_info_sku3)
+};
+
+static struct platform_device kp_pdev_sku3 = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &kp_pdata_sku3,
+ },
+};
+
+void __init msm7627a_add_io_devices(void)
+{
+ /* touchscreen */
+ if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
+ atmel_ts_pdata.min_x = 0;
+ atmel_ts_pdata.max_x = 480;
+ atmel_ts_pdata.min_y = 0;
+ atmel_ts_pdata.max_y = 320;
+ }
+
+ i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+ atmel_ts_i2c_info,
+ ARRAY_SIZE(atmel_ts_i2c_info));
+ /* keypad */
+ platform_device_register(&kp_pdev);
+
+ /* headset */
+ platform_device_register(&hs_pdev);
+
+ /* LED: configure it as a pdm function */
+ if (gpio_tlmm_config(GPIO_CFG(LED_GPIO_PDM, 3,
+ GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_8MA), GPIO_CFG_ENABLE))
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, LED_GPIO_PDM);
+ else
+ platform_device_register(&led_pdev);
+
+ /* Vibrator */
+ if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
+ msm_init_pmic_vibrator();
+}
+
+void __init qrd7627a_add_io_devices(void)
+{
+ int rc;
+
+ /* touchscreen */
+ if (machine_is_msm7627a_qrd1()) {
+ i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+ synaptic_i2c_clearpad3k,
+ ARRAY_SIZE(synaptic_i2c_clearpad3k));
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, MXT_TS_IRQ_GPIO);
+ }
+
+ rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_RESET_GPIO, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+ GPIO_CFG_8MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, MXT_TS_RESET_GPIO);
+ }
+
+ i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+ mxt_device_info,
+ ARRAY_SIZE(mxt_device_info));
+ } else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+ ft5x06_touchpad_setup();
+ }
+
+ /* headset */
+ platform_device_register(&hs_pdev);
+
+ /* vibrator */
+#ifdef CONFIG_MSM_RPC_VIBRATOR
+ msm_init_pmic_vibrator();
+#endif
+
+ /* keypad */
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ platform_device_register(&kp_pdev_8625);
+ else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+ platform_device_register(&kp_pdev_sku3);
+
+ /* leds */
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, LED_RED_GPIO_8625);
+ }
+
+ rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+ GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+ if (rc) {
+ pr_err("%s: gpio_tlmm_config for %d failed\n",
+ __func__, LED_GREEN_GPIO_8625);
+ }
+
+ platform_device_register(&gpio_leds_8625);
+ }
+}
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index e4ee52e..11d9a21 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -151,7 +151,9 @@
static void gpio_sdc1_config(void)
{
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
- || machine_is_msm8625_evb())
+ || machine_is_msm8625_evb()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7())
gpio_sdc1_hw_det = 42;
}
@@ -253,7 +255,9 @@
if (!status) {
if (machine_is_msm7627a_qrd1() ||
machine_is_msm7627a_evb() ||
- machine_is_msm8625_evb())
+ machine_is_msm8625_evb() ||
+ machine_is_msm7627a_qrd3() ||
+ machine_is_msm8625_qrd7())
status = !gpio_get_value(gpio_sdc1_hw_det);
else
status = gpio_get_value(gpio_sdc1_hw_det);
@@ -289,9 +293,7 @@
.ocr_mask = MMC_VDD_28_29 | MMC_VDD_165_195,
.translate_vdd = msm_sdcc_setup_power,
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
-#endif
.msmsdcc_fmin = 144000,
.msmsdcc_fmid = 24576000,
.msmsdcc_fmax = 49152000,
@@ -367,11 +369,15 @@
{
/* eMMC slot */
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
- if (mmc_regulator_init(3, "emmc", 3000000))
- return;
- sdc3_plat_data.swfi_latency = msm7627a_power_collapse_latency(
+
+ /* There is no eMMC on SDC3 for QRD3 based devices */
+ if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
+ if (mmc_regulator_init(3, "emmc", 3000000))
+ return;
+ sdc3_plat_data.swfi_latency = msm7627a_power_collapse_latency(
MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
- msm_add_sdcc(3, &sdc3_plat_data);
+ msm_add_sdcc(3, &sdc3_plat_data);
+ }
#endif
/* Micro-SD slot */
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
@@ -392,9 +398,12 @@
/* Not Used */
#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
&& !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
- if (mmc_regulator_init(4, "smps3", 1800000))
- return;
- msm_add_sdcc(4, &sdc4_plat_data);
+ /* There is no SDC4 for QRD3/7 based devices */
+ if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
+ if (mmc_regulator_init(4, "smps3", 1800000))
+ return;
+ msm_add_sdcc(4, &sdc4_plat_data);
+ }
#endif
}
#endif
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 53d3c56..b72ecd4 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -49,7 +49,9 @@
static void gpio_wlan_config(void)
{
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
- || machine_is_msm8625_evb())
+ || machine_is_msm8625_evb()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7())
gpio_wlan_sys_rest_en = 124;
}
@@ -231,7 +233,9 @@
* EVB1.0 and QRD8625,so the below step is required for those devices.
*/
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
- || machine_is_msm8625_evb()) {
+ || machine_is_msm8625_evb()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA), GPIO_CFG_ENABLE);
@@ -305,7 +309,9 @@
* EVB1.0 and QRD8625,so the below step is required for those devices.
*/
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
- || machine_is_msm8625_evb()) {
+ || machine_is_msm8625_evb()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA), GPIO_CFG_ENABLE);
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index bde9b61..68e333f 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -104,4 +104,7 @@
void __init msm7627a_camera_init(void);
u32 msm7627a_power_collapse_latency(enum msm_pm_sleep_mode);
+
+void __init msm7627a_add_io_devices(void);
+void __init qrd7627a_add_io_devices(void);
#endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 34ae4c8..f1ff49a 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -1518,9 +1518,7 @@
.ocr_mask = MMC_VDD_28_29,
.translate_vdd = msm_sdcc_setup_power,
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
.sdiowakeup_irq = MSM_GPIO_TO_INT(66),
-#endif
.msmsdcc_fmin = 144000,
.msmsdcc_fmid = 24576000,
.msmsdcc_fmax = 49152000,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index e75a963..09f44a7 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -950,7 +950,7 @@
{
msm7x27a_reserve();
memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
- msm_pm_8625_boot_pdata.p_addr = memblock_alloc(SZ_16, SZ_64K);
+ memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
}
static void __init msm7x27a_device_i2c_init(void)
@@ -1001,215 +1001,6 @@
iounmap(ebi2_cfg_ptr);
}
-#define ATMEL_TS_I2C_NAME "maXTouch"
-
-static struct regulator_bulk_data regs_atmel[] = {
- { .supply = "ldo2", .min_uV = 2850000, .max_uV = 2850000 },
- { .supply = "smps3", .min_uV = 1800000, .max_uV = 1800000 },
-};
-
-#define ATMEL_TS_GPIO_IRQ 82
-
-static int atmel_ts_power_on(bool on)
-{
- int rc = on ?
- regulator_bulk_enable(ARRAY_SIZE(regs_atmel), regs_atmel) :
- regulator_bulk_disable(ARRAY_SIZE(regs_atmel), regs_atmel);
-
- if (rc)
- pr_err("%s: could not %sable regulators: %d\n",
- __func__, on ? "en" : "dis", rc);
- else
- msleep(50);
-
- return rc;
-}
-
-static int atmel_ts_platform_init(struct i2c_client *client)
-{
- int rc;
- struct device *dev = &client->dev;
-
- rc = regulator_bulk_get(dev, ARRAY_SIZE(regs_atmel), regs_atmel);
- if (rc) {
- dev_err(dev, "%s: could not get regulators: %d\n",
- __func__, rc);
- goto out;
- }
-
- rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_atmel), regs_atmel);
- if (rc) {
- dev_err(dev, "%s: could not set voltages: %d\n",
- __func__, rc);
- goto reg_free;
- }
-
- rc = gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
- GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_8MA), GPIO_CFG_ENABLE);
- if (rc) {
- dev_err(dev, "%s: gpio_tlmm_config for %d failed\n",
- __func__, ATMEL_TS_GPIO_IRQ);
- goto reg_free;
- }
-
- /* configure touchscreen interrupt gpio */
- rc = gpio_request(ATMEL_TS_GPIO_IRQ, "atmel_maxtouch_gpio");
- if (rc) {
- dev_err(dev, "%s: unable to request gpio %d\n",
- __func__, ATMEL_TS_GPIO_IRQ);
- goto ts_gpio_tlmm_unconfig;
- }
-
- rc = gpio_direction_input(ATMEL_TS_GPIO_IRQ);
- if (rc < 0) {
- dev_err(dev, "%s: unable to set the direction of gpio %d\n",
- __func__, ATMEL_TS_GPIO_IRQ);
- goto free_ts_gpio;
- }
- return 0;
-
-free_ts_gpio:
- gpio_free(ATMEL_TS_GPIO_IRQ);
-ts_gpio_tlmm_unconfig:
- gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
- GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA), GPIO_CFG_DISABLE);
-reg_free:
- regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
-out:
- return rc;
-}
-
-static int atmel_ts_platform_exit(struct i2c_client *client)
-{
- gpio_free(ATMEL_TS_GPIO_IRQ);
- gpio_tlmm_config(GPIO_CFG(ATMEL_TS_GPIO_IRQ, 0,
- GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA), GPIO_CFG_DISABLE);
- regulator_bulk_free(ARRAY_SIZE(regs_atmel), regs_atmel);
- return 0;
-}
-
-static u8 atmel_ts_read_chg(void)
-{
- return gpio_get_value(ATMEL_TS_GPIO_IRQ);
-}
-
-static u8 atmel_ts_valid_interrupt(void)
-{
- return !atmel_ts_read_chg();
-}
-
-#define ATMEL_X_OFFSET 13
-#define ATMEL_Y_OFFSET 0
-
-static struct maxtouch_platform_data atmel_ts_pdata = {
- .numtouch = 4,
- .init_platform_hw = atmel_ts_platform_init,
- .exit_platform_hw = atmel_ts_platform_exit,
- .power_on = atmel_ts_power_on,
- .display_res_x = 480,
- .display_res_y = 864,
- .min_x = ATMEL_X_OFFSET,
- .max_x = (505 - ATMEL_X_OFFSET),
- .min_y = ATMEL_Y_OFFSET,
- .max_y = (863 - ATMEL_Y_OFFSET),
- .valid_interrupt = atmel_ts_valid_interrupt,
- .read_chg = atmel_ts_read_chg,
-};
-
-static struct i2c_board_info atmel_ts_i2c_info[] __initdata = {
- {
- I2C_BOARD_INFO(ATMEL_TS_I2C_NAME, 0x4a),
- .platform_data = &atmel_ts_pdata,
- .irq = MSM_GPIO_TO_INT(ATMEL_TS_GPIO_IRQ),
- },
-};
-
-#define KP_INDEX(row, col) ((row)*ARRAY_SIZE(kp_col_gpios) + (col))
-
-static unsigned int kp_row_gpios[] = {31, 32, 33, 34, 35};
-static unsigned int kp_col_gpios[] = {36, 37, 38, 39, 40};
-
-static const unsigned short keymap[ARRAY_SIZE(kp_col_gpios) *
- ARRAY_SIZE(kp_row_gpios)] = {
- [KP_INDEX(0, 0)] = KEY_7,
- [KP_INDEX(0, 1)] = KEY_DOWN,
- [KP_INDEX(0, 2)] = KEY_UP,
- [KP_INDEX(0, 3)] = KEY_RIGHT,
- [KP_INDEX(0, 4)] = KEY_ENTER,
-
- [KP_INDEX(1, 0)] = KEY_LEFT,
- [KP_INDEX(1, 1)] = KEY_SEND,
- [KP_INDEX(1, 2)] = KEY_1,
- [KP_INDEX(1, 3)] = KEY_4,
- [KP_INDEX(1, 4)] = KEY_CLEAR,
-
- [KP_INDEX(2, 0)] = KEY_6,
- [KP_INDEX(2, 1)] = KEY_5,
- [KP_INDEX(2, 2)] = KEY_8,
- [KP_INDEX(2, 3)] = KEY_3,
- [KP_INDEX(2, 4)] = KEY_NUMERIC_STAR,
-
- [KP_INDEX(3, 0)] = KEY_9,
- [KP_INDEX(3, 1)] = KEY_NUMERIC_POUND,
- [KP_INDEX(3, 2)] = KEY_0,
- [KP_INDEX(3, 3)] = KEY_2,
- [KP_INDEX(3, 4)] = KEY_SLEEP,
-
- [KP_INDEX(4, 0)] = KEY_BACK,
- [KP_INDEX(4, 1)] = KEY_HOME,
- [KP_INDEX(4, 2)] = KEY_MENU,
- [KP_INDEX(4, 3)] = KEY_VOLUMEUP,
- [KP_INDEX(4, 4)] = KEY_VOLUMEDOWN,
-};
-
-/* SURF keypad platform device information */
-static struct gpio_event_matrix_info kp_matrix_info = {
- .info.func = gpio_event_matrix_func,
- .keymap = keymap,
- .output_gpios = kp_row_gpios,
- .input_gpios = kp_col_gpios,
- .noutputs = ARRAY_SIZE(kp_row_gpios),
- .ninputs = ARRAY_SIZE(kp_col_gpios),
- .settle_time.tv_nsec = 40 * NSEC_PER_USEC,
- .poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
- .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
- GPIOKPF_PRINT_UNMAPPED_KEYS,
-};
-
-static struct gpio_event_info *kp_info[] = {
- &kp_matrix_info.info
-};
-
-static struct gpio_event_platform_data kp_pdata = {
- .name = "7x27a_kp",
- .info = kp_info,
- .info_count = ARRAY_SIZE(kp_info)
-};
-
-static struct platform_device kp_pdev = {
- .name = GPIO_EVENT_DEV_NAME,
- .id = -1,
- .dev = {
- .platform_data = &kp_pdata,
- },
-};
-
-static struct msm_handset_platform_data hs_platform_data = {
- .hs_name = "7k_handset",
- .pwr_key_delay_ms = 500, /* 0 will disable end key */
-};
-
-static struct platform_device hs_pdev = {
- .name = "msm-handset",
- .id = -1,
- .dev = {
- .platform_data = &hs_platform_data,
- },
-};
-
static struct platform_device msm_proccomm_regulator_dev = {
.name = PROCCOMM_REGULATOR_DEV_NAME,
.id = -1,
@@ -1262,7 +1053,6 @@
msm8x25_spm_device_init();
}
-#define LED_GPIO_PDM 96
#define UART1DM_RX_GPIO 45
#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
@@ -1330,39 +1120,6 @@
}
}
-static void __init msm7x27a_add_io_devices(void)
-{
- /* touchscreen */
- if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
- atmel_ts_pdata.min_x = 0;
- atmel_ts_pdata.max_x = 480;
- atmel_ts_pdata.min_y = 0;
- atmel_ts_pdata.max_y = 320;
- }
-
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- atmel_ts_i2c_info,
- ARRAY_SIZE(atmel_ts_i2c_info));
- /* keypad */
- platform_device_register(&kp_pdev);
-
- /* headset */
- platform_device_register(&hs_pdev);
-
- /* LED: configure it as a pdm function */
- if (gpio_tlmm_config(GPIO_CFG(LED_GPIO_PDM, 3,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_8MA), GPIO_CFG_ENABLE))
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, LED_GPIO_PDM);
- else
- platform_device_register(&led_pdev);
-
- /* Vibrator */
- if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
- msm_init_pmic_vibrator();
-}
-
static void __init msm7x27a_pm_init(void)
{
if (machine_is_msm8625_surf()) {
@@ -1407,9 +1164,11 @@
register_i2c_devices();
msm7627a_bt_power_init();
msm7627a_camera_init();
- msm7x27a_add_io_devices();
+ msm7627a_add_io_devices();
/*7x25a kgsl initializations*/
msm7x25a_kgsl_3d0_init();
+ /*8x25 kgsl initializations*/
+ msm8x25_kgsl_3d0_init();
}
static void __init msm7x2x_init_early(void)
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index cd1e5b8..cf608ad 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -99,6 +99,11 @@
#else
#define MSM_FB_SIZE 0x500000
#endif
+/*
+ * Reserve space for double buffered full screen
+ * res V4L2 video overlay - i.e. 1280x720x1.5x2
+ */
+#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
#define MSM_PMEM_ADSP_SIZE 0x1E00000
#define MSM_FLUID_PMEM_ADSP_SIZE 0x2800000
#define PMEM_KERNEL_EBI0_SIZE 0x600000
@@ -3770,6 +3775,14 @@
}
};
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+static struct resource msm_v4l2_video_overlay_resources[] = {
+ {
+ .flags = IORESOURCE_DMA,
+ }
+};
+#endif
+
static int msm_fb_detect_panel(const char *name)
{
if (machine_is_msm7x30_fluid()) {
@@ -3803,6 +3816,16 @@
}
};
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+
+static struct platform_device msm_v4l2_video_overlay_device = {
+ .name = "msm_v4l2_overlay_pd",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_v4l2_video_overlay_resources),
+ .resource = msm_v4l2_video_overlay_resources,
+};
+#endif
+
static struct platform_device msm_migrate_pages_device = {
.name = "msm_migrate_pages",
.id = -1,
@@ -5192,6 +5215,9 @@
#endif
&android_pmem_device,
&msm_fb_device,
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+ &msm_v4l2_video_overlay_device,
+#endif
&msm_migrate_pages_device,
&mddi_toshiba_device,
&lcdc_toshiba_panel_device,
@@ -6077,9 +6103,7 @@
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
.translate_vdd = msm_sdcc_setup_power,
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
.sdiowakeup_irq = MSM_GPIO_TO_INT(118),
-#endif
.msmsdcc_fmin = 144000,
.msmsdcc_fmid = 24576000,
.msmsdcc_fmax = 49152000,
@@ -7025,6 +7049,16 @@
msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
size, addr, __pa(addr));
+
+#ifdef CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE
+ size = MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE;
+ addr = alloc_bootmem_align(size, 0x1000);
+ msm_v4l2_video_overlay_resources[0].start = __pa(addr);
+ msm_v4l2_video_overlay_resources[0].end =
+ msm_v4l2_video_overlay_resources[0].start + size - 1;
+ pr_debug("allocating %lu bytes at %p (%lx physical) for v4l2\n",
+ size, addr, __pa(addr));
+#endif
}
static void __init msm7x30_map_io(void)
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
new file mode 100644
index 0000000..95561e4
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -0,0 +1,471 @@
+/* Copyright (c) 2012 Code Aurora Forum. 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 <asm/mach-types.h>
+#include <devices-msm8x60.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/pmic8901.h>
+#include <mach/board.h>
+#include <mach/board-msm8660.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include "devices.h"
+
+#define GPIO_EXT_CAMIF_PWR_EN1 (PM8901_MPP_BASE + PM8901_MPPS + 13)
+#ifdef CONFIG_MSM_CAMERA_FLASH
+#define VFE_CAMIF_TIMER1_GPIO 29
+#define VFE_CAMIF_TIMER2_GPIO 30
+#define VFE_CAMIF_TIMER3_GPIO_INT 31
+#define FUSION_VFE_CAMIF_TIMER1_GPIO 42
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_PMIC,
+ ._fsrc.pmic_src.num_of_src = 2,
+ ._fsrc.pmic_src.low_current = 100,
+ ._fsrc.pmic_src.high_current = 300,
+ ._fsrc.pmic_src.led_src_1 = PMIC8058_ID_FLASH_LED_0,
+ ._fsrc.pmic_src.led_src_2 = PMIC8058_ID_FLASH_LED_1,
+ ._fsrc.pmic_src.pmic_set_current = pm8058_set_flash_led_current,
+};
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+ .flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+ .flash_charge = VFE_CAMIF_TIMER1_GPIO,
+ .flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+ .flash_recharge_duration = 50000,
+ .irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 283115520,
+ .ib = 452984832,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 283115520,
+ .ib = 452984832,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 283115520,
+ .ib = 452984832,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 319610880,
+ .ib = 511377408,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 566231040,
+ .ib = 905969664,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 69984000,
+ .ib = 111974400,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 566231040,
+ .ib = 905969664,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 706199040,
+ .ib = 1129918464,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+};
+
+static struct msm_bus_vectors cam_stereo_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 212336640,
+ .ib = 339738624,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 25090560,
+ .ib = 40144896,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 239708160,
+ .ib = 383533056,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 79902720,
+ .ib = 127844352,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_stereo_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 300902400,
+ .ib = 481443840,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 230307840,
+ .ib = 368492544,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 245113344,
+ .ib = 392181351,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 106536960,
+ .ib = 170459136,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 106536960,
+ .ib = 170459136,
+ },
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+ {
+ ARRAY_SIZE(cam_init_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_preview_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_video_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_snapshot_vectors),
+ cam_snapshot_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_zsl_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_stereo_video_vectors),
+ cam_stereo_video_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_stereo_snapshot_vectors),
+ cam_stereo_snapshot_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+ cam_bus_client_config,
+ ARRAY_SIZE(cam_bus_client_config),
+ .name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+ {
+ .csid_core = 0,
+ .is_csic = 1,
+ .is_vpe = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ .ioclk = {
+ .vfe_clk_rate = 228570000,
+ },
+ },
+ {
+ .csid_core = 1,
+ .is_csic = 1,
+ .is_vpe = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ .ioclk = {
+ .vfe_clk_rate = 228570000,
+ },
+ },
+};
+static struct camera_vreg_t msm_8x60_back_cam_vreg[] = {
+ {"cam_vana", REG_LDO, 2850000, 2850000, -1},
+ {"cam_vio", REG_VS, 0, 0, 0},
+ {"cam_vdig", REG_LDO, 1200000, 1200000, -1},
+};
+
+static struct gpio msm8x60_common_cam_gpio[] = {
+ {32, GPIOF_DIR_IN, "CAMIF_MCLK"},
+ {47, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
+ {48, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
+ {105, GPIOF_DIR_IN, "STANDBY"},
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
+};
+
+static struct gpio msm8x60_back_cam_gpio[] = {
+ {106, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl msm8x60_back_cam_gpio_set_tbl[] = {
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_OUT_INIT_LOW, 10000},
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_OUT_INIT_HIGH, 5000},
+ {106, GPIOF_OUT_INIT_LOW, 1000},
+ {106, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf msm_8x60_back_cam_gpio_conf = {
+ .cam_gpio_common_tbl = msm8x60_common_cam_gpio,
+ .cam_gpio_common_tbl_size = ARRAY_SIZE(msm8x60_common_cam_gpio),
+ .cam_gpio_req_tbl = msm8x60_back_cam_gpio,
+ .cam_gpio_req_tbl_size = ARRAY_SIZE(msm8x60_back_cam_gpio),
+ .cam_gpio_set_tbl = msm8x60_back_cam_gpio_set_tbl,
+ .cam_gpio_set_tbl_size = ARRAY_SIZE(msm8x60_back_cam_gpio_set_tbl),
+};
+
+
+static struct i2c_board_info imx074_actuator_i2c_info = {
+ I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+ .board_info = &imx074_actuator_i2c_info,
+ .bus_id = MSM_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+ .flash_type = MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+ .flash_src = &msm_flash_src,
+#endif
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+ .mount_angle = 0,
+ .cam_vreg = msm_8x60_back_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+ .gpio_conf = &msm_8x60_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+ .sensor_name = "imx074",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_imx074,
+ .strobe_flash_data = &strobe_flash_xenon,
+ .sensor_platform_info = &sensor_board_info_imx074,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+ .actuator_info = &imx074_actuator_info
+};
+
+void __init msm8x60_init_cam(void)
+{
+ platform_device_register(&msm_device_csic0);
+ platform_device_register(&msm_device_csic1);
+ platform_device_register(&msm_device_vfe);
+ platform_device_register(&msm_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm8x60_camera_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+};
+
+struct msm_camera_board_info msm8x60_camera_board_info = {
+ .board_info = msm8x60_camera_i2c_boardinfo,
+ .num_i2c_board_info = ARRAY_SIZE(msm8x60_camera_i2c_boardinfo),
+};
+#endif
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index f181133..9497735 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -433,7 +433,7 @@
.name = "8901_s0",
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
.min_uV = 800000,
- .max_uV = 1250000,
+ .max_uV = 1325000,
},
.consumer_supplies = vreg_consumers_8901_S0,
.num_consumer_supplies = ARRAY_SIZE(vreg_consumers_8901_S0),
@@ -444,7 +444,7 @@
.name = "8901_s1",
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
.min_uV = 800000,
- .max_uV = 1250000,
+ .max_uV = 1325000,
},
.consumer_supplies = vreg_consumers_8901_S1,
.num_consumer_supplies = ARRAY_SIZE(vreg_consumers_8901_S1),
@@ -924,7 +924,7 @@
[MSM_RPMRS_VDD_MEM_RET_LOW] = 500,
[MSM_RPMRS_VDD_MEM_RET_HIGH] = 750,
[MSM_RPMRS_VDD_MEM_ACTIVE] = 1000,
- [MSM_RPMRS_VDD_MEM_MAX] = 1250,
+ [MSM_RPMRS_VDD_MEM_MAX] = 1325,
},
.vdd_dig_levels = {
[MSM_RPMRS_VDD_DIG_RET_LOW] = 500,
@@ -1562,6 +1562,7 @@
#endif
#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
static struct resource msm_vpe_resources[] = {
{
.start = 0x05300000,
@@ -1582,8 +1583,10 @@
.resource = msm_vpe_resources,
};
#endif
+#endif
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
#ifdef CONFIG_MSM_CAMERA_FLASH
#define VFE_CAMIF_TIMER1_GPIO 29
#define VFE_CAMIF_TIMER2_GPIO 30
@@ -2486,6 +2489,7 @@
#endif
};
#endif
+#endif
#ifdef CONFIG_MSM_GEMINI
static struct resource msm_gemini_resources[] = {
@@ -2629,10 +2633,12 @@
if (machine_is_msm8x60_fluid()) {
/* fluid has different firmware, gpios */
pdata->pil_name = DSPS_PIL_FLUID_NAME;
+ msm_pil_dsps.dev.platform_data = DSPS_PIL_FLUID_NAME;
pdata->gpios = dsps_fluid_gpios;
pdata->gpios_num = ARRAY_SIZE(dsps_fluid_gpios);
} else {
pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+ msm_pil_dsps.dev.platform_data = DSPS_PIL_GENERIC_NAME;
pdata->gpios = dsps_surf_gpios;
pdata->gpios_num = ARRAY_SIZE(dsps_surf_gpios);
}
@@ -2664,7 +2670,7 @@
MSM_FB_DSUB_PMEM_ADDER, 4096)
#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
-#define MSM_HDMI_PRIM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SF_SIZE 0x8000000 /* 128 Mbytes */
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
unsigned char hdmi_is_primary = 1;
@@ -2684,9 +2690,9 @@
#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
#endif /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x600000
+#define MSM_PMEM_KERNEL_EBI1_SIZE 0x3BC000
#define MSM_PMEM_ADSP_SIZE 0x2000000
-#define MSM_PMEM_AUDIO_SIZE 0x28B000
+#define MSM_PMEM_AUDIO_SIZE 0x4CF000
#define MSM_SMI_BASE 0x38000000
#define MSM_SMI_SIZE 0x4000000
@@ -2703,11 +2709,16 @@
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) */
#define MSM_ION_MFC_SIZE SZ_8K
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_ION_WB_SIZE 0xC00000 /* 12MB */
+#else
#define MSM_ION_WB_SIZE 0x600000 /* 6MB */
+#endif
+
#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
-#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#define MSM_ION_HEAP_NUM 9
#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SF_SIZE
static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
@@ -2765,6 +2776,8 @@
}
};
+static void set_mdp_clocks_for_wuxga(void);
+
static int msm_fb_detect_panel(const char *name)
{
if (machine_is_msm8x60_fluid()) {
@@ -2819,8 +2832,11 @@
if (!strncmp(name, HDMI_PANEL_NAME,
strnlen(HDMI_PANEL_NAME,
- PANEL_NAME_MAX_LEN)))
+ PANEL_NAME_MAX_LEN))) {
+ if (hdmi_is_primary)
+ set_mdp_clocks_for_wuxga();
return 0;
+ }
if (!strncmp(name, TVOUT_PANEL_NAME,
strnlen(TVOUT_PANEL_NAME,
@@ -2870,7 +2886,7 @@
.id = 2,
.dev = { .platform_data = &android_pmem_adsp_pdata },
};
-#endif
+
static struct android_pmem_platform_data android_pmem_audio_pdata = {
.name = "pmem_audio",
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -2883,7 +2899,7 @@
.id = 4,
.dev = { .platform_data = &android_pmem_audio_pdata },
};
-
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
#define PMEM_BUS_WIDTH(_bw) \
{ \
.vectors = &(struct msm_bus_vectors){ \
@@ -2942,8 +2958,8 @@
.id = 7,
.dev = { .platform_data = &android_pmem_smipool_pdata },
};
-#endif
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
#define GPIO_DONGLE_PWR_EN 258
static void setup_display_power(void);
@@ -3185,6 +3201,7 @@
pr_debug("HDMI is the primary display by"
" boot parameter\n");
hdmi_is_primary = 1;
+ set_mdp_clocks_for_wuxga();
}
}
if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
@@ -3855,6 +3872,7 @@
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L15[] = {
REGULATOR_SUPPLY("8058_l15", NULL),
+ REGULATOR_SUPPLY("cam_vana", "1-001a"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L16[] = {
REGULATOR_SUPPLY("8058_l16", NULL),
@@ -3885,6 +3903,7 @@
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L25[] = {
REGULATOR_SUPPLY("8058_l25", NULL),
+ REGULATOR_SUPPLY("cam_vdig", "1-001a"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_S0[] = {
REGULATOR_SUPPLY("8058_s0", NULL),
@@ -3903,6 +3922,7 @@
};
static struct regulator_consumer_supply vreg_consumers_PM8058_LVS0[] = {
REGULATOR_SUPPLY("8058_lvs0", NULL),
+ REGULATOR_SUPPLY("cam_vio", "1-001a"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_LVS1[] = {
REGULATOR_SUPPLY("8058_lvs1", NULL),
@@ -4090,7 +4110,7 @@
/* RPM early regulator constraints */
static struct rpm_regulator_init_data rpm_regulator_early_init_data[] = {
/* ID a_on pd ss min_uV max_uV init_ip freq */
- RPM_SMPS(PM8058_S0, 0, 1, 1, 500000, 1250000, SMPS_HMIN, 1p60),
+ RPM_SMPS(PM8058_S0, 0, 1, 1, 500000, 1325000, SMPS_HMIN, 1p60),
RPM_SMPS(PM8058_S1, 0, 1, 1, 500000, 1250000, SMPS_HMIN, 1p60),
};
@@ -4251,9 +4271,9 @@
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_smipool_device,
-#endif
&android_pmem_audio_device,
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
@@ -4266,6 +4286,7 @@
&hdmi_msm_device,
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
#ifdef CONFIG_MT9E013
&msm_camera_sensor_mt9e013,
#endif
@@ -4285,12 +4306,15 @@
&msm_camera_sensor_qs_s5k4e1,
#endif
#endif
+#endif
#ifdef CONFIG_MSM_GEMINI
&msm_gemini_device,
#endif
#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
&msm_vpe_device,
#endif
+#endif
&msm_device_vidc,
};
@@ -5136,6 +5160,7 @@
&msm_pil_q6v3,
&msm_pil_modem,
&msm_pil_tzapps,
+ &msm_pil_dsps,
#ifdef CONFIG_I2C_QUP
&msm_gsbi3_qup_i2c_device,
&msm_gsbi4_qup_i2c_device,
@@ -5181,9 +5206,9 @@
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_smipool_device,
-#endif
&android_pmem_audio_device,
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
@@ -5209,6 +5234,7 @@
&mipi_dsi_novatek_panel_device,
#endif
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
#ifdef CONFIG_MT9E013
&msm_camera_sensor_mt9e013,
#endif
@@ -5228,12 +5254,15 @@
&msm_camera_sensor_vx6953,
#endif
#endif
+#endif
#ifdef CONFIG_MSM_GEMINI
&msm_gemini_device,
#endif
#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
&msm_vpe_device,
#endif
+#endif
#if defined(CONFIG_MSM_RPM_LOG) || defined(CONFIG_MSM_RPM_LOG_MODULE)
&msm8660_rpm_log_device,
@@ -5463,6 +5492,7 @@
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+ msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
#endif
}
@@ -5476,15 +5506,19 @@
if (hdmi_is_primary)
pmem_sf_size = MSM_HDMI_PRIM_PMEM_SF_SIZE;
android_pmem_pdata.size = pmem_sf_size;
-#endif
android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
-#endif
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
}
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
{
msm8x60_reserve_table[p->memory_type].size += p->size;
}
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
+#endif /*CONFIG_ANDROID_PMEM*/
static void __init reserve_pmem_memory(void)
{
@@ -5493,10 +5527,10 @@
reserve_memory_for(&android_pmem_adsp_pdata);
reserve_memory_for(&android_pmem_smipool_pdata);
reserve_memory_for(&android_pmem_pdata);
-#endif
reserve_memory_for(&android_pmem_audio_pdata);
+#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
msm8x60_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
-#endif
+#endif /*CONFIG_ANDROID_PMEM*/
}
static void __init reserve_mdp_memory(void);
@@ -7226,6 +7260,7 @@
},
#endif
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
{
I2C_SURF | I2C_FFA | I2C_FLUID ,
MSM_GSBI4_QUP_I2C_BUS_ID,
@@ -7239,6 +7274,7 @@
ARRAY_SIZE(msm_camera_dragon_boardinfo),
},
#endif
+#endif
{
I2C_SURF | I2C_FFA | I2C_FLUID,
MSM_GSBI7_QUP_I2C_BUS_ID,
@@ -7321,6 +7357,14 @@
#ifdef CONFIG_I2C
u8 mach_mask = 0;
int i;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+ struct i2c_registry msm8x60_camera_i2c_devices = {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_GSBI4_QUP_I2C_BUS_ID,
+ msm8x60_camera_board_info.board_info,
+ msm8x60_camera_board_info.num_i2c_board_info,
+ };
+#endif
/* Build the matching 'supported_machs' bitmask */
if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion())
@@ -7345,6 +7389,12 @@
msm8x60_i2c_devices[i].info,
msm8x60_i2c_devices[i].len);
}
+#ifdef CONFIG_MSM_CAMERA_V4L2
+ if (msm8x60_camera_i2c_devices.machs & mach_mask)
+ i2c_register_board_info(msm8x60_camera_i2c_devices.bus,
+ msm8x60_camera_i2c_devices.info,
+ msm8x60_camera_i2c_devices.len);
+#endif
#endif
}
@@ -8481,10 +8531,8 @@
if (machine_is_msm8x60_fusion())
msm8x60_sdc2_data.msmsdcc_fmax = 24000000;
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
msm8x60_sdc2_data.sdiowakeup_irq = gpio_to_irq(144);
msm_sdcc_setup_gpio(2, 1);
-#endif
msm_add_sdcc(2, &msm8x60_sdc2_data);
}
#endif
@@ -8545,10 +8593,8 @@
if (machine_is_msm8x60_fusion())
msm8x60_sdc5_data.msmsdcc_fmax = 24000000;
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa()) {
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
msm8x60_sdc5_data.sdiowakeup_irq = gpio_to_irq(99);
msm_sdcc_setup_gpio(5, 1);
-#endif
msm_add_sdcc(5, &msm8x60_sdc5_data);
}
#endif
@@ -9224,51 +9270,6 @@
},
};
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors hdmi_as_primary_vectors[] = {
- /* If HDMI is used as primary */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_SMI,
- .ab = 2000000000,
- .ib = 2000000000,
- },
- /* Master and slaves can be from different fabrics */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 2000000000,
- .ib = 2000000000,
- },
-};
-
-static struct msm_bus_paths mdp_bus_scale_usecases[] = {
- {
- ARRAY_SIZE(mdp_init_vectors),
- mdp_init_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
- {
- ARRAY_SIZE(hdmi_as_primary_vectors),
- hdmi_as_primary_vectors,
- },
-};
-#else
#ifdef CONFIG_FB_MSM_LCDC_DSUB
static struct msm_bus_vectors mdp_sd_smi_vectors[] = {
/* Default case static display/UI/2d/3d if FB SMI */
@@ -9463,7 +9464,6 @@
mdp_1080p_vectors,
},
};
-#endif
static struct msm_bus_scale_pdata mdp_bus_scale_pdata = {
mdp_bus_scale_usecases,
ARRAY_SIZE(mdp_bus_scale_usecases),
@@ -9819,6 +9819,45 @@
#endif
}
+/**
+ * Set MDP clocks to high frequency to avoid underflow when
+ * using high resolution 1200x1920 WUXGA/HDMI as primary panels
+ */
+static void set_mdp_clocks_for_wuxga(void)
+{
+ int i;
+
+ mdp_sd_smi_vectors[0].ab = 2000000000;
+ mdp_sd_smi_vectors[0].ib = 2000000000;
+ mdp_sd_smi_vectors[1].ab = 2000000000;
+ mdp_sd_smi_vectors[1].ib = 2000000000;
+
+ mdp_sd_ebi_vectors[0].ab = 2000000000;
+ mdp_sd_ebi_vectors[0].ib = 2000000000;
+ mdp_sd_ebi_vectors[1].ab = 2000000000;
+ mdp_sd_ebi_vectors[1].ib = 2000000000;
+
+ mdp_vga_vectors[0].ab = 2000000000;
+ mdp_vga_vectors[0].ib = 2000000000;
+ mdp_vga_vectors[1].ab = 2000000000;
+ mdp_vga_vectors[1].ib = 2000000000;
+
+ mdp_720p_vectors[0].ab = 2000000000;
+ mdp_720p_vectors[0].ib = 2000000000;
+ mdp_720p_vectors[1].ab = 2000000000;
+ mdp_720p_vectors[1].ib = 2000000000;
+
+ mdp_1080p_vectors[0].ab = 2000000000;
+ mdp_1080p_vectors[0].ib = 2000000000;
+ mdp_1080p_vectors[1].ab = 2000000000;
+ mdp_1080p_vectors[1].ib = 2000000000;
+
+ mdp_pdata.mdp_core_clk_rate = 200000000;
+
+ for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
+ mdp_core_clk_rate_table[i] = 200000000;
+}
+
#if (defined(CONFIG_MARIMBA_CORE)) && \
(defined(CONFIG_MSM_BT_POWER) || defined(CONFIG_MSM_BT_POWER_MODULE))
@@ -10315,8 +10354,12 @@
msm8x60_init_tlmm();
msm8x60_init_gpiomux(board_data->gpiomux_cfgs);
msm8x60_init_uart12dm();
+#ifdef CONFIG_MSM_CAMERA_V4L2
+ msm8x60_init_cam();
+#endif
msm8x60_init_mmc();
+
#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
msm8x60_init_pm8058_othc();
#endif
@@ -10327,13 +10370,13 @@
pm8058_platform_data.keypad_pdata = &dragon_keypad_data;
else
pm8058_platform_data.keypad_pdata = &ffa_keypad_data;
-
+#ifndef CONFIG_MSM_CAMERA_V4L2
/* Specify reset pin for OV9726 */
if (machine_is_msm8x60_dragon()) {
msm_camera_sensor_ov9726_data.sensor_reset = 62;
ov9726_sensor_8660_info.mount_angle = 270;
}
-
+#endif
#ifdef CONFIG_BATTERY_MSM8X60
if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 91bc1ab..07aec8a 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -59,7 +59,7 @@
#include "board-msm7627a.h"
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
-#define MSM_PMEM_AUDIO_SIZE 0x5B000
+#define MSM_PMEM_AUDIO_SIZE 0x1F4000
#define BAHAMA_SLAVE_ID_FM_REG 0x02
#define FM_GPIO 83
#define BT_PCM_BCLK_MODE 0x88
@@ -130,219 +130,6 @@
#define MSM_PMEM_ADSP_SIZE 0x1100000
#endif
-#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
-defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
-
-#ifndef CLEARPAD3000_ATTEN_GPIO
-#define CLEARPAD3000_ATTEN_GPIO (48)
-#endif
-
-#ifndef CLEARPAD3000_RESET_GPIO
-#define CLEARPAD3000_RESET_GPIO (26)
-#endif
-
-static int synaptics_touchpad_setup(void);
-
-static struct msm_gpio clearpad3000_cfg_data[] = {
- {GPIO_CFG(CLEARPAD3000_ATTEN_GPIO, 0, GPIO_CFG_INPUT,
- GPIO_CFG_NO_PULL, GPIO_CFG_6MA), "rmi4_attn"},
- {GPIO_CFG(CLEARPAD3000_RESET_GPIO, 0, GPIO_CFG_OUTPUT,
- GPIO_CFG_PULL_DOWN, GPIO_CFG_8MA), "rmi4_reset"},
-};
-
-static struct rmi_XY_pair rmi_offset = {.x = 0, .y = 0};
-static struct rmi_range rmi_clipx = {.min = 48, .max = 980};
-static struct rmi_range rmi_clipy = {.min = 7, .max = 1647};
-static struct rmi_f11_functiondata synaptics_f11_data = {
- .swap_axes = false,
- .flipX = false,
- .flipY = false,
- .offset = &rmi_offset,
- .button_height = 113,
- .clipX = &rmi_clipx,
- .clipY = &rmi_clipy,
-};
-
-#define MAX_LEN 100
-
-static ssize_t clearpad3000_virtual_keys_register(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
- ":60:830:120:60" ":" __stringify(EV_KEY) \
- ":" __stringify(KEY_HOME) ":180:830:120:60" \
- ":" __stringify(EV_KEY) ":" \
- __stringify(KEY_SEARCH) ":300:830:120:60" \
- ":" __stringify(EV_KEY) ":" \
- __stringify(KEY_BACK) ":420:830:120:60" "\n";
-
- return snprintf(buf, strnlen(virtual_keys, MAX_LEN) + 1 , "%s",
- virtual_keys);
-}
-
-static struct kobj_attribute clearpad3000_virtual_keys_attr = {
- .attr = {
- .name = "virtualkeys.sensor00fn11",
- .mode = S_IRUGO,
- },
- .show = &clearpad3000_virtual_keys_register,
-};
-
-static struct attribute *virtual_key_properties_attrs[] = {
- &clearpad3000_virtual_keys_attr.attr,
- NULL
-};
-
-static struct attribute_group virtual_key_properties_attr_group = {
- .attrs = virtual_key_properties_attrs,
-};
-
-struct kobject *virtual_key_properties_kobj;
-
-static struct rmi_functiondata synaptics_functiondata[] = {
- {
- .function_index = RMI_F11_INDEX,
- .data = &synaptics_f11_data,
- },
-};
-
-static struct rmi_functiondata_list synaptics_perfunctiondata = {
- .count = ARRAY_SIZE(synaptics_functiondata),
- .functiondata = synaptics_functiondata,
-};
-
-static struct rmi_sensordata synaptics_sensordata = {
- .perfunctiondata = &synaptics_perfunctiondata,
- .rmi_sensor_setup = synaptics_touchpad_setup,
-};
-
-static struct rmi_i2c_platformdata synaptics_platformdata = {
- .i2c_address = 0x2c,
- .irq_type = IORESOURCE_IRQ_LOWLEVEL,
- .sensordata = &synaptics_sensordata,
-};
-
-static struct i2c_board_info synaptic_i2c_clearpad3k[] = {
- {
- I2C_BOARD_INFO("rmi4_ts", 0x2c),
- .platform_data = &synaptics_platformdata,
- },
-};
-
-static int synaptics_touchpad_setup(void)
-{
- int retval = 0;
-
- virtual_key_properties_kobj =
- kobject_create_and_add("board_properties", NULL);
- if (virtual_key_properties_kobj)
- retval = sysfs_create_group(virtual_key_properties_kobj,
- &virtual_key_properties_attr_group);
- if (!virtual_key_properties_kobj || retval)
- pr_err("failed to create ft5202 board_properties\n");
-
- retval = msm_gpios_request_enable(clearpad3000_cfg_data,
- sizeof(clearpad3000_cfg_data)/sizeof(struct msm_gpio));
- if (retval) {
- pr_err("%s:Failed to obtain touchpad GPIO %d. Code: %d.",
- __func__, CLEARPAD3000_ATTEN_GPIO, retval);
- retval = 0; /* ignore the err */
- }
- synaptics_platformdata.irq = gpio_to_irq(CLEARPAD3000_ATTEN_GPIO);
-
- gpio_set_value(CLEARPAD3000_RESET_GPIO, 0);
- usleep(10000);
- gpio_set_value(CLEARPAD3000_RESET_GPIO, 1);
- usleep(50000);
-
- return retval;
-}
-#endif
-
-#define FT5X06_IRQ_GPIO 48
-#define FT5X06_RESET_GPIO 26
-
-static ssize_t
-ft5x06_virtual_keys_register(struct kobject *kobj,
- struct kobj_attribute *attr,
- char *buf)
-{
- return snprintf(buf, 200,
- __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":40:510:80:60"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":120:510:80:60"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":200:510:80:60"
- ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":280:510:80:60"
- "\n");
-}
-
-static struct kobj_attribute ft5x06_virtual_keys_attr = {
- .attr = {
- .name = "virtualkeys.ft5x06_ts",
- .mode = S_IRUGO,
- },
- .show = &ft5x06_virtual_keys_register,
-};
-
-static struct attribute *ft5x06_virtual_key_properties_attrs[] = {
- &ft5x06_virtual_keys_attr.attr,
- NULL,
-};
-
-static struct attribute_group ft5x06_virtual_key_properties_attr_group = {
- .attrs = ft5x06_virtual_key_properties_attrs,
-};
-
-struct kobject *ft5x06_virtual_key_properties_kobj;
-
-static struct ft5x06_ts_platform_data ft5x06_platformdata = {
- .x_max = 320,
- .y_max = 480,
- .reset_gpio = FT5X06_RESET_GPIO,
- .irq_gpio = FT5X06_IRQ_GPIO,
- .irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-};
-
-static struct i2c_board_info ft5x06_device_info[] __initdata = {
- {
- I2C_BOARD_INFO("ft5x06_ts", 0x38),
- .platform_data = &ft5x06_platformdata,
- .irq = MSM_GPIO_TO_INT(FT5X06_IRQ_GPIO),
- },
-};
-
-static void ft5x06_touchpad_setup(void)
-{
- int rc;
-
- rc = gpio_tlmm_config(GPIO_CFG(FT5X06_IRQ_GPIO, 0,
- GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_8MA), GPIO_CFG_ENABLE);
- if (rc)
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, FT5X06_IRQ_GPIO);
-
- rc = gpio_tlmm_config(GPIO_CFG(FT5X06_RESET_GPIO, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
- GPIO_CFG_8MA), GPIO_CFG_ENABLE);
- if (rc)
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, FT5X06_RESET_GPIO);
-
- ft5x06_virtual_key_properties_kobj =
- kobject_create_and_add("board_properties", NULL);
-
- if (ft5x06_virtual_key_properties_kobj)
- rc = sysfs_create_group(ft5x06_virtual_key_properties_kobj,
- &ft5x06_virtual_key_properties_attr_group);
-
- if (!ft5x06_virtual_key_properties_kobj || rc)
- pr_err("%s: failed to create board_properties\n", __func__);
-
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- ft5x06_device_info,
- ARRAY_SIZE(ft5x06_device_info));
-}
-
static struct android_usb_platform_data android_usb_pdata = {
.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
};
@@ -723,6 +510,7 @@
/* Concurrency 6 */
(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
0, 0, 0, 0,
/* Concurrency 7 */
@@ -924,7 +712,7 @@
{
reserve_info = &msm7627a_reserve_info;
msm_reserve();
- msm_pm_8625_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
+ memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
}
static void __init msm8625_reserve(void)
@@ -970,19 +758,6 @@
= &msm_gsbi1_qup_i2c_pdata;
}
-static struct msm_handset_platform_data hs_platform_data = {
- .hs_name = "7k_handset",
- .pwr_key_delay_ms = 500, /* 0 will disable end key */
-};
-
-static struct platform_device hs_pdev = {
- .name = "msm-handset",
- .id = -1,
- .dev = {
- .platform_data = &hs_platform_data,
- },
-};
-
static struct platform_device msm_proccomm_regulator_dev = {
.name = PROCCOMM_REGULATOR_DEV_NAME,
.id = -1,
@@ -999,231 +774,6 @@
__func__, rc);
}
-/* 8625 keypad device information */
-static unsigned int kp_row_gpios_8625[] = {31};
-static unsigned int kp_col_gpios_8625[] = {36, 37};
-
-static const unsigned short keymap_8625[] = {
- KEY_VOLUMEUP,
- KEY_VOLUMEDOWN,
-};
-
-static struct gpio_event_matrix_info kp_matrix_info_8625 = {
- .info.func = gpio_event_matrix_func,
- .keymap = keymap_8625,
- .output_gpios = kp_row_gpios_8625,
- .input_gpios = kp_col_gpios_8625,
- .noutputs = ARRAY_SIZE(kp_row_gpios_8625),
- .ninputs = ARRAY_SIZE(kp_col_gpios_8625),
- .settle_time.tv_nsec = 40 * NSEC_PER_USEC,
- .poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
- .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
- GPIOKPF_PRINT_UNMAPPED_KEYS,
-};
-
-static struct gpio_event_info *kp_info_8625[] = {
- &kp_matrix_info_8625.info,
-};
-static struct gpio_event_platform_data kp_pdata_8625 = {
- .name = "8625_kp",
- .info = kp_info_8625,
- .info_count = ARRAY_SIZE(kp_info_8625)
-};
-
-static struct platform_device kp_pdev_8625 = {
- .name = GPIO_EVENT_DEV_NAME,
- .id = -1,
- .dev = {
- .platform_data = &kp_pdata_8625,
- },
-};
-
-#define LED_RED_GPIO_8625 49
-#define LED_GREEN_GPIO_8625 34
-
-static struct gpio_led gpio_leds_config_8625[] = {
- {
- .name = "green",
- .gpio = LED_GREEN_GPIO_8625,
- },
- {
- .name = "red",
- .gpio = LED_RED_GPIO_8625,
- },
-};
-
-static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
- .num_leds = ARRAY_SIZE(gpio_leds_config_8625),
- .leds = gpio_leds_config_8625,
-};
-
-static struct platform_device gpio_leds_8625 = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &gpio_leds_pdata_8625,
- },
-};
-
-#define MXT_TS_IRQ_GPIO 48
-#define MXT_TS_RESET_GPIO 26
-
-static const u8 mxt_config_data[] = {
- /* T6 Object */
- 0, 0, 0, 0, 0, 0,
- /* T38 Object */
- 16, 0, 0, 0, 0, 0, 0, 0,
- /* T7 Object */
- 32, 16, 50,
- /* T8 Object */
- 30, 0, 20, 20, 0, 0, 20, 0, 50, 0,
- /* T9 Object */
- 3, 0, 0, 18, 11, 0, 32, 75, 3, 3,
- 0, 1, 1, 0, 10, 10, 10, 10, 31, 3,
- 223, 1, 11, 11, 15, 15, 151, 43, 145, 80,
- 100, 15, 0, 0, 0,
- /* T15 Object */
- 131, 0, 11, 11, 1, 1, 0, 45, 3, 0,
- 0,
- /* T18 Object */
- 0, 0,
- /* T19 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
- /* T23 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- /* T25 Object */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- /* T40 Object */
- 0, 0, 0, 0, 0,
- /* T42 Object */
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* T46 Object */
- 0, 2, 32, 48, 0, 0, 0, 0, 0,
- /* T47 Object */
- 1, 20, 60, 5, 2, 50, 40, 0, 0, 40,
- /* T48 Object */
- 1, 12, 80, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
- 10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
- 0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
- 10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
- 80, 100, 15, 3,
-};
-
-static struct mxt_config_info mxt_config_array[] = {
- {
- .config = mxt_config_data,
- .config_length = ARRAY_SIZE(mxt_config_data),
- .family_id = 0x81,
- .variant_id = 0x01,
- .version = 0x10,
- .build = 0xAA,
- },
-};
-
-static int mxt_key_codes[MXT_KEYARRAY_MAX_KEYS] = {
- [0] = KEY_HOME,
- [1] = KEY_MENU,
- [9] = KEY_BACK,
- [10] = KEY_SEARCH,
-};
-
-static struct mxt_platform_data mxt_platform_data = {
- .config_array = mxt_config_array,
- .config_array_size = ARRAY_SIZE(mxt_config_array),
- .panel_minx = 0,
- .panel_maxx = 479,
- .panel_miny = 0,
- .panel_maxy = 799,
- .disp_minx = 0,
- .disp_maxx = 479,
- .disp_miny = 0,
- .disp_maxy = 799,
- .irqflags = IRQF_TRIGGER_FALLING,
- .i2c_pull_up = true,
- .reset_gpio = MXT_TS_RESET_GPIO,
- .irq_gpio = MXT_TS_IRQ_GPIO,
- .key_codes = mxt_key_codes,
-};
-
-static struct i2c_board_info mxt_device_info[] __initdata = {
- {
- I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
- .platform_data = &mxt_platform_data,
- .irq = MSM_GPIO_TO_INT(MXT_TS_IRQ_GPIO),
- },
-};
-
-static void msm7627a_add_io_devices(void)
-{
- int rc;
-
- /* touchscreen */
- if (machine_is_msm7627a_qrd1()) {
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- synaptic_i2c_clearpad3k,
- ARRAY_SIZE(synaptic_i2c_clearpad3k));
- } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
- rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
- GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_8MA), GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, MXT_TS_IRQ_GPIO);
- }
-
- rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_RESET_GPIO, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
- GPIO_CFG_8MA), GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, MXT_TS_RESET_GPIO);
- }
-
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- mxt_device_info,
- ARRAY_SIZE(mxt_device_info));
- } else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
- ft5x06_touchpad_setup();
- }
-
- /* headset */
- platform_device_register(&hs_pdev);
-
- /* vibrator */
-#ifdef CONFIG_MSM_RPC_VIBRATOR
- msm_init_pmic_vibrator();
-#endif
-
- /* keypad */
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
- platform_device_register(&kp_pdev_8625);
-
- /* leds */
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
- rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_16MA), GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, LED_RED_GPIO_8625);
- }
-
- rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_16MA), GPIO_CFG_ENABLE);
- if (rc) {
- pr_err("%s: gpio_tlmm_config for %d failed\n",
- __func__, LED_GREEN_GPIO_8625);
- }
-
- platform_device_register(&gpio_leds_8625);
- }
-}
-
static int __init msm_qrd_init_ar6000pm(void)
{
msm_wlan_ar6000_pm_device.dev.platform_data = &ar600x_wlan_power;
@@ -1248,9 +798,9 @@
ARRAY_SIZE(qrd7627a_devices));
}
- if (machine_is_msm7627a_qrd3())
+ if (machine_is_msm7627a_qrd3() || machine_is_msm7627a_evb())
platform_add_devices(qrd3_devices,
- ARRAY_SIZE(qrd3_devices));
+ ARRAY_SIZE(qrd3_devices));
platform_add_devices(common_devices,
ARRAY_SIZE(common_devices));
@@ -1286,10 +836,8 @@
static void __init msm_pm_init(void)
{
- if (machine_is_msm8625_qrd7())
- return;
- if (!machine_is_msm8625_evb()) {
+ if (!cpu_is_msm8625()) {
msm_pm_set_platform_data(msm7627a_pm_data,
ARRAY_SIZE(msm7627a_pm_data));
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
@@ -1337,8 +885,9 @@
#endif
msm7627a_camera_init();
- msm7627a_add_io_devices();
+ qrd7627a_add_io_devices();
msm7x25a_kgsl_3d0_init();
+ msm8x25_kgsl_3d0_init();
}
static void __init qrd7627a_init_early(void)
@@ -1389,7 +938,7 @@
MACHINE_START(MSM8625_QRD7, "QRD MSM8625 QRD7")
.boot_params = PHYS_OFFSET + 0x100,
.map_io = msm8625_map_io,
- .reserve = msm7627a_reserve,
+ .reserve = msm8625_reserve,
.init_irq = msm8625_init_irq,
.init_machine = msm_qrd_init,
.timer = &msm_timer,
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index a2882a5..b4b2855 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2653,7 +2653,6 @@
static struct clk_ops measure_clk_ops = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
- .is_local = local_clk_is_local,
};
static struct clk measure_clk = {
@@ -2965,8 +2964,7 @@
{USBH3_NS_REG, BIT(6), BIT(6)},
};
-/* Local clock driver initialization. */
-static void __init msm7x30_clock_init(void)
+static void __init msm7x30_clock_pre_init(void)
{
int i;
uint32_t val;
@@ -2979,15 +2977,17 @@
* function is a NOP since writes to shadow regions that we don't own
* are ignored. */
- clk_set_rate(&usb_hs_src_clk.c, clk_tbl_usb[1].freq_hz);
-
for (i = 0; i < ARRAY_SIZE(ri_list); i++) {
val = readl_relaxed(ri_list[i].reg);
val &= ~ri_list[i].mask;
val |= ri_list[i].val;
writel_relaxed(val, ri_list[i].reg);
}
+}
+static void __init msm7x30_clock_post_init(void)
+{
+ clk_set_rate(&usb_hs_src_clk.c, 60000000);
clk_set_rate(&i2c_clk.c, 19200000);
clk_set_rate(&i2c_2_clk.c, 19200000);
clk_set_rate(&qup_i2c_clk.c, 19200000);
@@ -3006,7 +3006,8 @@
struct clock_init_data msm7x30_clock_init_data __initdata = {
.table = msm_clocks_7x30,
.size = ARRAY_SIZE(msm_clocks_7x30),
- .init = msm7x30_clock_init,
+ .pre_init = msm7x30_clock_pre_init,
+ .post_init = msm7x30_clock_post_init,
};
/*
@@ -3022,7 +3023,6 @@
.round_rate = rcg_clk_round_rate,
.reset = msm7x30_clk_reset,
.set_flags = soc_clk_set_flags,
- .is_local = local_clk_is_local,
.get_parent = rcg_clk_get_parent,
};
@@ -3033,7 +3033,5 @@
.is_enabled = branch_clk_is_enabled,
.reset = soc_branch_clk_reset,
.set_flags = soc_clk_set_flags,
- .is_local = local_clk_is_local,
.get_parent = branch_clk_get_parent,
- .set_parent = branch_clk_set_parent,
};
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 3421bc1..0561a18 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -565,7 +565,6 @@
.is_enabled = rcg_clk_is_enabled,
.round_rate = rcg_clk_round_rate,
.reset = rcg_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = rcg_clk_get_parent,
.set_flags = rcg_clk_set_flags,
};
@@ -579,16 +578,13 @@
.auto_off = branch_clk_disable,
.is_enabled = branch_clk_is_enabled,
.reset = branch_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = branch_clk_get_parent,
- .set_parent = branch_clk_set_parent,
.handoff = branch_clk_handoff,
.set_flags = branch_clk_set_flags,
};
static struct clk_ops clk_ops_reset = {
.reset = branch_clk_reset,
- .is_local = local_clk_is_local,
};
/* AXI Interfaces */
@@ -2866,16 +2862,22 @@
return -ENXIO;
}
-static int pix_rdi_clk_handoff(struct clk *c)
+static enum handoff pix_rdi_clk_handoff(struct clk *c)
{
u32 reg;
struct pix_rdi_clk *clk = to_pix_rdi_clk(c);
+ enum handoff ret;
+
+ ret = branch_handoff(&clk->b, &clk->c);
+ if (ret == HANDOFF_DISABLED_CLK)
+ return ret;
reg = readl_relaxed(clk->s_reg);
clk->cur_rate = reg & clk->s_mask ? 1 : 0;
reg = readl_relaxed(clk->s2_reg);
clk->cur_rate = reg & clk->s2_mask ? 2 : clk->cur_rate;
- return 0;
+
+ return HANDOFF_ENABLED_CLK;
}
static struct clk_ops clk_ops_pix_rdi_8960 = {
@@ -2887,7 +2889,6 @@
.get_rate = pix_rdi_clk_get_rate,
.list_rate = pix_rdi_clk_list_rate,
.reset = pix_rdi_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = pix_rdi_clk_get_parent,
};
@@ -3350,6 +3351,7 @@
F_GFX3D(145455000, pll2, 2, 11),
F_GFX3D(160000000, pll2, 1, 5),
F_GFX3D(177778000, pll2, 2, 9),
+ F_GFX3D(192000000, pll8, 1, 2),
F_GFX3D(200000000, pll2, 1, 4),
F_GFX3D(228571000, pll2, 2, 7),
F_GFX3D(266667000, pll2, 1, 3),
@@ -3367,7 +3369,7 @@
};
static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
- [VDD_DIG_LOW] = 128000000,
+ [VDD_DIG_LOW] = 192000000,
[VDD_DIG_NOMINAL] = 320000000,
[VDD_DIG_HIGH] = 450000000
};
@@ -3817,7 +3819,6 @@
.enable = hdmi_pll_clk_enable,
.disable = hdmi_pll_clk_disable,
.get_rate = hdmi_pll_clk_get_rate,
- .is_local = local_clk_is_local,
.get_parent = hdmi_pll_clk_get_parent,
};
@@ -4492,6 +4493,8 @@
static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_tzcom_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
@@ -4887,7 +4890,6 @@
static struct clk_ops measure_clk_ops = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
- .is_local = local_clk_is_local,
};
static struct measure_clk measure_clk = {
@@ -4902,7 +4904,6 @@
static struct clk_lookup msm_clocks_8064[] = {
CLK_LOOKUP("xo", cxo_a_clk.c, ""),
CLK_LOOKUP("xo", pxo_a_clk.c, ""),
- CLK_LOOKUP("xo", cxo_clk.c, "msm_otg"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
@@ -4928,10 +4929,10 @@
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, ""),
- CLK_LOOKUP("dfab_clk", dfab_clk.c, ""),
- CLK_LOOKUP("dfab_a_clk", dfab_a_clk.c, ""),
CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, ""),
CLK_LOOKUP("mmfpb_a_clk", mmfpb_a_clk.c, "clock-8960"),
CLK_LOOKUP("cfpb_a_clk", cfpb_a_clk.c, "clock-8960"),
@@ -5006,6 +5007,7 @@
CLK_LOOKUP("core_clk", amp_clk.c, ""),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-001a"),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0034"),
+ CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-0048"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-006c"),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
@@ -5070,7 +5072,7 @@
CLK_LOOKUP("tv_clk", mdp_tv_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("hdmi_clk", hdmi_tv_clk.c, NULL),
CLK_LOOKUP("core_clk", hdmi_app_clk.c, "hdmi_msm.1"),
- CLK_LOOKUP("vpe_clk", vpe_clk.c, ""),
+ CLK_LOOKUP("vpe_clk", vpe_clk.c, "msm_vpe.0"),
CLK_LOOKUP("core_clk", vpe_clk.c, "footswitch-8x60.9"),
CLK_LOOKUP("vfe_clk", vfe_clk.c, "msm_vfe.0"),
CLK_LOOKUP("core_clk", vfe_clk.c, "footswitch-8x60.8"),
@@ -5176,6 +5178,9 @@
CLK_LOOKUP("core_clk", gfx3d_axi_clk_8064.c, "msm_iommu.10"),
CLK_LOOKUP("core_clk", vcap_axi_clk.c, "msm_iommu.11"),
+ CLK_LOOKUP("core_clk", vcodec_axi_clk.c, "pil_vidc"),
+ CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "pil_vidc"),
+
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
@@ -5188,7 +5193,6 @@
static struct clk_lookup msm_clocks_8960[] = {
CLK_LOOKUP("xo", cxo_a_clk.c, ""),
CLK_LOOKUP("xo", pxo_a_clk.c, ""),
- CLK_LOOKUP("xo", cxo_clk.c, "msm_otg"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
@@ -5213,10 +5217,10 @@
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
- CLK_LOOKUP("dfab_clk", dfab_clk.c, NULL),
- CLK_LOOKUP("dfab_a_clk", dfab_a_clk.c, NULL),
CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, NULL),
CLK_LOOKUP("mmfpb_a_clk", mmfpb_a_clk.c, "clock-8960"),
CLK_LOOKUP("cfpb_a_clk", cfpb_a_clk.c, "clock-8960"),
@@ -5231,7 +5235,7 @@
CLK_LOOKUP("core_clk", gsbi5_uart_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("core_clk", gsbi6_uart_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("core_clk", gsbi7_uart_clk.c, ""),
- CLK_LOOKUP("core_clk", gsbi8_uart_clk.c, ""),
+ CLK_LOOKUP("core_clk", gsbi8_uart_clk.c, "msm_serial_hsl.1"),
CLK_LOOKUP("core_clk", gsbi9_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi10_uart_clk.c, ""),
CLK_LOOKUP("core_clk", gsbi11_uart_clk.c, ""),
@@ -5284,7 +5288,7 @@
CLK_LOOKUP("iface_clk", gsbi5_p_clk.c, "msm_serial_hsl.0"),
CLK_LOOKUP("iface_clk", gsbi6_p_clk.c, "msm_serial_hs.0"),
CLK_LOOKUP("iface_clk", gsbi7_p_clk.c, ""),
- CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gsbi8_p_clk.c, "msm_serial_hsl.1"),
CLK_LOOKUP("iface_clk", gsbi9_p_clk.c, ""),
CLK_LOOKUP("iface_clk", gsbi10_p_clk.c, "qup_i2c.10"),
CLK_LOOKUP("iface_clk", gsbi11_p_clk.c, ""),
@@ -5455,6 +5459,8 @@
CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_a_clk.c, "msm_vidc.0"),
CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_clk.c, "msm_vidc.0"),
CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("core_clk", vcodec_axi_clk.c, "pil_vidc"),
+ CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "pil_vidc"),
CLK_LOOKUP("dfab_dsps_clk", dfab_dsps_clk.c, NULL),
CLK_LOOKUP("core_clk", dfab_usb_hs_clk.c, "msm_otg"),
@@ -5480,7 +5486,7 @@
};
static struct clk_lookup msm_clocks_8930[] = {
- CLK_LOOKUP("xo", cxo_clk.c, "msm_otg"),
+ CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
@@ -5504,10 +5510,10 @@
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
- CLK_LOOKUP("dfab_clk", dfab_clk.c, NULL),
- CLK_LOOKUP("dfab_a_clk", dfab_a_clk.c, NULL),
CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, NULL),
CLK_LOOKUP("mmfpb_a_clk", mmfpb_a_clk.c, "clock-8960"),
CLK_LOOKUP("cfpb_a_clk", cfpb_a_clk.c, "clock-8960"),
@@ -5727,6 +5733,8 @@
CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_a_clk.c, "msm_vidc.0"),
CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_b_clk.c, "msm_vidc.0"),
CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("core_clk", vcodec_axi_clk.c, "pil_vidc"),
+ CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "pil_vidc"),
CLK_LOOKUP("dfab_dsps_clk", dfab_dsps_clk.c, NULL),
CLK_LOOKUP("core_clk", dfab_usb_hs_clk.c, "msm_otg"),
@@ -5899,18 +5907,6 @@
writel_relaxed(0, SW_RESET_CORE_REG);
writel_relaxed(0, SW_RESET_CORE2_REG);
- /* Reset 3D core once more, with its clock enabled. This can
- * eventually be done as part of the GDFS footswitch driver. */
- clk_set_rate(&gfx3d_clk.c, 27000000);
- clk_prepare_enable(&gfx3d_clk.c);
- writel_relaxed(BIT(12), SW_RESET_CORE_REG);
- mb();
- udelay(5);
- writel_relaxed(0, SW_RESET_CORE_REG);
- /* Make sure reset is de-asserted before clock is disabled. */
- mb();
- clk_disable_unprepare(&gfx3d_clk.c);
-
/* Enable TSSC and PDM PXO sources. */
writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
writel_relaxed(BIT(15), PDM_CLK_NS_REG);
@@ -5982,14 +5978,23 @@
if (!readl_relaxed(PRNG_CLK_NS_REG))
writel_relaxed(0x2B, PRNG_CLK_NS_REG);
}
+
+ /*
+ * Program PLL15 to 900MHz with ref clk = 27MHz and
+ * only enable PLL main output.
+ */
+ if (cpu_is_msm8930()) {
+ writel_relaxed(0x30021, MM_PLL3_L_VAL_REG);
+ writel_relaxed(0x1, MM_PLL3_M_VAL_REG);
+ writel_relaxed(0x3, MM_PLL3_N_VAL_REG);
+
+ writel_relaxed(0xC20000, MM_PLL3_CONFIG_REG);
+ writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+ }
}
-/* Local clock driver initialization. */
-static void __init msm8960_clock_init(void)
+static void __init msm8960_clock_pre_init(void)
{
- /* Keep PXO on whenever APPS cpu is active */
- clk_prepare_enable(&pxo_a_clk.c);
-
if (cpu_is_apq8064()) {
vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
@@ -6038,6 +6043,20 @@
/* Initialize clock registers. */
reg_init();
+}
+
+static void __init msm8960_clock_post_init(void)
+{
+ /* Keep PXO on whenever APPS cpu is active */
+ clk_prepare_enable(&pxo_a_clk.c);
+
+ /* Reset 3D core while clocked to ensure it resets completely. */
+ clk_set_rate(&gfx3d_clk.c, 27000000);
+ clk_prepare_enable(&gfx3d_clk.c);
+ clk_reset(&gfx3d_clk.c, CLK_RESET_ASSERT);
+ udelay(5);
+ clk_reset(&gfx3d_clk.c, CLK_RESET_DEASSERT);
+ clk_disable_unprepare(&gfx3d_clk.c);
/* Initialize rates for clocks that only support one. */
clk_set_rate(&pdm_clk.c, 27000000);
@@ -6119,20 +6138,23 @@
struct clock_init_data msm8960_clock_init_data __initdata = {
.table = msm_clocks_8960,
.size = ARRAY_SIZE(msm_clocks_8960),
- .init = msm8960_clock_init,
+ .pre_init = msm8960_clock_pre_init,
+ .post_init = msm8960_clock_post_init,
.late_init = msm8960_clock_late_init,
};
struct clock_init_data apq8064_clock_init_data __initdata = {
.table = msm_clocks_8064,
.size = ARRAY_SIZE(msm_clocks_8064),
- .init = msm8960_clock_init,
+ .pre_init = msm8960_clock_pre_init,
+ .post_init = msm8960_clock_post_init,
.late_init = msm8960_clock_late_init,
};
struct clock_init_data msm8930_clock_init_data __initdata = {
.table = msm_clocks_8930,
.size = ARRAY_SIZE(msm_clocks_8930),
- .init = msm8960_clock_init,
+ .pre_init = msm8960_clock_pre_init,
+ .post_init = msm8960_clock_post_init,
.late_init = msm8960_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index c2632ee..3bfb5a3 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -439,7 +439,6 @@
.is_enabled = rcg_clk_is_enabled,
.round_rate = rcg_clk_round_rate,
.reset = rcg_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = rcg_clk_get_parent,
.set_flags = rcg_clk_set_flags,
};
@@ -450,15 +449,12 @@
.auto_off = branch_clk_disable,
.is_enabled = branch_clk_is_enabled,
.reset = branch_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = branch_clk_get_parent,
- .set_parent = branch_clk_set_parent,
.set_flags = branch_clk_set_flags,
};
static struct clk_ops clk_ops_reset = {
.reset = branch_clk_reset,
- .is_local = local_clk_is_local,
};
/*
@@ -3482,7 +3478,6 @@
static struct clk_ops measure_clk_ops = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
- .is_local = local_clk_is_local,
};
static struct measure_clk measure_clk = {
@@ -3617,6 +3612,7 @@
CLK_LOOKUP("csi_clk", csi0_clk.c, NULL),
CLK_LOOKUP("csi_clk", csi1_clk.c, "msm_camera_ov7692.0"),
CLK_LOOKUP("csi_clk", csi1_clk.c, "msm_camera_ov9726.0"),
+ CLK_LOOKUP("csi_clk", csi1_clk.c, "msm_csic.1"),
CLK_LOOKUP("csi_src_clk", csi_src_clk.c, NULL),
CLK_LOOKUP("dsi_byte_div_clk", dsi_byte_clk.c, NULL),
CLK_LOOKUP("dsi_esc_clk", dsi_esc_clk.c, NULL),
@@ -3654,6 +3650,7 @@
CLK_LOOKUP("csi_vfe_clk", csi0_vfe_clk.c, NULL),
CLK_LOOKUP("csi_vfe_clk", csi1_vfe_clk.c, "msm_camera_ov7692.0"),
CLK_LOOKUP("csi_vfe_clk", csi1_vfe_clk.c, "msm_camera_ov9726.0"),
+ CLK_LOOKUP("csi_vfe_clk", csi1_vfe_clk.c, "msm_csic.1"),
CLK_LOOKUP("vfe_clk", vfe_clk.c, NULL),
CLK_LOOKUP("core_clk", vfe_clk.c, "footswitch-8x60.8"),
CLK_LOOKUP("bus_clk", vfe_axi_clk.c, "footswitch-8x60.8"),
@@ -3667,6 +3664,7 @@
CLK_LOOKUP("csi_pclk", csi0_p_clk.c, NULL),
CLK_LOOKUP("csi_pclk", csi1_p_clk.c, "msm_camera_ov7692.0"),
CLK_LOOKUP("csi_pclk", csi1_p_clk.c, "msm_camera_ov9726.0"),
+ CLK_LOOKUP("csi_pclk", csi1_p_clk.c, "msm_csic.1"),
CLK_LOOKUP("dsi_m_pclk", dsi_m_p_clk.c, NULL),
CLK_LOOKUP("dsi_s_pclk", dsi_s_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gfx2d0_p_clk.c, "kgsl-2d0.0"),
@@ -3751,8 +3749,10 @@
writel_relaxed(regval, reg);
}
-static void __init reg_init(void)
+static void __init msm8660_clock_pre_init(void)
{
+ vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
/* Setup MM_PLL2 (PLL3), but turn it off. Rate set by set_rate_tv(). */
rmwreg(0, MM_PLL2_MODE_REG, BIT(0)); /* Disable output */
/* Set ref, bypass, assert reset, disable output, disable test mode */
@@ -3816,18 +3816,6 @@
/* Deassert all MM core resets. */
writel_relaxed(0, SW_RESET_CORE_REG);
- /* Reset 3D core once more, with its clock enabled. This can
- * eventually be done as part of the GDFS footswitch driver. */
- clk_set_rate(&gfx3d_clk.c, 27000000);
- clk_prepare_enable(&gfx3d_clk.c);
- writel_relaxed(BIT(12), SW_RESET_CORE_REG);
- mb();
- udelay(5);
- writel_relaxed(0, SW_RESET_CORE_REG);
- /* Make sure reset is de-asserted before clock is disabled. */
- mb();
- clk_disable_unprepare(&gfx3d_clk.c);
-
/* Enable TSSC and PDM PXO sources. */
writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
writel_relaxed(BIT(15), PDM_CLK_NS_REG);
@@ -3836,14 +3824,18 @@
rmwreg(0x400001, MISC_CC2_REG, 0x424003);
}
-/* Local clock driver initialization. */
-static void __init msm8660_clock_init(void)
+static void __init msm8660_clock_post_init(void)
{
- vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
/* Keep PXO on whenever APPS cpu is active */
clk_prepare_enable(&pxo_a_clk.c);
- /* Initialize clock registers. */
- reg_init();
+
+ /* Reset 3D core while clocked to ensure it resets completely. */
+ clk_set_rate(&gfx3d_clk.c, 27000000);
+ clk_prepare_enable(&gfx3d_clk.c);
+ clk_reset(&gfx3d_clk.c, CLK_RESET_ASSERT);
+ udelay(5);
+ clk_reset(&gfx3d_clk.c, CLK_RESET_DEASSERT);
+ clk_disable_unprepare(&gfx3d_clk.c);
/* Initialize rates for clocks that only support one. */
clk_set_rate(&pdm_clk.c, 27000000);
@@ -3885,6 +3877,7 @@
struct clock_init_data msm8x60_clock_init_data __initdata = {
.table = msm_clocks_8x60,
.size = ARRAY_SIZE(msm_clocks_8x60),
- .init = msm8660_clock_init,
+ .pre_init = msm8660_clock_pre_init,
+ .post_init = msm8660_clock_post_init,
.late_init = msm8660_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 6f02b75..89e3036 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -248,7 +248,6 @@
.auto_off = pll_acpu_vote_clk_disable,
.is_enabled = pll_vote_clk_is_enabled,
.get_parent = pll_vote_clk_get_parent,
- .is_local = local_clk_is_local,
};
#define PLL_SOFT_VOTE_PRIMARY BIT(0)
@@ -372,7 +371,6 @@
.is_enabled = rcg_clk_is_enabled,
.round_rate = rcg_clk_round_rate,
.reset = rcg_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = rcg_clk_get_parent,
};
@@ -386,9 +384,7 @@
.handoff = branch_clk_handoff,
.is_enabled = branch_clk_is_enabled,
.reset = branch_clk_reset,
- .is_local = local_clk_is_local,
.get_parent = branch_clk_get_parent,
- .set_parent = branch_clk_set_parent,
};
/*
@@ -1360,6 +1356,8 @@
static DEFINE_CLK_VOTER(dfab_sdc2_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c);
@@ -1586,7 +1584,6 @@
static struct clk_ops measure_clk_ops = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
- .is_local = local_clk_is_local,
};
static struct measure_clk measure_clk = {
@@ -1600,7 +1597,6 @@
static struct clk_lookup msm_clocks_9615[] = {
CLK_LOOKUP("xo", cxo_a_clk.c, ""),
- CLK_LOOKUP("xo", cxo_clk.c, "msm_otg"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("pll0", pll0_clk.c, NULL),
@@ -1617,14 +1613,14 @@
CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
+ CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("bus_clk", sfpb_clk.c, NULL),
CLK_LOOKUP("bus_a_clk", sfpb_a_clk.c, NULL),
CLK_LOOKUP("bus_clk", cfpb_clk.c, NULL),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, NULL),
CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
- CLK_LOOKUP("dfab_clk", dfab_clk.c, NULL),
- CLK_LOOKUP("dfab_a_clk", dfab_a_clk.c, NULL),
CLK_LOOKUP("core_clk", gp0_clk.c, ""),
CLK_LOOKUP("core_clk", gp1_clk.c, ""),
@@ -1740,10 +1736,14 @@
/*
* Miscellaneous clock register initializations
*/
-static void __init reg_init(void)
+static void __init msm9615_clock_pre_init(void)
{
u32 regval, is_pll_enabled, pll9_lval;
+ vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
+
+ clk_ops_pll.enable = sr_pll_clk_enable;
+
/* Enable PDM CXO source. */
regval = readl_relaxed(PDM_CLK_NS_REG);
writel_relaxed(BIT(13) | regval, PDM_CLK_NS_REG);
@@ -1832,18 +1832,11 @@
writel_relaxed(regval, DMA_BAM_HCLK_CTL);
}
-/* Local clock driver initialization. */
-static void __init msm9615_clock_init(void)
+static void __init msm9615_clock_post_init(void)
{
- vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
/* Keep CXO on whenever APPS cpu is active */
clk_prepare_enable(&cxo_a_clk.c);
- clk_ops_pll.enable = sr_pll_clk_enable;
-
- /* Initialize clock registers. */
- reg_init();
-
/* Initialize rates for clocks that only support one. */
clk_set_rate(&pdm_clk.c, 19200000);
clk_set_rate(&prng_clk.c, 32000000);
@@ -1869,6 +1862,7 @@
struct clock_init_data msm9615_clock_init_data __initdata = {
.table = msm_clocks_9615,
.size = ARRAY_SIZE(msm_clocks_9615),
- .init = msm9615_clock_init,
+ .pre_init = msm9615_clock_pre_init,
+ .post_init = msm9615_clock_post_init,
.late_init = msm9615_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 31be6af..54b13e6 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -120,7 +120,10 @@
{
struct clk *clock = data;
- *val = clock->ops->is_local(clock);
+ if (!clock->ops->is_local)
+ *val = true;
+ else
+ *val = clock->ops->is_local(clock);
return 0;
}
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
index dfd4a67..54c9de8 100644
--- a/arch/arm/mach-msm/clock-dummy.c
+++ b/arch/arm/mach-msm/clock-dummy.c
@@ -42,11 +42,6 @@
return rate;
}
-static bool dummy_clk_is_local(struct clk *clk)
-{
- return true;
-}
-
static struct clk_ops clk_ops_dummy = {
.reset = dummy_clk_reset,
.set_rate = dummy_clk_set_rate,
@@ -54,7 +49,6 @@
.set_flags = dummy_clk_set_flags,
.get_rate = dummy_clk_get_rate,
.round_rate = dummy_clk_round_rate,
- .is_local = dummy_clk_is_local,
};
struct clk dummy_clk = {
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 3546ce0..84aa086 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -545,11 +545,6 @@
return -EPERM;
}
-bool local_clk_is_local(struct clk *clk)
-{
- return true;
-}
-
/* Return the nth supported frequency for a given clock. */
int rcg_clk_list_rate(struct clk *c, unsigned n)
{
@@ -567,34 +562,36 @@
}
/* Disable hw clock gating if not set at boot */
-static void branch_handoff(struct branch *clk, struct clk *c)
+enum handoff branch_handoff(struct branch *clk, struct clk *c)
{
if (!branch_in_hwcg_mode(clk)) {
clk->hwcg_mask = 0;
c->flags &= ~CLKFLAG_HWCG;
+ if (readl_relaxed(clk->ctl_reg) & clk->en_mask)
+ return HANDOFF_ENABLED_CLK;
} else {
c->flags |= CLKFLAG_HWCG;
}
+ return HANDOFF_DISABLED_CLK;
}
-int branch_clk_handoff(struct clk *c)
+enum handoff branch_clk_handoff(struct clk *c)
{
struct branch_clk *clk = to_branch_clk(c);
- branch_handoff(&clk->b, &clk->c);
- return 0;
+ return branch_handoff(&clk->b, &clk->c);
}
-int rcg_clk_handoff(struct clk *c)
+enum handoff rcg_clk_handoff(struct clk *c)
{
struct rcg_clk *clk = to_rcg_clk(c);
uint32_t ctl_val, ns_val, md_val, ns_mask;
struct clk_freq_tbl *freq;
-
- branch_handoff(&clk->b, &clk->c);
+ enum handoff ret;
ctl_val = readl_relaxed(clk->b.ctl_reg);
- if (!(ctl_val & clk->root_en_mask))
- return 0;
+ ret = branch_handoff(&clk->b, &clk->c);
+ if (ret == HANDOFF_DISABLED_CLK)
+ return HANDOFF_DISABLED_CLK;
if (clk->bank_info) {
const struct bank_masks *bank_masks = clk->bank_info;
@@ -611,7 +608,8 @@
ns_mask = clk->ns_mask;
md_val = clk->md_reg ? readl_relaxed(clk->md_reg) : 0;
}
-
+ if (!ns_mask)
+ return HANDOFF_UNKNOWN_RATE;
ns_val = readl_relaxed(clk->ns_reg) & ns_mask;
for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
if ((freq->ns_val & ns_mask) == ns_val &&
@@ -621,12 +619,12 @@
}
}
if (freq->freq_hz == FREQ_END)
- return 0;
+ return HANDOFF_UNKNOWN_RATE;
clk->current_freq = freq;
c->rate = freq->freq_hz;
- return 1;
+ return HANDOFF_ENABLED_CLK;
}
int pll_vote_clk_enable(struct clk *clk)
@@ -679,7 +677,6 @@
.auto_off = pll_vote_clk_disable,
.is_enabled = pll_vote_clk_is_enabled,
.get_parent = pll_vote_clk_get_parent,
- .is_local = local_clk_is_local,
};
static int pll_clk_enable(struct clk *clk)
@@ -780,11 +777,9 @@
.disable = pll_clk_disable,
.auto_off = pll_clk_disable,
.get_parent = pll_clk_get_parent,
- .is_local = local_clk_is_local,
};
struct clk_ops clk_ops_gnd = {
- .is_local = local_clk_is_local,
};
struct fixed_clk gnd_clk = {
@@ -796,7 +791,6 @@
};
struct clk_ops clk_ops_measure = {
- .is_local = local_clk_is_local,
};
int branch_clk_enable(struct clk *clk)
@@ -829,19 +823,6 @@
return branch->parent;
}
-int branch_clk_set_parent(struct clk *clk, struct clk *parent)
-{
- /*
- * We setup the parent pointer at init time in msm_clock_init().
- * This check is to make sure drivers can't change the parent.
- */
- if (parent && list_empty(&clk->siblings)) {
- list_add(&clk->siblings, &parent->children);
- return 0;
- }
- return -EINVAL;
-}
-
int branch_clk_is_enabled(struct clk *clk)
{
struct branch_clk *branch = to_branch_clk(clk);
@@ -1058,12 +1039,15 @@
return n > clk->max_div ? -ENXIO : n;
}
-static int cdiv_clk_handoff(struct clk *c)
+static enum handoff cdiv_clk_handoff(struct clk *c)
{
struct cdiv_clk *clk = to_cdiv_clk(c);
+ enum handoff ret;
u32 reg_val;
- branch_handoff(&clk->b, &clk->c);
+ ret = branch_handoff(&clk->b, &clk->c);
+ if (ret == HANDOFF_DISABLED_CLK)
+ return ret;
reg_val = readl_relaxed(clk->ns_reg);
if (reg_val & clk->ext_mask) {
@@ -1073,7 +1057,7 @@
clk->cur_div = (reg_val & (clk->max_div - 1)) + 1;
}
- return 0;
+ return HANDOFF_ENABLED_CLK;
}
static void cdiv_clk_enable_hwcg(struct clk *c)
@@ -1106,5 +1090,4 @@
.get_rate = cdiv_clk_get_rate,
.list_rate = cdiv_clk_list_rate,
.round_rate = cdiv_clk_round_rate,
- .is_local = local_clk_is_local,
};
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 44e86b1..3dd849a 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -171,7 +171,8 @@
int branch_reset(struct branch *b, enum clk_reset_action action);
void __branch_clk_enable_reg(const struct branch *clk, const char *name);
u32 __branch_clk_disable_reg(const struct branch *clk, const char *name);
-int branch_clk_handoff(struct clk *c);
+enum handoff branch_clk_handoff(struct clk *c);
+enum handoff branch_handoff(struct branch *clk, struct clk *c);
int branch_clk_set_flags(struct clk *clk, unsigned flags);
/*
@@ -211,7 +212,7 @@
int rcg_clk_is_enabled(struct clk *clk);
long rcg_clk_round_rate(struct clk *clk, unsigned long rate);
struct clk *rcg_clk_get_parent(struct clk *c);
-int rcg_clk_handoff(struct clk *c);
+enum handoff rcg_clk_handoff(struct clk *c);
int rcg_clk_reset(struct clk *clk, enum clk_reset_action action);
void rcg_clk_enable_hwcg(struct clk *clk);
void rcg_clk_disable_hwcg(struct clk *clk);
@@ -330,7 +331,6 @@
int branch_clk_enable(struct clk *clk);
void branch_clk_disable(struct clk *clk);
struct clk *branch_clk_get_parent(struct clk *clk);
-int branch_clk_set_parent(struct clk *clk, struct clk *parent);
int branch_clk_is_enabled(struct clk *clk);
int branch_clk_reset(struct clk *c, enum clk_reset_action action);
void branch_clk_enable_hwcg(struct clk *clk);
@@ -365,11 +365,6 @@
extern struct fixed_clk gnd_clk;
/*
- * Local-clock APIs
- */
-bool local_clk_is_local(struct clk *clk);
-
-/*
* PLL vote clock APIs
*/
int pll_vote_clk_enable(struct clk *clk);
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index a0defe3..ed3b8c2 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -307,7 +307,7 @@
struct clock_init_data msm7x27_clock_init_data __initdata = {
.table = msm_clocks_7x27,
.size = ARRAY_SIZE(msm_clocks_7x27),
- .init = msm_shared_pll_control_init,
+ .pre_init = msm_shared_pll_control_init,
};
/* Clock table for common clocks between 7627a and 7625a */
@@ -413,7 +413,7 @@
static struct clk_lookup msm_clk_7627a_7625a[ARRAY_SIZE(msm_cmn_clk_7625a_7627a)
+ ARRAY_SIZE(msm_clk_7627a)];
-static void __init msm7627a_clock_init(void)
+static void __init msm7627a_clock_pre_init(void)
{
int size = ARRAY_SIZE(msm_cmn_clk_7625a_7627a);
@@ -432,7 +432,7 @@
struct clock_init_data msm7x27a_clock_init_data __initdata = {
.table = msm_clk_7627a_7625a,
- .init = msm7627a_clock_init,
+ .pre_init = msm7627a_clock_pre_init,
};
static struct clk_lookup msm_clocks_8x50[] = {
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index b5b6ca7..68c390a 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -156,7 +156,7 @@
return true;
}
-static int pll_clk_handoff(struct clk *clk)
+static enum handoff pll_clk_handoff(struct clk *clk)
{
struct pll_shared_clk *pll = to_pll_shared_clk(clk);
unsigned int pll_lval;
@@ -184,7 +184,7 @@
BUG();
}
- return 0;
+ return HANDOFF_ENABLED_CLK;
}
struct clk_ops clk_pll_ops = {
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index ef502b3..8ff4878 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -29,7 +29,7 @@
list_for_each_entry(clk, &parent->children, siblings) {
struct clk_voter *v = to_clk_voter(clk);
if (v->enabled)
- rate = max(v->rate, rate);
+ rate = max(clk->rate, rate);
}
return rate;
}
@@ -54,10 +54,10 @@
list_for_each_entry(clkp, &parent->children, siblings) {
clkh = to_clk_voter(clkp);
if (clkh->enabled && clkh != v)
- other_rate = max(clkh->rate, other_rate);
+ other_rate = max(clkp->rate, other_rate);
}
- cur_rate = max(other_rate, v->rate);
+ cur_rate = max(other_rate, clk->rate);
new_rate = max(other_rate, rate);
if (new_rate != cur_rate) {
@@ -66,7 +66,7 @@
goto unlock;
}
}
- v->rate = rate;
+ clk->rate = rate;
unlock:
spin_unlock_irqrestore(&voter_clk_lock, flags);
@@ -89,8 +89,8 @@
* than the current rate.
*/
cur_rate = voter_clk_aggregate_rate(parent);
- if (v->rate > cur_rate) {
- ret = clk_set_rate(parent, v->rate);
+ if (clk->rate > cur_rate) {
+ ret = clk_set_rate(parent, clk->rate);
if (ret)
goto out;
}
@@ -116,7 +116,7 @@
*/
v->enabled = false;
new_rate = voter_clk_aggregate_rate(parent);
- cur_rate = max(new_rate, v->rate);
+ cur_rate = max(new_rate, clk->rate);
if (new_rate < cur_rate)
clk_set_rate(parent, new_rate);
@@ -124,18 +124,6 @@
spin_unlock_irqrestore(&voter_clk_lock, flags);
}
-static unsigned long voter_clk_get_rate(struct clk *clk)
-{
- unsigned long rate, flags;
- struct clk_voter *v = to_clk_voter(clk);
-
- spin_lock_irqsave(&voter_clk_lock, flags);
- rate = v->rate;
- spin_unlock_irqrestore(&voter_clk_lock, flags);
-
- return rate;
-}
-
static int voter_clk_is_enabled(struct clk *clk)
{
struct clk_voter *v = to_clk_voter(clk);
@@ -148,18 +136,6 @@
return clk_round_rate(v->parent, rate);
}
-static int voter_clk_set_parent(struct clk *clk, struct clk *parent)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&voter_clk_lock, flags);
- if (list_empty(&clk->siblings))
- list_add(&clk->siblings, &parent->children);
- spin_unlock_irqrestore(&voter_clk_lock, flags);
-
- return 0;
-}
-
static struct clk *voter_clk_get_parent(struct clk *clk)
{
struct clk_voter *v = to_clk_voter(clk);
@@ -175,10 +151,8 @@
.enable = voter_clk_enable,
.disable = voter_clk_disable,
.set_rate = voter_clk_set_rate,
- .get_rate = voter_clk_get_rate,
.is_enabled = voter_clk_is_enabled,
.round_rate = voter_clk_round_rate,
- .set_parent = voter_clk_set_parent,
.get_parent = voter_clk_get_parent,
.is_local = voter_clk_is_local,
};
diff --git a/arch/arm/mach-msm/clock-voter.h b/arch/arm/mach-msm/clock-voter.h
index 10353d4..de17894 100644
--- a/arch/arm/mach-msm/clock-voter.h
+++ b/arch/arm/mach-msm/clock-voter.h
@@ -19,7 +19,6 @@
struct clk_voter {
bool enabled;
- unsigned long rate;
struct clk *parent;
struct clk c;
};
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 884a27e..09bf036 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -399,27 +399,40 @@
unsigned n;
struct clk_lookup *clock_tbl;
size_t num_clocks;
+ struct clk *clk;
clk_init_data = data;
- if (clk_init_data->init)
- clk_init_data->init();
+ if (clk_init_data->pre_init)
+ clk_init_data->pre_init();
clock_tbl = data->table;
num_clocks = data->size;
for (n = 0; n < num_clocks; n++) {
- struct clk *clk = clock_tbl[n].clk;
- struct clk *parent = clk_get_parent(clk);
- clk_set_parent(clk, parent);
- if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE)) {
- if (clk->ops->handoff(clk)) {
- clk->flags |= CLKFLAG_HANDOFF_RATE;
- clk_prepare_enable(clk);
- }
+ struct clk *parent;
+ clk = clock_tbl[n].clk;
+ parent = clk_get_parent(clk);
+ if (parent && list_empty(&clk->siblings))
+ list_add(&clk->siblings, &parent->children);
+ }
+
+ /*
+ * Detect and preserve initial clock state until clock_late_init() or
+ * a driver explicitly changes it, whichever is first.
+ */
+ for (n = 0; n < num_clocks; n++) {
+ clk = clock_tbl[n].clk;
+ if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE) &&
+ (clk->ops->handoff(clk) == HANDOFF_ENABLED_CLK)) {
+ clk->flags |= CLKFLAG_HANDOFF_RATE;
+ clk_prepare_enable(clk);
}
}
clkdev_add_table(clock_tbl, num_clocks);
+
+ if (clk_init_data->post_init)
+ clk_init_data->post_init();
}
/*
@@ -439,24 +452,24 @@
bool handoff = false;
clock_debug_add(clk);
+ spin_lock_irqsave(&clk->lock, flags);
if (!(clk->flags & CLKFLAG_SKIP_AUTO_OFF)) {
- spin_lock_irqsave(&clk->lock, flags);
if (!clk->count && clk->ops->auto_off) {
count++;
clk->ops->auto_off(clk);
}
- if (clk->flags & CLKFLAG_HANDOFF_RATE) {
- clk->flags &= ~CLKFLAG_HANDOFF_RATE;
- handoff = true;
- }
- spin_unlock_irqrestore(&clk->lock, flags);
- /*
- * Calling this outside the lock is safe since
- * it doesn't need to be atomic with the flag change.
- */
- if (handoff)
- clk_disable_unprepare(clk);
}
+ if (clk->flags & CLKFLAG_HANDOFF_RATE) {
+ clk->flags &= ~CLKFLAG_HANDOFF_RATE;
+ handoff = true;
+ }
+ spin_unlock_irqrestore(&clk->lock, flags);
+ /*
+ * Calling this outside the lock is safe since
+ * it doesn't need to be atomic with the flag change.
+ */
+ if (handoff)
+ clk_disable_unprepare(clk);
}
pr_info("clock_late_init() disabled %d unused clocks\n", count);
if (clk_init_data->late_init)
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 785e838..60be654 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -63,6 +63,12 @@
.lock = __SPIN_LOCK_UNLOCKED(lock) \
}
+enum handoff {
+ HANDOFF_ENABLED_CLK,
+ HANDOFF_DISABLED_CLK,
+ HANDOFF_UNKNOWN_RATE,
+};
+
struct clk_ops {
int (*prepare)(struct clk *clk);
int (*enable)(struct clk *clk);
@@ -72,7 +78,7 @@
void (*enable_hwcg)(struct clk *clk);
void (*disable_hwcg)(struct clk *clk);
int (*in_hwcg_mode)(struct clk *clk);
- int (*handoff)(struct clk *clk);
+ enum handoff (*handoff)(struct clk *clk);
int (*reset)(struct clk *clk, enum clk_reset_action action);
int (*set_rate)(struct clk *clk, unsigned long rate);
int (*set_max_rate)(struct clk *clk, unsigned long rate);
@@ -126,13 +132,15 @@
* struct clock_init_data - SoC specific clock initialization data
* @table: table of lookups to add
* @size: size of @table
- * @init: called before registering @table
+ * @pre_init: called before initializing the clock driver.
+ * @post_init: called after registering @table. clock APIs can be called inside.
* @late_init: called during late init
*/
struct clock_init_data {
struct clk_lookup *table;
size_t size;
- void (*init)(void);
+ void (*pre_init)(void);
+ void (*post_init)(void);
int (*late_init)(void);
};
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 3965413..7c2fca4 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -31,6 +31,7 @@
#include <mach/mdm2.h>
#include <mach/msm_smd.h>
#include <mach/msm_dcvs.h>
+#include <mach/qdss.h>
#include <linux/ion.h>
#include "clock.h"
#include "devices.h"
@@ -2210,3 +2211,42 @@
.num_resources = ARRAY_SIZE(msm_cache_erp_resources),
.resource = msm_cache_erp_resources,
};
+
+#define MSM_QDSS_PHYS_BASE 0x01A00000
+#define MSM_ETM_PHYS_BASE (MSM_QDSS_PHYS_BASE + 0x1C000)
+
+#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
+
+static struct qdss_source msm_qdss_sources[] = {
+ QDSS_SOURCE("msm_etm", 0x33),
+ QDSS_SOURCE("msm_oxili", 0x80),
+};
+
+static struct msm_qdss_platform_data qdss_pdata = {
+ .src_table = msm_qdss_sources,
+ .size = ARRAY_SIZE(msm_qdss_sources),
+ .afamily = 1,
+};
+
+struct platform_device apq8064_qdss_device = {
+ .name = "msm_qdss",
+ .id = -1,
+ .dev = {
+ .platform_data = &qdss_pdata,
+ },
+};
+
+static struct resource msm_etm_resources[] = {
+ {
+ .start = MSM_ETM_PHYS_BASE,
+ .end = MSM_ETM_PHYS_BASE + (SZ_4K * 4) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device apq8064_etm_device = {
+ .name = "msm_etm",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_etm_resources),
+ .resource = msm_etm_resources,
+};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c45a137..818deaf 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -31,9 +31,12 @@
#include <mach/msm_bus_board.h>
#include <mach/msm_memtypes.h>
#include <mach/msm_smd.h>
+#include <mach/msm_dcvs.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
+#include <mach/qdss.h>
+#include <mach/msm_serial_hs_lite.h>
#include "clock.h"
#include "devices.h"
#include "devices-msm8x60.h"
@@ -70,6 +73,7 @@
#define MSM_UART2DM_PHYS (MSM_GSBI2_PHYS + 0x40000)
#define MSM_UART5DM_PHYS (MSM_GSBI5_PHYS + 0x40000)
#define MSM_UART6DM_PHYS (MSM_GSBI6_PHYS + 0x40000)
+#define MSM_UART8DM_PHYS (MSM_GSBI8_PHYS + 0x40000)
/* GSBI QUP devices */
#define MSM_GSBI1_QUP_PHYS (MSM_GSBI1_PHYS + 0x80000)
@@ -306,6 +310,39 @@
.num_resources = ARRAY_SIZE(resources_uart_gsbi5),
.resource = resources_uart_gsbi5,
};
+
+static struct msm_serial_hslite_platform_data uart_gsbi8_pdata = {
+ .line = 0,
+};
+
+static struct resource resources_uart_gsbi8[] = {
+ {
+ .start = GSBI8_UARTDM_IRQ,
+ .end = GSBI8_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART8DM_PHYS,
+ .end = MSM_UART8DM_PHYS + PAGE_SIZE - 1,
+ .name = "uartdm_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_GSBI8_PHYS,
+ .end = MSM_GSBI8_PHYS + PAGE_SIZE - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8960_device_uart_gsbi8 = {
+ .name = "msm_serial_hsl",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(resources_uart_gsbi8),
+ .resource = resources_uart_gsbi8,
+ .dev.platform_data = &uart_gsbi8_pdata,
+};
+
/* MSM Video core device */
#ifdef CONFIG_MSM_BUS_SCALING
static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -953,6 +990,17 @@
.id = -1,
};
+struct platform_device msm_pil_dsps = {
+ .name = "pil_dsps",
+ .id = -1,
+ .dev.platform_data = "dsps",
+};
+
+struct platform_device msm_pil_vidc = {
+ .name = "pil_vidc",
+ .id = -1,
+};
+
static struct resource smd_resource[] = {
{
.name = "a9_m2a_0",
@@ -1101,7 +1149,6 @@
.smd_ssr_config = &smd_ssr_config,
};
-
struct platform_device msm_device_smd = {
.name = "msm_smd",
.id = -1,
@@ -1887,7 +1934,88 @@
};
unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
#ifdef CONFIG_MSM_ROTATOR
+static struct msm_bus_vectors rotator_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ROTATOR,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors rotator_ui_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ROTATOR,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = (1024 * 600 * 4 * 2 * 60),
+ .ib = (1024 * 600 * 4 * 2 * 60 * 1.5),
+ },
+};
+
+static struct msm_bus_vectors rotator_vga_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ROTATOR,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = (640 * 480 * 2 * 2 * 30),
+ .ib = (640 * 480 * 2 * 2 * 30 * 1.5),
+ },
+};
+static struct msm_bus_vectors rotator_720p_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ROTATOR,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = (1280 * 736 * 2 * 2 * 30),
+ .ib = (1280 * 736 * 2 * 2 * 30 * 1.5),
+ },
+};
+
+static struct msm_bus_vectors rotator_1080p_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ROTATOR,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = (1920 * 1088 * 2 * 2 * 30),
+ .ib = (1920 * 1088 * 2 * 2 * 30 * 1.5),
+ },
+};
+
+static struct msm_bus_paths rotator_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(rotator_init_vectors),
+ rotator_init_vectors,
+ },
+ {
+ ARRAY_SIZE(rotator_ui_vectors),
+ rotator_ui_vectors,
+ },
+ {
+ ARRAY_SIZE(rotator_vga_vectors),
+ rotator_vga_vectors,
+ },
+ {
+ ARRAY_SIZE(rotator_720p_vectors),
+ rotator_720p_vectors,
+ },
+ {
+ ARRAY_SIZE(rotator_1080p_vectors),
+ rotator_1080p_vectors,
+ },
+};
+
+struct msm_bus_scale_pdata rotator_bus_scale_pdata = {
+ rotator_bus_scale_usecases,
+ ARRAY_SIZE(rotator_bus_scale_usecases),
+ .name = "rotator",
+};
+
+void __init msm_rotator_update_bus_vectors(unsigned int xres,
+ unsigned int yres)
+{
+ rotator_ui_vectors[0].ab = xres * yres * 4 * 2 * 60;
+ rotator_ui_vectors[0].ib = xres * yres * 4 * 2 * 60 * 3 / 2;
+}
+
#define ROTATOR_HW_BASE 0x04E00000
static struct resource resources_msm_rotator[] = {
{
@@ -2397,6 +2525,49 @@
},
};
+static struct msm_dcvs_freq_entry grp3d_freq[] = {
+ {0, 0, 333932},
+ {0, 0, 497532},
+ {0, 0, 707610},
+ {0, 0, 844545},
+};
+
+static struct msm_dcvs_freq_entry grp2d_freq[] = {
+ {0, 0, 86000},
+ {0, 0, 200000},
+};
+
+static struct msm_dcvs_core_info grp3d_core_info = {
+ .freq_tbl = &grp3d_freq[0],
+ .core_param = {
+ .max_time_us = 100000,
+ .num_freq = ARRAY_SIZE(grp3d_freq),
+ },
+ .algo_param = {
+ .slack_time_us = 39000,
+ .disable_pc_threshold = 86000,
+ .ss_window_size = 1000000,
+ .ss_util_pct = 95,
+ .em_max_util_pct = 97,
+ .ss_iobusy_conv = 100,
+ },
+};
+
+static struct msm_dcvs_core_info grp2d_core_info = {
+ .freq_tbl = &grp2d_freq[0],
+ .core_param = {
+ .max_time_us = 100000,
+ .num_freq = ARRAY_SIZE(grp2d_freq),
+ },
+ .algo_param = {
+ .slack_time_us = 39000,
+ .disable_pc_threshold = 90000,
+ .ss_window_size = 1000000,
+ .ss_util_pct = 90,
+ .em_max_util_pct = 95,
+ },
+};
+
#ifdef CONFIG_MSM_BUS_SCALING
static struct msm_bus_vectors grp3d_init_vectors[] = {
{
@@ -2626,7 +2797,7 @@
},
},
.init_level = 0,
- .num_levels = 5,
+ .num_levels = ARRAY_SIZE(grp3d_freq) + 1,
.set_grp_async = NULL,
.idle_timeout = HZ/20,
.nap_allowed = true,
@@ -2636,6 +2807,7 @@
#endif
.iommu_data = kgsl_3d0_iommu_data,
.iommu_count = ARRAY_SIZE(kgsl_3d0_iommu_data),
+ .core_info = &grp3d_core_info,
};
struct platform_device msm_kgsl_3d0 = {
@@ -2692,7 +2864,7 @@
},
},
.init_level = 0,
- .num_levels = 3,
+ .num_levels = ARRAY_SIZE(grp2d_freq) + 1,
.set_grp_async = NULL,
.idle_timeout = HZ/5,
.nap_allowed = true,
@@ -2702,6 +2874,7 @@
#endif
.iommu_data = kgsl_2d0_iommu_data,
.iommu_count = ARRAY_SIZE(kgsl_2d0_iommu_data),
+ .core_info = &grp2d_core_info,
};
struct platform_device msm_kgsl_2d0 = {
@@ -2758,7 +2931,7 @@
},
},
.init_level = 0,
- .num_levels = 3,
+ .num_levels = ARRAY_SIZE(grp2d_freq) + 1,
.set_grp_async = NULL,
.idle_timeout = HZ/5,
.nap_allowed = true,
@@ -2768,6 +2941,7 @@
#endif
.iommu_data = kgsl_2d1_iommu_data,
.iommu_count = ARRAY_SIZE(kgsl_2d1_iommu_data),
+ .core_info = &grp2d_core_info,
};
struct platform_device msm_kgsl_2d1 = {
@@ -3162,6 +3336,26 @@
#define MSM_FUNNEL_PHYS_BASE (MSM_QDSS_PHYS_BASE + 0x4000)
#define MSM_ETM_PHYS_BASE (MSM_QDSS_PHYS_BASE + 0x1C000)
+#define QDSS_SOURCE(src_name, fpm) { .name = src_name, .fport_mask = fpm, }
+
+static struct qdss_source msm_qdss_sources[] = {
+ QDSS_SOURCE("msm_etm", 0x3),
+};
+
+static struct msm_qdss_platform_data qdss_pdata = {
+ .src_table = msm_qdss_sources,
+ .size = ARRAY_SIZE(msm_qdss_sources),
+ .afamily = 1,
+};
+
+struct platform_device msm_qdss_device = {
+ .name = "msm_qdss",
+ .id = -1,
+ .dev = {
+ .platform_data = &qdss_pdata,
+ },
+};
+
static struct resource msm_etb_resources[] = {
{
.start = MSM_ETB_PHYS_BASE,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index bb0d9b9..f7306d2 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -64,7 +64,8 @@
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
- .has_secure = true,
+ .has_secure = false,
+ .use_kernel_fiq = true,
};
struct platform_device msm9615_device_watchdog = {
@@ -428,7 +429,7 @@
* Machine specific data for AUX PCM Interface
* which the driver will be unware of.
*/
-struct msm_dai_auxpcm_pdata auxpcm_rx_pdata = {
+struct msm_dai_auxpcm_pdata auxpcm_pdata = {
.clk = "pcm_clk",
.mode = AFE_PCM_CFG_MODE_PCM,
.sync = AFE_PCM_CFG_SYNC_INT,
@@ -443,13 +444,16 @@
.name = "msm-dai-q6",
.id = 2,
.dev = {
- .platform_data = &auxpcm_rx_pdata,
+ .platform_data = &auxpcm_pdata,
},
};
struct platform_device msm_cpudai_auxpcm_tx = {
.name = "msm-dai-q6",
.id = 3,
+ .dev = {
+ .platform_data = &auxpcm_pdata,
+ },
};
struct platform_device msm_cpu_fe = {
@@ -846,6 +850,30 @@
return platform_device_register(pdev);
}
+#ifdef CONFIG_FB_MSM_EBI2
+static struct resource msm_ebi2_lcdc_resources[] = {
+ {
+ .name = "base",
+ .start = 0x1B300000,
+ .end = 0x1B300000 + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "lcd01",
+ .start = 0x1FC00000,
+ .end = 0x1FC00000 + 0x80000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm_ebi2_lcdc_device = {
+ .name = "ebi2_lcd",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_ebi2_lcdc_resources),
+ .resource = msm_ebi2_lcdc_resources,
+};
+#endif
+
#ifdef CONFIG_CACHE_L2X0
static int __init l2x0_cache_init(void)
{
@@ -1269,3 +1297,26 @@
.name = "msm_bus_fabric",
.id = MSM_BUS_FAB_DEFAULT,
};
+
+#ifdef CONFIG_FB_MSM_EBI2
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+ int ret;
+
+ pdev->dev.platform_data = data;
+
+ ret = platform_device_register(pdev);
+ if (ret)
+ dev_err(&pdev->dev,
+ "%s: platform_device_register() failed = %d\n",
+ __func__, ret);
+}
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+ if (!strncmp(name, "ebi2", 4))
+ msm_register_device(&msm_ebi2_lcdc_device, data);
+ else
+ pr_err("%s: unknown device! %s\n", __func__, name);
+}
+#endif
diff --git a/arch/arm/mach-msm/devices-fsm9xxx.c b/arch/arm/mach-msm/devices-fsm9xxx.c
index d46e4d6..777b6d6 100644
--- a/arch/arm/mach-msm/devices-fsm9xxx.c
+++ b/arch/arm/mach-msm/devices-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,7 @@
#include "devices.h"
#include "smd_private.h"
#include "clock-local.h"
+#include "msm_watchdog.h"
#include <asm/mach/flash.h>
#include <asm/mach/mmc.h>
@@ -389,3 +390,22 @@
.id = -1,
};
+/*
+ * Watchdog
+ */
+
+static struct msm_watchdog_pdata fsm_watchdog_pdata = {
+ .pet_time = 10000,
+ .bark_time = 11000,
+ .has_secure = false,
+ .has_vic = true,
+};
+
+struct platform_device fsm9xxx_device_watchdog = {
+ .name = "msm_watchdog",
+ .id = -1,
+ .dev = {
+ .platform_data = &fsm_watchdog_pdata,
+ },
+};
+
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 96ee564..29e8180 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -364,11 +364,13 @@
static struct msm_iommu_dev gfx3d_iommu = {
.name = "gfx3d",
.ncb = 3,
+ .ttbr_split = 2,
};
static struct msm_iommu_dev gfx3d1_iommu = {
.name = "gfx3d1",
.ncb = 3,
+ .ttbr_split = 2,
};
static struct msm_iommu_dev gfx2d0_iommu = {
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 3008fe9..5ec339e 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -854,7 +854,8 @@
.init_level = 0,
.num_levels = 1,
.set_grp_async = NULL,
- .idle_timeout = HZ/5,
+ .idle_timeout = HZ,
+ .strtstp_sleepwake = true,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
};
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 8236e1e..70f1c2c 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -808,7 +808,8 @@
.init_level = 0,
.num_levels = 3,
.set_grp_async = set_grp_xbar_async,
- .idle_timeout = HZ/5,
+ .idle_timeout = HZ,
+ .strtstp_sleepwake = true,
.nap_allowed = false,
.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM,
};
@@ -834,6 +835,14 @@
}
}
+void __init msm8x25_kgsl_3d0_init(void)
+{
+ if (cpu_is_msm8625()) {
+ kgsl_3d0_pdata.idle_timeout = HZ/5;
+ kgsl_3d0_pdata.strtstp_sleepwake = false;
+ }
+}
+
static void __init msm_register_device(struct platform_device *pdev, void *data)
{
int ret;
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 3c81ccf..407554c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -31,4 +31,5 @@
void __init msm8625_map_io(void);
int ar600x_wlan_power(bool on);
void __init msm8x25_spm_device_init(void);
+void __init msm8x25_kgsl_3d0_init(void);
#endif
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index ae90301..84ba9fe 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -220,6 +220,12 @@
.id = -1,
};
+struct platform_device msm_pil_dsps = {
+ .name = "pil_dsps",
+ .id = -1,
+ .dev.platform_data = "dsps",
+};
+
static struct resource msm_uart1_dm_resources[] = {
{
.start = MSM_UART1DM_PHYS,
@@ -325,6 +331,7 @@
.config_gpio = 1,
.uart_tx_gpio = 67,
.uart_rx_gpio = 66,
+ .line = 1,
};
static struct resource msm_uart_gsbi9_resources[] = {
@@ -1371,6 +1378,98 @@
return platform_device_register(pdev);
}
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm_csic0_resources[] = {
+ {
+ .name = "csic",
+ .start = 0x04800000,
+ .end = 0x04800000 + 0x00000400 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "csic",
+ .start = CSI_0_IRQ,
+ .end = CSI_0_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource msm_csic1_resources[] = {
+ {
+ .name = "csic",
+ .start = 0x04900000,
+ .end = 0x04900000 + 0x00000400 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "csic",
+ .start = CSI_1_IRQ,
+ .end = CSI_1_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct resource msm_vfe_resources[] = {
+ {
+ .name = "msm_vfe",
+ .start = 0x04500000,
+ .end = 0x04500000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "msm_vfe",
+ .start = VFE_IRQ,
+ .end = VFE_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource msm_vpe_resources[] = {
+ {
+ .name = "vpe",
+ .start = 0x05300000,
+ .end = 0x05300000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "vpe",
+ .start = INT_VPE,
+ .end = INT_VPE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_device_csic0 = {
+ .name = "msm_csic",
+ .id = 0,
+ .resource = msm_csic0_resources,
+ .num_resources = ARRAY_SIZE(msm_csic0_resources),
+};
+
+struct platform_device msm_device_csic1 = {
+ .name = "msm_csic",
+ .id = 1,
+ .resource = msm_csic1_resources,
+ .num_resources = ARRAY_SIZE(msm_csic1_resources),
+};
+
+struct platform_device msm_device_vfe = {
+ .name = "msm_vfe",
+ .id = 0,
+ .resource = msm_vfe_resources,
+ .num_resources = ARRAY_SIZE(msm_vfe_resources),
+};
+
+struct platform_device msm_device_vpe = {
+ .name = "msm_vpe",
+ .id = 0,
+ .resource = msm_vpe_resources,
+ .num_resources = ARRAY_SIZE(msm_vpe_resources),
+};
+
+#endif
+
+
#define MIPI_DSI_HW_BASE 0x04700000
#define ROTATOR_HW_BASE 0x04E00000
#define TVENC_HW_BASE 0x04F00000
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 1c5f397..624debd 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -25,6 +25,8 @@
void __init msm9615_map_io(void);
void __init msm_map_msm9615_io(void);
void __init msm9615_init_irq(void);
+void __init msm_rotator_update_bus_vectors(unsigned int xres,
+ unsigned int yres);
extern struct platform_device asoc_msm_pcm;
extern struct platform_device asoc_msm_dai0;
@@ -53,6 +55,7 @@
extern struct platform_device msm8960_device_uart_gsbi2;
extern struct platform_device msm8960_device_uart_gsbi5;
+extern struct platform_device msm8960_device_uart_gsbi8;
extern struct platform_device msm8960_device_ssbi_pmic;
extern struct platform_device msm8960_device_qup_i2c_gsbi3;
extern struct platform_device msm8960_device_qup_i2c_gsbi4;
@@ -217,6 +220,8 @@
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
extern struct platform_device msm_pil_tzapps;
+extern struct platform_device msm_pil_dsps;
+extern struct platform_device msm_pil_vidc;
extern struct platform_device msm_8960_q6_lpass;
extern struct platform_device msm_8960_q6_mss_fw;
extern struct platform_device msm_8960_q6_mss_sw;
@@ -266,6 +271,7 @@
extern struct platform_device msm_mipi_dsi1_device;
extern struct platform_device msm_lvds_device;
+extern struct platform_device msm_ebi2_lcdc_device;
extern struct clk_lookup msm_clocks_fsm9xxx[];
extern unsigned msm_num_clocks_fsm9xxx;
@@ -315,11 +321,15 @@
extern struct platform_device msm8660_device_watchdog;
extern struct platform_device msm8064_device_watchdog;
extern struct platform_device msm9615_device_watchdog;
+extern struct platform_device fsm9xxx_device_watchdog;
+extern struct platform_device apq8064_qdss_device;
+extern struct platform_device msm_qdss_device;
extern struct platform_device msm_etb_device;
extern struct platform_device msm_tpiu_device;
extern struct platform_device msm_funnel_device;
extern struct platform_device msm_etm_device;
+extern struct platform_device apq8064_etm_device;
#endif
extern struct platform_device msm_bus_8064_apps_fabric;
@@ -346,3 +356,9 @@
extern struct platform_device msm_bus_8930_mm_fabric;
extern struct platform_device msm_bus_8930_sys_fpb;
extern struct platform_device msm_bus_8930_cpss_fpb;
+
+extern struct platform_device msm_device_csic0;
+extern struct platform_device msm_device_csic1;
+extern struct platform_device msm_device_vfe;
+extern struct platform_device msm_device_vpe;
+
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 4609a4b..d5a1d3f 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -653,7 +653,8 @@
regval &= ~RETENTION_BIT;
writel_relaxed(regval, fs->gfs_ctl_reg);
- fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
+ fs->rdev = regulator_register(&fs->desc, &pdev->dev,
+ init_data, fs, NULL);
if (IS_ERR(footswitches[pdev->id].rdev)) {
pr_err("regulator_register(\"%s\") failed\n",
fs->desc.name);
diff --git a/arch/arm/mach-msm/footswitch-pcom.c b/arch/arm/mach-msm/footswitch-pcom.c
index 673253b..73cbab1 100644
--- a/arch/arm/mach-msm/footswitch-pcom.c
+++ b/arch/arm/mach-msm/footswitch-pcom.c
@@ -266,7 +266,8 @@
if (rc)
return rc;
- fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
+ fs->rdev = regulator_register(&fs->desc, &pdev->dev,
+ init_data, fs, NULL);
if (IS_ERR(fs->rdev)) {
pr_err("regulator_register(%s) failed\n", fs->desc.name);
rc = PTR_ERR(fs->rdev);
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index 1ddb7a3..3c475d6 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -113,7 +113,7 @@
/* FIXME: Get address, size from PIL */
static struct ramdump_segment gss_segments[] = {
- {0x89D00000 - 0x89000000}
+ {0x89000000, 0x00D00000}
};
static struct ramdump_segment smem_segments[] = {
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 32d162d..0028286 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -19,18 +19,31 @@
#include <linux/threads.h>
#include <asm/assembler.h>
-#ifdef CONFIG_MSM_CPU_AVS
-/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
-#else
-/* 11 general purpose registers (r4-r14), 10 cp15 registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
-#endif
+#include "idle.h"
+
#ifdef CONFIG_ARCH_MSM_KRAIT
#define SCM_SVC_BOOT 0x1
#define SCM_CMD_TERMINATE_PC 0x2
#endif
+/* Switch between smp_to_amp/amp_to_smp configuration */
+.macro SET_SMP_COHERENCY, on = 0
+ldr r0, =target_type
+ldr r0, [r0]
+mov r1, #TARGET_IS_8625
+cmp r0, r1
+bne skip\@
+mrc p15, 0, r0, c1, c0, 1 /* read ACTLR register */
+.if \on
+orr r0, r0, #(1 << 6) /* Set the SMP bit in ACTLR */
+.else
+bic r0, r0, #(1 << 6) /* Clear the SMP bit */
+.endif
+mcr p15, 0, r0, c1, c0, 1 /* write ACTLR register */
+isb
+skip\@:
+.endm
+
ENTRY(msm_arch_idle)
wfi
#ifdef CONFIG_ARCH_MSM8X60
@@ -45,7 +58,8 @@
cpsid f
#endif
- ldr r0, =saved_state
+ ldr r0, =msm_saved_state /* address of msm_saved_state ptr */
+ ldr r0, [r0] /* load ptr */
#if (NR_CPUS >= 2)
mrc p15, 0, r1, c0, c0, 5 /* MPIDR */
ands r1, r1, #15 /* What CPU am I */
@@ -100,14 +114,7 @@
cmp r1, #1
bne skip
bl v7_flush_dcache_all
- b skip2
-
-skip: ldr r0, =saved_state
- ldr r1, =saved_state_end
- sub r1, r1, r0
- bl v7_flush_kern_dcache_area
-
-skip2:
+skip:
#ifdef CONFIG_ARCH_MSM_KRAIT
ldr r0, =SCM_SVC_BOOT
ldr r1, =SCM_CMD_TERMINATE_PC
@@ -121,20 +128,21 @@
mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
dsb
+ SET_SMP_COHERENCY OFF
wfi
mcr p15, 0, r4, c1, c0, 0 /* restore d/i cache */
isb
#endif
-
-
+ SET_SMP_COHERENCY ON
#if defined(CONFIG_MSM_FIQ_SUPPORT)
cpsie f
#endif
#ifdef CONFIG_MSM_JTAG
bl msm_jtag_restore_state
#endif
- ldr r0, =saved_state /* restore registers */
+ ldr r0, =msm_saved_state /* address of msm_saved_state ptr */
+ ldr r0, [r0] /* load ptr */
#if (NR_CPUS >= 2)
mrc p15, 0, r1, c0, c0, 5 /* MPIDR */
ands r1, r1, #15 /* What CPU am I */
@@ -142,8 +150,7 @@
mul r2, r2, r1
add r0, r0, r2
#endif
-
- ldmfd r0, {r4-r14}
+ ldmfd r0, {r4-r14} /* restore registers */
mov r0, #0 /* return power collapse failed */
bx lr
@@ -157,11 +164,12 @@
mov r1, #'A'
str r1, [r0, #0x00C]
#endif
- ldr r1, =saved_state
+ ldr r1, =msm_saved_state_phys
ldr r2, =msm_pm_collapse_exit
adr r3, msm_pm_collapse_exit
add r1, r1, r3
sub r1, r1, r2
+ ldr r1, [r1]
add r1, r1, #CPU_SAVED_STATE_SIZE
#if (NR_CPUS >= 2)
mrc p15, 0, r2, c0, c0, 5 /* MPIDR */
@@ -218,6 +226,8 @@
mcr p15, 0, r3, c7, c5, 6 /* BPIALL */
dsb
isb
+
+ SET_SMP_COHERENCY ON
#ifdef CONFIG_ARCH_MSM_KRAIT
mrc p15, 0, r1, c0, c0, 0
ldr r3, =0xff00fc00
@@ -228,12 +238,11 @@
biceq r3, r3, #0x400
mcreq p15, 7, r3, c15, c0, 2
#endif
- stmfd sp!, {lr}
- bl v7_flush_kern_cache_all
#ifdef CONFIG_MSM_JTAG
+ stmfd sp!, {lr}
bl msm_jtag_restore_state
-#endif
ldmfd sp!, {lr}
+#endif
mov r0, #1
bx lr
nop
@@ -256,17 +265,6 @@
add r1, r1, r0, LSL #2 /* locate boot vector for our cpu */
ldr pc, [r1] /* jump */
-ENTRY(msm_pm_write_boot_vector)
- ldr r2, =msm_pm_boot_vector
- add r2, r2, r0, LSL #2 /* locate boot vector for our cpu */
- str r1, [r2]
- mov r0, r2
- ldr r1, =4
- stmfd sp!, {lr}
- bl v7_flush_kern_dcache_area
- ldmfd sp!, {lr}
- bx lr
-
ENTRY(msm_pm_set_l2_flush_flag)
ldr r1, =msm_pm_flush_l2_flag
str r0, [r1]
@@ -278,13 +276,22 @@
msm_pm_pc_pgd:
.long 0x0
-saved_state:
- .space CPU_SAVED_STATE_SIZE * NR_CPUS
-saved_state_end:
+ .globl msm_saved_state
+msm_saved_state:
+ .long 0x0
+ .globl msm_saved_state_phys
+msm_saved_state_phys:
+ .long 0x0
+
+ .globl msm_pm_boot_vector
msm_pm_boot_vector:
.space 4 * NR_CPUS
+ .globl target_type
+target_type:
+ .long 0x0
+
/*
* Default the l2 flush flag to 1 so that caches are flushed during power
* collapse unless the L2 driver decides to flush them only during L2
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 6311b3c..bfd632f 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -14,15 +14,32 @@
#ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
#define _ARCH_ARM_MACH_MSM_IDLE_H_
+#ifdef CONFIG_MSM_CPU_AVS
+/* 11 general purpose registers (r4-r14), 10 cp15 registers, 3 AVS registers */
+#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10 + 4 * 3)
+#else
+/* 11 general purpose registers (r4-r14), 10 cp15 registers */
+#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
+#endif
+
+#define ON 1
+#define OFF 0
+#define TARGET_IS_8625 1
+
+#ifndef __ASSEMBLY__
+
int msm_arch_idle(void);
int msm_pm_collapse(void);
void msm_pm_collapse_exit(void);
+extern void *msm_saved_state;
+extern unsigned long msm_saved_state_phys;
#ifdef CONFIG_CPU_V7
void msm_pm_boot_entry(void);
-void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address);
void msm_pm_set_l2_flush_flag(unsigned int flag);
extern unsigned long msm_pm_pc_pgd;
+extern unsigned long msm_pm_boot_vector[NR_CPUS];
+extern uint32_t target_type;
#else
static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
{
@@ -38,5 +55,5 @@
/* empty */
}
#endif
-
+#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/board-msm8660.h b/arch/arm/mach-msm/include/mach/board-msm8660.h
index b07cc62..22e378c 100644
--- a/arch/arm/mach-msm/include/mach/board-msm8660.h
+++ b/arch/arm/mach-msm/include/mach/board-msm8660.h
@@ -33,4 +33,9 @@
#define PM8901_IRQ_BASE (PM8058_IRQ_BASE + \
NR_PMIC8058_IRQS)
+#ifdef CONFIG_MSM_CAMERA_V4L2
+extern struct msm_camera_board_info msm8x60_camera_board_info;
+void msm8x60_init_cam(void);
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index ae4d632..f01b0f7 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -99,6 +99,7 @@
#define MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER (0x00000001<<2)
#define MSM_CAMERA_FLASH_SRC_EXT (0x00000001<<3)
#define MSM_CAMERA_FLASH_SRC_LED (0x00000001<<3)
+#define MSM_CAMERA_FLASH_SRC_LED1 (0x00000001<<4)
struct msm_camera_sensor_flash_pmic {
uint8_t num_of_src;
@@ -172,6 +173,11 @@
BACK_CAMERA_INT_3D,
};
+enum msm_sensor_type {
+ BAYER_SENSOR,
+ YUV_SENSOR,
+};
+
enum camera_vreg_type {
REG_LDO,
REG_VS,
@@ -261,6 +267,7 @@
struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
char *eeprom_data;
enum msm_camera_type camera_type;
+ enum msm_sensor_type sensor_type;
struct msm_actuator_info *actuator_info;
int pmic_gpio_enable;
};
@@ -351,6 +358,7 @@
struct msm_panel_common_pdata {
uintptr_t hw_revision_addr;
int gpio;
+ bool bl_lock;
int (*backlight_level)(int level, int max, int min);
int (*pmic_backlight)(int level);
int (*panel_num)(void);
@@ -425,6 +433,7 @@
struct mipi_dsi_phy_ctrl *phy_ctrl_settings;
char dlane_swap;
void (*dsi_pwm_cfg)(void);
+ char enable_wled_bl_ctrl;
};
struct lvds_panel_platform_data {
@@ -493,6 +502,7 @@
#endif
void msm_add_devices(void);
void msm_copper_add_devices(void);
+void msm_copper_add_drivers(void);
void msm_map_common_io(void);
void msm_map_qsd8x50_io(void);
void msm_map_msm8x60_io(void);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 2aae5dd..5ee9e1a 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -200,12 +200,14 @@
struct msm_camera_csiphy_params csiphy_params;
};
+#ifndef CONFIG_MSM_CAMERA_V4L2
#define VFE31_OUTPUT_MODE_PT (0x1 << 0)
#define VFE31_OUTPUT_MODE_S (0x1 << 1)
#define VFE31_OUTPUT_MODE_V (0x1 << 2)
#define VFE31_OUTPUT_MODE_P (0x1 << 3)
#define VFE31_OUTPUT_MODE_T (0x1 << 4)
#define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5)
+#endif
#define CSI_EMBED_DATA 0x12
#define CSI_YUV422_8 0x1E
@@ -493,8 +495,6 @@
unsigned long len;
struct file *file;
struct msm_pmem_info info;
- struct msm_mapped_buffer *msm_buffer;
- int subsys_id;
struct ion_handle *handle;
};
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index d5a2ed4..994150f 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -41,6 +41,7 @@
struct msm_iommu_dev {
const char *name;
int ncb;
+ int ttbr_split;
};
/**
@@ -74,6 +75,7 @@
void __iomem *base;
int irq;
int ncb;
+ int ttbr_split;
struct clk *clk;
struct clk *pclk;
const char *name;
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index af9213f..c17795a 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -15,9 +15,9 @@
enum {
VIDEO_DOMAIN,
- CAMERA_DOMAIN = VIDEO_DOMAIN,
- DISPLAY_DOMAIN = CAMERA_DOMAIN,
- ROTATOR_DOMAIN = DISPLAY_DOMAIN,
+ CAMERA_DOMAIN,
+ DISPLAY_DOMAIN,
+ ROTATOR_DOMAIN,
MAX_DOMAINS
};
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
index 57f2d37..af82fd9 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
@@ -57,8 +57,9 @@
#define FL_TYPE_TABLE (1 << 0)
#define FL_TYPE_SECT (2 << 0)
#define FL_SUPERSECTION (1 << 18)
-#define FL_AP_WRITE (1 << 10)
-#define FL_AP_READ (1 << 11)
+#define FL_AP0 (1 << 10)
+#define FL_AP1 (1 << 11)
+#define FL_AP2 (1 << 15)
#define FL_SHARED (1 << 16)
#define FL_BUFFERABLE (1 << 2)
#define FL_CACHEABLE (1 << 3)
@@ -73,6 +74,7 @@
#define SL_TYPE_SMALL (2 << 0)
#define SL_AP0 (1 << 4)
#define SL_AP1 (2 << 4)
+#define SL_AP2 (1 << 9)
#define SL_SHARED (1 << 10)
#define SL_BUFFERABLE (1 << 2)
#define SL_CACHEABLE (1 << 3)
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index 6252cef..39058a6 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.h
@@ -21,6 +21,7 @@
* 32+: SPI (shared peripheral interrupts)
*/
+#define FIQ_START 16
#define GIC_PPI_START 16
#define GIC_SPI_START 32
diff --git a/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h b/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
index a0ec244..721db1d 100644
--- a/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
+++ b/arch/arm/mach-msm/include/mach/irqs-fsm9xxx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -86,6 +86,7 @@
#define INT_ADSP_A11 INT_Q6_SW_IRQ_0
#define INT_ADSP_A11_SMSM INT_ADSP_A11
#define INT_SIRC_0 INT_PERPH_SUPSS_IRQ
+#define WDT0_ACCSCSSNBARK_INT INT_WDT0_ACCSCSSBARK
#define NR_MSM_IRQS 128
#define NR_GPIO_IRQS 0
diff --git a/arch/arm/mach-msm/include/mach/msm_cache_dump.h b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
new file mode 100644
index 0000000..6e4f628
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_cache_dump.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MACH_MSM_CACHE_DUMP_
+#define _MACH_MSM_CACHE_DUMP_
+
+#include <asm-generic/sizes.h>
+
+
+struct l2_cache_line_dump {
+ unsigned int l2dcrtr0_val;
+ unsigned int l2dcrtr1_val;
+ unsigned int cache_line_data[32];
+ unsigned int ddr_data[32];
+} __packed;
+
+struct l2_cache_dump {
+ unsigned int magic_number;
+ unsigned int version;
+ unsigned int tag_size;
+ unsigned int line_size;
+ unsigned int total_lines;
+ struct l2_cache_line_dump cache[8*1024];
+ unsigned int l2esr;
+} __packed;
+
+
+struct l1_cache_dump {
+ unsigned int magic;
+ unsigned int version;
+ unsigned int flags;
+ unsigned int cpu_count;
+ unsigned int i_tag_size;
+ unsigned int i_line_size;
+ unsigned int i_num_sets;
+ unsigned int i_num_ways;
+ unsigned int d_tag_size;
+ unsigned int d_line_size;
+ unsigned int d_num_sets;
+ unsigned int d_num_ways;
+ unsigned int spare[32];
+ unsigned int lines[];
+} __packed;
+
+
+struct msm_cache_dump_platform_data {
+ unsigned int l1_size;
+ unsigned int l2_size;
+};
+
+#define L1_BUFFER_SIZE SZ_1M
+#define L2_BUFFER_SIZE SZ_4M
+
+#define CACHE_BUFFER_DUMP_SIZE (L1_BUFFER_SIZE + L2_BUFFER_SIZE)
+
+#define L1C_SERVICE_ID 3
+#define L1C_BUFFER_SET_COMMAND_ID 4
+#define CACHE_BUFFER_DUMP_COMMAND_ID 5
+#define L1C_BUFFER_GET_SIZE_COMMAND_ID 6
+#define L2C_BUFFER_SET_COMMAND_ID 7
+#define L2C_BUFFER_GET_SIZE_COMMAND_ID 8
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h
index 339fa46..3bbaa25 100644
--- a/arch/arm/mach-msm/include/mach/msm_fb.h
+++ b/arch/arm/mach-msm/include/mach/msm_fb.h
@@ -188,5 +188,11 @@
};
+struct mdp_v4l2_req;
+int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par);
+int msm_fb_v4l2_update(void *par,
+ unsigned long srcp0_addr, unsigned long srcp0_size,
+ unsigned long srcp1_addr, unsigned long srcp1_size,
+ unsigned long srcp2_addr, unsigned long srcp2_size);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8f5d673..34af610 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -51,6 +51,8 @@
#define MSM_DEBUG_UART_PHYS CONFIG_MSM_DEBUG_UART_PHYS
#endif
+#define MSM8625_WARM_BOOT_PHYS 0x0FD00000
+
#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
defined(CONFIG_ARCH_MSM8930) || defined(CONFIG_ARCH_MSM9615) || \
diff --git a/arch/arm/mach-msm/include/mach/msm_rtb.h b/arch/arm/mach-msm/include/mach/msm_rtb.h
index 5eea63f..74ddfbd 100644
--- a/arch/arm/mach-msm/include/mach/msm_rtb.h
+++ b/arch/arm/mach-msm/include/mach/msm_rtb.h
@@ -15,7 +15,7 @@
/*
* These numbers are used from the kernel command line and sysfs
- * to control filtering. Remove items from here with extreme caution
+ * to control filtering. Remove items from here with extreme caution.
*/
enum logk_event_type {
LOGK_NONE = 0,
@@ -24,9 +24,11 @@
LOGK_LOGBUF = 3,
LOGK_HOTPLUG = 4,
LOGK_CTXID = 5,
- LOGK_OTHER = 31,
+ LOGK_TIMESTAMP = 6,
};
+#define LOGTYPE_NOPC 0x80
+
struct msm_rtb_platform_data {
unsigned int size;
};
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
index e2bdaea..577a097 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_hs_lite.h
@@ -18,6 +18,7 @@
unsigned config_gpio;
unsigned uart_tx_gpio;
unsigned uart_rx_gpio;
+ int line;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 772c9f6..5c3307e 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -100,6 +100,21 @@
void *smem_get_entry(unsigned id, unsigned *size);
int smsm_change_state(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask);
+
+/*
+ * Changes the global interrupt mask. The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry SMSM entry to change
+ * @clear_mask 1 = clear bit, 0 = no-op
+ * @set_mask 1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
int smsm_change_intr_mask(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask);
int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index dd5ddd8..bd303b2 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -135,6 +135,8 @@
uint16_t event_types;
/* Input event source */
enum us_input_event_src_type event_src;
+ /* Bitmap of types of events from devs, conflicting with USF */
+ uint16_t conflicting_event_types;
};
struct us_tx_info_type {
@@ -208,6 +210,8 @@
/* Time (sec) to wait for data or special values: */
/* USF_NO_WAIT_TIMEOUT, USF_INFINITIVE_TIMEOUT, USF_DEFAULT_TIMEOUT */
uint32_t timeout;
+/* Events (from conflicting devs) to be disabled/enabled */
+ uint16_t event_filters;
/* Input transparent data: */
/* Parameters size */
diff --git a/arch/arm/mach-msm/include/mach/qdss.h b/arch/arm/mach-msm/include/mach/qdss.h
index 530bcb2..3b236b8 100644
--- a/arch/arm/mach-msm/include/mach/qdss.h
+++ b/arch/arm/mach-msm/include/mach/qdss.h
@@ -13,10 +13,30 @@
#ifndef __MACH_QDSS_H
#define __MACH_QDSS_H
+struct qdss_source {
+ struct list_head link;
+ const char *name;
+ uint32_t fport_mask;
+};
+
+struct msm_qdss_platform_data {
+ struct qdss_source *src_table;
+ size_t size;
+ uint8_t afamily;
+};
+
#ifdef CONFIG_MSM_QDSS
+extern struct qdss_source *qdss_get(const char *name);
+extern void qdss_put(struct qdss_source *src);
+extern int qdss_enable(struct qdss_source *src);
+extern void qdss_disable(struct qdss_source *src);
extern int qdss_clk_enable(void);
extern void qdss_clk_disable(void);
#else
+static inline struct qdss_source *qdss_get(const char *name) { return NULL; }
+static inline void qdss_put(struct qdss_source *src) {}
+static inline int qdss_enable(struct qdss_source *src) { return -ENOSYS; }
+static inline void qdss_disable(struct qdss_source *src) {}
static inline int qdss_clk_enable(void) { return -ENOSYS; }
static inline void qdss_clk_disable(void) {}
#endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 99bf212..aee562e 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -44,6 +44,8 @@
#define machine_is_copper_sim() 0
#endif
+#define PLATFORM_SUBTYPE_SGLTE 6
+
enum msm_cpu {
MSM_CPU_UNKNOWN = 0,
MSM_CPU_7X01,
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 34729b3..7eaf526 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -51,7 +51,12 @@
#define SPS_IOVEC_FLAG_INT 0x8000 /* Generate interrupt */
#define SPS_IOVEC_FLAG_EOT 0x4000 /* Generate end-of-transfer indication */
#define SPS_IOVEC_FLAG_EOB 0x2000 /* Generate end-of-block indication */
-#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0100 /* Do not submit descriptor to HW */
+#define SPS_IOVEC_FLAG_NWD 0x1000 /* notify when done */
+#define SPS_IOVEC_FLAG_CMD 0x0800 /* command descriptor */
+#define SPS_IOVEC_FLAG_LOCK 0x0400 /* pipe lock */
+#define SPS_IOVEC_FLAG_UNLOCK 0x0200 /* pipe unlock */
+#define SPS_IOVEC_FLAG_IMME 0x0100 /* immediate command descriptor */
+#define SPS_IOVEC_FLAG_NO_SUBMIT 0x0002 /* Do not submit descriptor to HW */
#define SPS_IOVEC_FLAG_DEFAULT 0x0001 /* Use driver default */
/* BAM device options flags */
@@ -127,6 +132,8 @@
SPS_O_STREAMING = 0x00010000, /* Enable streaming mode (no EOT) */
/* Use MTI/SETPEND instead of BAM interrupt */
SPS_O_IRQ_MTI = 0x00020000,
+ /* NWD bit written with EOT for BAM2BAM producer pipe */
+ SPS_O_WRITE_NWD = 0x00040000,
/* Options to enable software features */
/* Transfer operation should be polled */
@@ -233,6 +240,14 @@
/* SPS_TIMER_MODE_PERIODIC, Not supported by hardware yet */
};
+/*
+ * This enum indicates the command type in a command element
+ */
+enum sps_command_type {
+ SPS_WRITE_COMMAND = 0,
+ SPS_READ_COMMAND,
+};
+
/**
* This data type corresponds to the native I/O vector (BAM descriptor)
* supported by SPS hardware
@@ -248,6 +263,26 @@
u32 flags:16;
};
+/**
+ * This data type corresponds to the native Command Element
+ * supported by SPS hardware
+ *
+ * @addr - register address.
+ * @command - command type.
+ * @data - for write command: content to be written into peripheral register.
+ * for read command: dest addr to write peripheral register value to.
+ * @mask - register mask.
+ * @reserved - for future usage.
+ *
+ */
+struct sps_command_element {
+ u32 addr:24;
+ u32 command:8;
+ u32 data;
+ u32 mask;
+ u32 reserved;
+};
+
/*
* BAM device's security configuation
*/
@@ -398,6 +433,7 @@
* @data - Data FIFO (BAM-to-BAM mode only).
*
* @event_thresh - Pipe event threshold or derivative.
+ * @lock_group - The lock group this pipe belongs to.
*
* @sps_reserved - Reserved word - client must not modify.
*
@@ -419,6 +455,8 @@
u32 event_thresh;
+ u32 lock_group;
+
/* SETPEND/MTI interrupt generation parameters */
u32 irq_gen_addr;
@@ -1167,4 +1205,17 @@
int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
u32 addr, u32 size, int use_offset);
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ * @h - client context for SPS connection end point
+ *
+ * @desc_num - number of unused descriptors
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num);
+
#endif /* _SPS_H_ */
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index a310ba0..19e1684 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -176,7 +176,8 @@
}
static void __program_context(void __iomem *base, int ctx, int ncb,
- phys_addr_t pgtable, int redirect)
+ phys_addr_t pgtable, int redirect,
+ int ttbr_split)
{
unsigned int prrr, nmrr;
int i, j, found;
@@ -189,8 +190,10 @@
/* V2P configuration: HTW for access */
SET_V2PCFG(base, ctx, 0x3);
- SET_TTBCR(base, ctx, 0);
+ SET_TTBCR(base, ctx, ttbr_split);
SET_TTBR0_PA(base, ctx, (pgtable >> TTBR0_PA_SHIFT));
+ if (ttbr_split)
+ SET_TTBR1_PA(base, ctx, (pgtable >> TTBR1_PA_SHIFT));
/* Enable context fault interrupt */
SET_CFEIE(base, ctx, 1);
@@ -365,7 +368,8 @@
goto fail;
__program_context(iommu_drvdata->base, ctx_dev->num, iommu_drvdata->ncb,
- __pa(priv->pgtable), priv->redirect);
+ __pa(priv->pgtable), priv->redirect,
+ iommu_drvdata->ttbr_split);
__disable_clocks(iommu_drvdata);
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
@@ -417,6 +421,16 @@
unsigned int pgprot;
int tex;
+ if (!(prot & (IOMMU_READ | IOMMU_WRITE))) {
+ prot |= IOMMU_READ | IOMMU_WRITE;
+ WARN_ONCE(1, "No attributes in iommu mapping; assuming RW\n");
+ }
+
+ if ((prot & IOMMU_WRITE) && !(prot & IOMMU_READ)) {
+ prot |= IOMMU_READ;
+ WARN_ONCE(1, "Write-only iommu mappings unsupported; falling back to RW\n");
+ }
+
if (prot & IOMMU_CACHE)
tex = (pgprot_kernel >> 2) & 0x07;
else
@@ -430,11 +444,15 @@
pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0;
pgprot |= tex & 0x02 ? FL_CACHEABLE : 0;
pgprot |= tex & 0x04 ? FL_TEX0 : 0;
+ pgprot |= FL_AP0 | FL_AP1;
+ pgprot |= prot & IOMMU_WRITE ? 0 : FL_AP2;
} else {
pgprot = SL_SHARED;
pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0;
pgprot |= tex & 0x02 ? SL_CACHEABLE : 0;
pgprot |= tex & 0x04 ? SL_TEX0 : 0;
+ pgprot |= SL_AP0 | SL_AP1;
+ pgprot |= prot & IOMMU_WRITE ? 0 : SL_AP2;
}
return pgprot;
@@ -497,9 +515,8 @@
}
for (i = 0; i < 16; i++)
- *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
- FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
- FL_SHARED | FL_NG | pgprot;
+ *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
+ | FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
if (!priv->redirect)
clean_pte(fl_pte, fl_pte + 16);
}
@@ -510,8 +527,8 @@
goto fail;
}
- *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE | FL_NG |
- FL_TYPE_SECT | FL_SHARED | pgprot;
+ *fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
+ | pgprot;
if (!priv->redirect)
clean_pte(fl_pte, fl_pte + 1);
}
@@ -554,8 +571,8 @@
goto fail;
}
- *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 | SL_NG |
- SL_SHARED | SL_TYPE_SMALL | pgprot;
+ *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
+ | SL_TYPE_SMALL | pgprot;
if (!priv->redirect)
clean_pte(sl_pte, sl_pte + 1);
}
@@ -570,8 +587,8 @@
}
for (i = 0; i < 16; i++)
- *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
- SL_NG | SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
+ *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
+ | SL_SHARED | SL_TYPE_LARGE | pgprot;
if (!priv->redirect)
clean_pte(sl_pte, sl_pte + 16);
@@ -772,8 +789,7 @@
while (offset < len && sl_offset < NUM_SL_PTE) {
pa = chunk_pa + chunk_offset;
sl_table[sl_offset] = (pa & SL_BASE_MASK_SMALL) |
- pgprot | SL_AP0 | SL_AP1 | SL_NG |
- SL_SHARED | SL_TYPE_SMALL;
+ pgprot | SL_NG | SL_SHARED | SL_TYPE_SMALL;
sl_offset++;
offset += SZ_4K;
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index 70e96b0..6633cae 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -239,6 +239,7 @@
drvdata->base = regs_base;
drvdata->irq = irq;
drvdata->ncb = iommu_dev->ncb;
+ drvdata->ttbr_split = iommu_dev->ttbr_split;
drvdata->name = iommu_dev->name;
pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index a7663b6..1959f5d 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -13,6 +13,7 @@
#include <mach/msm_subsystem_map.h>
#include <linux/memory_alloc.h>
#include <linux/iommu.h>
+#include <linux/vmalloc.h>
#include <asm/sizes.h>
#include <asm/page.h>
#include <linux/init.h>
@@ -43,10 +44,145 @@
char *name;
int domain;
} msm_iommu_ctx_names[] = {
+ /* Camera */
+ {
+ .name = "vpe_src",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "vpe_dst",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "vfe_imgwr",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "vfe_misc",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "ijpeg_src",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "ijpeg_dst",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "jpegd_src",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Camera */
+ {
+ .name = "jpegd_dst",
+ .domain = CAMERA_DOMAIN,
+ },
+ /* Rotator */
+ {
+ .name = "rot_src",
+ .domain = ROTATOR_DOMAIN,
+ },
+ /* Rotator */
+ {
+ .name = "rot_dst",
+ .domain = ROTATOR_DOMAIN,
+ },
+ /* Video */
+ {
+ .name = "vcodec_a_mm1",
+ .domain = VIDEO_DOMAIN,
+ },
+ /* Video */
+ {
+ .name = "vcodec_b_mm2",
+ .domain = VIDEO_DOMAIN,
+ },
+ /* Video */
+ {
+ .name = "vcodec_a_stream",
+ .domain = VIDEO_DOMAIN,
+ },
};
+static struct mem_pool video_pools[] = {
+ /*
+ * Video hardware has the following requirements:
+ * 1. All video addresses used by the video hardware must be at a higher
+ * address than video firmware address.
+ * 2. Video hardware can only access a range of 256MB from the base of
+ * the video firmware.
+ */
+ [VIDEO_FIRMWARE_POOL] =
+ /* Low addresses, intended for video firmware */
+ {
+ .paddr = SZ_128K,
+ .size = SZ_16M - SZ_128K,
+ },
+ [VIDEO_MAIN_POOL] =
+ /* Main video pool */
+ {
+ .paddr = SZ_16M,
+ .size = SZ_256M - SZ_16M,
+ },
+ [GEN_POOL] =
+ /* Remaining address space up to 2G */
+ {
+ .paddr = SZ_256M,
+ .size = SZ_2G - SZ_256M,
+ },
+};
+
+static struct mem_pool camera_pools[] = {
+ [GEN_POOL] =
+ /* One address space for camera */
+ {
+ .paddr = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ },
+};
+
+static struct mem_pool display_pools[] = {
+ [GEN_POOL] =
+ /* One address space for display */
+ {
+ .paddr = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ },
+};
+
+static struct mem_pool rotator_pools[] = {
+ [GEN_POOL] =
+ /* One address space for rotator */
+ {
+ .paddr = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ },
+};
static struct msm_iommu_domain msm_iommu_domains[] = {
+ [VIDEO_DOMAIN] = {
+ .iova_pools = video_pools,
+ .npools = ARRAY_SIZE(video_pools),
+ },
+ [CAMERA_DOMAIN] = {
+ .iova_pools = camera_pools,
+ .npools = ARRAY_SIZE(camera_pools),
+ },
+ [DISPLAY_DOMAIN] = {
+ .iova_pools = display_pools,
+ .npools = ARRAY_SIZE(display_pools),
+ },
+ [ROTATOR_DOMAIN] = {
+ .iova_pools = rotator_pools,
+ .npools = ARRAY_SIZE(rotator_pools),
+ },
};
int msm_iommu_map_extra(struct iommu_domain *domain,
@@ -54,33 +190,32 @@
unsigned long size,
int cached)
{
- int i, ret;
- unsigned long temp_iova;
+ int i, ret = 0;
+ struct scatterlist *sglist;
+ unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
+ struct page *dummy_page = phys_to_page(
+ PFN_ALIGN(virt_to_phys(iommu_dummy)));
- for (i = size, temp_iova = start_iova; i > 0; i -= SZ_4K,
- temp_iova += SZ_4K) {
- ret = iommu_map(domain, temp_iova,
- PFN_ALIGN(virt_to_phys(iommu_dummy)),
- get_order(SZ_4K),
- 0);
-
- if (ret) {
- pr_err("%s: could not map %lx to dummy page in domain"
- " %p\n",
- __func__, temp_iova, domain);
- goto out;
- }
+ sglist = vmalloc(sizeof(*sglist) * nrpages);
+ if (!sglist) {
+ ret = -ENOMEM;
+ goto err1;
}
- return 0;
+ sg_init_table(sglist, nrpages);
-out:
+ for (i = 0; i < nrpages; i++)
+ sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
- for ( ; i < size; i += SZ_4K, temp_iova -= SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+ ret = iommu_map_range(domain, start_iova, sglist, size, cached);
+ if (ret) {
+ pr_err("%s: could not map extra %lx in domain %p\n",
+ __func__, start_iova, domain);
+ }
- return -EINVAL;
-
+ vfree(sglist);
+err1:
+ return ret;
}
@@ -181,8 +316,7 @@
int msm_use_iommu()
{
- /* Kill use of the iommu by these clients for now. */
- return 0;
+ return iommu_found();
}
static int __init msm_subsystem_iommu_init(void)
@@ -198,25 +332,29 @@
struct mem_pool *pool = &msm_iommu_domains[i].
iova_pools[j];
mutex_init(&pool->pool_mutex);
- pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
+ if (pool->size) {
+ pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
- if (!pool->gpool) {
- pr_err("%s: domain %d: could not allocate iova"
- " pool. iommu programming will not work"
- " with iova space %d\n", __func__,
- i, j);
- continue;
- }
+ if (!pool->gpool) {
+ pr_err("%s: could not allocate pool\n",
+ __func__);
+ pr_err("%s: domain %d iova space %d\n",
+ __func__, i, j);
+ continue;
+ }
- if (gen_pool_add(pool->gpool, pool->paddr, pool->size,
- -1)) {
- pr_err("%s: domain %d: could not add memory to"
- " iova pool. iommu programming will not"
- " work with iova space %d\n", __func__,
- i, j);
- gen_pool_destroy(pool->gpool);
+ if (gen_pool_add(pool->gpool, pool->paddr,
+ pool->size, -1)) {
+ pr_err("%s: could not add memory\n",
+ __func__);
+ pr_err("%s: domain %d pool %d\n",
+ __func__, i, j);
+ gen_pool_destroy(pool->gpool);
+ pool->gpool = NULL;
+ continue;
+ }
+ } else {
pool->gpool = NULL;
- continue;
}
}
}
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 7e538b4..e0d2696 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -47,7 +47,7 @@
#define MDM_MODEM_DELTA 100
static int mdm_debug_on;
-static int first_power_on = 1;
+static int power_on_count;
static int hsic_peripheral_status;
static DEFINE_MUTEX(hsic_status_lock);
@@ -77,6 +77,16 @@
static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
{
+ power_on_count++;
+
+ /* The second attempt to power-on the mdm is the first attempt
+ * from user space, but we're already powered on. Ignore this.
+ * Subsequent attempts are from SSR or if something failed, in
+ * which case we must always reset the modem.
+ */
+ if (power_on_count == 2)
+ return;
+
mdm_peripheral_disconnect(mdm_drv);
/* Pull RESET gpio low and wait for it to settle. */
@@ -84,7 +94,7 @@
gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
usleep_range(5000, 10000);
- /* Deassert RESET first and wait for ir to settle. */
+ /* Deassert RESET first and wait for it to settle. */
pr_debug("%s: Pulling RESET gpio high\n", __func__);
gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 1);
usleep(1000);
@@ -93,13 +103,12 @@
* the first time the mdm is powered up.
* Some targets do not use ap2mdm_kpdpwr_n_gpio.
*/
- if (first_power_on) {
+ if (power_on_count == 1) {
if (mdm_drv->ap2mdm_kpdpwr_n_gpio > 0) {
pr_debug("%s: Powering on mdm modem\n", __func__);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
usleep(1000);
}
- first_power_on = 0;
}
mdm_peripheral_connect(mdm_drv);
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 7fccf2e..a7ba4a0 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -42,6 +42,8 @@
#define MDM_MODEM_TIMEOUT 6000
#define MDM_MODEM_DELTA 100
+#define MDM_BOOT_TIMEOUT 60000L
+#define MDM_RDUMP_TIMEOUT 60000L
static int mdm_debug_on;
static struct workqueue_struct *mdm_queue;
@@ -250,8 +252,12 @@
mdm_drv->ops->power_on_mdm_cb(mdm_drv);
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
complete(&mdm_needs_reload);
- wait_for_completion(&mdm_boot);
- pr_info("%s: mdm modem has been restarted\n", __func__);
+ if (!wait_for_completion_timeout(&mdm_boot,
+ msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
+ mdm_drv->mdm_boot_status = -ETIMEDOUT;
+ pr_info("%s: mdm modem restart timed out.\n", __func__);
+ } else
+ pr_info("%s: mdm modem has been restarted\n", __func__);
INIT_COMPLETION(mdm_boot);
return mdm_drv->mdm_boot_status;
}
@@ -263,7 +269,14 @@
if (want_dumps) {
mdm_drv->boot_type = CHARM_RAM_DUMPS;
complete(&mdm_needs_reload);
- wait_for_completion(&mdm_ram_dumps);
+ if (!wait_for_completion_timeout(&mdm_ram_dumps,
+ msecs_to_jiffies(MDM_RDUMP_TIMEOUT))) {
+ mdm_drv->mdm_ram_dump_status = -ETIMEDOUT;
+ pr_info("%s: mdm modem ramdumps timed out.\n",
+ __func__);
+ } else
+ pr_info("%s: mdm modem ramdumps completed.\n",
+ __func__);
INIT_COMPLETION(mdm_ram_dumps);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
mdm_drv->ops->power_down_mdm_cb(mdm_drv);
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index d26d76b..8dbf304 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -146,7 +146,7 @@
flush_axi_bus_buffer();
}
-void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
+void * __init alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
{
void *unused_addr = NULL;
unsigned long addr, tmp_size, unused_size;
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index b03e2d2..3d341e3 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -29,14 +29,13 @@
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
"mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t"
- :
+ "isb\n\t"
+ "mrc p15, 3, %[l2cpdr_read], c15, c0, 7\n\t"
+ : [l2cpdr_read]"=r" (ret_val)
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
- isb();
- /* Ensure the value took */
- asm volatile ("mrc p15, 3, %0, c15, c0, 7" : "=r" (ret_val));
-
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return ret_val;
@@ -53,11 +52,12 @@
raw_spin_lock_irqsave(&l2_access_lock, flags);
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
"mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t"
+ "isb\n\t"
:
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
- isb();
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(set_l2_indirect_reg);
@@ -72,6 +72,7 @@
raw_spin_lock_irqsave(&l2_access_lock, flags);
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+ "isb\n\t"
"mrc p15, 3, %[l2cpdr], c15, c0, 7\n\t"
: [l2cpdr]"=r" (val)
: [l2cpselr]"r" (reg_addr)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
index d05eaea..5a3d722 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -360,6 +360,8 @@
.tier = tier2,
.num_tiers = ARRAY_SIZE(tier2),
.buswidth = 8,
+ .slaveclk[DUAL_CTX] = "dfab_clk",
+ .slaveclk[ACTIVE_CTX] = "dfab_a_clk",
},
{
.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
index 36fe156..0f37c6d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -316,6 +316,8 @@
.tier = tier2,
.num_tiers = ARRAY_SIZE(tier2),
.buswidth = 8,
+ .slaveclk[DUAL_CTX] = "dfab_clk",
+ .slaveclk[ACTIVE_CTX] = "dfab_a_clk",
},
{
.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 0d265c7..7ede23d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -356,6 +356,8 @@
.tier = tier2,
.num_tiers = ARRAY_SIZE(tier2),
.buswidth = 8,
+ .slaveclk[DUAL_CTX] = "dfab_clk",
+ .slaveclk[ACTIVE_CTX] = "dfab_a_clk",
},
{
.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
index 5b52cb9..34cb2db 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_9615.c
@@ -184,6 +184,8 @@
.tier = tier2,
.num_tiers = ARRAY_SIZE(tier2),
.buswidth = 8,
+ .slaveclk[DUAL_CTX] = "dfab_clk",
+ .slaveclk[ACTIVE_CTX] = "dfab_a_clk",
},
{
.id = MSM_BUS_SLAVE_EBI_CH0,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
index e63df1b..a936e6f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
@@ -550,7 +550,7 @@
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
(int)ts.tv_sec, (int)ts.tv_nsec);
- msm_bus_rpm_fill_cdata_buffer(&i, buf + i, MAX_BUFF_SIZE, cdata,
+ msm_bus_rpm_fill_cdata_buffer(&i, buf, MAX_BUFF_SIZE, cdata,
nmasters, nslaves, ntslaves);
i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
mutex_lock(&msm_bus_dbg_fablist_lock);
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
new file mode 100644
index 0000000..404c8f0
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/memory_alloc.h>
+#include <linux/notifier.h>
+#include <mach/scm.h>
+#include <mach/msm_cache_dump.h>
+#include <mach/memory.h>
+#include <mach/msm_iomap.h>
+
+#define L2C_IMEM_ADDR 0x2a03f014
+
+static unsigned long msm_cache_dump_addr;
+
+/*
+ * These are dummy pointers so the defintion of l1_cache_dump
+ * and l2_cache_dump don't get optimized away. If they aren't
+ * referenced, the structure definitions don't show up in the
+ * debugging information which is needed for post processing.
+ */
+static struct l1_cache_dump __used *l1_dump;
+static struct l2_cache_dump __used *l2_dump;
+
+static int msm_cache_dump_panic(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+ scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
+ scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
+#endif
+ return 0;
+}
+
+static struct notifier_block msm_cache_dump_blk = {
+ .notifier_call = msm_cache_dump_panic,
+ /*
+ * higher priority to ensure this runs before another panic handler
+ * flushes the caches.
+ */
+ .priority = 1,
+};
+
+static int msm_cache_dump_probe(struct platform_device *pdev)
+{
+ struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
+ int ret;
+ struct {
+ unsigned long buf;
+ unsigned long size;
+ } l1_cache_data;
+#ifndef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+ unsigned int *imem_loc;
+#endif
+ void *temp;
+ unsigned long total_size = d->l1_size + d->l2_size;
+
+ msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+
+ if (!msm_cache_dump_addr) {
+ pr_err("%s: Could not get memory for cache dumping\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ temp = ioremap(msm_cache_dump_addr, total_size);
+ memset(temp, 0xFF, total_size);
+ iounmap(temp);
+
+ l1_cache_data.buf = msm_cache_dump_addr;
+ l1_cache_data.size = d->l1_size;
+
+ ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
+ &l1_cache_data, sizeof(l1_cache_data), NULL, 0);
+
+ if (ret)
+ pr_err("%s: could not register L1 buffer ret = %d.\n",
+ __func__, ret);
+
+#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
+ l1_cache_data.buf = msm_cache_dump_addr + d->l1_size;
+ l1_cache_data.size = d->l2_size;
+
+ ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
+ &l1_cache_data, sizeof(l1_cache_data), NULL, 0);
+
+ if (ret)
+ pr_err("%s: could not register L2 buffer ret = %d.\n",
+ __func__, ret);
+#else
+ imem_loc = ioremap(L2C_IMEM_ADDR, SZ_4K);
+ __raw_writel(msm_cache_dump_addr + d->l1_size, imem_loc);
+ iounmap(imem_loc);
+#endif
+
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &msm_cache_dump_blk);
+ return 0;
+}
+
+static int msm_cache_dump_remove(struct platform_device *pdev)
+{
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &msm_cache_dump_blk);
+ return 0;
+}
+
+static struct platform_driver msm_cache_dump_driver = {
+ .remove = __devexit_p(msm_cache_dump_remove),
+ .driver = {
+ .name = "msm_cache_dump",
+ .owner = THIS_MODULE
+ },
+};
+
+static int __init msm_cache_dump_init(void)
+{
+ return platform_driver_probe(&msm_cache_dump_driver,
+ msm_cache_dump_probe);
+}
+
+static void __exit msm_cache_dump_exit(void)
+{
+ platform_driver_unregister(&msm_cache_dump_driver);
+}
+late_initcall(msm_cache_dump_init);
+module_exit(msm_cache_dump_exit)
diff --git a/arch/arm/mach-msm/msm_rtb.c b/arch/arm/mach-msm/msm_rtb.c
index 3f56d1a..403c13d 100644
--- a/arch/arm/mach-msm/msm_rtb.c
+++ b/arch/arm/mach-msm/msm_rtb.c
@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/atomic.h>
#include <asm/io.h>
#include <asm-generic/sizes.h>
#include <mach/memory.h>
@@ -76,7 +77,7 @@
int msm_rtb_event_should_log(enum logk_event_type log_type)
{
return msm_rtb.initialized && msm_rtb.enabled &&
- ((1 << log_type) & msm_rtb.filter);
+ ((1 << (log_type & ~LOGTYPE_NOPC)) & msm_rtb.filter);
}
EXPORT_SYMBOL(msm_rtb_event_should_log);
@@ -109,10 +110,39 @@
start->data = data;
}
+static void uncached_logk_pc_idx(enum logk_event_type log_type, void *caller,
+ void *data, int idx)
+{
+ struct msm_rtb_layout *start;
+
+ start = &msm_rtb.rtb[idx & (msm_rtb.nentries - 1)];
+
+ msm_rtb_emit_sentinel(start);
+ msm_rtb_write_type(log_type, start);
+ msm_rtb_write_caller(caller, start);
+ msm_rtb_write_idx(idx, start);
+ msm_rtb_write_data(data, start);
+ mb();
+
+ return;
+}
+
+static void uncached_logk_timestamp(int idx)
+{
+ unsigned long long timestamp;
+ void *timestamp_upper, *timestamp_lower;
+ timestamp = sched_clock();
+ timestamp_lower = (void *)lower_32_bits(timestamp);
+ timestamp_upper = (void *)upper_32_bits(timestamp);
+
+ uncached_logk_pc_idx(LOGK_TIMESTAMP|LOGTYPE_NOPC, timestamp_lower,
+ timestamp_upper, idx);
+}
+
#if defined(CONFIG_MSM_RTB_SEPARATE_CPUS)
static int msm_rtb_get_idx(void)
{
- int cpu, i;
+ int cpu, i, offset;
atomic_t *index;
/*
@@ -126,16 +156,34 @@
i = atomic_add_return(msm_rtb.step_size, index);
i -= msm_rtb.step_size;
+ /* Check if index has wrapped around */
+ offset = (i & (msm_rtb.nentries - 1)) -
+ ((i - msm_rtb.step_size) & (msm_rtb.nentries - 1));
+ if (offset < 0) {
+ uncached_logk_timestamp(i);
+ i = atomic_add_return(msm_rtb.step_size, index);
+ i -= msm_rtb.step_size;
+ }
+
return i;
}
#else
static int msm_rtb_get_idx(void)
{
- int i;
+ int i, offset;
i = atomic_inc_return(&msm_rtb_idx);
i--;
+ /* Check if index has wrapped around */
+ offset = (i & (msm_rtb.nentries - 1)) -
+ ((i - 1) & (msm_rtb.nentries - 1));
+ if (offset < 0) {
+ uncached_logk_timestamp(i);
+ i = atomic_inc_return(&msm_rtb_idx);
+ i--;
+ }
+
return i;
}
#endif
@@ -144,21 +192,13 @@
void *data)
{
int i;
- struct msm_rtb_layout *start;
if (!msm_rtb_event_should_log(log_type))
return 0;
i = msm_rtb_get_idx();
- start = &msm_rtb.rtb[i & (msm_rtb.nentries - 1)];
-
- msm_rtb_emit_sentinel(start);
- msm_rtb_write_type(log_type, start);
- msm_rtb_write_caller(caller, start);
- msm_rtb_write_idx(i, start);
- msm_rtb_write_data(data, start);
- mb();
+ uncached_logk_pc_idx(log_type, caller, data, i);
return 1;
}
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 994dca6..aabb644 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -23,6 +23,8 @@
#include <linux/suspend.h>
#include <linux/percpu.h>
#include <linux/interrupt.h>
+#include <asm/fiq.h>
+#include <asm/hardware/gic.h>
#include <mach/msm_iomap.h>
#include <asm/mach-types.h>
#include <mach/scm.h>
@@ -42,6 +44,8 @@
#define WDT_HZ 32768
+struct msm_watchdog_dump msm_dump_cpu_ctx;
+
static void __iomem *msm_tmr0_base;
static unsigned long delay_time;
@@ -78,6 +82,8 @@
static int appsbark;
module_param(appsbark, int, 0);
+static int appsbark_fiq;
+
/*
* Use /sys/module/msm_watchdog/parameters/print_all_stacks
* to control whether stacks of all running
@@ -96,6 +102,13 @@
static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
static DECLARE_WORK(init_dogwork_struct, init_watchdog_work);
+/* Called from the FIQ bark handler */
+void msm_wdog_bark_fin(void)
+{
+ pr_crit("\nApps Watchdog bark received - Calling Panic\n");
+ panic("Apps Watchdog Bark received\n");
+}
+
static int msm_watchdog_suspend(struct device *dev)
{
if (!enable)
@@ -166,9 +179,11 @@
free_irq(WDT0_ACCSCSSNBARK_INT, 0);
} else {
disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
- free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
- percpu_pdata);
- free_percpu(percpu_pdata);
+ if (!appsbark_fiq) {
+ free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+ percpu_pdata);
+ free_percpu(percpu_pdata);
+ }
}
enable = 0;
atomic_notifier_chain_unregister(&panic_notifier_list,
@@ -231,8 +246,11 @@
free_irq(WDT0_ACCSCSSNBARK_INT, 0);
} else {
disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
- free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
- free_percpu(percpu_pdata);
+ if (!appsbark_fiq) {
+ free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+ percpu_pdata);
+ free_percpu(percpu_pdata);
+ }
}
enable = 0;
/* In case we got suspended mid-exit */
@@ -329,26 +347,35 @@
__raw_writel(1, msm_tmr0_base + WDT0_RST);
last_pet = sched_clock();
+ if (!has_vic)
+ enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, IRQ_TYPE_EDGE_RISING);
+
printk(KERN_INFO "MSM Watchdog Initialized\n");
return;
}
+struct fiq_handler wdog_fh = {
+ .name = MODULE_NAME,
+};
+
static int msm_watchdog_probe(struct platform_device *pdev)
{
struct msm_watchdog_pdata *pdata = pdev->dev.platform_data;
int ret;
+ void *stack;
if (!enable || !pdata || !pdata->pet_time || !pdata->bark_time) {
printk(KERN_INFO "MSM Watchdog Not Initialized\n");
return -ENODEV;
}
- if (!pdata->has_secure)
- appsbark = 1;
-
bark_time = pdata->bark_time;
has_vic = pdata->has_vic;
+ if (!pdata->has_secure) {
+ appsbark = 1;
+ appsbark_fiq = pdata->use_kernel_fiq;
+ }
msm_tmr0_base = msm_timer_get_timer0_base();
@@ -357,6 +384,18 @@
"apps_wdog_bark", NULL);
if (ret)
return ret;
+ } else if (appsbark_fiq) {
+ claim_fiq(&wdog_fh);
+ set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
+ stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
+ if (!stack) {
+ pr_info("No free pages available - %s fails\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ msm_wdog_fiq_setup(stack);
+ gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
} else {
percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
if (!percpu_pdata) {
@@ -373,8 +412,6 @@
free_percpu(percpu_pdata);
return ret;
}
-
- enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, IRQ_TYPE_EDGE_RISING);
}
/*
diff --git a/arch/arm/mach-msm/msm_watchdog.h b/arch/arm/mach-msm/msm_watchdog.h
index 7156dfc..00ff0b6 100644
--- a/arch/arm/mach-msm/msm_watchdog.h
+++ b/arch/arm/mach-msm/msm_watchdog.h
@@ -21,8 +21,53 @@
bool has_secure;
bool needs_expired_enable;
bool has_vic;
+ /* You have to be running in secure mode to use FIQ */
+ bool use_kernel_fiq;
};
+struct msm_watchdog_dump {
+ uint32_t magic;
+ uint32_t curr_cpsr;
+ uint32_t usr_r0;
+ uint32_t usr_r1;
+ uint32_t usr_r2;
+ uint32_t usr_r3;
+ uint32_t usr_r4;
+ uint32_t usr_r5;
+ uint32_t usr_r6;
+ uint32_t usr_r7;
+ uint32_t usr_r8;
+ uint32_t usr_r9;
+ uint32_t usr_r10;
+ uint32_t usr_r11;
+ uint32_t usr_r12;
+ uint32_t usr_r13;
+ uint32_t usr_r14;
+ uint32_t irq_spsr;
+ uint32_t irq_r13;
+ uint32_t irq_r14;
+ uint32_t svc_spsr;
+ uint32_t svc_r13;
+ uint32_t svc_r14;
+ uint32_t abt_spsr;
+ uint32_t abt_r13;
+ uint32_t abt_r14;
+ uint32_t und_spsr;
+ uint32_t und_r13;
+ uint32_t und_r14;
+ uint32_t fiq_spsr;
+ uint32_t fiq_r8;
+ uint32_t fiq_r9;
+ uint32_t fiq_r10;
+ uint32_t fiq_r11;
+ uint32_t fiq_r12;
+ uint32_t fiq_r13;
+ uint32_t fiq_r14;
+};
+
+void msm_wdog_fiq_setup(void *stack);
+extern unsigned int msm_wdog_fiq_length, msm_wdog_fiq_start;
+
#ifdef CONFIG_MSM_WATCHDOG
void pet_watchdog(void);
#else
diff --git a/arch/arm/mach-msm/msm_watchdog_asm.S b/arch/arm/mach-msm/msm_watchdog_asm.S
new file mode 100644
index 0000000..c0377d6
--- /dev/null
+++ b/arch/arm/mach-msm/msm_watchdog_asm.S
@@ -0,0 +1,84 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/linkage.h>
+#include <asm/assembler.h>
+
+#define VERSION_ID 0x1
+#define MAGIC 0xDEAD0000 | VERSION_ID
+
+ .text
+
+ .align 3
+
+ENTRY(msm_wdog_fiq_start)
+ mov sp, r8 @get stack
+ ldr r8, Ldump_cpu_ctx
+ @ store magic to indicate a valid dump
+ ldr r9, Lmagic
+ str r9, [r8], #4
+ @ get the current cpsr
+ mrs r9, cpsr
+ str r9, [r8],#4
+ @ get the USR r0-r7
+ stmia r8!, {r0-r7}
+ mov r4, r8
+ mov r5, #PSR_I_BIT | PSR_F_BIT | SYSTEM_MODE
+ msr cpsr_c, r5 @ select SYSTEM mode
+ stmia r4!, {r8-r14}
+ mov r5, #PSR_I_BIT | PSR_F_BIT | IRQ_MODE
+ msr cpsr_c, r5 @ select IRQ mode
+ mrs r5, spsr
+ str r5, [r4], #4
+ stmia r4!, {r13-r14}
+ mov r5, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+ msr cpsr_c, r5 @ select SVC mode
+ mrs r5, spsr
+ str r5, [r4], #4
+ stmia r4!, {r13-r14}
+ mov r5, #PSR_I_BIT | PSR_F_BIT | ABT_MODE
+ msr cpsr_c, r5 @ select ABT mode
+ mrs r5, spsr
+ str r5, [r4], #4
+ stmia r4!, {r13-r14}
+ mov r5, #PSR_I_BIT | PSR_F_BIT | UND_MODE
+ msr cpsr_c, r5 @ select UND mode
+ mrs r5, spsr
+ str r5, [r4], #4
+ stmia r4!, {r13-r14}
+ mov r5, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+ msr cpsr_c, r5 @ select FIQ mode
+ mrs r5, spsr
+ str r5, [r4], #4
+ stmia r4!, {r8-r14}
+ dsb
+ mov r5, #PSR_F_BIT | SVC_MODE
+ msr cpsr_c, r5 @ select SVC mode
+ ldr r2, Lwatchdog_bark_fin
+ blx r2
+Ldump_cpu_ctx:
+ .word msm_dump_cpu_ctx
+Lmagic:
+ .word MAGIC
+Lwatchdog_bark_fin:
+ .word msm_wdog_bark_fin
+ENTRY(msm_wdog_fiq_length)
+ .word . - msm_wdog_fiq_start
+
+/* setup the stack */
+ENTRY(msm_wdog_fiq_setup)
+ mrs r3, cpsr
+ msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
+ mov r8, r0
+ msr cpsr_c, r3
+ bx lr
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 86776d3..407231a 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/seq_file.h>
@@ -29,7 +29,7 @@
#include "rpm_resources.h"
-static DEFINE_SPINLOCK(msm_xo_lock);
+static DEFINE_MUTEX(msm_xo_lock);
struct msm_xo {
unsigned votes[NUM_MSM_XO_MODES];
@@ -151,13 +151,12 @@
static int msm_xo_show_voters(struct seq_file *m, void *v)
{
- unsigned long flags;
int i;
- spin_lock_irqsave(&msm_xo_lock, flags);
+ mutex_lock(&msm_xo_lock);
for (i = 0; i < ARRAY_SIZE(msm_xo_sources); i++)
msm_xo_dump_xo(m, &msm_xo_sources[i], msm_xo_to_str[i]);
- spin_unlock_irqrestore(&msm_xo_lock, flags);
+ mutex_unlock(&msm_xo_lock);
return 0;
}
@@ -221,7 +220,7 @@
*/
((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20) |
((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 18);
- ret = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
+ ret = msm_rpm_set(MSM_RPM_CTX_SET_0, &cmd, 1);
if (ret)
xo->mode = prev_vote;
@@ -281,7 +280,6 @@
int msm_xo_mode_vote(struct msm_xo_voter *xo_voter, enum msm_xo_modes mode)
{
int ret;
- unsigned long flags;
if (!xo_voter)
return 0;
@@ -289,9 +287,9 @@
if (mode >= NUM_MSM_XO_MODES || IS_ERR(xo_voter))
return -EINVAL;
- spin_lock_irqsave(&msm_xo_lock, flags);
+ mutex_lock(&msm_xo_lock);
ret = __msm_xo_mode_vote(xo_voter, mode);
- spin_unlock_irqrestore(&msm_xo_lock, flags);
+ mutex_unlock(&msm_xo_lock);
return ret;
}
@@ -310,7 +308,6 @@
struct msm_xo_voter *msm_xo_get(enum msm_xo_ids xo_id, const char *voter)
{
int ret;
- unsigned long flags;
struct msm_xo_voter *xo_voter;
if (xo_id >= NUM_MSM_XO_IDS) {
@@ -333,10 +330,10 @@
xo_voter->xo = &msm_xo_sources[xo_id];
/* Voters vote for OFF by default */
- spin_lock_irqsave(&msm_xo_lock, flags);
+ mutex_lock(&msm_xo_lock);
xo_voter->xo->votes[MSM_XO_MODE_OFF]++;
list_add(&xo_voter->list, &xo_voter->xo->voters);
- spin_unlock_irqrestore(&msm_xo_lock, flags);
+ mutex_unlock(&msm_xo_lock);
return xo_voter;
@@ -357,16 +354,14 @@
*/
void msm_xo_put(struct msm_xo_voter *xo_voter)
{
- unsigned long flags;
-
if (!xo_voter || IS_ERR(xo_voter))
return;
- spin_lock_irqsave(&msm_xo_lock, flags);
+ mutex_lock(&msm_xo_lock);
__msm_xo_mode_vote(xo_voter, MSM_XO_MODE_OFF);
xo_voter->xo->votes[MSM_XO_MODE_OFF]--;
list_del(&xo_voter->list);
- spin_unlock_irqrestore(&msm_xo_lock, flags);
+ mutex_unlock(&msm_xo_lock);
kfree(xo_voter->name);
kfree(xo_voter);
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 6f7f771..fa9159e 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -24,6 +24,9 @@
#include <linux/suspend.h>
#include <linux/rwsem.h>
#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/wakelock.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
@@ -51,6 +54,9 @@
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
#endif
+ struct delayed_work proxy;
+ struct wake_lock wlock;
+ char wake_name[32];
};
#define to_pil_device(d) container_of(d, struct pil_device, dev)
@@ -97,6 +103,30 @@
return dev ? to_pil_device(dev) : NULL;
}
+static void pil_proxy_work(struct work_struct *work)
+{
+ struct pil_device *pil;
+
+ pil = container_of(work, struct pil_device, proxy.work);
+ pil->desc->ops->proxy_unvote(pil->desc);
+ wake_unlock(&pil->wlock);
+}
+
+static int pil_proxy_vote(struct pil_device *pil)
+{
+ if (pil->desc->ops->proxy_vote) {
+ wake_lock(&pil->wlock);
+ return pil->desc->ops->proxy_vote(pil->desc);
+ }
+ return 0;
+}
+
+static void pil_proxy_unvote(struct pil_device *pil, unsigned long timeout)
+{
+ if (pil->desc->ops->proxy_unvote)
+ schedule_delayed_work(&pil->proxy, msecs_to_jiffies(timeout));
+}
+
#define IOMAP_SIZE SZ_4M
static int load_segment(const struct elf32_phdr *phdr, unsigned num,
@@ -202,6 +232,7 @@
struct elf32_hdr *ehdr;
const struct elf32_phdr *phdr;
const struct firmware *fw;
+ unsigned long proxy_timeout = pil->desc->proxy_timeout;
down_read(&pil_pm_rwsem);
snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
@@ -255,13 +286,21 @@
}
}
+ ret = pil_proxy_vote(pil);
+ if (ret) {
+ dev_err(&pil->dev, "Failed to proxy vote\n");
+ goto release_fw;
+ }
+
ret = pil->desc->ops->auth_and_reset(pil->desc);
if (ret) {
dev_err(&pil->dev, "Failed to bring out of reset\n");
- goto release_fw;
+ proxy_timeout = 0; /* Remove proxy vote immediately on error */
+ goto err_boot;
}
dev_info(&pil->dev, "brought %s out of reset\n", pil->desc->name);
-
+err_boot:
+ pil_proxy_unvote(pil, proxy_timeout);
release_fw:
release_firmware(fw);
out:
@@ -332,6 +371,13 @@
}
EXPORT_SYMBOL(pil_get);
+static void pil_shutdown(struct pil_device *pil)
+{
+ pil->desc->ops->shutdown(pil->desc);
+ flush_delayed_work(&pil->proxy);
+ pil_set_state(pil, PIL_OFFLINE);
+}
+
/**
* pil_put() - Inform PIL the peripheral no longer needs to be active
* @peripheral_handle: pointer from a previous call to pil_get()
@@ -349,10 +395,8 @@
mutex_lock(&pil->lock);
if (WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
goto err_out;
- if (!--pil->count) {
- pil->desc->ops->shutdown(pil->desc);
- pil_set_state(pil, PIL_OFFLINE);
- }
+ if (!--pil->count)
+ pil_shutdown(pil);
mutex_unlock(&pil->lock);
pil_d = find_peripheral(pil->desc->depends_on);
@@ -381,8 +425,7 @@
mutex_lock(&pil->lock);
if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
- pil->desc->ops->shutdown(pil->desc);
- pil_set_state(pil, PIL_OFFLINE);
+ pil_shutdown(pil);
mutex_unlock(&pil->lock);
put_device(&pil->dev);
@@ -502,8 +545,7 @@
static int __msm_pil_shutdown(struct device *dev, void *data)
{
- struct pil_device *pil = to_pil_device(dev);
- pil->desc->ops->shutdown(pil->desc);
+ pil_shutdown(to_pil_device(dev));
return 0;
}
@@ -516,6 +558,7 @@
static void pil_device_release(struct device *dev)
{
struct pil_device *pil = to_pil_device(dev);
+ wake_lock_destroy(&pil->wlock);
mutex_destroy(&pil->lock);
kfree(pil);
}
@@ -524,8 +567,14 @@
{
int err;
static atomic_t pil_count = ATOMIC_INIT(-1);
- struct pil_device *pil = kzalloc(sizeof(*pil), GFP_KERNEL);
+ struct pil_device *pil;
+ /* Ignore users who don't make any sense */
+ if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
+ "invalid proxy voting. ignoring\n"))
+ ((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
+
+ pil = kzalloc(sizeof(*pil), GFP_KERNEL);
if (!pil)
return ERR_PTR(-ENOMEM);
@@ -536,10 +585,15 @@
pil->dev.bus = &pil_bus_type;
pil->dev.release = pil_device_release;
+ snprintf(pil->wake_name, sizeof(pil->wake_name), "pil-%s", desc->name);
+ wake_lock_init(&pil->wlock, WAKE_LOCK_SUSPEND, pil->wake_name);
+ INIT_DELAYED_WORK(&pil->proxy, pil_proxy_work);
+
dev_set_name(&pil->dev, "pil%d", atomic_inc_return(&pil_count));
err = device_register(&pil->dev);
if (err) {
put_device(&pil->dev);
+ wake_lock_destroy(&pil->wlock);
mutex_destroy(&pil->lock);
kfree(pil);
return ERR_PTR(err);
@@ -563,6 +617,7 @@
if (get_device(&pil->dev)) {
mutex_lock(&pil->lock);
WARN_ON(pil->count);
+ flush_delayed_work_sync(&pil->proxy);
msm_pil_debugfs_remove(pil);
device_unregister(&pil->dev);
mutex_unlock(&pil->lock);
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index cc00446..e3b250b 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -15,19 +15,41 @@
struct device;
struct module;
+/**
+ * struct pil_desc - PIL descriptor
+ * @name: string used for pil_get()
+ * @depends_on: booted before this peripheral
+ * @dev: parent device
+ * @ops: callback functions
+ * @owner: module the descriptor belongs to
+ * @proxy_timeout: delay in ms until proxy vote is removed
+ */
struct pil_desc {
const char *name;
const char *depends_on;
struct device *dev;
const struct pil_reset_ops *ops;
struct module *owner;
+ unsigned long proxy_timeout;
};
+/**
+ * struct pil_reset_ops - PIL operations
+ * @init_image: prepare an image for authentication
+ * @verify_blob: authenticate a program segment, called once for each loadable
+ * program segment (optional)
+ * @proxy_vote: make proxy votes before auth_and_reset (optional)
+ * @auth_and_reset: boot the processor
+ * @proxy_unvote: remove any proxy votes (optional)
+ * @shutdown: shutdown the processor
+ */
struct pil_reset_ops {
int (*init_image)(struct pil_desc *pil, const u8 *metadata,
size_t size);
int (*verify_blob)(struct pil_desc *pil, u32 phy_addr, size_t size);
+ int (*proxy_vote)(struct pil_desc *pil);
int (*auth_and_reset)(struct pil_desc *pil);
+ void (*proxy_unvote)(struct pil_desc *pil);
int (*shutdown)(struct pil_desc *pil);
};
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
deleted file mode 100644
index 7965193..0000000
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/msm_iomap.h>
-#include <mach/scm.h>
-
-#include "peripheral-loader.h"
-#include "scm-pas.h"
-
-#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
-#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
-#define PPSS_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2580)
-
-static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
- return 0;
-}
-
-static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- /* Bring memory and bus interface out of reset */
- writel_relaxed(0x2, PPSS_RESET);
- writel_relaxed(0x10, PPSS_HCLK_CTL);
- return 0;
-}
-
-static int reset_dsps_untrusted(struct pil_desc *pil)
-{
- writel_relaxed(0x10, PPSS_PROC_CLK_CTL);
- /* Bring DSPS out of reset */
- writel_relaxed(0x0, PPSS_RESET);
- return 0;
-}
-
-static int shutdown_dsps_untrusted(struct pil_desc *pil)
-{
- writel_relaxed(0x3, PPSS_RESET);
- writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
- return 0;
-}
-
-static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- return pas_init_image(PAS_DSPS, metadata, size);
-}
-
-static int reset_dsps_trusted(struct pil_desc *pil)
-{
- return pas_auth_and_reset(PAS_DSPS);
-}
-
-static int shutdown_dsps_trusted(struct pil_desc *pil)
-{
- return pas_shutdown(PAS_DSPS);
-}
-
-struct pil_reset_ops pil_dsps_ops = {
- .init_image = init_image_dsps_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_dsps_untrusted,
- .shutdown = shutdown_dsps_untrusted,
-};
-
-static struct platform_device pil_dsps = {
- .name = "pil_dsps",
-};
-
-static struct pil_desc pil_dsps_desc = {
- .name = "dsps",
- .dev = &pil_dsps.dev,
- .ops = &pil_dsps_ops,
- .owner = THIS_MODULE,
-};
-
-static void __init use_secure_pil(void)
-{
- if (pas_supported(PAS_DSPS) > 0) {
- pil_dsps_ops.init_image = init_image_dsps_trusted;
- pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
- pil_dsps_ops.shutdown = shutdown_dsps_trusted;
- }
-}
-
-static int __init msm_peripheral_reset_init(void)
-{
- /*
- * Don't initialize PIL on simulated targets, as some
- * subsystems may not be emulated on them.
- */
- if (machine_is_msm8960_sim() || machine_is_msm8960_rumi3())
- return 0;
-
- use_secure_pil();
-
- BUG_ON(platform_device_register(&pil_dsps));
- BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
-
- return 0;
-}
-module_init(msm_peripheral_reset_init);
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
deleted file mode 100644
index 45617e3..0000000
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/platform_device.h>
-
-#include <asm/mach-types.h>
-
-#include <mach/scm.h>
-#include <mach/msm_iomap.h>
-
-#include "peripheral-loader.h"
-#include "scm-pas.h"
-
-#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
-#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
-#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
-
-static int dsps_start;
-
-static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- return pas_init_image(PAS_DSPS, metadata, size);
-}
-
-static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
- size_t size)
-{
- struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- dsps_start = ehdr->e_entry;
- /* Bring memory and bus interface out of reset */
- __raw_writel(0x2, PPSS_RESET);
- mb();
- return 0;
-}
-
-static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
-{
- return 0;
-}
-
-static int reset_dsps_untrusted(struct pil_desc *pil)
-{
- __raw_writel(0x10, PPSS_PROC_CLK_CTL);
- while (__raw_readl(CLK_HALT_DFAB_STATE) & BIT(18))
- cpu_relax();
-
- /* Bring DSPS out of reset */
- __raw_writel(0x0, PPSS_RESET);
- return 0;
-}
-
-static int reset_dsps_trusted(struct pil_desc *pil)
-{
- return pas_auth_and_reset(PAS_DSPS);
-}
-
-static int shutdown_dsps_trusted(struct pil_desc *pil)
-{
- return pas_shutdown(PAS_DSPS);
-}
-
-static int shutdown_dsps_untrusted(struct pil_desc *pil)
-{
- __raw_writel(0x3, PPSS_RESET);
- __raw_writel(0x0, PPSS_PROC_CLK_CTL);
- return 0;
-}
-
-struct pil_reset_ops pil_dsps_ops = {
- .init_image = init_image_dsps_untrusted,
- .verify_blob = verify_blob,
- .auth_and_reset = reset_dsps_untrusted,
- .shutdown = shutdown_dsps_untrusted,
-};
-
-static struct platform_device pil_dsps = {
- .name = "pil_dsps",
-};
-
-static struct pil_desc pil_dsps_desc = {
- .name = "dsps",
- .dev = &pil_dsps.dev,
- .ops = &pil_dsps_ops,
- .owner = THIS_MODULE,
-};
-
-static int __init msm_peripheral_reset_init(void)
-{
- if (pas_supported(PAS_DSPS) > 0) {
- pil_dsps_ops.init_image = init_image_dsps_trusted;
- pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
- pil_dsps_ops.shutdown = shutdown_dsps_trusted;
- }
-
- if (machine_is_msm8x60_fluid())
- pil_dsps_desc.name = "dsps_fluid";
- BUG_ON(platform_device_register(&pil_dsps));
- BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
-
- return 0;
-}
-
-module_init(msm_peripheral_reset_init);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Validate and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
new file mode 100644
index 0000000..81f5330
--- /dev/null
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -0,0 +1,146 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <mach/msm_iomap.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PPSS_RESET (MSM_CLK_CTL_BASE + 0x2594)
+#define PPSS_RESET_PROC_RESET 0x2
+#define PPSS_RESET_RESET 0x1
+#define PPSS_PROC_CLK_CTL (MSM_CLK_CTL_BASE + 0x2588)
+#define CLK_BRANCH_ENA 0x10
+#define PPSS_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2580)
+#define CLK_HALT_DFAB_STATE (MSM_CLK_CTL_BASE + 0x2FC8)
+
+static int init_image_dsps(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ /* Bring memory and bus interface out of reset */
+ writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
+ writel_relaxed(CLK_BRANCH_ENA, PPSS_HCLK_CTL);
+ mb();
+ return 0;
+}
+
+static int reset_dsps(struct pil_desc *pil)
+{
+ writel_relaxed(CLK_BRANCH_ENA, PPSS_PROC_CLK_CTL);
+ while (readl_relaxed(CLK_HALT_DFAB_STATE) & BIT(18))
+ cpu_relax();
+ /* Bring DSPS out of reset */
+ writel_relaxed(0x0, PPSS_RESET);
+ return 0;
+}
+
+static int shutdown_dsps(struct pil_desc *pil)
+{
+ writel_relaxed(PPSS_RESET_PROC_RESET | PPSS_RESET_RESET, PPSS_RESET);
+ usleep_range(1000, 2000);
+ writel_relaxed(PPSS_RESET_PROC_RESET, PPSS_RESET);
+ writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
+ return 0;
+}
+
+struct pil_reset_ops pil_dsps_ops = {
+ .init_image = init_image_dsps,
+ .auth_and_reset = reset_dsps,
+ .shutdown = shutdown_dsps,
+};
+
+static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ return pas_init_image(PAS_DSPS, metadata, size);
+}
+
+static int reset_dsps_trusted(struct pil_desc *pil)
+{
+ return pas_auth_and_reset(PAS_DSPS);
+}
+
+static int shutdown_dsps_trusted(struct pil_desc *pil)
+{
+ return pas_shutdown(PAS_DSPS);
+}
+
+struct pil_reset_ops pil_dsps_ops_trusted = {
+ .init_image = init_image_dsps_trusted,
+ .auth_and_reset = reset_dsps_trusted,
+ .shutdown = shutdown_dsps_trusted,
+};
+
+static int __devinit pil_dsps_driver_probe(struct platform_device *pdev)
+{
+ struct pil_desc *desc;
+ struct pil_device *pil;
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->name = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ if (pas_supported(PAS_DSPS) > 0) {
+ desc->ops = &pil_dsps_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_dsps_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+ pil = msm_pil_register(desc);
+ if (IS_ERR(pil))
+ return PTR_ERR(pil);
+ platform_set_drvdata(pdev, pil);
+ return 0;
+}
+
+static int __devexit pil_dsps_driver_exit(struct platform_device *pdev)
+{
+ struct pil_device *pil = platform_get_drvdata(pdev);
+ msm_pil_unregister(pil);
+ return 0;
+}
+
+static struct platform_driver pil_dsps_driver = {
+ .probe = pil_dsps_driver_probe,
+ .remove = __devexit_p(pil_dsps_driver_exit),
+ .driver = {
+ .name = "pil_dsps",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_dsps_init(void)
+{
+ return platform_driver_register(&pil_dsps_driver);
+}
+module_init(pil_dsps_init);
+
+static void __exit pil_dsps_exit(void)
+{
+ platform_driver_unregister(&pil_dsps_driver);
+}
+module_exit(pil_dsps_exit);
+
+MODULE_DESCRIPTION("Support for booting sensors (DSPS) images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index fa4f28c..f41a6e3 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-#include <linux/workqueue.h>
#include <linux/clk.h>
#include <linux/smp.h>
@@ -58,13 +57,10 @@
#define SLP_CLK_BRANCH_ENA BIT(4)
#define A5_RESET BIT(0)
-#define PROXY_VOTE_TIMEOUT 10000
-
struct gss_data {
void __iomem *base;
void __iomem *qgic2_base;
unsigned long start_addr;
- struct delayed_work work;
struct clk *xo;
struct pil_device *pil;
};
@@ -78,31 +74,25 @@
return 0;
}
-static int make_gss_proxy_votes(struct device *dev)
+static int make_gss_proxy_votes(struct pil_desc *pil)
{
int ret;
- struct gss_data *drv = dev_get_drvdata(dev);
+ struct gss_data *drv = dev_get_drvdata(pil->dev);
ret = clk_prepare_enable(drv->xo);
if (ret) {
- dev_err(dev, "Failed to enable XO\n");
+ dev_err(pil->dev, "Failed to enable XO\n");
return ret;
}
- schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
return 0;
}
-static void remove_gss_proxy_votes(struct work_struct *work)
+static void remove_gss_proxy_votes(struct pil_desc *pil)
{
- struct gss_data *drv = container_of(work, struct gss_data, work.work);
+ struct gss_data *drv = dev_get_drvdata(pil->dev);
clk_disable_unprepare(drv->xo);
}
-static void remove_gss_proxy_votes_now(struct gss_data *drv)
-{
- flush_delayed_work(&drv->work);
-}
-
static void gss_init(struct gss_data *drv)
{
void __iomem *base = drv->base;
@@ -200,7 +190,6 @@
mb();
clk_disable_unprepare(drv->xo);
- remove_gss_proxy_votes_now(drv);
return 0;
}
@@ -212,15 +201,10 @@
unsigned long start_addr = drv->start_addr;
int ret;
- ret = make_gss_proxy_votes(pil->dev);
- if (ret)
- return ret;
-
/* Unhalt bus port. */
ret = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV);
if (ret) {
dev_err(pil->dev, "Failed to unhalt bus port\n");
- remove_gss_proxy_votes_now(drv);
return ret;
}
@@ -262,6 +246,8 @@
.init_image = pil_gss_init_image,
.auth_and_reset = pil_gss_reset,
.shutdown = pil_gss_shutdown,
+ .proxy_vote = make_gss_proxy_votes,
+ .proxy_unvote = remove_gss_proxy_votes,
};
static int pil_gss_init_image_trusted(struct pil_desc *pil,
@@ -288,24 +274,18 @@
msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
ret = pas_shutdown(PAS_GSS);
clk_disable_unprepare(drv->xo);
- remove_gss_proxy_votes_now(drv);
return ret;
}
static int pil_gss_reset_trusted(struct pil_desc *pil)
{
- struct gss_data *drv = dev_get_drvdata(pil->dev);
int err;
- err = make_gss_proxy_votes(pil->dev);
- if (err)
- goto out;
-
err = msm_bus_axi_portunhalt(MSM_BUS_MASTER_GSS_NAV);
if (err) {
dev_err(pil->dev, "Failed to unhalt bus port\n");
- goto remove_votes;
+ goto out;
}
err = pas_auth_and_reset(PAS_GSS);
@@ -316,8 +296,6 @@
halt_port:
msm_bus_axi_porthalt(MSM_BUS_MASTER_GSS_NAV);
-remove_votes:
- remove_gss_proxy_votes_now(drv);
out:
return err;
}
@@ -326,6 +304,8 @@
.init_image = pil_gss_init_image_trusted,
.auth_and_reset = pil_gss_reset_trusted,
.shutdown = pil_gss_shutdown_trusted,
+ .proxy_vote = make_gss_proxy_votes,
+ .proxy_unvote = remove_gss_proxy_votes,
};
static int __devinit pil_gss_probe(struct platform_device *pdev)
@@ -367,6 +347,7 @@
desc->name = "gss";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
if (pas_supported(PAS_GSS) > 0) {
desc->ops = &pil_gss_ops_trusted;
@@ -376,11 +357,8 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
- INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
-
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil)) {
- flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
return PTR_ERR(drv->pil);
}
@@ -391,7 +369,6 @@
{
struct gss_data *drv = platform_get_drvdata(pdev);
msm_pil_unregister(drv->pil);
- flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 80e0ac9..998e606 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -18,7 +18,6 @@
#include <linux/elf.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/workqueue.h>
#include <linux/clk.h>
#include <mach/msm_iomap.h>
@@ -48,42 +47,32 @@
#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
-#define PROXY_VOTE_TIMEOUT 10000
-
struct modem_data {
void __iomem *base;
unsigned long start_addr;
struct pil_device *pil;
struct clk *xo;
- struct delayed_work work;
};
-static int make_modem_proxy_votes(struct device *dev)
+static int make_modem_proxy_votes(struct pil_desc *pil)
{
int ret;
- struct modem_data *drv = dev_get_drvdata(dev);
+ struct modem_data *drv = dev_get_drvdata(pil->dev);
ret = clk_prepare_enable(drv->xo);
if (ret) {
- dev_err(dev, "Failed to enable XO\n");
+ dev_err(pil->dev, "Failed to enable XO\n");
return ret;
}
- schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
return 0;
}
-static void remove_modem_proxy_votes(struct work_struct *work)
+static void remove_modem_proxy_votes(struct pil_desc *pil)
{
- struct modem_data *drv;
- drv = container_of(work, struct modem_data, work.work);
+ struct modem_data *drv = dev_get_drvdata(pil->dev);
clk_disable_unprepare(drv->xo);
}
-static void remove_modem_proxy_votes_now(struct modem_data *drv)
-{
- flush_delayed_work(&drv->work);
-}
-
static int modem_init_image(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -96,13 +85,8 @@
static int modem_reset(struct pil_desc *pil)
{
u32 reg;
- int ret;
const struct modem_data *drv = dev_get_drvdata(pil->dev);
- ret = make_modem_proxy_votes(pil->dev);
- if (ret)
- return ret;
-
/* Put modem AHB0,1,2 clocks into reset */
writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
writel_relaxed(BIT(7), MAHB1_CLK_CTL);
@@ -180,7 +164,6 @@
static int modem_shutdown(struct pil_desc *pil)
{
u32 reg;
- struct modem_data *drv = dev_get_drvdata(pil->dev);
/* Put modem into reset */
writel_relaxed(0x1, MARM_RESET);
@@ -214,8 +197,6 @@
/* Clear modem's votes for PLLs */
writel_relaxed(0x0, PLL_ENA_MARM);
- remove_modem_proxy_votes_now(drv);
-
return 0;
}
@@ -223,6 +204,8 @@
.init_image = modem_init_image,
.auth_and_reset = modem_reset,
.shutdown = modem_shutdown,
+ .proxy_vote = make_modem_proxy_votes,
+ .proxy_unvote = remove_modem_proxy_votes,
};
static int modem_init_image_trusted(struct pil_desc *pil, const u8 *metadata,
@@ -233,37 +216,20 @@
static int modem_reset_trusted(struct pil_desc *pil)
{
- int ret;
- struct modem_data *drv = dev_get_drvdata(pil->dev);
-
- ret = make_modem_proxy_votes(pil->dev);
- if (ret)
- return ret;
-
- ret = pas_auth_and_reset(PAS_MODEM);
- if (ret)
- remove_modem_proxy_votes_now(drv);
-
- return ret;
+ return pas_auth_and_reset(PAS_MODEM);
}
static int modem_shutdown_trusted(struct pil_desc *pil)
{
- int ret;
- struct modem_data *drv = dev_get_drvdata(pil->dev);
-
- ret = pas_shutdown(PAS_MODEM);
- if (ret)
- return ret;
-
- remove_modem_proxy_votes_now(drv);
- return 0;
+ return pas_shutdown(PAS_MODEM);
}
static struct pil_reset_ops pil_modem_ops_trusted = {
.init_image = modem_init_image_trusted,
.auth_and_reset = modem_reset_trusted,
.shutdown = modem_shutdown_trusted,
+ .proxy_vote = make_modem_proxy_votes,
+ .proxy_unvote = remove_modem_proxy_votes,
};
static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
@@ -297,6 +263,7 @@
desc->depends_on = "q6";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
if (pas_supported(PAS_MODEM) > 0) {
desc->ops = &pil_modem_ops_trusted;
@@ -305,11 +272,8 @@
desc->ops = &pil_modem_ops;
dev_info(&pdev->dev, "using non-secure boot\n");
}
- INIT_DELAYED_WORK(&drv->work, remove_modem_proxy_votes);
-
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil)) {
- flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
return PTR_ERR(drv->pil);
}
@@ -320,7 +284,6 @@
{
struct modem_data *drv = platform_get_drvdata(pdev);
msm_pil_unregister(drv->pil);
- flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 6c00ae7..235d881 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -19,7 +19,6 @@
#include <linux/elf.h>
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/workqueue.h>
#include <mach/msm_iomap.h>
@@ -61,14 +60,11 @@
#define Q6_STRAP_TCM_BASE (0x28C << 15)
#define Q6_STRAP_TCM_CONFIG 0x28B
-#define PROXY_VOTE_TIMEOUT 10000
-
struct q6v3_data {
void __iomem *base;
unsigned long start_addr;
struct pil_device *pil;
struct clk *pll;
- struct delayed_work work;
};
static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -80,41 +76,30 @@
return 0;
}
-static void q6v3_remove_proxy_votes(struct work_struct *work)
+static void pil_q6v3_remove_proxy_votes(struct pil_desc *pil)
{
- struct q6v3_data *drv = container_of(work, struct q6v3_data, work.work);
+ struct q6v3_data *drv = dev_get_drvdata(pil->dev);
clk_disable_unprepare(drv->pll);
}
-static int q6v3_make_proxy_votes(struct device *dev)
+static int pil_q6v3_make_proxy_votes(struct pil_desc *pil)
{
int ret;
- struct q6v3_data *drv = dev_get_drvdata(dev);
+ struct q6v3_data *drv = dev_get_drvdata(pil->dev);
ret = clk_prepare_enable(drv->pll);
if (ret) {
- dev_err(dev, "Failed to enable PLL\n");
+ dev_err(pil->dev, "Failed to enable PLL\n");
return ret;
}
- schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
return 0;
}
-static void q6v3_remove_proxy_votes_now(struct q6v3_data *drv)
-{
- flush_delayed_work(&drv->work);
-}
-
static int pil_q6v3_reset(struct pil_desc *pil)
{
u32 reg;
- int ret;
struct q6v3_data *drv = dev_get_drvdata(pil->dev);
- ret = q6v3_make_proxy_votes(pil->dev);
- if (ret)
- return ret;
-
/* Put Q6 into reset */
reg = readl_relaxed(LCC_Q6_FUNC);
reg |= Q6SS_SS_ARES | Q6SS_ISDB_ARES | Q6SS_ETM_ARES | STOP_CORE |
@@ -159,7 +144,6 @@
static int pil_q6v3_shutdown(struct pil_desc *pil)
{
u32 reg;
- struct q6v3_data *drv = dev_get_drvdata(pil->dev);
/* Put Q6 into reset */
reg = readl_relaxed(LCC_Q6_FUNC);
@@ -179,8 +163,6 @@
reg |= CLAMP_IO;
writel_relaxed(reg, LCC_Q6_FUNC);
- q6v3_remove_proxy_votes_now(drv);
-
return 0;
}
@@ -188,6 +170,8 @@
.init_image = pil_q6v3_init_image,
.auth_and_reset = pil_q6v3_reset,
.shutdown = pil_q6v3_shutdown,
+ .proxy_vote = pil_q6v3_make_proxy_votes,
+ .proxy_unvote = pil_q6v3_remove_proxy_votes,
};
static int pil_q6v3_init_image_trusted(struct pil_desc *pil,
@@ -198,31 +182,20 @@
static int pil_q6v3_reset_trusted(struct pil_desc *pil)
{
- int ret;
- ret = q6v3_make_proxy_votes(pil->dev);
- if (ret)
- return ret;
return pas_auth_and_reset(PAS_Q6);
}
static int pil_q6v3_shutdown_trusted(struct pil_desc *pil)
{
- int ret;
- struct q6v3_data *drv = dev_get_drvdata(pil->dev);
-
- ret = pas_shutdown(PAS_Q6);
- if (ret)
- return ret;
-
- q6v3_remove_proxy_votes_now(drv);
-
- return 0;
+ return pas_shutdown(PAS_Q6);
}
static struct pil_reset_ops pil_q6v3_ops_trusted = {
.init_image = pil_q6v3_init_image_trusted,
.auth_and_reset = pil_q6v3_reset_trusted,
.shutdown = pil_q6v3_shutdown_trusted,
+ .proxy_vote = pil_q6v3_make_proxy_votes,
+ .proxy_unvote = pil_q6v3_remove_proxy_votes,
};
static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
@@ -255,6 +228,7 @@
desc->name = "q6";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
if (pas_supported(PAS_Q6) > 0) {
desc->ops = &pil_q6v3_ops_trusted;
@@ -264,11 +238,8 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
- INIT_DELAYED_WORK(&drv->work, q6v3_remove_proxy_votes);
-
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil)) {
- flush_delayed_work_sync(&drv->work);
return PTR_ERR(drv->pil);
}
return 0;
@@ -278,7 +249,6 @@
{
struct q6v3_data *drv = platform_get_drvdata(pdev);
msm_pil_unregister(drv->pil);
- flush_delayed_work_sync(&drv->work);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index b689846..b6ea03b 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -19,7 +19,6 @@
#include <linux/elf.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/workqueue.h>
#include <linux/clk.h>
#include <mach/msm_bus.h>
@@ -29,8 +28,6 @@
#include "pil-q6v4.h"
#include "scm-pas.h"
-#define PROXY_VOTE_TIMEOUT 10000
-
#define QDSP6SS_RST_EVB 0x0
#define QDSP6SS_RESET 0x04
#define QDSP6SS_STRAP_TCM 0x1C
@@ -70,7 +67,6 @@
struct regulator *pll_supply;
bool vreg_enabled;
struct clk *xo;
- struct delayed_work work;
struct pil_device *pil;
};
@@ -83,24 +79,23 @@
return 0;
}
-static int pil_q6v4_make_proxy_votes(struct device *dev)
+static int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
{
- struct q6v4_data *drv = dev_get_drvdata(dev);
+ const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
int ret;
ret = clk_prepare_enable(drv->xo);
if (ret) {
- dev_err(dev, "Failed to enable XO\n");
+ dev_err(pil->dev, "Failed to enable XO\n");
goto err;
}
if (drv->pll_supply) {
ret = regulator_enable(drv->pll_supply);
if (ret) {
- dev_err(dev, "Failed to enable pll supply\n");
+ dev_err(pil->dev, "Failed to enable pll supply\n");
goto err_regulator;
}
}
- schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
return 0;
err_regulator:
clk_disable_unprepare(drv->xo);
@@ -108,20 +103,14 @@
return ret;
}
-static void pil_q6v4_remove_proxy_votes(struct work_struct *work)
+static void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
{
- struct q6v4_data *drv = container_of(work, struct q6v4_data, work.work);
+ const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
if (drv->pll_supply)
regulator_disable(drv->pll_supply);
clk_disable_unprepare(drv->xo);
}
-static void pil_q6v4_remove_proxy_votes_now(struct device *dev)
-{
- struct q6v4_data *drv = dev_get_drvdata(dev);
- flush_delayed_work(&drv->work);
-}
-
static int pil_q6v4_power_up(struct device *dev)
{
int err;
@@ -192,14 +181,10 @@
static int pil_q6v4_reset(struct pil_desc *pil)
{
- u32 reg, err = 0;
+ u32 reg, err;
const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
- err = pil_q6v4_make_proxy_votes(pil->dev);
- if (err)
- return err;
-
err = pil_q6v4_power_up(pil->dev);
if (err)
return err;
@@ -295,8 +280,6 @@
drv->vreg_enabled = false;
}
- pil_q6v4_remove_proxy_votes_now(pil->dev);
-
return 0;
}
@@ -304,6 +287,8 @@
.init_image = pil_q6v4_init_image,
.auth_and_reset = pil_q6v4_reset,
.shutdown = pil_q6v4_shutdown,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
};
static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
@@ -318,10 +303,6 @@
const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
int err;
- err = pil_q6v4_make_proxy_votes(pil->dev);
- if (err)
- return err;
-
err = pil_q6v4_power_up(pil->dev);
if (err)
return err;
@@ -351,8 +332,6 @@
drv->vreg_enabled = false;
}
- pil_q6v4_remove_proxy_votes_now(pil->dev);
-
return ret;
}
@@ -360,6 +339,8 @@
.init_image = pil_q6v4_init_image_trusted,
.auth_and_reset = pil_q6v4_reset_trusted,
.shutdown = pil_q6v4_shutdown_trusted,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
};
static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
@@ -395,7 +376,7 @@
if (!desc)
return -ENOMEM;
- drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+ drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
if (IS_ERR(drv->pll_supply)) {
drv->pll_supply = NULL;
} else {
@@ -416,6 +397,7 @@
desc->depends_on = pdata->depends;
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
if (pas_supported(pdata->pas_id) > 0) {
desc->ops = &pil_q6v4_ops_trusted;
@@ -425,7 +407,7 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
- drv->vreg = regulator_get(&pdev->dev, "core_vdd");
+ drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
if (IS_ERR(drv->vreg)) {
ret = PTR_ERR(drv->vreg);
goto err;
@@ -434,9 +416,8 @@
drv->xo = clk_get(&pdev->dev, "xo");
if (IS_ERR(drv->xo)) {
ret = PTR_ERR(drv->xo);
- goto err_xo;
+ goto err;
}
- INIT_DELAYED_WORK(&drv->work, pil_q6v4_remove_proxy_votes);
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil)) {
@@ -445,22 +426,15 @@
}
return 0;
err_pil:
- flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
-err_xo:
- regulator_put(drv->vreg);
err:
- regulator_put(drv->pll_supply);
return ret;
}
static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
{
struct q6v4_data *drv = platform_get_drvdata(pdev);
- flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
- regulator_put(drv->vreg);
- regulator_put(drv->pll_supply);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 24a78f0..ecbbcb9 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -19,17 +19,13 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
#include <linux/clk.h>
-#include <linux/wakelock.h>
#include <mach/msm_iomap.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
-#define PROXY_VOTE_TIMEOUT 10000
-
#define RIVA_PMU_A2XB_CFG 0xB8
#define RIVA_PMU_A2XB_CFG_EN BIT(0)
@@ -84,32 +80,32 @@
void __iomem *base;
unsigned long start_addr;
struct clk *xo;
- bool use_cxo;
- struct delayed_work work;
struct regulator *pll_supply;
struct pil_device *pil;
- struct wake_lock wlock;
};
-static int pil_riva_make_proxy_votes(struct device *dev)
+static bool cxo_is_needed(struct riva_data *drv)
{
- struct riva_data *drv = dev_get_drvdata(dev);
+ u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+ return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+ != RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
+static int pil_riva_make_proxy_vote(struct pil_desc *pil)
+{
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
int ret;
- wake_lock(&drv->wlock);
ret = regulator_enable(drv->pll_supply);
if (ret) {
- dev_err(dev, "failed to enable pll supply\n");
+ dev_err(pil->dev, "failed to enable pll supply\n");
goto err;
}
- if (drv->use_cxo) {
- ret = clk_prepare_enable(drv->xo);
- if (ret) {
- dev_err(dev, "failed to enable xo\n");
- goto err_clk;
- }
+ ret = clk_prepare_enable(drv->xo);
+ if (ret) {
+ dev_err(pil->dev, "failed to enable xo\n");
+ goto err_clk;
}
- schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
return 0;
err_clk:
regulator_disable(drv->pll_supply);
@@ -117,19 +113,11 @@
return ret;
}
-static void pil_riva_remove_proxy_votes(struct work_struct *work)
+static void pil_riva_remove_proxy_vote(struct pil_desc *pil)
{
- struct riva_data *drv = container_of(work, struct riva_data, work.work);
+ struct riva_data *drv = dev_get_drvdata(pil->dev);
regulator_disable(drv->pll_supply);
- if (drv->use_cxo)
- clk_disable_unprepare(drv->xo);
- wake_unlock(&drv->wlock);
-}
-
-static void pil_riva_remove_proxy_votes_now(struct device *dev)
-{
- struct riva_data *drv = dev_get_drvdata(dev);
- flush_delayed_work(&drv->work);
+ clk_disable_unprepare(drv->xo);
}
static int pil_riva_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -141,45 +129,25 @@
return 0;
}
-static bool cxo_is_needed(struct riva_data *drv)
-{
- u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
- return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
- != RIVA_PMU_CFG_IRIS_XO_MODE_48;
-}
-
static int pil_riva_reset(struct pil_desc *pil)
{
u32 reg, sel;
struct riva_data *drv = dev_get_drvdata(pil->dev);
void __iomem *base = drv->base;
unsigned long start_addr = drv->start_addr;
- int ret;
+ bool use_cxo = cxo_is_needed(drv);
- ret = clk_prepare_enable(drv->xo);
- if (ret)
- return ret;
/* Enable A2XB bridge */
reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
reg |= RIVA_PMU_A2XB_CFG_EN;
writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
- drv->use_cxo = cxo_is_needed(drv);
- ret = pil_riva_make_proxy_votes(pil->dev);
- if (ret) {
- reg &= ~RIVA_PMU_A2XB_CFG_EN;
- writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
- mb();
- clk_disable_unprepare(drv->xo);
- return ret;
- }
-
/* Program PLL 13 to 960 MHz */
reg = readl_relaxed(RIVA_PLL_MODE);
reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
writel_relaxed(reg, RIVA_PLL_MODE);
- if (drv->use_cxo)
+ if (use_cxo)
writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
else
writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
@@ -189,7 +157,7 @@
reg = readl_relaxed(RIVA_PLL_MODE);
reg &= ~(PLL_MODE_REF_XO_SEL);
- reg |= drv->use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+ reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
writel_relaxed(reg, RIVA_PLL_MODE);
/* Enable PLL 13 */
@@ -254,7 +222,6 @@
/* Take cCPU out of reset */
reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
- clk_disable_unprepare(drv->xo);
return 0;
}
@@ -263,11 +230,7 @@
{
struct riva_data *drv = dev_get_drvdata(pil->dev);
u32 reg;
- int ret;
- ret = clk_prepare_enable(drv->xo);
- if (ret)
- return ret;
/* Put cCPU and cCPU clock into reset */
reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
@@ -286,9 +249,6 @@
writel_relaxed(0, RIVA_RESET);
mb();
- clk_disable_unprepare(drv->xo);
- pil_riva_remove_proxy_votes_now(pil->dev);
-
return 0;
}
@@ -296,6 +256,8 @@
.init_image = pil_riva_init_image,
.auth_and_reset = pil_riva_reset,
.shutdown = pil_riva_shutdown,
+ .proxy_vote = pil_riva_make_proxy_vote,
+ .proxy_unvote = pil_riva_remove_proxy_vote,
};
static int pil_riva_init_image_trusted(struct pil_desc *pil,
@@ -306,39 +268,20 @@
static int pil_riva_reset_trusted(struct pil_desc *pil)
{
- struct riva_data *drv = dev_get_drvdata(pil->dev);
- int ret;
-
- ret = clk_prepare_enable(drv->xo);
- if (ret)
- return ret;
- /* Proxy-vote for resources RIVA needs */
- ret = pil_riva_make_proxy_votes(pil->dev);
- if (!ret)
- ret = pas_auth_and_reset(PAS_RIVA);
- clk_disable_unprepare(drv->xo);
- return ret;
+ return pas_auth_and_reset(PAS_RIVA);
}
static int pil_riva_shutdown_trusted(struct pil_desc *pil)
{
- int ret;
- struct riva_data *drv = dev_get_drvdata(pil->dev);
-
- ret = clk_prepare_enable(drv->xo);
- if (ret)
- return ret;
- ret = pas_shutdown(PAS_RIVA);
- pil_riva_remove_proxy_votes_now(pil->dev);
- clk_disable_unprepare(drv->xo);
-
- return ret;
+ return pas_shutdown(PAS_RIVA);
}
static struct pil_reset_ops pil_riva_ops_trusted = {
.init_image = pil_riva_init_image_trusted,
.auth_and_reset = pil_riva_reset_trusted,
.shutdown = pil_riva_shutdown_trusted,
+ .proxy_vote = pil_riva_make_proxy_vote,
+ .proxy_unvote = pil_riva_remove_proxy_vote,
};
static int __devinit pil_riva_probe(struct platform_device *pdev)
@@ -365,7 +308,7 @@
if (!desc)
return -ENOMEM;
- drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+ drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
if (IS_ERR(drv->pll_supply)) {
dev_err(&pdev->dev, "failed to get pll supply\n");
return PTR_ERR(drv->pll_supply);
@@ -389,6 +332,7 @@
desc->name = "wcnss";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
if (pas_supported(PAS_RIVA) > 0) {
desc->ops = &pil_riva_ops_trusted;
@@ -403,8 +347,6 @@
ret = PTR_ERR(drv->xo);
goto err;
}
- wake_lock_init(&drv->wlock, WAKE_LOCK_SUSPEND, "riva-wlock");
- INIT_DELAYED_WORK(&drv->work, pil_riva_remove_proxy_votes);
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil)) {
@@ -413,11 +355,8 @@
}
return 0;
err_register:
- flush_delayed_work_sync(&drv->work);
- wake_lock_destroy(&drv->wlock);
clk_put(drv->xo);
err:
- regulator_put(drv->pll_supply);
return ret;
}
@@ -425,10 +364,7 @@
{
struct riva_data *drv = platform_get_drvdata(pdev);
msm_pil_unregister(drv->pil);
- flush_delayed_work_sync(&drv->work);
- wake_lock_destroy(&drv->wlock);
clk_put(drv->xo);
- regulator_put(drv->pll_supply);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-vidc.c b/arch/arm/mach-msm/pil-vidc.c
new file mode 100644
index 0000000..ceb9bcd
--- /dev/null
+++ b/arch/arm/mach-msm/pil-vidc.c
@@ -0,0 +1,146 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+struct vidc_data {
+ struct clk *smmu_iface;
+ struct clk *core;
+ struct pil_device *pil;
+};
+
+static int pil_vidc_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size)
+{
+ return pas_init_image(PAS_VIDC, metadata, size);
+}
+
+static int pil_vidc_reset(struct pil_desc *pil)
+{
+ int ret;
+ struct vidc_data *drv = dev_get_drvdata(pil->dev);
+
+ ret = clk_prepare_enable(drv->smmu_iface);
+ if (ret)
+ goto err_smmu;
+ ret = clk_prepare_enable(drv->core);
+ if (ret)
+ goto err_core;
+ ret = pas_auth_and_reset(PAS_VIDC);
+
+ clk_disable_unprepare(drv->core);
+err_core:
+ clk_disable_unprepare(drv->smmu_iface);
+err_smmu:
+ return ret;
+}
+
+static int pil_vidc_shutdown(struct pil_desc *pil)
+{
+ return pas_shutdown(PAS_VIDC);
+}
+
+static struct pil_reset_ops pil_vidc_ops = {
+ .init_image = pil_vidc_init_image,
+ .auth_and_reset = pil_vidc_reset,
+ .shutdown = pil_vidc_shutdown,
+};
+
+static int __devinit pil_vidc_driver_probe(struct platform_device *pdev)
+{
+ struct pil_desc *desc;
+ struct vidc_data *drv;
+ int ret;
+
+ if (pas_supported(PAS_VIDC) < 0)
+ return -ENOSYS;
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+ drv->smmu_iface = clk_get(&pdev->dev, "smmu_iface_clk");
+ if (IS_ERR(drv->smmu_iface)) {
+ dev_err(&pdev->dev, "failed to get smmu interface clock\n");
+ ret = PTR_ERR(drv->smmu_iface);
+ goto err_smmu;
+ }
+ drv->core = clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(drv->core)) {
+ dev_err(&pdev->dev, "failed to get core clock\n");
+ ret = PTR_ERR(drv->core);
+ goto err_core;
+ }
+
+ desc->name = "vidc";
+ desc->dev = &pdev->dev;
+ desc->ops = &pil_vidc_ops;
+ desc->owner = THIS_MODULE;
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil)) {
+ ret = PTR_ERR(drv->pil);
+ goto err_register;
+ }
+ return 0;
+
+err_register:
+ clk_put(drv->core);
+err_core:
+ clk_put(drv->smmu_iface);
+err_smmu:
+ return ret;
+}
+
+static int __devexit pil_vidc_driver_exit(struct platform_device *pdev)
+{
+ struct vidc_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
+ clk_put(drv->smmu_iface);
+ clk_put(drv->core);
+ return 0;
+}
+
+static struct platform_driver pil_vidc_driver = {
+ .probe = pil_vidc_driver_probe,
+ .remove = __devexit_p(pil_vidc_driver_exit),
+ .driver = {
+ .name = "pil_vidc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_vidc_init(void)
+{
+ return platform_driver_register(&pil_vidc_driver);
+}
+module_init(pil_vidc_init);
+
+static void __exit pil_vidc_exit(void)
+{
+ platform_driver_unregister(&pil_vidc_driver);
+}
+module_exit(pil_vidc_exit);
+
+MODULE_DESCRIPTION("Support for secure booting vidc images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 9257f2f..b0fbebb 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1182,6 +1182,17 @@
pmd[0] = __pmd(pmdval);
pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+ msm_saved_state_phys =
+ allocate_contiguous_ebi_nomap(CPU_SAVED_STATE_SIZE *
+ num_possible_cpus(), 4);
+ if (!msm_saved_state_phys)
+ return -ENOMEM;
+ msm_saved_state = ioremap_nocache(msm_saved_state_phys,
+ CPU_SAVED_STATE_SIZE *
+ num_possible_cpus());
+ if (!msm_saved_state)
+ return -ENOMEM;
+
/* It is remotely possible that the code in msm_pm_collapse_exit()
* which turns on the MMU with this mapping is in the
* next even-numbered megabyte beyond the
@@ -1191,6 +1202,8 @@
pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
flush_pmd_entry(pmd);
msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+ clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+ virt_to_phys(&msm_pm_pc_pgd));
ret = request_irq(rpm_cpu0_wakeup_irq,
msm_pm_rpm_wakeup_interrupt, IRQF_TRIGGER_RISING,
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index f65b8ad..b5f0fdc 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -28,6 +28,14 @@
static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
static void (*msm_pm_boot_after_pc)(unsigned int cpu);
+static void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address)
+{
+ msm_pm_boot_vector[cpu] = address;
+ clean_caches((unsigned long)&msm_pm_boot_vector[cpu],
+ sizeof(msm_pm_boot_vector[cpu]),
+ virt_to_phys(&msm_pm_boot_vector[cpu]));
+}
+
#ifdef CONFIG_MSM_SCM
static int __init msm_pm_tz_boot_init(void)
{
@@ -102,6 +110,7 @@
{
int ret = 0;
unsigned long entry;
+ void __iomem *warm_boot_ptr;
switch (pdata->mode) {
case MSM_PM_BOOT_CONFIG_TZ:
@@ -124,16 +133,19 @@
= msm_pm_config_rst_vector_after_pc;
break;
case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
- /*
- * Set the boot remap address and enable remapping of
- * reset vector
- */
- if (!pdata->p_addr || !pdata->v_addr)
- return -ENODEV;
-
- ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
-
if (!cpu_is_msm8625()) {
+ void *remapped;
+
+ /*
+ * Set the boot remap address and enable remapping of
+ * reset vector
+ */
+ if (!pdata->p_addr || !pdata->v_addr)
+ return -ENODEV;
+
+ remapped = ioremap_nocache(pdata->p_addr, SZ_8);
+ ret = msm_pm_boot_reset_vector_init(remapped);
+
__raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
pdata->v_addr);
@@ -142,6 +154,10 @@
msm_pm_boot_after_pc
= msm_pm_config_rst_vector_after_pc;
} else {
+ warm_boot_ptr = ioremap_nocache(
+ MSM8625_WARM_BOOT_PHYS, SZ_64);
+ ret = msm_pm_boot_reset_vector_init(warm_boot_ptr);
+
entry = virt_to_phys(msm_pm_boot_entry);
/* Below sequence is a work around for cores
@@ -159,8 +175,8 @@
/* Here upper 16bits[16:31] used by CORE1
* lower 16bits[0:15] used by CORE0
*/
- entry = (pdata->p_addr) |
- ((pdata->p_addr & 0xFFFF0000) >> 16);
+ entry = (MSM8625_WARM_BOOT_PHYS |
+ ((MSM8625_WARM_BOOT_PHYS & 0xFFFF0000) >> 16));
/* write 'entry' to boot remapper register */
__raw_writel(entry, (pdata->v_addr +
@@ -175,7 +191,6 @@
__raw_writel(readl_relaxed(pdata->v_addr +
MPA5_CFG_CTL_REG) | BIT(26),
pdata->v_addr + MPA5_CFG_CTL_REG);
-
msm_pm_boot_before_pc = msm_pm_write_boot_vector;
}
break;
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index c66c809..4f3c7e4 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -28,6 +28,7 @@
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/tick.h>
#include <linux/memory.h>
#ifdef CONFIG_HAS_WAKELOCK
#include <linux/wakelock.h>
@@ -49,6 +50,7 @@
#include <mach/msm_migrate_pages.h>
#endif
#include <mach/socinfo.h>
+#include <asm/smp_scu.h>
#include "smd_private.h"
#include "smd_rpcrouter.h"
@@ -63,6 +65,7 @@
#include "spm.h"
#include "sirc.h"
#include "pm-boot.h"
+#define MSM_CORE1_RESET 0xA8600590
/******************************************************************************
* Debug Definitions
@@ -478,10 +481,78 @@
}
/*
+ * Program the top csr from core0 context to put the
+ * core1 into GDFS, as core1 is not running yet.
+ */
+static void configure_top_csr(void)
+{
+ void __iomem *base_ptr;
+ unsigned int value = 0;
+
+ base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+ if (!base_ptr)
+ return;
+
+ /* bring the core1 out of reset */
+ __raw_writel(0x3, base_ptr);
+ mb();
+ /*
+ * override DBGNOPOWERDN and program the GDFS
+ * count val
+ */
+
+ __raw_writel(0x00030002, (MSM_CFG_CTL_BASE + 0x38));
+ mb();
+
+ /* Initialize the SPM0 and SPM1 registers */
+ msm_spm_reinit();
+
+ /* enable TCSR for core1 */
+ value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+ value |= BIT(22);
+ __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+ mb();
+
+ /* set reset bit for SPM1 */
+ value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+ value |= BIT(20);
+ __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+ mb();
+
+ /* set CLK_OFF bit */
+ value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+ value |= BIT(18);
+ __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+ mb();
+
+ /* set clamps bit */
+ value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+ value |= BIT(21);
+ __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+ mb();
+
+ /* set power_up bit */
+ value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+ value |= BIT(19);
+ __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+ mb();
+
+ /* Disable TSCR for core0 */
+ value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
+ value &= ~BIT(22);
+ __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
+ mb();
+ __raw_writel(0x0, base_ptr);
+ mb();
+ iounmap(base_ptr);
+}
+
+/*
* Clear hardware registers after Apps powers up.
*/
static void msm_pm_config_hw_after_power_up(void)
{
+
if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
__raw_writel(0, APPS_SECOP);
mb();
@@ -493,6 +564,18 @@
mb();
__raw_writel(0, APPS_CLK_SLEEP_EN);
mb();
+
+ if (cpu_is_msm8625() && power_collapsed) {
+ /*
+ * enable the SCU while coming out of power
+ * collapse.
+ */
+ scu_enable(MSM_SCU_BASE);
+ /*
+ * Program the top csr to put the core1 into GDFS.
+ */
+ configure_top_csr();
+ }
}
}
@@ -1006,6 +1089,8 @@
unsigned long saved_acpuclk_rate;
int collapsed = 0;
int ret;
+ int val;
+ int modem_early_exit = 0;
MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
@@ -1111,8 +1196,25 @@
#endif
collapsed = msm_pm_collapse();
- if (collapsed)
- power_collapsed = 1;
+
+ /*
+ * TBD: Currently recognise the MODEM early exit
+ * path by reading the MPA5_GDFS_CNT_VAL register.
+ */
+ if (cpu_is_msm8625()) {
+ /*
+ * on system reset default value of MPA5_GDFS_CNT_VAL
+ * is = 0xFF, later power driver reprogrammed this
+ * as: 0x000300FF. Currently based on the value of
+ * MPA5_GDFS_CNT_VAL register decide whether it is
+ * a modem early exit are not.
+ */
+ val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
+ if (val != 0xFF)
+ modem_early_exit = 1;
+ else
+ power_collapsed = 1;
+ }
#ifdef CONFIG_CACHE_L2X0
l2x0_resume(collapsed);
@@ -1173,7 +1275,7 @@
}
/* Sanity check */
- if (collapsed) {
+ if (collapsed && !modem_early_exit) {
BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
} else {
BUG_ON(!(state_grps[0].value_read &
@@ -1359,7 +1461,7 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
WARN_ON(ret);
- return 0;
+ return !collapsed;
}
/*
@@ -1415,17 +1517,15 @@
bool allow[MSM_PM_SLEEP_MODE_NR];
uint32_t sleep_limit = SLEEP_LIMIT_NONE;
- int latency_qos;
int64_t timer_expiration;
-
- int low_power;
+ int latency_qos;
int ret;
int i;
unsigned int cpu;
#ifdef CONFIG_MSM_IDLE_STATS
int64_t t1;
- static int64_t t2;
+ static DEFINE_PER_CPU(int64_t, t2);
int exit_stat;
#endif
@@ -1435,15 +1535,14 @@
cpu = smp_processor_id();
latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
- timer_expiration = msm_timer_enter_idle();
+ /* get the next timer expiration */
+ timer_expiration = ktime_to_ns(tick_nohz_get_sleep_length());
#ifdef CONFIG_MSM_IDLE_STATS
t1 = ktime_to_ns(ktime_get());
- msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
+ msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - __get_cpu_var(t2));
msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
-
exit_stat = MSM_PM_STAT_IDLE_SPIN;
- low_power = 0;
#endif
for (i = 0; i < ARRAY_SIZE(allow); i++)
@@ -1499,10 +1598,16 @@
if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+ /* Sync the timer with SCLK, it is needed only for modem
+ * assissted pollapse case.
+ */
+ int64_t next_timer_exp = msm_timer_enter_idle();
uint32_t sleep_delay;
+ bool low_power = false;
sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
- timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+ next_timer_exp, MSM_PM_SLEEP_TICK_LIMIT);
+
if (sleep_delay == 0) /* 0 would mean infinite time */
sleep_delay = 1;
@@ -1517,6 +1622,7 @@
ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
+ msm_timer_exit_idle(low_power);
#ifdef CONFIG_MSM_IDLE_STATS
if (ret)
@@ -1528,7 +1634,6 @@
#endif
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
ret = msm_pm_power_collapse_standalone(true);
- low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = ret ?
MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
@@ -1539,30 +1644,25 @@
if (ret)
while (!msm_pm_irq_extns->irq_pending())
udelay(1);
- low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
#endif
} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
msm_pm_swfi(false);
- low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_WFI;
#endif
} else {
while (!msm_pm_irq_extns->irq_pending())
udelay(1);
- low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_SPIN;
#endif
}
- msm_timer_exit_idle(low_power);
-
#ifdef CONFIG_MSM_IDLE_STATS
- t2 = ktime_to_ns(ktime_get());
- msm_pm_add_stat(exit_stat, t2 - t1);
+ __get_cpu_var(t2) = ktime_to_ns(ktime_get());
+ msm_pm_add_stat(exit_stat, __get_cpu_var(t2) - t1);
#endif
}
@@ -1781,6 +1881,7 @@
unsigned int cpu;
#endif
int ret;
+ int val;
#ifdef CONFIG_CPU_V7
pgd_t *pc_pgd;
pmd_t *pmd;
@@ -1798,6 +1899,17 @@
pmd[0] = __pmd(pmdval);
pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+ msm_saved_state_phys =
+ allocate_contiguous_ebi_nomap(CPU_SAVED_STATE_SIZE *
+ num_possible_cpus(), 4);
+ if (!msm_saved_state_phys)
+ return -ENOMEM;
+ msm_saved_state = ioremap_nocache(msm_saved_state_phys,
+ CPU_SAVED_STATE_SIZE *
+ num_possible_cpus());
+ if (!msm_saved_state)
+ return -ENOMEM;
+
/* It is remotely possible that the code in msm_pm_collapse_exit()
* which turns on the MMU with this mapping is in the
* next even-numbered megabyte beyond the
@@ -1807,6 +1919,8 @@
pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
flush_pmd_entry(pmd);
msm_pm_pc_pgd = virt_to_phys(pc_pgd);
+ clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
+ virt_to_phys(&msm_pm_pc_pgd));
#endif
pm_power_off = msm_pm_power_off;
@@ -1831,6 +1945,19 @@
return ret;
}
+ if (cpu_is_msm8625()) {
+ target_type = TARGET_IS_8625;
+ clean_caches((unsigned long)&target_type, sizeof(target_type),
+ virt_to_phys(&target_type));
+
+ /* Override the DBGNOPOWERDN for each cpu in
+ * MPA5_GDFS_CNT_VAL register
+ */
+ val = __raw_readl((MSM_CFG_CTL_BASE + 0x38));
+ val = val | 0x00030000;
+ __raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+ }
+
#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
/* The wakeup_reason field is overloaded during initialization time
to signal Modem that Apps will control the low power modes of
@@ -1842,7 +1969,6 @@
BUG_ON(msm_pm_modes == NULL);
- atomic_set(&msm_pm_init_done, 1);
suspend_set_ops(&msm_pm_ops);
msm_pm_mode_sysfs_add();
@@ -1898,6 +2024,9 @@
stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
}
+
+ atomic_set(&msm_pm_init_done, 1);
+
d_entry = create_proc_entry("msm_pm_stats",
S_IRUGO | S_IWUSR | S_IWGRP, NULL);
if (d_entry) {
diff --git a/arch/arm/mach-msm/proccomm-regulator.c b/arch/arm/mach-msm/proccomm-regulator.c
index ba10d38..fff3a11 100644
--- a/arch/arm/mach-msm/proccomm-regulator.c
+++ b/arch/arm/mach-msm/proccomm-regulator.c
@@ -196,7 +196,7 @@
static struct regulator_dev *__devinit create_proccomm_rdev(
struct proccomm_regulator_info *info, struct device *parent)
{
- char *name;
+ const char *name;
struct proccomm_regulator_drvdata *d;
struct regulator_dev *rdev;
int rc = 0;
@@ -247,7 +247,7 @@
d->negative = info->negative;
d->rdesc.n_voltages = info->n_voltages;
- rdev = regulator_register(&d->rdesc, parent, &info->init_data, d);
+ rdev = regulator_register(&d->rdesc, parent, &info->init_data, d, NULL);
if (IS_ERR(rdev)) {
rc = PTR_ERR(rdev);
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index dab53dc..8760e443 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -73,7 +73,7 @@
/* Size must be power of 2 */
#define MAX_BUF 2
-#define BUFSZ (524288)
+#define BUFSZ (1024000)
#define AUDDEC_DEC_PCM 0
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index b5f071f..2403c02 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -371,14 +371,11 @@
mutex_lock(&q6.lock);
if (q6.state == APR_Q6_NOIMG) {
q6.pil = pil_get("q6");
- if (!q6.pil) {
- pr_err("APR: Unable to load q6 image\n");
+ if (IS_ERR(q6.pil)) {
+ rc = PTR_ERR(q6.pil);
+ pr_err("APR: Unable to load q6 image, error:%d\n", rc);
mutex_unlock(&q6.lock);
- /* Return failure if not intended for simulator */
- if (!machine_is_apq8064_sim()) {
- pr_debug("APR: Not apq8064 sim\n");
- return svc;
- }
+ return svc;
}
q6.state = APR_Q6_LOADED;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 75af881..ee32b80 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -69,7 +69,7 @@
/* Configure PCM output block */
rc = q6asm_enc_cfg_blk_pcm(audio->ac,
0, /*native sampling rate*/
- (audio->pcm_cfg.channel_count <= 2) ? 0 : 2);
+ 0 /*native channel count*/);
if (rc < 0) {
pr_err("pcm output block config failed\n");
break;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile b/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile
index 540119b..0be1303 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/Makefile
@@ -1,2 +1,2 @@
-obj-y += q6usm.o usf.o
+obj-y += q6usm.o usf.o usfcdev.o
EXTRA_CFLAGS += -I$(src)/..
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 64f70c5..b4a0a7f 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -24,9 +24,10 @@
#include <sound/apr_audio.h>
#include <mach/qdsp6v2/usf.h>
#include "q6usm.h"
+#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "1.3"
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (3*HZ) /* 3 sec */
@@ -111,6 +112,10 @@
struct input_dev *input_if;
/* The event source */
int event_src;
+ /* Bitmap of types of events, conflicting to USF's ones */
+ uint16_t conflicting_event_types;
+ /* Bitmap of types of events from devs, conflicting with USF */
+ uint16_t conflicting_event_filters;
};
/* The MAX number of the supported devices */
@@ -126,6 +131,9 @@
/* The opened devices container */
static int s_opened_devs[MAX_DEVS_NUMBER];
+#define USF_NAME_PREFIX "USF_"
+#define USF_NAME_PREFIX_SIZE 4
+
static void usf_rx_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -316,11 +324,70 @@
return rc;
}
+static bool usf_match(uint16_t event_type_ind, struct input_dev *dev)
+{
+ bool rc = false;
+
+ rc = (event_type_ind < MAX_EVENT_TYPE_NUM) &&
+ ((dev->name == NULL) ||
+ strncmp(dev->name, USF_NAME_PREFIX, USF_NAME_PREFIX_SIZE));
+ pr_debug("%s: name=[%s]; rc=%d\n",
+ __func__, dev->name, rc);
+
+ return rc;
+}
+
+static bool usf_register_conflicting_events(uint16_t event_types)
+{
+ bool rc = true;
+ uint16_t ind = 0;
+ uint16_t mask = 1;
+
+ for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+ if (event_types & mask) {
+ rc = usfcdev_register(ind, usf_match);
+ if (!rc)
+ break;
+ }
+ mask = mask << 1;
+ }
+
+ return rc;
+}
+
+static void usf_unregister_conflicting_events(uint16_t event_types)
+{
+ uint16_t ind = 0;
+ uint16_t mask = 1;
+
+ for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+ if (event_types & mask)
+ usfcdev_unregister(ind);
+ mask = mask << 1;
+ }
+}
+
+static void usf_set_event_filters(struct usf_type *usf, uint16_t event_filters)
+{
+ uint16_t ind = 0;
+ uint16_t mask = 1;
+
+ if (usf->conflicting_event_filters != event_filters) {
+ for (ind = 0; ind < MAX_EVENT_TYPE_NUM; ++ind) {
+ if (usf->conflicting_event_types & mask)
+ usfcdev_set_filter(ind, event_filters&mask);
+ mask = mask << 1;
+ }
+ usf->conflicting_event_filters = event_filters;
+ }
+}
+
static int register_input_device(struct usf_type *usf_info,
struct us_input_info_type *input_info)
{
int rc = 0;
struct input_dev *input_dev = NULL;
+ bool ret = true;
if ((usf_info == NULL) ||
(input_info == NULL) ||
@@ -417,6 +484,11 @@
usf_info->event_types = input_info->event_types;
pr_debug("%s: input device[%s] was registered\n",
__func__, input_dev->name);
+ ret = usf_register_conflicting_events(
+ input_info->conflicting_event_types);
+ if (ret)
+ usf_info->conflicting_event_types =
+ input_info->conflicting_event_types;
}
return rc;
@@ -826,6 +898,7 @@
}
if (!usf_xx->user_upd_info_na) {
+ usf_set_event_filters(usf, upd_tx_info.event_filters);
handle_input_event(usf,
upd_tx_info.event_counter,
upd_tx_info.event);
@@ -963,16 +1036,23 @@
return rc;
} /* usf_set_rx_update */
+static void usf_release_input(struct usf_type *usf)
+{
+ if (usf->input_if != NULL) {
+ usf_unregister_conflicting_events(
+ usf->conflicting_event_types);
+ usf->conflicting_event_types = 0;
+ input_unregister_device(usf->input_if);
+ usf->input_if = NULL;
+ pr_debug("%s input_unregister_device\n", __func__);
+ }
+} /* usf_release_input */
+
static int usf_stop_tx(struct usf_type *usf)
{
struct usf_xx_type *usf_xx = &usf->usf_tx;
- if (usf->input_if != NULL) {
- input_unregister_device(usf->input_if);
- usf->input_if = NULL;
- pr_debug("%s input_unregister_device",
- __func__);
- }
+ usf_release_input(usf);
usf_disable(usf_xx);
return 0;
@@ -1225,18 +1305,13 @@
return 0;
}
-
static int usf_release(struct inode *inode, struct file *file)
{
struct usf_type *usf = file->private_data;
pr_debug("%s: release entry\n", __func__);
- if (usf->input_if != NULL) {
- input_unregister_device(usf->input_if);
- usf->input_if = NULL;
- pr_debug("%s input_unregister_device\n", __func__);
- }
+ usf_release_input(usf);
usf_disable(&usf->usf_tx);
usf_disable(&usf->usf_rx);
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
new file mode 100644
index 0000000..b99a9b0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.c
@@ -0,0 +1,236 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/sched.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include "usfcdev.h"
+
+struct usfcdev_event {
+ bool (*match_cb)(uint16_t, struct input_dev *dev);
+ bool registered_event;
+ bool filter;
+};
+static struct usfcdev_event s_usfcdev_events[MAX_EVENT_TYPE_NUM];
+
+static bool usfcdev_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value);
+static bool usfcdev_match(struct input_handler *handler,
+ struct input_dev *dev);
+static int usfcdev_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id);
+static void usfcdev_disconnect(struct input_handle *handle);
+
+static const struct input_device_id usfc_tsc_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+ .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, usfc_tsc_ids);
+
+static struct input_handler s_usfc_handlers[MAX_EVENT_TYPE_NUM] = {
+ { /* TSC handler */
+ .filter = usfcdev_filter,
+ .match = usfcdev_match,
+ .connect = usfcdev_connect,
+ .disconnect = usfcdev_disconnect,
+ /* .minor can be used as index in the container, */
+ /* because .fops isn't supported */
+ .minor = TSC_EVENT_TYPE_IND,
+ .name = "usfc_tsc_handler",
+ .id_table = usfc_tsc_ids,
+ },
+};
+
+/* For each event type, one conflicting device (and handle) is supported */
+static struct input_handle s_usfc_handles[MAX_EVENT_TYPE_NUM] = {
+ { /* TSC handle */
+ .handler = &s_usfc_handlers[TSC_EVENT_TYPE_IND],
+ .name = "usfc_tsc_handle",
+ },
+};
+
+static bool usfcdev_match(struct input_handler *handler, struct input_dev *dev)
+{
+ bool rc = false;
+ int ind = handler->minor;
+
+ pr_debug("%s: name=[%s]; ind=%d\n", __func__, dev->name, ind);
+ if (s_usfcdev_events[ind].registered_event &&
+ s_usfcdev_events[ind].match_cb) {
+ rc = (*s_usfcdev_events[ind].match_cb)((uint16_t)ind, dev);
+ pr_debug("%s: [%s]; rc=%d\n", __func__, dev->name, rc);
+ }
+
+ return rc;
+}
+
+static int usfcdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ int ret = 0;
+ uint16_t ind = handler->minor;
+
+ s_usfc_handles[ind].dev = dev;
+ ret = input_register_handle(&s_usfc_handles[ind]);
+ if (ret) {
+ pr_err("%s: input_register_handle[%d] failed: ret=%d\n",
+ __func__,
+ ind,
+ ret);
+ } else {
+ ret = input_open_device(&s_usfc_handles[ind]);
+ if (ret) {
+ pr_err("%s: input_open_device[%d] failed: ret=%d\n",
+ __func__,
+ ind,
+ ret);
+ input_unregister_handle(&s_usfc_handles[ind]);
+ } else
+ pr_debug("%s: device[%d] is opened\n",
+ __func__,
+ ind);
+ }
+
+ return ret;
+}
+
+static void usfcdev_disconnect(struct input_handle *handle)
+{
+ input_unregister_handle(handle);
+ pr_debug("%s: handle[%d] is disconnect\n",
+ __func__,
+ handle->handler->minor);
+}
+
+static bool usfcdev_filter(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
+{
+ uint16_t ind = (uint16_t)handle->handler->minor;
+
+ pr_debug("%s: event_type=%d; filter=%d\n",
+ __func__,
+ ind,
+ s_usfcdev_events[ind].filter);
+
+ return s_usfcdev_events[ind].filter;
+}
+
+bool usfcdev_register(
+ uint16_t event_type_ind,
+ bool (*match_cb)(uint16_t, struct input_dev *dev))
+{
+ int ret = 0;
+ bool rc = false;
+
+ if ((event_type_ind >= MAX_EVENT_TYPE_NUM) || !match_cb) {
+ pr_err("%s: wrong input: event_type_ind=%d; match_cb=0x%p\n",
+ __func__,
+ event_type_ind,
+ match_cb);
+ return false;
+ }
+
+ if (s_usfcdev_events[event_type_ind].registered_event) {
+ pr_info("%s: handler[%d] was already registered\n",
+ __func__,
+ event_type_ind);
+ return true;
+ }
+
+ s_usfcdev_events[event_type_ind].registered_event = true;
+ s_usfcdev_events[event_type_ind].match_cb = match_cb;
+ s_usfcdev_events[event_type_ind].filter = false;
+ ret = input_register_handler(&s_usfc_handlers[event_type_ind]);
+ if (!ret) {
+ rc = true;
+ pr_debug("%s: handler[%d] was registered\n",
+ __func__,
+ event_type_ind);
+ } else {
+ s_usfcdev_events[event_type_ind].registered_event = false;
+ s_usfcdev_events[event_type_ind].match_cb = NULL;
+ pr_err("%s: handler[%d] registration failed: ret=%d\n",
+ __func__,
+ event_type_ind,
+ ret);
+ }
+
+ return rc;
+}
+
+void usfcdev_unregister(uint16_t event_type_ind)
+{
+ if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+ pr_err("%s: wrong input: event_type_ind=%d\n",
+ __func__,
+ event_type_ind);
+ return;
+ }
+ if (s_usfcdev_events[event_type_ind].registered_event) {
+ input_unregister_handler(&s_usfc_handlers[event_type_ind]);
+ pr_debug("%s: handler[%d] was unregistered\n",
+ __func__,
+ event_type_ind);
+ s_usfcdev_events[event_type_ind].registered_event = false;
+ s_usfcdev_events[event_type_ind].match_cb = NULL;
+ s_usfcdev_events[event_type_ind].filter = false;
+ }
+}
+
+bool usfcdev_set_filter(uint16_t event_type_ind, bool filter)
+{
+ bool rc = true;
+
+ if (event_type_ind >= MAX_EVENT_TYPE_NUM) {
+ pr_err("%s: wrong input: event_type_ind=%d\n",
+ __func__,
+ event_type_ind);
+ return false;
+ }
+
+ if (s_usfcdev_events[event_type_ind].registered_event) {
+ s_usfcdev_events[event_type_ind].filter = filter;
+ pr_debug("%s: event_type[%d]; filter=%d\n",
+ __func__,
+ event_type_ind,
+ filter
+ );
+ } else {
+ pr_err("%s: event_type[%d] isn't registered\n",
+ __func__,
+ event_type_ind);
+ rc = false;
+ }
+
+ return rc;
+}
+
+static int __init usfcdev_init(void)
+{
+ return 0;
+}
+
+device_initcall(usfcdev_init);
+
+MODULE_DESCRIPTION("Handle of events from devices, conflicting with USF");
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.h
new file mode 100644
index 0000000..042b293
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usfcdev.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __USFCDEV_H__
+#define __USFCDEV_H__
+
+#include <linux/input.h>
+
+/* TSC event type index in the containers of the handlers & handles */
+#define TSC_EVENT_TYPE_IND 0
+/* Number of supported event types to be filtered */
+#define MAX_EVENT_TYPE_NUM 1
+
+bool usfcdev_register(
+ uint16_t event_type_ind,
+ bool (*match_cb)(uint16_t, struct input_dev *dev));
+void usfcdev_unregister(uint16_t event_type_ind);
+bool usfcdev_set_filter(uint16_t event_type_ind, bool filter);
+#endif /* __USFCDEV_H__ */
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
index 8b5f8db..96eba26 100644
--- a/arch/arm/mach-msm/qdss-etb.c
+++ b/arch/arm/mach-msm/qdss-etb.c
@@ -318,7 +318,7 @@
return ret;
}
-static void etb_sysfs_exit(void)
+static void __exit etb_sysfs_exit(void)
{
sysfs_remove_file(etb.kobj, &trigger_cntr_attr.attr);
kobject_put(etb.kobj);
@@ -371,7 +371,7 @@
return ret;
}
-static int etb_remove(struct platform_device *pdev)
+static int __devexit etb_remove(struct platform_device *pdev)
{
if (etb.enabled)
etb_disable();
@@ -386,18 +386,23 @@
static struct platform_driver etb_driver = {
.probe = etb_probe,
- .remove = etb_remove,
+ .remove = __devexit_p(etb_remove),
.driver = {
.name = "msm_etb",
},
};
-int __init etb_init(void)
+static int __init etb_init(void)
{
return platform_driver_register(&etb_driver);
}
+module_init(etb_init);
-void etb_exit(void)
+static void __exit etb_exit(void)
{
platform_driver_unregister(&etb_driver);
}
+module_exit(etb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
diff --git a/arch/arm/mach-msm/qdss-etm.c b/arch/arm/mach-msm/qdss-etm.c
index eeb7519..251db45 100644
--- a/arch/arm/mach-msm/qdss-etm.c
+++ b/arch/arm/mach-msm/qdss-etm.c
@@ -156,6 +156,7 @@
bool enabled;
struct wake_lock wake_lock;
struct pm_qos_request_list qos_req;
+ struct qdss_source *src;
struct mutex mutex;
struct device *dev;
struct kobject *kobj;
@@ -339,10 +340,6 @@
goto err;
}
- ret = qdss_clk_enable();
- if (ret)
- goto err;
-
wake_lock(&etm.wake_lock);
/* 1. causes all online cpus to come out of idle PC
* 2. prevents idle PC until save restore flag is enabled atomically
@@ -353,11 +350,10 @@
*/
pm_qos_update_request(&etm.qos_req, 0);
- etb_disable();
- tpiu_disable();
- /* enable ETB first to avoid loosing any trace data */
- etb_enable();
- funnel_enable(0x0, 0x3);
+ ret = qdss_enable(etm.src);
+ if (ret)
+ goto err_qdss;
+
for_each_online_cpu(cpu)
__etm_enable(cpu);
@@ -368,6 +364,10 @@
dev_info(etm.dev, "ETM tracing enabled\n");
return 0;
+
+err_qdss:
+ pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
+ wake_unlock(&etm.wake_lock);
err:
return ret;
}
@@ -407,17 +407,14 @@
for_each_online_cpu(cpu)
__etm_disable(cpu);
- etb_dump();
- etb_disable();
- funnel_disable(0x0, 0x3);
+
+ qdss_disable(etm.src);
etm.enabled = false;
pm_qos_update_request(&etm.qos_req, PM_QOS_DEFAULT_VALUE);
wake_unlock(&etm.wake_lock);
- qdss_clk_disable();
-
dev_info(etm.dev, "ETM tracing disabled\n");
return 0;
err:
@@ -1151,14 +1148,14 @@
return ret;
}
-static void etm_sysfs_exit(void)
+static void __exit etm_sysfs_exit(void)
{
sysfs_remove_group(etm.kobj, &etm_attr_grp);
sysfs_remove_file(etm.kobj, &enabled_attr.attr);
kobject_put(etm.kobj);
}
-static bool etm_arch_supported(uint8_t arch)
+static bool __init etm_arch_supported(uint8_t arch)
{
switch (arch) {
case PFT_ARCH_V1_1:
@@ -1249,6 +1246,12 @@
wake_lock_init(&etm.wake_lock, WAKE_LOCK_SUSPEND, "msm_etm");
pm_qos_add_request(&etm.qos_req, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
+ etm.src = qdss_get("msm_etm");
+ if (IS_ERR(etm.src)) {
+ ret = PTR_ERR(etm.src);
+ goto err_qdssget;
+ }
+
ret = qdss_clk_enable();
if (ret)
goto err_clk;
@@ -1276,6 +1279,8 @@
err_arch:
qdss_clk_disable();
err_clk:
+ qdss_put(etm.src);
+err_qdssget:
pm_qos_remove_request(&etm.qos_req);
wake_lock_destroy(&etm.wake_lock);
mutex_destroy(&etm.mutex);
@@ -1286,11 +1291,12 @@
return ret;
}
-static int etm_remove(struct platform_device *pdev)
+static int __devexit etm_remove(struct platform_device *pdev)
{
if (etm.enabled)
etm_disable();
etm_sysfs_exit();
+ qdss_put(etm.src);
pm_qos_remove_request(&etm.qos_req);
wake_lock_destroy(&etm.wake_lock);
mutex_destroy(&etm.mutex);
@@ -1301,7 +1307,7 @@
static struct platform_driver etm_driver = {
.probe = etm_probe,
- .remove = etm_remove,
+ .remove = __devexit_p(etm_remove),
.driver = {
.name = "msm_etm",
},
@@ -1311,8 +1317,13 @@
{
return platform_driver_register(&etm_driver);
}
+module_init(etm_init);
-void etm_exit(void)
+void __exit etm_exit(void)
{
platform_driver_unregister(&etm_driver);
}
+module_exit(etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Program Flow Trace driver");
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
index 990295b..2d80603 100644
--- a/arch/arm/mach-msm/qdss-funnel.c
+++ b/arch/arm/mach-msm/qdss-funnel.c
@@ -159,7 +159,7 @@
return ret;
}
-static void funnel_sysfs_exit(void)
+static void __exit funnel_sysfs_exit(void)
{
sysfs_remove_file(funnel.kobj, &priority_attr.attr);
kobject_put(funnel.kobj);
@@ -197,7 +197,7 @@
return ret;
}
-static int funnel_remove(struct platform_device *pdev)
+static int __devexit funnel_remove(struct platform_device *pdev)
{
if (funnel.enabled)
funnel_disable(0x0, 0xFF);
@@ -210,18 +210,23 @@
static struct platform_driver funnel_driver = {
.probe = funnel_probe,
- .remove = funnel_remove,
+ .remove = __devexit_p(funnel_remove),
.driver = {
.name = "msm_funnel",
},
};
-int __init funnel_init(void)
+static int __init funnel_init(void)
{
return platform_driver_register(&funnel_driver);
}
+module_init(funnel_init);
-void funnel_exit(void)
+static void __exit funnel_exit(void)
{
platform_driver_unregister(&funnel_driver);
}
+module_exit(funnel_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Funnel driver");
diff --git a/arch/arm/mach-msm/qdss-priv.h b/arch/arm/mach-msm/qdss-priv.h
index b9f3072..f39bc52 100644
--- a/arch/arm/mach-msm/qdss-priv.h
+++ b/arch/arm/mach-msm/qdss-priv.h
@@ -58,15 +58,6 @@
#define BMVAL(val, lsb, msb) ((val & BM(lsb, msb)) >> lsb)
#define BVAL(val, n) ((val & BIT(n)) >> n)
-int etb_init(void);
-void etb_exit(void);
-int tpiu_init(void);
-void tpiu_exit(void);
-int funnel_init(void);
-void funnel_exit(void);
-int etm_init(void);
-void etm_exit(void);
-
void etb_enable(void);
void etb_disable(void);
void etb_dump(void);
diff --git a/arch/arm/mach-msm/qdss-tpiu.c b/arch/arm/mach-msm/qdss-tpiu.c
index 4481a0a..fa15635 100644
--- a/arch/arm/mach-msm/qdss-tpiu.c
+++ b/arch/arm/mach-msm/qdss-tpiu.c
@@ -108,7 +108,7 @@
return ret;
}
-static int tpiu_remove(struct platform_device *pdev)
+static int __devexit tpiu_remove(struct platform_device *pdev)
{
if (tpiu.enabled)
tpiu_disable();
@@ -119,18 +119,23 @@
static struct platform_driver tpiu_driver = {
.probe = tpiu_probe,
- .remove = tpiu_remove,
+ .remove = __devexit_p(tpiu_remove),
.driver = {
.name = "msm_tpiu",
},
};
-int __init tpiu_init(void)
+static int __init tpiu_init(void)
{
return platform_driver_register(&tpiu_driver);
}
+module_init(tpiu_init);
-void tpiu_exit(void)
+static void __exit tpiu_exit(void)
{
platform_driver_unregister(&tpiu_driver);
}
+module_exit(tpiu_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
index 80ec65a..cfe65ad 100644
--- a/arch/arm/mach-msm/qdss.c
+++ b/arch/arm/mach-msm/qdss.c
@@ -24,26 +24,155 @@
#include "rpm_resources.h"
#include "qdss-priv.h"
+#define MAX_STR_LEN (65535)
+
enum {
QDSS_CLK_OFF,
QDSS_CLK_ON_DBG,
QDSS_CLK_ON_HSDBG,
};
+/*
+ * Exclusion rules for structure fields.
+ *
+ * S: qdss.sources_mutex protected.
+ * I: qdss.sink_mutex protected.
+ * C: qdss.clk_mutex protected.
+ */
struct qdss_ctx {
- struct kobject *modulekobj;
- uint8_t max_clk;
- uint8_t clk_count;
- struct mutex clk_mutex;
+ struct kobject *modulekobj;
+ struct msm_qdss_platform_data *pdata;
+ struct list_head sources; /* S: sources list */
+ struct mutex sources_mutex;
+ uint8_t sink_count; /* I: sink count */
+ struct mutex sink_mutex;
+ uint8_t max_clk;
+ uint8_t clk_count; /* C: clk count */
+ struct mutex clk_mutex;
};
static struct qdss_ctx qdss;
-
-struct kobject *qdss_get_modulekobj(void)
+/**
+ * qdss_get - get the qdss source handle
+ * @name: name of the qdss source
+ *
+ * Searches the sources list to get the qdss source handle for this source.
+ *
+ * CONTEXT:
+ * Typically called from init or probe functions
+ *
+ * RETURNS:
+ * pointer to struct qdss_source on success, %NULL on failure
+ */
+struct qdss_source *qdss_get(const char *name)
{
- return qdss.modulekobj;
+ struct qdss_source *src, *source = NULL;
+
+ mutex_lock(&qdss.sources_mutex);
+ list_for_each_entry(src, &qdss.sources, link) {
+ if (src->name) {
+ if (strncmp(src->name, name, MAX_STR_LEN))
+ continue;
+ source = src;
+ break;
+ }
+ }
+ mutex_unlock(&qdss.sources_mutex);
+
+ return source ? source : ERR_PTR(-ENOENT);
}
+EXPORT_SYMBOL(qdss_get);
+
+/**
+ * qdss_put - release the qdss source handle
+ * @name: name of the qdss source
+ *
+ * CONTEXT:
+ * Typically called from driver remove or exit functions
+ */
+void qdss_put(struct qdss_source *src)
+{
+}
+EXPORT_SYMBOL(qdss_put);
+
+/**
+ * qdss_enable - enable qdss for the source
+ * @src: handle for the source making the call
+ *
+ * Enables qdss block (relevant funnel ports and sink) if not already
+ * enabled, otherwise increments the reference count
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ *
+ * RETURNS:
+ * 0 on success, non-zero on failure
+ */
+int qdss_enable(struct qdss_source *src)
+{
+ int ret;
+
+ if (!src)
+ return -EINVAL;
+
+ ret = qdss_clk_enable();
+ if (ret)
+ goto err;
+
+ if ((qdss.pdata)->afamily) {
+ mutex_lock(&qdss.sink_mutex);
+ if (qdss.sink_count == 0) {
+ etb_disable();
+ tpiu_disable();
+ /* enable ETB first to avoid losing any trace data */
+ etb_enable();
+ }
+ qdss.sink_count++;
+ mutex_unlock(&qdss.sink_mutex);
+ }
+
+ funnel_enable(0x0, src->fport_mask);
+ return 0;
+err:
+ return ret;
+}
+EXPORT_SYMBOL(qdss_enable);
+
+/**
+ * qdss_disable - disable qdss for the source
+ * @src: handle for the source making the call
+ *
+ * Disables qdss block (relevant funnel ports and sink) if the reference count
+ * is one, otherwise decrements the reference count
+ *
+ * CONTEXT:
+ * Might sleep. Uses a mutex lock. Should be called from a non-atomic context.
+ */
+void qdss_disable(struct qdss_source *src)
+{
+ if (!src)
+ return;
+
+ if ((qdss.pdata)->afamily) {
+ mutex_lock(&qdss.sink_mutex);
+ if (WARN(qdss.sink_count == 0, "qdss is unbalanced\n"))
+ goto out;
+ if (qdss.sink_count == 1) {
+ etb_dump();
+ etb_disable();
+ }
+ qdss.sink_count--;
+ mutex_unlock(&qdss.sink_mutex);
+ }
+
+ funnel_disable(0x0, src->fport_mask);
+ qdss_clk_disable();
+ return;
+out:
+ mutex_unlock(&qdss.sink_mutex);
+}
+EXPORT_SYMBOL(qdss_disable);
/**
* qdss_clk_enable - enable qdss clocks
@@ -111,6 +240,11 @@
}
EXPORT_SYMBOL(qdss_clk_disable);
+struct kobject *qdss_get_modulekobj(void)
+{
+ return qdss.modulekobj;
+}
+
#define QDSS_ATTR(name) \
static struct kobj_attribute name##_attr = \
__ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
@@ -136,6 +270,16 @@
}
QDSS_ATTR(max_clk);
+static void __init qdss_add_sources(struct qdss_source *srcs, size_t num)
+{
+ mutex_lock(&qdss.sources_mutex);
+ while (num--) {
+ list_add_tail(&srcs->link, &qdss.sources);
+ srcs++;
+ }
+ mutex_unlock(&qdss.sources_mutex);
+}
+
static int __init qdss_sysfs_init(void)
{
int ret;
@@ -158,58 +302,85 @@
return ret;
}
-static void qdss_sysfs_exit(void)
+static void __exit qdss_sysfs_exit(void)
{
sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
}
-static int __init qdss_init(void)
+static int __devinit qdss_probe(struct platform_device *pdev)
{
int ret;
+ struct qdss_source *src_table;
+ size_t num_srcs;
+ mutex_init(&qdss.sources_mutex);
mutex_init(&qdss.clk_mutex);
+ mutex_init(&qdss.sink_mutex);
+
+ if (pdev->dev.platform_data == NULL) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ ret = -ENODEV;
+ goto err_pdata;
+ }
+ qdss.pdata = pdev->dev.platform_data;
+
+ INIT_LIST_HEAD(&qdss.sources);
+ src_table = (qdss.pdata)->src_table;
+ num_srcs = (qdss.pdata)->size;
+ qdss_add_sources(src_table, num_srcs);
+
+ pr_info("QDSS arch initialized\n");
+ return 0;
+err_pdata:
+ mutex_destroy(&qdss.sink_mutex);
+ mutex_destroy(&qdss.clk_mutex);
+ mutex_destroy(&qdss.sources_mutex);
+ pr_err("QDSS init failed\n");
+ return ret;
+}
+
+static int __devexit qdss_remove(struct platform_device *pdev)
+{
+ qdss_sysfs_exit();
+ mutex_destroy(&qdss.sink_mutex);
+ mutex_destroy(&qdss.clk_mutex);
+ mutex_destroy(&qdss.sources_mutex);
+
+ return 0;
+}
+
+static struct platform_driver qdss_driver = {
+ .probe = qdss_probe,
+ .remove = __devexit_p(qdss_remove),
+ .driver = {
+ .name = "msm_qdss",
+ },
+};
+
+static int __init qdss_init(void)
+{
+ return platform_driver_register(&qdss_driver);
+}
+arch_initcall(qdss_init);
+
+static int __init qdss_module_init(void)
+{
+ int ret;
ret = qdss_sysfs_init();
if (ret)
goto err_sysfs;
- ret = etb_init();
- if (ret)
- goto err_etb;
- ret = tpiu_init();
- if (ret)
- goto err_tpiu;
- ret = funnel_init();
- if (ret)
- goto err_funnel;
- ret = etm_init();
- if (ret)
- goto err_etm;
- pr_info("QDSS initialized\n");
+ pr_info("QDSS module initialized\n");
return 0;
-err_etm:
- funnel_exit();
-err_funnel:
- tpiu_exit();
-err_tpiu:
- etb_exit();
-err_etb:
- qdss_sysfs_exit();
err_sysfs:
- mutex_destroy(&qdss.clk_mutex);
- pr_err("QDSS init failed\n");
return ret;
}
-module_init(qdss_init);
+module_init(qdss_module_init);
static void __exit qdss_exit(void)
{
- qdss_sysfs_exit();
- etm_exit();
- funnel_exit();
- tpiu_exit();
- etb_exit();
- mutex_destroy(&qdss.clk_mutex);
+ platform_driver_unregister(&qdss_driver);
}
module_exit(qdss_exit);
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 719ea8a..c708df5 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -1330,7 +1330,7 @@
if (rc)
goto bail;
- rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
+ rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg, NULL);
if (IS_ERR(rdev)) {
rc = PTR_ERR(rdev);
pr_err("regulator_register failed: %s, rc=%d\n",
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index 2eac3c1..b0fa3d2 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -437,7 +437,6 @@
*
* Return value:
* 0: success
- * -EINTR: interrupted
* -EINVAL: invalid <ctx> or invalid id in <req> array
* -ENOSPC: request rejected
* -ENODEV: RPM driver not initialized
@@ -464,10 +463,7 @@
rc = msm_rpm_set_exclusive_noirq(ctx, sel_masks, req, count);
spin_unlock_irqrestore(&msm_rpm_lock, flags);
} else {
- rc = mutex_lock_interruptible(&msm_rpm_mutex);
- if (rc)
- goto set_common_exit;
-
+ mutex_lock(&msm_rpm_mutex);
rc = msm_rpm_set_exclusive(ctx, sel_masks, req, count);
mutex_unlock(&msm_rpm_mutex);
}
@@ -479,7 +475,6 @@
/*
* Return value:
* 0: success
- * -EINTR: interrupted
* -EINVAL: invalid <ctx> or invalid id in <req> array
* -ENODEV: RPM driver not initialized.
*/
@@ -518,10 +513,7 @@
spin_unlock_irqrestore(&msm_rpm_lock, flags);
BUG_ON(rc);
} else {
- rc = mutex_lock_interruptible(&msm_rpm_mutex);
- if (rc)
- goto clear_common_exit;
-
+ mutex_lock(&msm_rpm_mutex);
rc = msm_rpm_set_exclusive(ctx, sel_masks, r, ARRAY_SIZE(r));
mutex_unlock(&msm_rpm_mutex);
BUG_ON(rc);
@@ -683,7 +675,6 @@
*
* Return value:
* 0: success
- * -EINTR: interrupted
* -EINVAL: invalid <ctx> or invalid id in <req> array
* -ENOSPC: request rejected
* -ENODEV: RPM driver not initialized
@@ -724,7 +715,6 @@
*
* Return value:
* 0: success
- * -EINTR: interrupted
* -EINVAL: invalid <ctx> or invalid id in <req> array
*/
int msm_rpm_clear(int ctx, struct msm_rpm_iv_pair *req, int count)
@@ -769,7 +759,6 @@
*
* Return value:
* 0: success
- * -EINTR: interrupted
* -EINVAL: invalid id in <req> array
* -ENODEV: RPM driver not initialized
*/
@@ -787,9 +776,7 @@
if (rc)
goto register_notification_exit;
- rc = mutex_lock_interruptible(&msm_rpm_mutex);
- if (rc)
- goto register_notification_exit;
+ mutex_lock(&msm_rpm_mutex);
if (!msm_rpm_init_notif_done) {
msm_rpm_initialize_notification();
@@ -823,7 +810,6 @@
*
* Return value:
* 0: success
- * -EINTR: interrupted
* -ENODEV: RPM driver not initialized
*/
int msm_rpm_unregister_notification(struct msm_rpm_notification *n)
@@ -831,13 +817,10 @@
unsigned long flags;
unsigned int ctx;
struct msm_rpm_notif_config cfg;
- int rc;
+ int rc = 0;
int i;
- rc = mutex_lock_interruptible(&msm_rpm_mutex);
- if (rc)
- goto unregister_notification_exit;
-
+ mutex_lock(&msm_rpm_mutex);
ctx = MSM_RPM_CTX_SET_0;
cfg = msm_rpm_notif_cfgs[ctx];
@@ -854,7 +837,6 @@
msm_rpm_update_notification(ctx, &msm_rpm_notif_cfgs[ctx], &cfg);
mutex_unlock(&msm_rpm_mutex);
-unregister_notification_exit:
return rc;
}
EXPORT_SYMBOL(msm_rpm_unregister_notification);
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 546a917..6282eca 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -895,6 +895,9 @@
if (latency_us < level->latency_us)
continue;
+ if (sleep_us <= level->time_overhead_us)
+ continue;
+
if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
irqs_detectable, gpio_detectable))
continue;
diff --git a/arch/arm/mach-msm/saw-regulator.c b/arch/arm/mach-msm/saw-regulator.c
index b11b1fa..c747e5b 100644
--- a/arch/arm/mach-msm/saw-regulator.c
+++ b/arch/arm/mach-msm/saw-regulator.c
@@ -174,8 +174,8 @@
vreg->desc.owner = THIS_MODULE;
vreg->uV = MIN_CORE_VOLTAGE;
- vreg->rdev = regulator_register(&vreg->desc, &pdev->dev, init_data,
- vreg);
+ vreg->rdev = regulator_register(&vreg->desc, &pdev->dev,
+ init_data, vreg, NULL);
if (IS_ERR(vreg->rdev)) {
rc = PTR_ERR(vreg->rdev);
pr_err("regulator_register failed, rc=%d.\n", rc);
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index 3651ee1..2fe71a9 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -22,6 +22,7 @@
PAS_RIVA,
PAS_SECAPP,
PAS_GSS,
+ PAS_VIDC,
};
extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index bbfe702..839f932 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -39,6 +39,7 @@
#include <mach/system.h>
#include <mach/subsystem_notif.h>
#include <mach/socinfo.h>
+#include <asm/cacheflush.h>
#include "smd_private.h"
#include "proc_comm.h"
@@ -70,6 +71,10 @@
uint32_t SMSM_NUM_ENTRIES = 8;
uint32_t SMSM_NUM_HOSTS = 3;
+/* Legacy SMSM interrupt notifications */
+#define LEGACY_MODEM_SMSM_MASK (SMSM_RESET | SMSM_INIT | SMSM_SMDINIT \
+ | SMSM_RUN | SMSM_SYSTEM_DOWNLOAD)
+
enum {
MSM_SMD_DEBUG = 1U << 0,
MSM_SMSM_DEBUG = 1U << 1,
@@ -107,6 +112,8 @@
struct smsm_state_info {
struct list_head callbacks;
uint32_t last_value;
+ uint32_t intr_mask_set;
+ uint32_t intr_mask_clear;
};
struct interrupt_config_item {
@@ -2245,6 +2252,8 @@
for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
state_info = &smsm_states[n];
state_info->last_value = __raw_readl(SMSM_STATE_ADDR(n));
+ state_info->intr_mask_set = 0x0;
+ state_info->intr_mask_clear = 0x0;
INIT_LIST_HEAD(&state_info->callbacks);
}
mutex_unlock(&smsm_lock);
@@ -2301,10 +2310,16 @@
SMSM_NUM_HOSTS *
sizeof(uint32_t));
- if (smsm_info.intr_mask)
+ if (smsm_info.intr_mask) {
for (i = 0; i < SMSM_NUM_ENTRIES; i++)
- __raw_writel(0xffffffff,
- SMSM_INTR_MASK_ADDR(i, SMSM_APPS));
+ __raw_writel(0x0,
+ SMSM_INTR_MASK_ADDR(i, SMSM_APPS));
+
+ /* Configure legacy modem bits */
+ __raw_writel(LEGACY_MODEM_SMSM_MASK,
+ SMSM_INTR_MASK_ADDR(SMSM_MODEM_STATE,
+ SMSM_APPS));
+ }
}
if (!smsm_info.intr_mux)
@@ -2365,26 +2380,19 @@
return;
}
- /* queue state entries */
- for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
- new_state = __raw_readl(SMSM_STATE_ADDR(n));
-
- ret = kfifo_in(&smsm_snapshot_fifo,
- &new_state, sizeof(new_state));
- if (ret != sizeof(new_state)) {
- pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
- return;
- }
- }
-
- /* queue wakelock usage flag */
- ret = kfifo_in(&smsm_snapshot_fifo,
- &use_wakelock, sizeof(use_wakelock));
- if (ret != sizeof(use_wakelock)) {
- pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
- return;
- }
-
+ /*
+ * To avoid a race condition with notify_smsm_cb_clients_worker, the
+ * following sequence must be followed:
+ * 1) increment snapshot count
+ * 2) insert data into FIFO
+ *
+ * Potentially in parallel, the worker:
+ * a) verifies >= 1 snapshots are in FIFO
+ * b) processes snapshot
+ * c) decrements reference count
+ *
+ * This order ensures that 1 will always occur before abc.
+ */
if (use_wakelock) {
spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
if (smsm_snapshot_count == 0) {
@@ -2394,7 +2402,44 @@
++smsm_snapshot_count;
spin_unlock_irqrestore(&smsm_snapshot_count_lock, flags);
}
+
+ /* queue state entries */
+ for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+ new_state = __raw_readl(SMSM_STATE_ADDR(n));
+
+ ret = kfifo_in(&smsm_snapshot_fifo,
+ &new_state, sizeof(new_state));
+ if (ret != sizeof(new_state)) {
+ pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+ goto restore_snapshot_count;
+ }
+ }
+
+ /* queue wakelock usage flag */
+ ret = kfifo_in(&smsm_snapshot_fifo,
+ &use_wakelock, sizeof(use_wakelock));
+ if (ret != sizeof(use_wakelock)) {
+ pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+ goto restore_snapshot_count;
+ }
+
schedule_work(&smsm_cb_work);
+ return;
+
+restore_snapshot_count:
+ if (use_wakelock) {
+ spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
+ if (smsm_snapshot_count) {
+ --smsm_snapshot_count;
+ if (smsm_snapshot_count == 0) {
+ SMx_POWER_INFO("SMSM snapshot wake unlock\n");
+ wake_unlock(&smsm_snapshot_wakelock);
+ }
+ } else {
+ pr_err("%s: invalid snapshot count\n", __func__);
+ }
+ spin_unlock_irqrestore(&smsm_snapshot_count_lock, flags);
+ }
}
static irqreturn_t smsm_irq_handler(int irq, void *data)
@@ -2443,10 +2488,12 @@
modem_queue_start_reset_notify();
} else if (modm & SMSM_RESET) {
- if (!disable_smsm_reset_handshake)
- apps |= SMSM_RESET;
-
pr_err("\nSMSM: Modem SMSM state changed to SMSM_RESET.");
+ if (!disable_smsm_reset_handshake) {
+ apps |= SMSM_RESET;
+ flush_cache_all();
+ outer_flush_all();
+ }
modem_queue_start_reset_notify();
} else if (modm & SMSM_INIT) {
@@ -2506,6 +2553,20 @@
return smsm_irq_handler(irq, data);
}
+/*
+ * Changes the global interrupt mask. The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry SMSM entry to change
+ * @clear_mask 1 = clear bit, 0 = no-op
+ * @set_mask 1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
int smsm_change_intr_mask(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask)
{
@@ -2524,6 +2585,8 @@
}
spin_lock_irqsave(&smem_lock, flags);
+ smsm_states[smsm_entry].intr_mask_clear = clear_mask;
+ smsm_states[smsm_entry].intr_mask_set = set_mask;
old_mask = __raw_readl(SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
new_mask = (old_mask & ~clear_mask) | set_mask;
@@ -2700,8 +2763,10 @@
int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
void (*notify)(void *, uint32_t, uint32_t), void *data)
{
+ struct smsm_state_info *state;
struct smsm_state_cb_info *cb_info;
struct smsm_state_cb_info *cb_found = 0;
+ uint32_t new_mask = 0;
int ret = 0;
if (smsm_entry >= SMSM_NUM_ENTRIES)
@@ -2715,15 +2780,16 @@
goto cleanup;
}
+ state = &smsm_states[smsm_entry];
list_for_each_entry(cb_info,
- &smsm_states[smsm_entry].callbacks, cb_list) {
- if ((cb_info->notify == notify) &&
+ &state->callbacks, cb_list) {
+ if (!ret && (cb_info->notify == notify) &&
(cb_info->data == data)) {
cb_info->mask |= mask;
cb_found = cb_info;
ret = 1;
- break;
}
+ new_mask |= cb_info->mask;
}
if (!cb_found) {
@@ -2739,7 +2805,24 @@
cb_info->data = data;
INIT_LIST_HEAD(&cb_info->cb_list);
list_add_tail(&cb_info->cb_list,
- &smsm_states[smsm_entry].callbacks);
+ &state->callbacks);
+ new_mask |= mask;
+ }
+
+ /* update interrupt notification mask */
+ if (smsm_entry == SMSM_MODEM_STATE)
+ new_mask |= LEGACY_MODEM_SMSM_MASK;
+
+ if (smsm_info.intr_mask) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&smem_lock, flags);
+ new_mask = (new_mask & ~state->intr_mask_clear)
+ | state->intr_mask_set;
+ __raw_writel(new_mask,
+ SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
+ wmb();
+ spin_unlock_irqrestore(&smem_lock, flags);
}
cleanup:
@@ -2767,6 +2850,9 @@
void (*notify)(void *, uint32_t, uint32_t), void *data)
{
struct smsm_state_cb_info *cb_info;
+ struct smsm_state_cb_info *cb_tmp;
+ struct smsm_state_info *state;
+ uint32_t new_mask = 0;
int ret = 0;
if (smsm_entry >= SMSM_NUM_ENTRIES)
@@ -2780,9 +2866,10 @@
return -ENODEV;
}
- list_for_each_entry(cb_info,
- &smsm_states[smsm_entry].callbacks, cb_list) {
- if ((cb_info->notify == notify) &&
+ state = &smsm_states[smsm_entry];
+ list_for_each_entry_safe(cb_info, cb_tmp,
+ &state->callbacks, cb_list) {
+ if (!ret && (cb_info->notify == notify) &&
(cb_info->data == data)) {
cb_info->mask &= ~mask;
ret = 1;
@@ -2791,9 +2878,26 @@
list_del(&cb_info->cb_list);
kfree(cb_info);
ret = 2;
+ continue;
}
- break;
}
+ new_mask |= cb_info->mask;
+ }
+
+ /* update interrupt notification mask */
+ if (smsm_entry == SMSM_MODEM_STATE)
+ new_mask |= LEGACY_MODEM_SMSM_MASK;
+
+ if (smsm_info.intr_mask) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&smem_lock, flags);
+ new_mask = (new_mask & ~state->intr_mask_clear)
+ | state->intr_mask_set;
+ __raw_writel(new_mask,
+ SMSM_INTR_MASK_ADDR(smsm_entry, SMSM_APPS));
+ wmb();
+ spin_unlock_irqrestore(&smem_lock, flags);
}
mutex_unlock(&smsm_lock);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 9ef4028..5f835a2 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -88,24 +88,65 @@
static int msm_smd_pkt_debug_mask;
module_param_named(debug_mask, msm_smd_pkt_debug_mask,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum {
+ SMD_PKT_STATUS = 1U << 0,
+ SMD_PKT_READ = 1U << 1,
+ SMD_PKT_WRITE = 1U << 2,
+ SMD_PKT_READ_DUMP_BUFFER = 1U << 3,
+ SMD_PKT_WRITE_DUMP_BUFFER = 1U << 4,
+ SMD_PKT_POLL = 1U << 5,
+};
+
#define DEBUG
#ifdef DEBUG
-#define D_DUMP_BUFFER(prestr, cnt, buf) \
+#define D_STATUS(x...) \
do { \
- if (msm_smd_pkt_debug_mask) \
- print_hex_dump(KERN_DEBUG, prestr, \
- DUMP_PREFIX_NONE, 16, 1, \
- buf, cnt, 1); \
+ if (msm_smd_pkt_debug_mask & SMD_PKT_STATUS) \
+ pr_info("Status: "x); \
+} while (0)
+
+#define D_READ(x...) \
+do { \
+ if (msm_smd_pkt_debug_mask & SMD_PKT_READ) \
+ pr_info("Read: "x); \
+} while (0)
+
+#define D_WRITE(x...) \
+do { \
+ if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE) \
+ pr_info("Write: "x); \
+} while (0)
+
+#define D_READ_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+ if (msm_smd_pkt_debug_mask & SMD_PKT_READ_DUMP_BUFFER) \
+ print_hex_dump(KERN_INFO, prestr, \
+ DUMP_PREFIX_NONE, 16, 1, \
+ buf, cnt, 1); \
+} while (0)
+
+#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+ if (msm_smd_pkt_debug_mask & SMD_PKT_WRITE_DUMP_BUFFER) \
+ print_hex_dump(KERN_INFO, prestr, \
+ DUMP_PREFIX_NONE, 16, 1, \
+ buf, cnt, 1); \
+} while (0)
+
+#define D_POLL(x...) \
+do { \
+ if (msm_smd_pkt_debug_mask & SMD_PKT_POLL) \
+ pr_info("Poll: "x); \
} while (0)
#else
-#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
-#endif
-
-#ifdef DEBUG
-#define D(x...) if (msm_smd_pkt_debug_mask) printk(x)
-#else
-#define D(x...) do {} while (0)
+#define D_STATUS(x...) do {} while (0)
+#define D_READ(x...) do {} while (0)
+#define D_WRITE(x...) do {} while (0)
+#define D_READ_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D_WRITE_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#define D_POLL(x...) do {} while (0)
#endif
static ssize_t open_timeout_store(struct device *d,
@@ -171,6 +212,7 @@
wake_up(&smd_pkt_devp->ch_read_wait_queue);
wake_up(&smd_pkt_devp->ch_write_wait_queue);
wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
+ D_STATUS("%s smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
}
static void loopback_probe_worker(struct work_struct *work)
@@ -195,9 +237,12 @@
smd_pkt_devp = container_of(work, struct smd_pkt_dev,
packet_arrival_work);
mutex_lock(&smd_pkt_devp->ch_lock);
- if (smd_pkt_devp->ch)
+ if (smd_pkt_devp->ch) {
+ D_READ("%s locking smd_pkt_dev id:%d wakelock\n",
+ __func__, smd_pkt_devp->i);
wake_lock_timeout(&smd_pkt_devp->pa_wake_lock,
WAKELOCK_TIMEOUT);
+ }
mutex_unlock(&smd_pkt_devp->ch_lock);
}
@@ -213,15 +258,20 @@
switch (cmd) {
case TIOCMGET:
+ D_STATUS("%s TIOCMGET command on smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
ret = smd_tiocmget(smd_pkt_devp->ch);
break;
case TIOCMSET:
+ D_STATUS("%s TIOCSET command on smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
ret = smd_tiocmset(smd_pkt_devp->ch, arg, ~arg);
break;
case SMD_PKT_IOCTL_BLOCKING_WRITE:
ret = get_user(smd_pkt_devp->blocking_write, (int *)arg);
break;
default:
+ pr_err("%s: Unrecognized ioctl command %d\n", __func__, cmd);
ret = -1;
}
@@ -240,18 +290,27 @@
struct smd_channel *chl;
unsigned long flags;
- D(KERN_ERR "%s: read %i bytes\n",
- __func__, count);
-
smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
+ if (!smd_pkt_devp) {
+ pr_err("%s on NULL smd_pkt_dev\n", __func__);
return -EINVAL;
+ }
+
+ if (!smd_pkt_devp->ch) {
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
+ return -EINVAL;
+ }
if (smd_pkt_devp->do_reset_notification) {
/* notify client that a reset occurred */
+ pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
}
+ D_READ("Begin %s on smd_pkt_dev id:%d buffer_size %d\n",
+ __func__, smd_pkt_devp->i, count);
chl = smd_pkt_devp->ch;
wait_for_packet:
@@ -260,20 +319,19 @@
smd_read_avail(chl)) ||
smd_pkt_devp->has_reset);
- if (smd_pkt_devp->has_reset)
+ if (smd_pkt_devp->has_reset) {
+ pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
+ }
if (r < 0) {
/* qualify error message */
if (r != -ERESTARTSYS) {
/* we get this anytime a signal comes in */
- printk(KERN_ERR "ERROR:%s:%i:%s: "
- "wait_event_interruptible ret %i\n",
- __FILE__,
- __LINE__,
- __func__,
- r
- );
+ pr_err("%s: wait_event_interruptible on smd_pkt_dev"
+ " id:%d ret %i\n",
+ __func__, smd_pkt_devp->i, r);
}
return r;
}
@@ -284,13 +342,16 @@
pkt_size = smd_cur_packet_size(smd_pkt_devp->ch);
if (!pkt_size) {
- D(KERN_ERR "%s: Nothing to read\n", __func__);
+ pr_err("%s: No data on smd_pkt_dev id:%d, False wakeup\n",
+ __func__, smd_pkt_devp->i);
mutex_unlock(&smd_pkt_devp->rx_lock);
goto wait_for_packet;
}
if (pkt_size > count) {
- pr_err("packet size %i > buffer size %i,", pkt_size, count);
+ pr_err("%s: failure on smd_pkt_dev id: %d - packet size %d"
+ " > buffer size %d,", __func__, smd_pkt_devp->i,
+ pkt_size, count);
mutex_unlock(&smd_pkt_devp->rx_lock);
return -ETOOSMALL;
}
@@ -302,8 +363,12 @@
(pkt_size - bytes_read));
if (r < 0) {
mutex_unlock(&smd_pkt_devp->rx_lock);
- if (smd_pkt_devp->has_reset)
+ if (smd_pkt_devp->has_reset) {
+ pr_err("%s notifying reset for smd_pkt_dev"
+ " id:%d\n", __func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
+ }
+ pr_err("%s Error while reading %d\n", __func__, r);
return r;
}
bytes_read += r;
@@ -313,10 +378,12 @@
smd_pkt_devp->has_reset);
if (smd_pkt_devp->has_reset) {
mutex_unlock(&smd_pkt_devp->rx_lock);
+ pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
}
} while (pkt_size != bytes_read);
- D_DUMP_BUFFER("read: ", bytes_read, buf);
+ D_READ_DUMP_BUFFER("Read: ", (bytes_read > 16 ? 16 : bytes_read), buf);
mutex_unlock(&smd_pkt_devp->rx_lock);
mutex_lock(&smd_pkt_devp->ch_lock);
@@ -325,12 +392,14 @@
!smd_cur_packet_size(smd_pkt_devp->ch)) {
wake_unlock(&smd_pkt_devp->pa_wake_lock);
smd_pkt_devp->poll_mode = 0;
+ D_READ("%s unlocked smd_pkt_dev id:%d wakelock\n",
+ __func__, smd_pkt_devp->i);
}
spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
mutex_unlock(&smd_pkt_devp->ch_lock);
- D(KERN_ERR "%s: just read %i bytes\n",
- __func__, bytes_read);
+ D_READ("Finished %s on smd_pkt_dev id:%d %d bytes\n",
+ __func__, smd_pkt_devp->i, bytes_read);
/* check and wakeup read threads waiting on this device */
check_and_wakeup_reader(smd_pkt_devp);
@@ -347,24 +416,33 @@
struct smd_pkt_dev *smd_pkt_devp;
DEFINE_WAIT(write_wait);
- D(KERN_ERR "%s: writting %i bytes\n",
- __func__, count);
-
smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
+ if (!smd_pkt_devp) {
+ pr_err("%s on NULL smd_pkt_dev\n", __func__);
return -EINVAL;
+ }
+
+ if (!smd_pkt_devp->ch) {
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
+ return -EINVAL;
+ }
if (smd_pkt_devp->do_reset_notification) {
+ pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
/* notify client that a reset occurred */
return notify_reset(smd_pkt_devp);
}
+ D_WRITE("Begin %s on smd_pkt_dev id:%d data_size %d\n",
+ __func__, smd_pkt_devp->i, count);
mutex_lock(&smd_pkt_devp->tx_lock);
if (!smd_pkt_devp->blocking_write) {
if (smd_write_avail(smd_pkt_devp->ch) < count) {
- D(KERN_ERR "%s: Not enough space to write\n",
- __func__);
+ pr_err("%s: Not enough space in smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
mutex_unlock(&smd_pkt_devp->tx_lock);
return -ENOMEM;
}
@@ -373,7 +451,8 @@
r = smd_write_start(smd_pkt_devp->ch, count);
if (r < 0) {
mutex_unlock(&smd_pkt_devp->tx_lock);
- pr_err("%s: Error %d @ smd_write_start\n", __func__, r);
+ pr_err("%s: Error:%d in smd_pkt_dev id:%d @ smd_write_start\n",
+ __func__, r, smd_pkt_devp->i);
return r;
}
@@ -391,6 +470,8 @@
if (smd_pkt_devp->has_reset) {
mutex_unlock(&smd_pkt_devp->tx_lock);
+ pr_err("%s notifying reset for smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
} else {
r = smd_write_segment(smd_pkt_devp->ch,
@@ -398,17 +479,22 @@
(count - bytes_written), 1);
if (r < 0) {
mutex_unlock(&smd_pkt_devp->tx_lock);
- if (smd_pkt_devp->has_reset)
+ if (smd_pkt_devp->has_reset) {
+ pr_err("%s notifying reset for"
+ " smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return notify_reset(smd_pkt_devp);
+ }
}
bytes_written += r;
}
} while (bytes_written != count);
smd_write_end(smd_pkt_devp->ch);
mutex_unlock(&smd_pkt_devp->tx_lock);
-
- D(KERN_ERR "%s: just wrote %i bytes\n",
- __func__, count);
+ D_WRITE_DUMP_BUFFER("Write: ",
+ (bytes_written > 16 ? 16 : bytes_written), buf);
+ D_WRITE("Finished %s on smd_pkt_dev id:%d %d bytes\n",
+ __func__, smd_pkt_devp->i, count);
return count;
}
@@ -419,13 +505,18 @@
unsigned int mask = 0;
smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp)
+ if (!smd_pkt_devp) {
+ pr_err("%s on a NULL device\n", __func__);
return POLLERR;
+ }
smd_pkt_devp->poll_mode = 1;
poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
- if (smd_read_avail(smd_pkt_devp->ch))
+ if (smd_read_avail(smd_pkt_devp->ch)) {
mask |= POLLIN | POLLRDNORM;
+ D_POLL("%s sets POLLIN for smd_pkt_dev id: %d\n",
+ __func__, smd_pkt_devp->i);
+ }
return mask;
}
@@ -435,18 +526,27 @@
int sz;
unsigned long flags;
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
+ if (!smd_pkt_devp) {
+ pr_err("%s on a NULL device\n", __func__);
return;
+ }
+
+ if (!smd_pkt_devp->ch) {
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
+ return;
+ }
sz = smd_cur_packet_size(smd_pkt_devp->ch);
if (sz == 0) {
- D(KERN_ERR "%s: packet size is 0\n", __func__);
+ D_READ("%s: No packet in smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return;
}
if (!smd_read_avail(smd_pkt_devp->ch)) {
- D(KERN_ERR "%s: packet size is %i - "
- "but the data isn't here\n",
- __func__, sz);
+ D_READ("%s: packet size is %d in smd_pkt_dev id:%d -"
+ " but the data isn't here\n",
+ __func__, sz, smd_pkt_devp->i);
return;
}
@@ -456,20 +556,28 @@
wake_lock(&smd_pkt_devp->pa_wake_lock);
spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
schedule_work(&smd_pkt_devp->packet_arrival_work);
- D(KERN_ERR "%s: after wake_up\n", __func__);
+ D_READ("%s: wake_up smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
}
static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp)
{
int sz;
- if (!smd_pkt_devp || !smd_pkt_devp->ch)
+ if (!smd_pkt_devp) {
+ pr_err("%s on a NULL device\n", __func__);
return;
+ }
+
+ if (!smd_pkt_devp->ch) {
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
+ return;
+ }
sz = smd_write_avail(smd_pkt_devp->ch);
if (sz) {
- D(KERN_ERR "%s: %d bytes Write Space available\n",
- __func__, sz);
+ D_WRITE("%s: %d bytes write space in smd_pkt_dev id:%d\n",
+ __func__, sz, smd_pkt_devp->i);
smd_disable_read_intr(smd_pkt_devp->ch);
wake_up(&smd_pkt_devp->ch_write_wait_queue);
}
@@ -479,31 +587,32 @@
{
struct smd_pkt_dev *smd_pkt_devp = priv;
- if (smd_pkt_devp->ch == 0)
+ if (smd_pkt_devp->ch == 0) {
+ pr_err("%s on a closed smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return;
+ }
switch (event) {
case SMD_EVENT_DATA: {
- D(KERN_ERR "%s: data\n", __func__);
+ D_STATUS("%s: DATA event in smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
check_and_wakeup_reader(smd_pkt_devp);
if (smd_pkt_devp->blocking_write)
check_and_wakeup_writer(smd_pkt_devp);
- D(KERN_ERR "%s: data after check_and_wakeup\n", __func__);
break;
}
case SMD_EVENT_OPEN:
- D(KERN_ERR "%s: smd opened\n",
- __func__);
-
+ D_STATUS("%s: OPEN event in smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
smd_pkt_devp->has_reset = 0;
smd_pkt_devp->is_open = 1;
wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
break;
case SMD_EVENT_CLOSE:
+ D_STATUS("%s: CLOSE event in smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
smd_pkt_devp->is_open = 0;
- printk(KERN_ERR "%s: smd closed\n",
- __func__);
-
/* put port into reset state */
clean_and_signal(smd_pkt_devp);
if (smd_pkt_devp->i == LOOPBACK_INX)
@@ -591,6 +700,8 @@
for (i = 0; i < NUM_SMD_PKT_PORTS; i++) {
if (!strncmp(pdev->name, smd_ch_name[i], SMD_MAX_CH_NAME_LEN)) {
complete_all(&smd_pkt_devp[i]->ch_allocated);
+ D_STATUS("%s allocated SMD ch for smd_pkt_dev id:%d\n",
+ __func__, i);
break;
}
}
@@ -614,8 +725,11 @@
smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
- if (!smd_pkt_devp)
+ if (!smd_pkt_devp) {
+ pr_err("%s on a NULL device\n", __func__);
return -EINVAL;
+ }
+ D_STATUS("Begin %s on smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
wake_lock_init(&smd_pkt_devp->pa_wake_lock, WAKE_LOCK_SUSPEND,
smd_pkt_dev_name[smd_pkt_devp->i]);
@@ -643,6 +757,9 @@
smd_pkt_devp->pil = pil_get(peripheral);
if (IS_ERR(smd_pkt_devp->pil)) {
r = PTR_ERR(smd_pkt_devp->pil);
+ pr_err("%s failed on smd_pkt_dev id:%d -"
+ " pil_get failed for %s\n", __func__,
+ smd_pkt_devp->i, peripheral);
goto release_pd;
}
@@ -672,8 +789,9 @@
if (r == 0)
r = -ETIMEDOUT;
if (r < 0) {
- pr_err("%s: wait failed for smd port:"
- " %d\n", __func__, r);
+ pr_err("%s: wait on smd_pkt_dev id:%d"
+ " allocation failed rc:%d\n",
+ __func__, smd_pkt_devp->i, r);
goto release_pil;
}
}
@@ -697,16 +815,19 @@
r = -ETIMEDOUT;
if (r < 0) {
- pr_err("%s: wait failed for smd open: %d\n",
- __func__, r);
+ pr_err("%s: wait on smd_pkt_dev id:%d OPEN event failed"
+ " rc:%d\n", __func__, smd_pkt_devp->i, r);
} else if (!smd_pkt_devp->is_open) {
- pr_err("%s: Invalid open notification\n", __func__);
+ pr_err("%s: Invalid OPEN event on smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
r = -ENODEV;
} else {
smd_disable_read_intr(smd_pkt_devp->ch);
smd_pkt_devp->ch_size =
smd_write_avail(smd_pkt_devp->ch);
r = 0;
+ D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
}
}
release_pil:
@@ -730,8 +851,12 @@
int r = 0;
struct smd_pkt_dev *smd_pkt_devp = file->private_data;
- if (!smd_pkt_devp)
+ if (!smd_pkt_devp) {
+ pr_err("%s on a NULL device\n", __func__);
return -EINVAL;
+ }
+ D_STATUS("Begin %s on smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
clean_and_signal(smd_pkt_devp);
@@ -750,6 +875,8 @@
smd_pkt_devp->has_reset = 0;
smd_pkt_devp->do_reset_notification = 0;
wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
+ D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
+ __func__, smd_pkt_devp->i);
return r;
}
@@ -774,22 +901,14 @@
NUM_SMD_PKT_PORTS,
DEVICE_NAME);
if (IS_ERR_VALUE(r)) {
- printk(KERN_ERR "ERROR:%s:%i:%s: "
- "alloc_chrdev_region() ret %i.\n",
- __FILE__,
- __LINE__,
- __func__,
- r);
+ pr_err("%s: alloc_chrdev_region() failed ret:%i\n",
+ __func__, r);
goto error0;
}
smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
if (IS_ERR(smd_pkt_classp)) {
- printk(KERN_ERR "ERROR:%s:%i:%s: "
- "class_create() ENOMEM\n",
- __FILE__,
- __LINE__,
- __func__);
+ pr_err("%s: class_create() failed ENOMEM\n", __func__);
r = -ENOMEM;
goto error1;
}
@@ -798,10 +917,8 @@
smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
GFP_KERNEL);
if (IS_ERR(smd_pkt_devp[i])) {
- printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n",
- __FILE__,
- __LINE__,
- __func__);
+ pr_err("%s: kzalloc() failed for smd_pkt_dev id:%d\n",
+ __func__, i);
r = -ENOMEM;
goto error2;
}
@@ -827,11 +944,8 @@
1);
if (IS_ERR_VALUE(r)) {
- printk(KERN_ERR "%s:%i:%s: cdev_add() ret %i\n",
- __FILE__,
- __LINE__,
- __func__,
- r);
+ pr_err("%s: cdev_add() failed for smd_pkt_dev id:%d"
+ " ret:%i\n", __func__, i, r);
kfree(smd_pkt_devp[i]);
goto error2;
}
@@ -844,11 +958,8 @@
smd_pkt_dev_name[i]);
if (IS_ERR(smd_pkt_devp[i]->devicep)) {
- printk(KERN_ERR "%s:%i:%s: "
- "device_create() ENOMEM\n",
- __FILE__,
- __LINE__,
- __func__);
+ pr_err("%s: device_create() failed for smd_pkt_dev"
+ " id:%d\n", __func__, i);
r = -ENOMEM;
cdev_del(&smd_pkt_devp[i]->cdev);
kfree(smd_pkt_devp[i]);
@@ -856,13 +967,13 @@
}
if (device_create_file(smd_pkt_devp[i]->devicep,
&dev_attr_open_timeout))
- pr_err("%s: unable to create device attr on #%d\n",
- __func__, i);
+ pr_err("%s: unable to create device attr for"
+ " smd_pkt_dev id:%d\n", __func__, i);
}
INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
- D(KERN_INFO "SMD Packet Port Driver Initialized.\n");
+ D_STATUS("SMD Packet Port Driver Initialized.\n");
return 0;
error2:
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 28850d0..68e0f41 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -83,6 +83,8 @@
{2, "APPS_RIVA_BT_ACL", NULL, SMD_APPS_WCNSS},
{3, "APPS_RIVA_BT_CMD", NULL, SMD_APPS_WCNSS},
{4, "MBALBRIDGE", NULL, SMD_APPS_MODEM},
+ {5, "APPS_RIVA_ANT_CMD", NULL, SMD_APPS_WCNSS},
+ {6, "APPS_RIVA_ANT_DATA", NULL, SMD_APPS_WCNSS},
{7, "DATA1", NULL, SMD_APPS_MODEM},
{11, "DATA11", NULL, SMD_APPS_MODEM},
{21, "DATA21", NULL, SMD_APPS_MODEM},
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 98f9957..2e9a97c 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -59,10 +59,20 @@
#define D(x...) do {} while (0)
#endif
+/*
+ * Legacy targets use the 32KHz hardware timer and new targets will use
+ * the scheduler timer scaled to a 32KHz tick count.
+ *
+ * As testing on legacy targets permits, we will move them to use
+ * sched_clock() and eventually remove the conditiona compilation.
+ */
#if defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) \
|| defined(CONFIG_ARCH_FSM9XXX)
#define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x08)
-#else
+#elif defined(CONFIG_ARCH_APQ8064) || defined(CONFIG_ARCH_MSM7X01A) || \
+ defined(CONFIG_ARCH_MSM7x25) || defined(CONFIG_ARCH_MSM7X27) || \
+ defined(CONFIG_ARCH_MSM7X27A) || defined(CONFIG_ARCH_MSM8960) || \
+ defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_QSD8X50)
#define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x04)
#endif
@@ -623,6 +633,8 @@
static void init_syms(void) {}
#endif
+#ifdef TIMESTAMP_ADDR
+/* legacy timestamp using 32.768KHz clock */
static inline unsigned int read_timestamp(void)
{
unsigned int tick = 0;
@@ -637,6 +649,18 @@
return tick;
}
+#else
+static inline unsigned int read_timestamp(void)
+{
+ unsigned long long val;
+
+ /* SMEM LOG uses a 32.768KHz timestamp */
+ val = sched_clock() * 32768U;
+ do_div(val, 1000000000U);
+
+ return (unsigned int)val;
+}
+#endif
static void smem_log_event_from_user(struct smem_log_inst *inst,
const char __user *buf, int size, int num)
@@ -649,6 +673,11 @@
int first = 1;
int ret;
+ if (!inst->idx) {
+ pr_err("%s: invalid write index\n", __func__);
+ return;
+ }
+
remote_spin_lock_irqsave(inst->remote_spinlock, flags);
while (num--) {
@@ -898,6 +927,9 @@
local_inst = fp->private_data;
+ if (!local_inst->idx)
+ return -ENODEV;
+
remote_spin_lock_irqsave(local_inst->remote_spinlock, flags);
orig_idx = *local_inst->idx;
@@ -947,6 +979,8 @@
struct smem_log_inst *inst;
inst = fp->private_data;
+ if (!inst->idx)
+ return -ENODEV;
remote_spin_lock_irqsave(inst->remote_spinlock, flags);
@@ -1185,8 +1219,10 @@
int curr_read_avail;
unsigned long flags = 0;
- remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+ if (!inst->idx)
+ return 0;
+ remote_spin_lock_irqsave(inst->remote_spinlock, flags);
curr_read_avail = (*inst->idx - inst->read_idx);
if (curr_read_avail < 0)
curr_read_avail = inst->num - inst->read_idx + *inst->idx;
@@ -1694,6 +1730,10 @@
static int debug_dump(char *buf, int max, uint32_t cont)
{
int r;
+
+ if (!inst[GEN].idx || !inst[GEN].events)
+ return -ENODEV;
+
while (cont) {
update_read_avail(&inst[GEN]);
r = wait_event_interruptible_timeout(inst[GEN].read_wait,
@@ -1714,6 +1754,10 @@
static int debug_dump_sym(char *buf, int max, uint32_t cont)
{
int r;
+
+ if (!inst[GEN].idx || !inst[GEN].events)
+ return -ENODEV;
+
while (cont) {
update_read_avail(&inst[GEN]);
r = wait_event_interruptible_timeout(inst[GEN].read_wait,
@@ -1734,6 +1778,10 @@
static int debug_dump_static(char *buf, int max, uint32_t cont)
{
int r;
+
+ if (!inst[STA].idx || !inst[STA].events)
+ return -ENODEV;
+
while (cont) {
update_read_avail(&inst[STA]);
r = wait_event_interruptible_timeout(inst[STA].read_wait,
@@ -1754,6 +1802,10 @@
static int debug_dump_static_sym(char *buf, int max, uint32_t cont)
{
int r;
+
+ if (!inst[STA].idx || !inst[STA].events)
+ return -ENODEV;
+
while (cont) {
update_read_avail(&inst[STA]);
r = wait_event_interruptible_timeout(inst[STA].read_wait,
@@ -1774,6 +1826,10 @@
static int debug_dump_power(char *buf, int max, uint32_t cont)
{
int r;
+
+ if (!inst[POW].idx || !inst[POW].events)
+ return -ENODEV;
+
while (cont) {
update_read_avail(&inst[POW]);
r = wait_event_interruptible_timeout(inst[POW].read_wait,
@@ -1794,6 +1850,10 @@
static int debug_dump_power_sym(char *buf, int max, uint32_t cont)
{
int r;
+
+ if (!inst[POW].idx || !inst[POW].events)
+ return -ENODEV;
+
while (cont) {
update_read_avail(&inst[POW]);
r = wait_event_interruptible_timeout(inst[POW].read_wait,
@@ -1822,10 +1882,15 @@
size_t count, loff_t *ppos)
{
int r;
- static int bsize;
+ int bsize = 0;
int (*fill)(char *, int, uint32_t) = file->private_data;
- if (!(*ppos))
+ if (!(*ppos)) {
bsize = fill(debug_buffer, EVENTS_PRINT_SIZE, 0);
+
+ if (bsize < 0)
+ bsize = scnprintf(debug_buffer,
+ EVENTS_PRINT_SIZE, "Log not available\n");
+ }
DBG("%s: count %d ppos %d\n", __func__, count, (unsigned int)*ppos);
r = simple_read_from_buffer(buf, count, ppos, debug_buffer,
bsize);
@@ -1840,12 +1905,21 @@
int bsize;
if (!buffer)
return -ENOMEM;
+
bsize = fill(buffer, count, 1);
+ if (bsize < 0) {
+ if (*ppos == 0)
+ bsize = scnprintf(buffer, count, "Log not available\n");
+ else
+ bsize = 0;
+ }
+
DBG("%s: count %d bsize %d\n", __func__, count, bsize);
if (copy_to_user(buf, buffer, bsize)) {
kfree(buffer);
return -EFAULT;
}
+ *ppos += bsize;
kfree(buffer);
return bsize;
}
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 378bcf2..2a6294f 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -68,6 +68,9 @@
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] &= ~0xFF;
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_0] |= vlevel;
+
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
}
static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
@@ -235,6 +238,7 @@
msm_spm_drv_set_vctl(dev, vlevel);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_VCTL);
msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_0);
+ msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW2_PMIC_DATA_1);
mb();
/* Wait for PMIC state to return to idle or until timeout */
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 04dc392..bc4bd21 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -23,6 +23,8 @@
#include <linux/io.h>
#include <linux/kthread.h>
#include <linux/time.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
#include <asm/current.h>
@@ -43,9 +45,12 @@
struct subsys_data *subsys_ptrs[];
};
-struct restart_thread_data {
+struct restart_wq_data {
struct subsys_data *subsys;
+ struct wake_lock ssr_wake_lock;
+ char wakelockname[64];
int coupled;
+ struct work_struct work;
};
struct restart_log {
@@ -56,6 +61,7 @@
static int restart_level;
static int enable_ramdumps;
+struct workqueue_struct *ssr_wq;
static LIST_HEAD(restart_log_list);
static LIST_HEAD(subsystem_list);
@@ -297,9 +303,10 @@
mutex_unlock(&restart_log_mutex);
}
-static int subsystem_restart_thread(void *data)
+static void subsystem_restart_wq_func(struct work_struct *work)
{
- struct restart_thread_data *r_work = data;
+ struct restart_wq_data *r_work = container_of(work,
+ struct restart_wq_data, work);
struct subsys_data **restart_list;
struct subsys_data *subsys = r_work->subsys;
struct subsys_soc_restart_order *soc_restart_order = NULL;
@@ -334,10 +341,8 @@
/* Try to acquire shutdown_lock. If this fails, these subsystems are
* already being restarted - return.
*/
- if (!mutex_trylock(shutdown_lock)) {
- kfree(data);
- do_exit(0);
- }
+ if (!mutex_trylock(shutdown_lock))
+ goto out;
pr_debug("[%p]: Attempting to get powerup lock!\n", current);
@@ -430,15 +435,17 @@
pr_debug("[%p]: Released powerup lock!\n", current);
- kfree(data);
- do_exit(0);
+out:
+ wake_unlock(&r_work->ssr_wake_lock);
+ wake_lock_destroy(&r_work->ssr_wake_lock);
+ kfree(r_work);
}
int subsystem_restart(const char *subsys_name)
{
struct subsys_data *subsys;
- struct task_struct *tsk;
- struct restart_thread_data *data = NULL;
+ struct restart_wq_data *data = NULL;
+ int rc;
if (!subsys_name) {
pr_err("Invalid subsystem name.\n");
@@ -459,7 +466,7 @@
}
if (restart_level != RESET_SOC) {
- data = kzalloc(sizeof(struct restart_thread_data), GFP_KERNEL);
+ data = kzalloc(sizeof(struct restart_wq_data), GFP_KERNEL);
if (!data) {
restart_level = RESET_SOC;
pr_warn("Failed to alloc restart data. Resetting.\n");
@@ -482,18 +489,18 @@
pr_debug("Restarting %s [level=%d]!\n", subsys_name,
restart_level);
- /* Let the kthread handle the actual restarting. Using a
- * workqueue will not work since all restart requests are
- * serialized and it prevents the short circuiting of
- * restart requests for subsystems already in a restart
- * sequence.
- */
- tsk = kthread_run(subsystem_restart_thread, data,
- "subsystem_restart_thread");
- if (IS_ERR(tsk))
- panic("%s: Unable to create thread to restart %s",
- __func__, subsys->name);
+ snprintf(data->wakelockname, sizeof(data->wakelockname),
+ "ssr(%s)", subsys_name);
+ wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND,
+ data->wakelockname);
+ wake_lock(&data->ssr_wake_lock);
+ INIT_WORK(&data->work, subsystem_restart_wq_func);
+ rc = schedule_work(&data->work);
+
+ if (rc < 0)
+ panic("%s: Unable to schedule work to restart %s",
+ __func__, subsys->name);
break;
case RESET_SOC:
@@ -597,6 +604,11 @@
restart_level = RESET_SOC;
+ ssr_wq = alloc_workqueue("ssr_wq", 0, 0);
+
+ if (!ssr_wq)
+ panic("Couldn't allocate workqueue for subsystem restart.\n");
+
ret = ssr_init_soc_restart_orders();
return ret;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index ae7bc32..ea8356c 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1032,7 +1032,7 @@
gpt->freq = 32765;
gpt_hz = 32765;
sclk_hz = 32765;
- if (!machine_is_apq8064_rumi3()) {
+ if (!cpu_is_msm8930()) {
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
}
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index caef19d..7da9e6a 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -17,9 +17,14 @@
extern struct sys_timer msm_timer;
void __iomem *msm_timer_get_timer0_base(void);
-int64_t msm_timer_enter_idle(void);
-void msm_timer_exit_idle(int low_power);
int64_t msm_timer_get_sclk_time(int64_t *period);
uint32_t msm_timer_get_sclk_ticks(void);
int msm_timer_init_time_sync(void (*timeout)(void));
+#ifndef CONFIG_ARM_ARCH_TIMER
+int64_t msm_timer_enter_idle(void);
+void msm_timer_exit_idle(int low_power);
+#else
+static inline int64_t msm_timer_enter_idle(void) { return 0; }
+static inline void msm_timer_exit_idle(int low_power) { return; }
+#endif
#endif
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 1bdec12..90948ea 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -84,7 +84,6 @@
MODULE_NAME);
return IRQ_HANDLED;
}
- disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
ss_restart_inprogress = true;
ret = schedule_work(&riva_fatal_work);
return IRQ_HANDLED;
@@ -115,6 +114,7 @@
{
pil_force_shutdown("wcnss");
flush_delayed_work(&cancel_vote_work);
+ disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
return 0;
}
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index bc5ffce..01d6ac5 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -17,9 +17,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
@@ -44,11 +47,19 @@
(L2X0_CACHE_ID_PART_L310 | rev);
}
+struct l2x0_regs l2x0_saved_regs;
+
+struct l2x0_of_data {
+ void (*setup)(const struct device_node *, u32 *, u32 *);
+ void (*save)(void);
+ void (*resume)(void);
+};
+
static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
{
/* wait for cache operation by line or way to complete */
while (readl_relaxed(reg) & mask)
- ;
+ cpu_relax();
}
#ifdef CONFIG_CACHE_PL310
@@ -64,7 +75,7 @@
{
void __iomem *base = l2x0_base;
-#ifdef CONFIG_ARM_ERRATA_753970
+#ifdef CONFIG_PL310_ERRATA_753970
/* write to an unmmapped register */
writel_relaxed(0, base + L2X0_DUMMY_REG);
#else
@@ -251,27 +262,6 @@
raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
-static void l2x0_inv_range_atomic(unsigned long start, unsigned long end)
-{
- unsigned long addr;
-
- if (start & (CACHE_LINE_SIZE - 1)) {
- start &= ~(CACHE_LINE_SIZE - 1);
- writel_relaxed(start, l2x0_base + L2X0_CLEAN_INV_LINE_PA);
- start += CACHE_LINE_SIZE;
- }
-
- if (end & (CACHE_LINE_SIZE - 1)) {
- end &= ~(CACHE_LINE_SIZE - 1);
- writel_relaxed(end, l2x0_base + L2X0_CLEAN_INV_LINE_PA);
- }
-
- for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
- writel_relaxed(addr, l2x0_base + L2X0_INV_LINE_PA);
-
- mb();
-}
-
static void l2x0_clean_range(unsigned long start, unsigned long end)
{
void __iomem *base = l2x0_base;
@@ -302,17 +292,6 @@
raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
-static void l2x0_clean_range_atomic(unsigned long start, unsigned long end)
-{
- unsigned long addr;
-
- start &= ~(CACHE_LINE_SIZE - 1);
- for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
- writel_relaxed(addr, l2x0_base + L2X0_CLEAN_LINE_PA);
-
- mb();
-}
-
static void l2x0_flush_range(unsigned long start, unsigned long end)
{
void __iomem *base = l2x0_base;
@@ -367,18 +346,36 @@
raw_spin_unlock_irqrestore(&l2x0_lock, flags);
}
-void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+static void l2x0_unlock(u32 cache_id)
{
- __u32 aux, bits;
- __u32 way_size = 0;
+ int lockregs;
+ int i;
+
+ if (cache_id == L2X0_CACHE_ID_PART_L310)
+ lockregs = 8;
+ else
+ /* L210 and unknown types */
+ lockregs = 1;
+
+ for (i = 0; i < lockregs; i++) {
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ }
+}
+
+void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
+{
+ u32 aux;
+ u32 cache_id;
+ u32 way_size = 0;
+ int ways;
const char *type;
l2x0_base = base;
- l2x0_cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
-
- bits = readl_relaxed(l2x0_base + L2X0_CTRL);
- bits &= ~0x01; /* clear bit 0 */
- writel_relaxed(bits, l2x0_base + L2X0_CTRL);
+ cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
+ l2x0_cache_id = cache_id;
aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
@@ -386,64 +383,59 @@
aux |= aux_val;
/* Determine the number of ways */
- switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) {
+ switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
case L2X0_CACHE_ID_PART_L310:
if (aux & (1 << 16))
- l2x0_ways = 16;
+ ways = 16;
else
- l2x0_ways = 8;
+ ways = 8;
type = "L310";
break;
case L2X0_CACHE_ID_PART_L210:
- l2x0_ways = (aux >> 13) & 0xf;
+ ways = (aux >> 13) & 0xf;
type = "L210";
break;
default:
/* Assume unknown chips have 8 ways */
- l2x0_ways = 8;
+ ways = 8;
type = "L2x0 series";
break;
}
writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
- l2x0_way_mask = (1 << l2x0_ways) - 1;
+ l2x0_way_mask = (1 << ways) - 1;
/*
* L2 cache Size = Way size * Number of ways
*/
way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
- way_size = SZ_1K << (way_size + 3);
- l2x0_size = l2x0_ways * way_size;
+ way_size = 1 << (way_size + 3);
+ l2x0_size = ways * way_size * SZ_1K;
l2x0_sets = way_size / CACHE_LINE_SIZE;
+ l2x0_ways = ways;
- l2x0_inv_all();
+ /*
+ * Check if l2x0 controller is already enabled.
+ * If you are booting from non-secure mode
+ * accessing the below registers will fault.
+ */
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* Make sure that I&D is not locked down when starting */
+ l2x0_unlock(cache_id);
- /* enable L2X0 */
- bits = readl_relaxed(l2x0_base + L2X0_CTRL);
- bits |= 0x01; /* set bit 0 */
- writel_relaxed(bits, l2x0_base + L2X0_CTRL);
+ /* l2x0 controller is disabled */
+ writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
- switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) {
- case L2X0_CACHE_ID_PART_L220:
- outer_cache.inv_range = l2x0_inv_range;
- outer_cache.clean_range = l2x0_clean_range;
- outer_cache.flush_range = l2x0_flush_range;
- printk(KERN_INFO "L220 cache controller enabled\n");
- break;
- case L2X0_CACHE_ID_PART_L310:
- outer_cache.inv_range = l2x0_inv_range;
- outer_cache.clean_range = l2x0_clean_range;
- outer_cache.flush_range = l2x0_flush_range;
- printk(KERN_INFO "L310 cache controller enabled\n");
- break;
- case L2X0_CACHE_ID_PART_L210:
- default:
- outer_cache.inv_range = l2x0_inv_range_atomic;
- outer_cache.clean_range = l2x0_clean_range_atomic;
- outer_cache.flush_range = l2x0_flush_range_atomic;
- printk(KERN_INFO "L210 cache controller enabled\n");
- break;
+ l2x0_saved_regs.aux_ctrl = aux;
+
+ l2x0_inv_all();
+
+ /* enable L2X0 */
+ writel_relaxed(1, l2x0_base + L2X0_CTRL);
}
+ outer_cache.inv_range = l2x0_inv_range;
+ outer_cache.clean_range = l2x0_clean_range;
+ outer_cache.flush_range = l2x0_flush_range;
outer_cache.sync = l2x0_cache_sync;
outer_cache.flush_all = l2x0_flush_all;
@@ -454,7 +446,7 @@
mb();
printk(KERN_INFO "%s cache controller enabled\n", type);
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
- l2x0_ways, l2x0_cache_id, aux, l2x0_size);
+ ways, cache_id, aux, l2x0_size);
}
void l2x0_suspend(void)
@@ -484,6 +476,16 @@
/* Invalidate the cache */
l2x0_inv_all();
+ /*
+ * TBD: make sure that l2xo_inv_all finished
+ * before actually enabling the cache. Logically this
+ * is not required as cache sync is atomic operation.
+ * but on 8x25, observed the random crashes and they go
+ * away if we add dmb or disable the L2.
+ * keeping this as temporary workaround until root
+ * cause is find out.
+ */
+ dmb();
}
/* Enable the cache */
@@ -491,3 +493,202 @@
mb();
}
+
+#ifdef CONFIG_OF
+static void __init l2x0_of_setup(const struct device_node *np,
+ u32 *aux_val, u32 *aux_mask)
+{
+ u32 data[2] = { 0, 0 };
+ u32 tag = 0;
+ u32 dirty = 0;
+ u32 val = 0, mask = 0;
+
+ of_property_read_u32(np, "arm,tag-latency", &tag);
+ if (tag) {
+ mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
+ val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
+ }
+
+ of_property_read_u32_array(np, "arm,data-latency",
+ data, ARRAY_SIZE(data));
+ if (data[0] && data[1]) {
+ mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
+ L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
+ val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
+ ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
+ }
+
+ of_property_read_u32(np, "arm,dirty-latency", &dirty);
+ if (dirty) {
+ mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
+ val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
+ }
+
+ *aux_val &= ~mask;
+ *aux_val |= val;
+ *aux_mask &= ~mask;
+}
+
+static void __init pl310_of_setup(const struct device_node *np,
+ u32 *aux_val, u32 *aux_mask)
+{
+ u32 data[3] = { 0, 0, 0 };
+ u32 tag[3] = { 0, 0, 0 };
+ u32 filter[2] = { 0, 0 };
+
+ of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
+ if (tag[0] && tag[1] && tag[2])
+ writel_relaxed(
+ ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+ ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+ ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+ l2x0_base + L2X0_TAG_LATENCY_CTRL);
+
+ of_property_read_u32_array(np, "arm,data-latency",
+ data, ARRAY_SIZE(data));
+ if (data[0] && data[1] && data[2])
+ writel_relaxed(
+ ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) |
+ ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) |
+ ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT),
+ l2x0_base + L2X0_DATA_LATENCY_CTRL);
+
+ of_property_read_u32_array(np, "arm,filter-ranges",
+ filter, ARRAY_SIZE(filter));
+ if (filter[1]) {
+ writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M),
+ l2x0_base + L2X0_ADDR_FILTER_END);
+ writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN,
+ l2x0_base + L2X0_ADDR_FILTER_START);
+ }
+}
+
+static void __init pl310_save(void)
+{
+ u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+ L2X0_CACHE_ID_RTL_MASK;
+
+ l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base +
+ L2X0_TAG_LATENCY_CTRL);
+ l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base +
+ L2X0_DATA_LATENCY_CTRL);
+ l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base +
+ L2X0_ADDR_FILTER_END);
+ l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base +
+ L2X0_ADDR_FILTER_START);
+
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
+ /*
+ * From r2p0, there is Prefetch offset/control register
+ */
+ l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base +
+ L2X0_PREFETCH_CTRL);
+ /*
+ * From r3p0, there is Power control register
+ */
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
+ l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base +
+ L2X0_POWER_CTRL);
+ }
+}
+
+static void l2x0_resume(void)
+{
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* restore aux ctrl and enable l2 */
+ l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
+
+ writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base +
+ L2X0_AUX_CTRL);
+
+ l2x0_inv_all();
+
+ writel_relaxed(1, l2x0_base + L2X0_CTRL);
+ }
+}
+
+static void pl310_resume(void)
+{
+ u32 l2x0_revision;
+
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* restore pl310 setup */
+ writel_relaxed(l2x0_saved_regs.tag_latency,
+ l2x0_base + L2X0_TAG_LATENCY_CTRL);
+ writel_relaxed(l2x0_saved_regs.data_latency,
+ l2x0_base + L2X0_DATA_LATENCY_CTRL);
+ writel_relaxed(l2x0_saved_regs.filter_end,
+ l2x0_base + L2X0_ADDR_FILTER_END);
+ writel_relaxed(l2x0_saved_regs.filter_start,
+ l2x0_base + L2X0_ADDR_FILTER_START);
+
+ l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) &
+ L2X0_CACHE_ID_RTL_MASK;
+
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) {
+ writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
+ l2x0_base + L2X0_PREFETCH_CTRL);
+ if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0)
+ writel_relaxed(l2x0_saved_regs.pwr_ctrl,
+ l2x0_base + L2X0_POWER_CTRL);
+ }
+ }
+
+ l2x0_resume();
+}
+
+static const struct l2x0_of_data pl310_data = {
+ pl310_of_setup,
+ pl310_save,
+ pl310_resume,
+};
+
+static const struct l2x0_of_data l2x0_data = {
+ l2x0_of_setup,
+ NULL,
+ l2x0_resume,
+};
+
+static const struct of_device_id l2x0_ids[] __initconst = {
+ { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
+ { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
+ { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data },
+ {}
+};
+
+int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
+{
+ struct device_node *np;
+ struct l2x0_of_data *data;
+ struct resource res;
+
+ np = of_find_matching_node(NULL, l2x0_ids);
+ if (!np)
+ return -ENODEV;
+
+ if (of_address_to_resource(np, 0, &res))
+ return -ENODEV;
+
+ l2x0_base = ioremap(res.start, resource_size(&res));
+ if (!l2x0_base)
+ return -ENOMEM;
+
+ l2x0_saved_regs.phy_base = res.start;
+
+ data = of_match_node(l2x0_ids, np)->data;
+
+ /* L2 configuration can only be changed if the cache is disabled */
+ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ if (data->setup)
+ data->setup(np, &aux_val, &aux_mask);
+ }
+
+ if (data->save)
+ data->save();
+
+ l2x0_init(l2x0_base, aux_val, aux_mask);
+
+ outer_cache.resume = data->resume;
+ return 0;
+}
+#endif
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 58f4720..338e8c2 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -36,6 +36,8 @@
return "arm/armv6";
case ARM_PERF_PMU_ID_V6MP:
return "arm/mpcore";
+ case ARM_PERF_PMU_ID_CA5:
+ return "arm/armv7";
case ARM_PERF_PMU_ID_CA8:
return "arm/armv7";
case ARM_PERF_PMU_ID_CA9:
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index cde8031..0ff30c3 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1136,6 +1136,7 @@
apq8064_cdp MACH_APQ8064_CDP APQ8064_CDP 3948
apq8064_mtp MACH_APQ8064_MTP APQ8064_MTP 3949
apq8064_liquid MACH_APQ8064_LIQUID APQ8064_LIQUID 3951
+mpq8064_cdp MACH_MPQ8064_CDP MPQ8064_CDP 3993
mpq8064_hrd MACH_MPQ8064_HRD MPQ8064_HRD 3994
mpq8064_dtv MACH_MPQ8064_DTV MPQ8064_DTV 3995
msm7627a_qrd3 MACH_MSM7627A_QRD3 MSM7627A_QRD3 4005
diff --git a/drivers/base/base.h b/drivers/base/base.h
index a34dca0..9641309 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -105,6 +105,7 @@
extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
+extern void driver_deferred_probe_del(struct device *dev);
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 78445f4..14cdf13 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -589,6 +589,7 @@
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
+ INIT_LIST_HEAD(&dev->deferred_probe);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
@@ -1120,6 +1121,7 @@
device_remove_file(dev, &uevent_attr);
device_remove_attrs(dev);
bus_remove_device(dev);
+ driver_deferred_probe_del(dev);
/*
* Some platform devices are driven without driver attached
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6658da7..455b502 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -28,6 +28,133 @@
#include "base.h"
#include "power/power.h"
+/*
+ * Deferred Probe infrastructure.
+ *
+ * Sometimes driver probe order matters, but the kernel doesn't always have
+ * dependency information which means some drivers will get probed before a
+ * resource it depends on is available. For example, an SDHCI driver may
+ * first need a GPIO line from an i2c GPIO controller before it can be
+ * initialized. If a required resource is not available yet, a driver can
+ * request probing to be deferred by returning -EPROBE_DEFER from its probe hook
+ *
+ * Deferred probe maintains two lists of devices, a pending list and an active
+ * list. A driver returning -EPROBE_DEFER causes the device to be added to the
+ * pending list. A successful driver probe will trigger moving all devices
+ * from the pending to the active list so that the workqueue will eventually
+ * retry them.
+ *
+ * The deferred_probe_mutex must be held any time the deferred_probe_*_list
+ * of the (struct device*)->deferred_probe pointers are manipulated
+ */
+static DEFINE_MUTEX(deferred_probe_mutex);
+static LIST_HEAD(deferred_probe_pending_list);
+static LIST_HEAD(deferred_probe_active_list);
+static struct workqueue_struct *deferred_wq;
+
+/**
+ * deferred_probe_work_func() - Retry probing devices in the active list.
+ */
+static void deferred_probe_work_func(struct work_struct *work)
+{
+ struct device *dev;
+ /*
+ * This block processes every device in the deferred 'active' list.
+ * Each device is removed from the active list and passed to
+ * bus_probe_device() to re-attempt the probe. The loop continues
+ * until every device in the active list is removed and retried.
+ *
+ * Note: Once the device is removed from the list and the mutex is
+ * released, it is possible for the device get freed by another thread
+ * and cause a illegal pointer dereference. This code uses
+ * get/put_device() to ensure the device structure cannot disappear
+ * from under our feet.
+ */
+ mutex_lock(&deferred_probe_mutex);
+ while (!list_empty(&deferred_probe_active_list)) {
+ dev = list_first_entry(&deferred_probe_active_list,
+ typeof(*dev), deferred_probe);
+ list_del_init(&dev->deferred_probe);
+
+ get_device(dev);
+
+ /* Drop the mutex while probing each device; the probe path
+ * may manipulate the deferred list */
+ mutex_unlock(&deferred_probe_mutex);
+ dev_dbg(dev, "Retrying from deferred list\n");
+ bus_probe_device(dev);
+ mutex_lock(&deferred_probe_mutex);
+
+ put_device(dev);
+ }
+ mutex_unlock(&deferred_probe_mutex);
+}
+static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
+
+static void driver_deferred_probe_add(struct device *dev)
+{
+ mutex_lock(&deferred_probe_mutex);
+ if (list_empty(&dev->deferred_probe)) {
+ dev_dbg(dev, "Added to deferred list\n");
+ list_add(&dev->deferred_probe, &deferred_probe_pending_list);
+ }
+ mutex_unlock(&deferred_probe_mutex);
+}
+
+void driver_deferred_probe_del(struct device *dev)
+{
+ mutex_lock(&deferred_probe_mutex);
+ if (!list_empty(&dev->deferred_probe)) {
+ dev_dbg(dev, "Removed from deferred list\n");
+ list_del_init(&dev->deferred_probe);
+ }
+ mutex_unlock(&deferred_probe_mutex);
+}
+
+static bool driver_deferred_probe_enable = false;
+/**
+ * driver_deferred_probe_trigger() - Kick off re-probing deferred devices
+ *
+ * This functions moves all devices from the pending list to the active
+ * list and schedules the deferred probe workqueue to process them. It
+ * should be called anytime a driver is successfully bound to a device.
+ */
+static void driver_deferred_probe_trigger(void)
+{
+ if (!driver_deferred_probe_enable)
+ return;
+
+ /* A successful probe means that all the devices in the pending list
+ * should be triggered to be reprobed. Move all the deferred devices
+ * into the active list so they can be retried by the workqueue */
+ mutex_lock(&deferred_probe_mutex);
+ list_splice_tail_init(&deferred_probe_pending_list,
+ &deferred_probe_active_list);
+ mutex_unlock(&deferred_probe_mutex);
+
+ /* Kick the re-probe thread. It may already be scheduled, but
+ * it is safe to kick it again. */
+ queue_work(deferred_wq, &deferred_probe_work);
+}
+
+/**
+ * deferred_probe_initcall() - Enable probing of deferred devices
+ *
+ * We don't want to get in the way when the bulk of drivers are getting probed.
+ * Instead, this initcall makes sure that deferred probing is delayed until
+ * late_initcall time.
+ */
+static int deferred_probe_initcall(void)
+{
+ deferred_wq = create_singlethread_workqueue("deferwq");
+ if (WARN_ON(!deferred_wq))
+ return -ENOMEM;
+
+ driver_deferred_probe_enable = true;
+ driver_deferred_probe_trigger();
+ return 0;
+}
+late_initcall(deferred_probe_initcall);
static void driver_bound(struct device *dev)
{
@@ -42,6 +169,11 @@
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
+ /* Make sure the device is no longer in one of the deferred lists
+ * and kick off retrying all pending devices */
+ driver_deferred_probe_del(dev);
+ driver_deferred_probe_trigger();
+
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
@@ -142,7 +274,11 @@
driver_sysfs_remove(dev);
dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
+ if (ret == -EPROBE_DEFER) {
+ /* Driver requested deferred probing */
+ dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
+ driver_deferred_probe_add(dev);
+ } else if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index cd32152..926bd69 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -164,7 +164,8 @@
unsigned char *buf_in_qdsp_1;
unsigned char *buf_in_qdsp_2;
unsigned char *buf_in_qdsp_cntl;
- unsigned char *buf_in_wcnss;
+ unsigned char *buf_in_wcnss_1;
+ unsigned char *buf_in_wcnss_2;
unsigned char *buf_in_wcnss_cntl;
unsigned char *usb_buf_out;
unsigned char *apps_rsp_buf;
@@ -183,7 +184,8 @@
int in_busy_2;
int in_busy_qdsp_1;
int in_busy_qdsp_2;
- int in_busy_wcnss;
+ int in_busy_wcnss_1;
+ int in_busy_wcnss_2;
int read_len_legacy;
unsigned char *hdlc_buf;
unsigned hdlc_count;
@@ -222,7 +224,8 @@
struct diag_request *write_ptr_svc;
struct diag_request *write_ptr_qdsp_1;
struct diag_request *write_ptr_qdsp_2;
- struct diag_request *write_ptr_wcnss;
+ struct diag_request *write_ptr_wcnss_1;
+ struct diag_request *write_ptr_wcnss_2;
int logging_mode;
int mask_check;
int logging_process_id;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index d9f12ac..7e2333a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -424,7 +424,8 @@
driver->in_busy_2 = 1;
driver->in_busy_qdsp_1 = 1;
driver->in_busy_qdsp_2 = 1;
- driver->in_busy_wcnss = 1;
+ driver->in_busy_wcnss_1 = 1;
+ driver->in_busy_wcnss_2 = 1;
#ifdef CONFIG_DIAG_SDIO_PIPE
driver->in_busy_sdio = 1;
#endif
@@ -434,7 +435,8 @@
driver->in_busy_2 = 0;
driver->in_busy_qdsp_1 = 0;
driver->in_busy_qdsp_2 = 0;
- driver->in_busy_wcnss = 0;
+ driver->in_busy_wcnss_1 = 0;
+ driver->in_busy_wcnss_2 = 0;
/* Poll SMD channels to check for data*/
if (driver->ch)
queue_work(driver->diag_wq,
@@ -465,9 +467,10 @@
diagfwd_disconnect();
driver->in_busy_1 = 0;
driver->in_busy_2 = 0;
+ driver->in_busy_qdsp_1 = 0;
driver->in_busy_qdsp_2 = 0;
- driver->in_busy_qdsp_2 = 0;
- driver->in_busy_wcnss = 0;
+ driver->in_busy_wcnss_1 = 0;
+ driver->in_busy_wcnss_2 = 0;
/* Poll SMD channels to check for data*/
if (driver->ch)
queue_work(driver->diag_wq,
@@ -607,16 +610,27 @@
driver->in_busy_qdsp_2 = 0;
}
/* copy wncss data */
- if (driver->in_busy_wcnss == 1) {
+ if (driver->in_busy_wcnss_1 == 1) {
num_data++;
/*Copy the length of data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret,
- (driver->write_ptr_wcnss->length), 4);
+ (driver->write_ptr_wcnss_1->length), 4);
/*Copy the actual data being passed*/
COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
- buf_in_wcnss),
- driver->write_ptr_wcnss->length);
- driver->in_busy_wcnss = 0;
+ buf_in_wcnss_1),
+ driver->write_ptr_wcnss_1->length);
+ driver->in_busy_wcnss_1 = 0;
+ }
+ if (driver->in_busy_wcnss_2 == 1) {
+ num_data++;
+ /*Copy the length of data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret,
+ (driver->write_ptr_wcnss_2->length), 4);
+ /*Copy the actual data being passed*/
+ COPY_USER_SPACE_OR_EXIT(buf+ret, *(driver->
+ buf_in_wcnss_2),
+ driver->write_ptr_wcnss_2->length);
+ driver->in_busy_wcnss_2 = 0;
}
#ifdef CONFIG_DIAG_SDIO_PIPE
/* copy 9K data over SDIO */
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 4cf6d33..65ddfec 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -271,7 +271,8 @@
queue_work(driver->diag_wq, &(driver->
diag_read_smd_qdsp_work));
} else if (proc_num == WCNSS_DATA) {
- driver->in_busy_wcnss = 0;
+ driver->in_busy_wcnss_1 = 0;
+ driver->in_busy_wcnss_2 = 0;
queue_work(driver->diag_wq, &(driver->
diag_read_smd_wcnss_work));
}
@@ -343,11 +344,21 @@
void __diag_smd_wcnss_send_req(void)
{
- void *buf = driver->buf_in_wcnss;
- int *in_busy_wcnss_ptr = &(driver->in_busy_wcnss);
- struct diag_request *write_ptr_wcnss = driver->write_ptr_wcnss;
+ void *buf = NULL;
+ int *in_busy_wcnss_ptr = NULL;
+ struct diag_request *write_ptr_wcnss = NULL;
- if ((!driver->in_busy_wcnss) && driver->ch_wcnss && buf) {
+ if (!driver->in_busy_wcnss_1) {
+ buf = driver->buf_in_wcnss_1;
+ write_ptr_wcnss = driver->write_ptr_wcnss_1;
+ in_busy_wcnss_ptr = &(driver->in_busy_wcnss_1);
+ } else if (!driver->in_busy_wcnss_2) {
+ buf = driver->buf_in_wcnss_2;
+ write_ptr_wcnss = driver->write_ptr_wcnss_2;
+ in_busy_wcnss_ptr = &(driver->in_busy_wcnss_2);
+ }
+
+ if (driver->ch_wcnss && buf) {
int r = smd_read_avail(driver->ch_wcnss);
if (r > IN_BUF_SIZE) {
if (r < MAX_IN_BUF_SIZE) {
@@ -499,6 +510,18 @@
}
+void diag_toggle_event_mask(int toggle)
+{
+ uint8_t *ptr = driver->event_masks;
+
+ mutex_lock(&driver->diagchar_mutex);
+ if (toggle)
+ memset(ptr, 0xFF, EVENT_MASK_SIZE);
+ else
+ memset(ptr, 0, EVENT_MASK_SIZE);
+ mutex_unlock(&driver->diagchar_mutex);
+}
+
static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
{
uint8_t *ptr = driver->event_masks;
@@ -802,9 +825,8 @@
*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
*(uint16_t *)(driver->apps_rsp_buf + 4) =
EVENT_LAST_ID + 1;
- for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
- *(unsigned char *)(driver->apps_rsp_buf + 6 + i)
- = 0x0;
+ memcpy(driver->apps_rsp_buf+6, driver->event_masks,
+ EVENT_LAST_ID/8+1);
/* cannot do this on work queue, as each event update
needs a num_bytes variable. Each queue_work call will
overwrite the previous input, as its the same struct */
@@ -821,6 +843,8 @@
#endif
} else if (*buf == 0x60) {
diag_event_config = *(buf+1);
+ diag_toggle_event_mask(*(buf+1));
+ diag_update_userspace_clients(EVENT_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
if (chk_apps_only()) {
driver->apps_rsp_buf[0] = 0x60;
@@ -1248,7 +1272,8 @@
driver->in_busy_2 = 0;
driver->in_busy_qdsp_1 = 0;
driver->in_busy_qdsp_2 = 0;
- driver->in_busy_wcnss = 0;
+ driver->in_busy_wcnss_1 = 0;
+ driver->in_busy_wcnss_2 = 0;
/* Poll SMD channels to check for data*/
queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
@@ -1282,7 +1307,8 @@
driver->in_busy_2 = 1;
driver->in_busy_qdsp_1 = 1;
driver->in_busy_qdsp_2 = 1;
- driver->in_busy_wcnss = 1;
+ driver->in_busy_wcnss_1 = 1;
+ driver->in_busy_wcnss_2 = 1;
}
#ifdef CONFIG_DIAG_SDIO_PIPE
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
@@ -1314,8 +1340,13 @@
driver->in_busy_qdsp_2 = 0;
APPEND_DEBUG('P');
queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
- } else if (buf == (void *)driver->buf_in_wcnss) {
- driver->in_busy_wcnss = 0;
+ } else if (buf == driver->buf_in_wcnss_1) {
+ driver->in_busy_wcnss_1 = 0;
+ APPEND_DEBUG('r');
+ queue_work(driver->diag_wq,
+ &(driver->diag_read_smd_wcnss_work));
+ } else if (buf == driver->buf_in_wcnss_2) {
+ driver->in_busy_wcnss_2 = 0;
APPEND_DEBUG('R');
queue_work(driver->diag_wq,
&(driver->diag_read_smd_wcnss_work));
@@ -1568,11 +1599,17 @@
if (driver->buf_in_qdsp_2 == NULL)
goto err;
}
- if (driver->buf_in_wcnss == NULL) {
- driver->buf_in_wcnss = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_wcnss == NULL)
+ if (driver->buf_in_wcnss_1 == NULL) {
+ driver->buf_in_wcnss_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_wcnss_1 == NULL)
goto err;
}
+ if (driver->buf_in_wcnss_2 == NULL) {
+ driver->buf_in_wcnss_2 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_wcnss_2 == NULL)
+ goto err;
+ }
+
if (driver->buf_msg_mask_update == NULL) {
driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
GFP_KERNEL);
@@ -1657,12 +1694,19 @@
if (driver->write_ptr_qdsp_2 == NULL)
goto err;
}
- if (driver->write_ptr_wcnss == NULL) {
- driver->write_ptr_wcnss = kzalloc(
+ if (driver->write_ptr_wcnss_1 == NULL) {
+ driver->write_ptr_wcnss_1 = kzalloc(
sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_wcnss == NULL)
+ if (driver->write_ptr_wcnss_1 == NULL)
goto err;
}
+ if (driver->write_ptr_wcnss_2 == NULL) {
+ driver->write_ptr_wcnss_2 = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->write_ptr_wcnss_2 == NULL)
+ goto err;
+ }
+
if (driver->usb_read_ptr == NULL) {
driver->usb_read_ptr = kzalloc(
sizeof(struct diag_request), GFP_KERNEL);
@@ -1712,7 +1756,8 @@
kfree(driver->buf_in_2);
kfree(driver->buf_in_qdsp_1);
kfree(driver->buf_in_qdsp_2);
- kfree(driver->buf_in_wcnss);
+ kfree(driver->buf_in_wcnss_1);
+ kfree(driver->buf_in_wcnss_2);
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -1730,7 +1775,8 @@
kfree(driver->write_ptr_2);
kfree(driver->write_ptr_qdsp_1);
kfree(driver->write_ptr_qdsp_2);
- kfree(driver->write_ptr_wcnss);
+ kfree(driver->write_ptr_wcnss_1);
+ kfree(driver->write_ptr_wcnss_2);
kfree(driver->usb_read_ptr);
kfree(driver->apps_rsp_buf);
kfree(driver->user_space_data);
@@ -1760,7 +1806,8 @@
kfree(driver->buf_in_2);
kfree(driver->buf_in_qdsp_1);
kfree(driver->buf_in_qdsp_2);
- kfree(driver->buf_in_wcnss);
+ kfree(driver->buf_in_wcnss_1);
+ kfree(driver->buf_in_wcnss_2);
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -1778,7 +1825,8 @@
kfree(driver->write_ptr_2);
kfree(driver->write_ptr_qdsp_1);
kfree(driver->write_ptr_qdsp_2);
- kfree(driver->write_ptr_wcnss);
+ kfree(driver->write_ptr_wcnss_1);
+ kfree(driver->write_ptr_wcnss_2);
kfree(driver->usb_read_ptr);
kfree(driver->apps_rsp_buf);
kfree(driver->user_space_data);
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 7a08e50..de9e2c4 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -271,10 +271,11 @@
unsigned long iova_length,
unsigned long flags)
{
- unsigned long temp_phys, temp_iova;
struct iommu_domain *domain;
- int i, ret = 0;
+ int ret = 0;
unsigned long extra;
+ int prot = ION_IS_CACHED(flags) ? 1 : 0;
+ struct scatterlist *sglist = 0;
data->mapped_size = iova_length;
@@ -300,32 +301,36 @@
goto out1;
}
- temp_iova = data->iova_addr;
- temp_phys = buffer->priv_phys;
- for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
- temp_phys += SZ_4K) {
- ret = iommu_map(domain, temp_iova, temp_phys,
- get_order(SZ_4K),
- ION_IS_CACHED(flags) ? 1 : 0);
+ sglist = vmalloc(sizeof(*sglist));
+ if (!sglist)
+ goto out1;
- if (ret) {
- pr_err("%s: could not map %lx to %lx in domain %p\n",
- __func__, temp_iova, temp_phys, domain);
- goto out2;
- }
+ sg_init_table(sglist, 1);
+ sglist->length = buffer->size;
+ sglist->offset = 0;
+ sglist->dma_address = buffer->priv_phys;
+
+ ret = iommu_map_range(domain, data->iova_addr, sglist,
+ buffer->size, prot);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p\n",
+ __func__, data->iova_addr, domain);
+ goto out1;
}
- if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
- goto out2;
-
- return 0;
-
+ if (extra) {
+ unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ if (ret)
+ goto out2;
+ }
+ vfree(sglist);
+ return ret;
out2:
- for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, buffer->size);
out1:
+ vfree(sglist);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
@@ -336,8 +341,6 @@
void ion_carveout_heap_unmap_iommu(struct ion_iommu_map *data)
{
- int i;
- unsigned long temp_iova;
unsigned int domain_num;
unsigned int partition_num;
struct iommu_domain *domain;
@@ -355,10 +358,7 @@
return;
}
- temp_iova = data->iova_addr;
- for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 85c0534..7d99482 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -295,8 +295,7 @@
buffer->priv_phys = ION_CP_ALLOCATE_FAIL;
}
-struct scatterlist *ion_cp_heap_map_dma(struct ion_heap *heap,
- struct ion_buffer *buffer)
+struct scatterlist *ion_cp_heap_create_sglist(struct ion_buffer *buffer)
{
struct scatterlist *sglist;
@@ -312,6 +311,12 @@
return sglist;
}
+struct scatterlist *ion_cp_heap_map_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ return ion_cp_heap_create_sglist(buffer);
+}
+
void ion_cp_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
@@ -570,10 +575,11 @@
unsigned long iova_length,
unsigned long flags)
{
- unsigned long temp_phys, temp_iova;
struct iommu_domain *domain;
- int i, ret = 0;
+ int ret = 0;
unsigned long extra;
+ int prot = ION_IS_CACHED(flags) ? 1 : 0;
+ struct scatterlist *sglist = 0;
data->mapped_size = iova_length;
@@ -599,30 +605,33 @@
goto out1;
}
- temp_iova = data->iova_addr;
- temp_phys = buffer->priv_phys;
- for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
- temp_phys += SZ_4K) {
- ret = iommu_map(domain, temp_iova, temp_phys,
- get_order(SZ_4K),
- ION_IS_CACHED(flags) ? 1 : 0);
-
- if (ret) {
- pr_err("%s: could not map %lx to %lx in domain %p\n",
- __func__, temp_iova, temp_phys, domain);
- goto out2;
- }
+ sglist = ion_cp_heap_create_sglist(buffer);
+ if (IS_ERR_OR_NULL(sglist)) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+ ret = iommu_map_range(domain, data->iova_addr, sglist,
+ buffer->size, prot);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p\n",
+ __func__, data->iova_addr, domain);
+ goto out1;
}
- if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
- goto out2;
-
- return 0;
+ if (extra) {
+ unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ if (ret)
+ goto out2;
+ }
+ vfree(sglist);
+ return ret;
out2:
- for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+ iommu_unmap_range(domain, data->iova_addr, buffer->size);
out1:
+ if (!IS_ERR_OR_NULL(sglist))
+ vfree(sglist);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
out:
@@ -631,8 +640,6 @@
static void ion_cp_heap_unmap_iommu(struct ion_iommu_map *data)
{
- int i;
- unsigned long temp_iova;
unsigned int domain_num;
unsigned int partition_num;
struct iommu_domain *domain;
@@ -650,10 +657,7 @@
return;
}
- temp_iova = data->iova_addr;
- for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index e754496..baf0a66 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -33,6 +33,7 @@
struct page **pages;
int nrpages;
unsigned long size;
+ struct scatterlist *iommu_sglist;
};
static int ion_iommu_heap_allocate(struct ion_heap *heap,
@@ -56,11 +57,22 @@
ret = -ENOMEM;
goto err1;
}
+ data->iommu_sglist = vmalloc(sizeof(*data->iommu_sglist) *
+ data->nrpages);
+ if (!data->iommu_sglist) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ sg_init_table(data->iommu_sglist, data->nrpages);
for (i = 0; i < data->nrpages; i++) {
data->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!data->pages[i])
goto err2;
+
+ sg_set_page(&data->iommu_sglist[i], data->pages[i],
+ PAGE_SIZE, 0);
}
@@ -73,6 +85,9 @@
err2:
+ vfree(data->iommu_sglist);
+ data->iommu_sglist = NULL;
+
for (i = 0; i < data->nrpages; i++) {
if (data->pages[i])
__free_page(data->pages[i]);
@@ -94,6 +109,9 @@
for (i = 0; i < data->nrpages; i++)
__free_page(data->pages[i]);
+ vfree(data->iommu_sglist);
+ data->iommu_sglist = NULL;
+
kfree(data->pages);
kfree(data);
}
@@ -160,11 +178,11 @@
unsigned long iova_length,
unsigned long flags)
{
- unsigned long temp_iova;
struct iommu_domain *domain;
- struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
- int i, j, ret = 0;
+ int ret = 0;
unsigned long extra;
+ int prot = ION_IS_CACHED(flags) ? 1 : 0;
+ struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
BUG_ON(!msm_use_iommu());
@@ -186,36 +204,24 @@
goto out1;
}
- temp_iova = data->iova_addr;
- for (i = buffer->size, j = 0; i > 0; j++, i -= SZ_4K,
- temp_iova += SZ_4K) {
- ret = iommu_map(domain, temp_iova,
- page_to_phys(buffer_data->pages[j]),
- get_order(SZ_4K),
- ION_IS_CACHED(flags) ? 1 : 0);
-
- if (ret) {
- pr_err("%s: could not map %lx to %x in domain %p\n",
- __func__, temp_iova,
- page_to_phys(buffer_data->pages[j]),
- domain);
- goto out2;
- }
+ ret = iommu_map_range(domain, data->iova_addr,
+ buffer_data->iommu_sglist, buffer->size, prot);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p\n",
+ __func__, data->iova_addr, domain);
+ goto out1;
}
-
- if (extra &&
- msm_iommu_map_extra
- (domain, temp_iova, extra, flags) < 0)
- goto out2;
-
- return 0;
-
+ if (extra) {
+ unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ if (ret)
+ goto out2;
+ }
+ return ret;
out2:
- for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, buffer->size);
out1:
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
buffer->size);
@@ -227,8 +233,6 @@
void ion_iommu_heap_unmap_iommu(struct ion_iommu_map *data)
{
- int i;
- unsigned long temp_iova;
unsigned int domain_num;
unsigned int partition_num;
struct iommu_domain *domain;
@@ -245,10 +249,7 @@
return;
}
- temp_iova = data->iova_addr;
- for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
@@ -293,30 +294,13 @@
static struct scatterlist *ion_iommu_heap_map_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- struct scatterlist *sglist = NULL;
- if (buffer->priv_virt) {
- struct ion_iommu_priv_data *data = buffer->priv_virt;
- unsigned int i;
-
- if (!data->nrpages)
- return NULL;
-
- sglist = vmalloc(sizeof(*sglist) * data->nrpages);
- if (!sglist)
- return ERR_PTR(-ENOMEM);
-
- sg_init_table(sglist, data->nrpages);
- for (i = 0; i < data->nrpages; ++i)
- sg_set_page(&sglist[i], data->pages[i], PAGE_SIZE, 0);
- }
- return sglist;
+ struct ion_iommu_priv_data *data = buffer->priv_virt;
+ return data->iommu_sglist;
}
static void ion_iommu_heap_unmap_dma(struct ion_heap *heap,
struct ion_buffer *buffer)
{
- if (buffer->sglist)
- vfree(buffer->sglist);
}
static struct ion_heap_ops iommu_heap_ops = {
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 316740e..bc288e7 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -104,8 +104,6 @@
void ion_system_heap_unmap_iommu(struct ion_iommu_map *data)
{
- int i;
- unsigned long temp_iova;
unsigned int domain_num;
unsigned int partition_num;
struct iommu_domain *domain;
@@ -123,10 +121,7 @@
return;
}
- temp_iova = data->iova_addr;
- for (i = data->mapped_size; i > 0; i -= SZ_4K, temp_iova += SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, data->mapped_size);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
@@ -206,11 +201,15 @@
unsigned long iova_length,
unsigned long flags)
{
- int ret, i;
- unsigned long temp_iova;
+ int ret = 0, i;
struct iommu_domain *domain;
- void *temp_phys;
unsigned long extra;
+ unsigned long extra_iova_addr;
+ struct page *page;
+ int npages = buffer->size >> PAGE_SHIFT;
+ void *vaddr = buffer->priv_virt;
+ struct scatterlist *sglist = 0;
+ int prot = ION_IS_CACHED(flags) ? 1 : 0;
if (!ION_IS_CACHED(flags))
return -EINVAL;
@@ -236,35 +235,46 @@
goto out1;
}
- temp_iova = data->iova_addr;
- temp_phys = buffer->vaddr;
- for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
- temp_phys += SZ_4K) {
- ret = iommu_map(domain, temp_iova,
- page_to_phys(vmalloc_to_page(temp_phys)),
- get_order(SZ_4K), ION_IS_CACHED(flags) ? 1 : 0);
- if (ret) {
- pr_err("%s: could not map %lx to %x in domain %p\n",
- __func__, temp_iova,
- page_to_phys(vmalloc_to_page(temp_phys)),
- domain);
- goto out2;
- }
+ sglist = vmalloc(sizeof(*sglist) * npages);
+ if (!sglist) {
+ ret = -ENOMEM;
+ goto out1;
}
- if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
- goto out2;
+ sg_init_table(sglist, npages);
+ for (i = 0; i < npages; i++) {
+ page = vmalloc_to_page(vaddr);
+ if (!page)
+ goto out1;
+ sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
+ vaddr += PAGE_SIZE;
+ }
- return 0;
+ ret = iommu_map_range(domain, data->iova_addr, sglist,
+ buffer->size, prot);
+
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p\n",
+ __func__, data->iova_addr, domain);
+ goto out1;
+ }
+
+ extra_iova_addr = data->iova_addr + buffer->size;
+ if (extra) {
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ if (ret)
+ goto out2;
+ }
+ vfree(sglist);
+ return ret;
out2:
- for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
-
+ iommu_unmap_range(domain, data->iova_addr, buffer->size);
out1:
+ vfree(sglist);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
- data->mapped_size);
+ data->mapped_size);
out:
return ret;
}
@@ -408,10 +418,12 @@
unsigned long iova_length,
unsigned long flags)
{
- int ret, i;
+ int ret = 0;
struct iommu_domain *domain;
- unsigned long temp_phys, temp_iova;
unsigned long extra;
+ int prot = ION_IS_CACHED(flags) ? 1 : 0;
+ struct scatterlist *sglist = 0;
+ struct page *page = 0;
if (!ION_IS_CACHED(flags))
return -EINVAL;
@@ -438,30 +450,36 @@
ret = -ENOMEM;
goto out1;
}
- temp_iova = data->iova_addr;
- temp_phys = virt_to_phys(buffer->vaddr);
- for (i = buffer->size; i > 0; i -= SZ_4K, temp_iova += SZ_4K,
- temp_phys += SZ_4K) {
- ret = iommu_map(domain, temp_iova,
- temp_phys,
- get_order(SZ_4K), ION_IS_CACHED(flags) ? 1 : 0);
+ page = virt_to_page(buffer->vaddr);
- if (ret) {
- pr_err("%s: could not map %lx to %lx in domain %p\n",
- __func__, temp_iova, temp_phys, domain);
- goto out2;
- }
+ sglist = vmalloc(sizeof(*sglist));
+ if (!sglist)
+ goto out1;
+
+ sg_init_table(sglist, 1);
+ sg_set_page(sglist, page, buffer->size, 0);
+
+ ret = iommu_map_range(domain, data->iova_addr, sglist,
+ buffer->size, prot);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p\n",
+ __func__, data->iova_addr, domain);
+ goto out1;
}
- if (extra && (msm_iommu_map_extra(domain, temp_iova, extra, flags) < 0))
- goto out2;
-
- return 0;
+ if (extra) {
+ unsigned long extra_iova_addr = data->iova_addr + buffer->size;
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ if (ret)
+ goto out2;
+ }
+ vfree(sglist);
+ return ret;
out2:
- for ( ; i < buffer->size; i += SZ_4K, temp_iova -= SZ_4K)
- iommu_unmap(domain, temp_iova, get_order(SZ_4K));
+ iommu_unmap_range(domain, data->iova_addr, buffer->size);
out1:
+ vfree(sglist);
msm_free_iova_address(data->iova_addr, domain_num, partition_num,
data->mapped_size);
out:
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 5189388..c3367b5 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -16,6 +16,7 @@
msm_kgsl_core-$(CONFIG_MSM_KGSL_DRM) += kgsl_drm.o
msm_kgsl_core-$(CONFIG_MSM_SCM) += kgsl_pwrscale_trustzone.o
msm_kgsl_core-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += kgsl_pwrscale_idlestats.o
+msm_kgsl_core-$(CONFIG_MSM_DCVS) += kgsl_pwrscale_msm.o
msm_adreno-y += \
adreno_ringbuffer.o \
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 970f377..fdf7304 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -46,6 +46,7 @@
#define A3XX_RBBM_HW_VERSION 0x000
#define A3XX_RBBM_HW_RELEASE 0x001
#define A3XX_RBBM_HW_CONFIGURATION 0x002
+#define A3XX_RBBM_SP_HYST_CNT 0x012
#define A3XX_RBBM_SW_RESET_CMD 0x018
#define A3XX_RBBM_AHB_CTL0 0x020
#define A3XX_RBBM_AHB_CTL1 0x021
@@ -54,6 +55,7 @@
#define A3XX_RBBM_GPR0_CTL 0x02E
/* This the same register as on A2XX, just in a different place */
#define A3XX_RBBM_STATUS 0x030
+#define A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL 0x33
#define A3XX_RBBM_INTERFACE_HANG_INT_CTL 0x50
#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL0 0x51
#define A3XX_RBBM_INTERFACE_HANG_MASK_CTL1 0x54
@@ -249,7 +251,7 @@
/* Bit flags for RBBM_CTL */
#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1)
-#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 (17 << 1)
+#define RBBM_RBBM_CTL_ENABLE_PWR_CTR1 (1 << 17)
/* Various flags used by the context switch code */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 3db397b..fb672e4 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -113,6 +113,7 @@
.pfp_fw = NULL,
.pm4_fw = NULL,
.wait_timeout = 10000, /* in milliseconds */
+ .ib_check_level = 0,
};
@@ -398,7 +399,7 @@
* adreno 22x gpus are indicated by coreid 2,
* but REG_RBBM_PERIPHID1 always contains 0 for this field
*/
- if (cpu_is_msm8960() || cpu_is_msm8x60() || cpu_is_msm8930())
+ if (cpu_is_msm8960() || cpu_is_msm8x60())
chipid = 2 << 24;
else
chipid = (coreid & 0xF) << 24;
@@ -975,7 +976,7 @@
return status;
}
-const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
unsigned int pt_base,
unsigned int gpuaddr,
unsigned int size)
@@ -1034,7 +1035,7 @@
uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
unsigned int gpuaddr, unsigned int size)
{
- const struct kgsl_memdesc *memdesc;
+ struct kgsl_memdesc *memdesc;
memdesc = adreno_find_region(device, pt_base, gpuaddr, size);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index e08088d..4885312 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -30,8 +30,10 @@
#define KGSL_CMD_FLAGS_NOT_KERNEL_CMD 0x00000004
/* Command identifiers */
-#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0xDEADBEEF
-#define KGSL_CMD_IDENTIFIER 0xFEEDFACE
+#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
+#define KGSL_CMD_IDENTIFIER 0x2EEDFACE
+#define KGSL_START_OF_IB_IDENTIFIER 0x2EADEABE
+#define KGSL_END_OF_IB_IDENTIFIER 0x2ABEDEAD
#ifdef CONFIG_MSM_SCM
#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz)
@@ -75,6 +77,7 @@
unsigned int istore_size;
unsigned int pix_shader_start;
unsigned int instruction_size;
+ unsigned int ib_check_level;
};
struct adreno_gpudev {
@@ -117,7 +120,7 @@
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
unsigned int value);
-const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
unsigned int pt_base,
unsigned int gpuaddr,
unsigned int size);
@@ -174,6 +177,12 @@
return (adreno_dev->gpurev >= 300);
}
+static inline int adreno_rb_ctxtswitch(unsigned int *cmd)
+{
+ return (cmd[0] == cp_nop_packet(1) &&
+ cmd[1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER);
+}
+
/**
* adreno_encode_istore_size - encode istore size in CP format
* @adreno_dev - The 3D device.
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index f31d120..52c2ab1 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1907,7 +1907,7 @@
adreno_regwrite(device, REG_SQ_VS_PROGRAM, 0x00000000);
adreno_regwrite(device, REG_SQ_PS_PROGRAM, 0x00000000);
- if (cpu_is_msm8960() || cpu_is_msm8930())
+ if (cpu_is_msm8960())
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0x200);
else
adreno_regwrite(device, REG_RBBM_PM_OVERRIDE1, 0);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index c01e676..2761b60 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2576,6 +2576,10 @@
/* Make all blocks contribute to the GPU BUSY perf counter */
adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
+ /* Tune the hystersis counters for SP and CP idle detection */
+ adreno_regwrite(device, A3XX_RBBM_SP_HYST_CNT, 0x10);
+ adreno_regwrite(device, A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10);
+
/* Enable the RBBM error reporting bits. This lets us get
useful information on failure */
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 3461316..9e022b9 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -113,6 +113,8 @@
&kgsl_cff_dump_enable_fops);
debugfs_create_u32("wait_timeout", 0644, device->d_debugfs,
&adreno_dev->wait_timeout);
+ debugfs_create_u32("ib_check", 0644, device->d_debugfs,
+ &adreno_dev->ib_check_level);
/* Create post mortem control files */
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index 6e85ec6..fb44b25 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -29,11 +29,6 @@
/* skip N 32-bit words to get to the next packet */
#define CP_NOP 0x10
-/* indirect buffer dispatch. prefetch parser uses this packet type to determine
-* whether to pre-fetch the IB
-*/
-#define CP_INDIRECT_BUFFER 0x3f
-
/* indirect buffer dispatch. same as IB, but init is pipelined */
#define CP_INDIRECT_BUFFER_PFD 0x37
@@ -120,6 +115,9 @@
/* load constants from a location in memory */
#define CP_LOAD_CONSTANT_CONTEXT 0x2e
+/* (A2x) sets binning configuration registers */
+#define CP_SET_BIN_DATA 0x2f
+
/* selective invalidation of state pointers */
#define CP_INVALIDATE_STATE 0x3b
@@ -213,7 +211,7 @@
/* packet headers */
#define CP_HDR_ME_INIT cp_type3_packet(CP_ME_INIT, 18)
#define CP_HDR_INDIRECT_BUFFER_PFD cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)
-#define CP_HDR_INDIRECT_BUFFER cp_type3_packet(CP_INDIRECT_BUFFER, 2)
+#define CP_HDR_INDIRECT_BUFFER_PFE cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2)
/* dword base address of the GFX decode space */
#define SUBBLOCK_OFFSET(reg) ((unsigned int)((reg) - (0x2000)))
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 5b197b4..d97659c 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -54,7 +54,7 @@
{CP_IM_LOAD, "IN__LOAD"},
{CP_IM_LOAD_IMMEDIATE, "IM_LOADI"},
{CP_IM_STORE, "IM_STORE"},
- {CP_INDIRECT_BUFFER, "IND_BUF_"},
+ {CP_INDIRECT_BUFFER_PFE, "IND_BUF_"},
{CP_INDIRECT_BUFFER_PFD, "IND_BUFP"},
{CP_INTERRUPT, "PM4_INTR"},
{CP_INVALIDATE_STATE, "INV_STAT"},
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index d6648e2..b9c0a28 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -22,6 +22,7 @@
#include "adreno.h"
#include "adreno_pm4types.h"
#include "adreno_ringbuffer.h"
+#include "adreno_debugfs.h"
#include "a2xx_reg.h"
#include "a3xx_reg.h"
@@ -545,6 +546,198 @@
adreno_ringbuffer_addcmds(rb, flags, cmds, sizedwords);
}
+static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
+ int sizedwords);
+
+static bool
+_handle_type3(struct kgsl_device_private *dev_priv, uint *hostaddr)
+{
+ unsigned int opcode = cp_type3_opcode(*hostaddr);
+ switch (opcode) {
+ case CP_INDIRECT_BUFFER_PFD:
+ case CP_INDIRECT_BUFFER_PFE:
+ case CP_COND_INDIRECT_BUFFER_PFE:
+ case CP_COND_INDIRECT_BUFFER_PFD:
+ return _parse_ibs(dev_priv, hostaddr[1], hostaddr[2]);
+ case CP_NOP:
+ case CP_WAIT_FOR_IDLE:
+ case CP_WAIT_REG_MEM:
+ case CP_WAIT_REG_EQ:
+ case CP_WAT_REG_GTE:
+ case CP_WAIT_UNTIL_READ:
+ case CP_WAIT_IB_PFD_COMPLETE:
+ case CP_REG_RMW:
+ case CP_REG_TO_MEM:
+ case CP_MEM_WRITE:
+ case CP_MEM_WRITE_CNTR:
+ case CP_COND_EXEC:
+ case CP_COND_WRITE:
+ case CP_EVENT_WRITE:
+ case CP_EVENT_WRITE_SHD:
+ case CP_EVENT_WRITE_CFL:
+ case CP_EVENT_WRITE_ZPD:
+ case CP_DRAW_INDX:
+ case CP_DRAW_INDX_2:
+ case CP_DRAW_INDX_BIN:
+ case CP_DRAW_INDX_2_BIN:
+ case CP_VIZ_QUERY:
+ case CP_SET_STATE:
+ case CP_SET_CONSTANT:
+ case CP_IM_LOAD:
+ case CP_IM_LOAD_IMMEDIATE:
+ case CP_LOAD_CONSTANT_CONTEXT:
+ case CP_INVALIDATE_STATE:
+ case CP_SET_SHADER_BASES:
+ case CP_SET_BIN_MASK:
+ case CP_SET_BIN_SELECT:
+ case CP_SET_BIN_BASE_OFFSET:
+ case CP_SET_BIN_DATA:
+ case CP_CONTEXT_UPDATE:
+ case CP_INTERRUPT:
+ case CP_IM_STORE:
+ case CP_LOAD_STATE:
+ break;
+ /* these shouldn't come from userspace */
+ case CP_ME_INIT:
+ case CP_SET_PROTECTED_MODE:
+ default:
+ KGSL_CMD_ERR(dev_priv->device, "bad CP opcode %0x\n", opcode);
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+static bool
+_handle_type0(struct kgsl_device_private *dev_priv, uint *hostaddr)
+{
+ unsigned int reg = type0_pkt_offset(*hostaddr);
+ unsigned int cnt = type0_pkt_size(*hostaddr);
+ if (reg < 0x0192 || (reg + cnt) >= 0x8000) {
+ KGSL_CMD_ERR(dev_priv->device, "bad type0 reg: 0x%0x cnt: %d\n",
+ reg, cnt);
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Traverse IBs and dump them to test vector. Detect swap by inspecting
+ * register writes, keeping note of the current state, and dump
+ * framebuffer config to test vector
+ */
+static bool _parse_ibs(struct kgsl_device_private *dev_priv,
+ uint gpuaddr, int sizedwords)
+{
+ static uint level; /* recursion level */
+ bool ret = false;
+ uint *hostaddr, *hoststart;
+ int dwords_left = sizedwords; /* dwords left in the current command
+ buffer */
+ struct kgsl_mem_entry *entry;
+
+ spin_lock(&dev_priv->process_priv->mem_lock);
+ entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
+ gpuaddr, sizedwords * sizeof(uint));
+ spin_unlock(&dev_priv->process_priv->mem_lock);
+ if (entry == NULL) {
+ KGSL_CMD_ERR(dev_priv->device,
+ "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
+ return false;
+ }
+
+ hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(&entry->memdesc, gpuaddr);
+ if (hostaddr == NULL) {
+ KGSL_CMD_ERR(dev_priv->device,
+ "no mapping for gpuaddr: 0x%08x\n", gpuaddr);
+ return false;
+ }
+
+ hoststart = hostaddr;
+
+ level++;
+
+ KGSL_CMD_INFO(dev_priv->device, "ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
+ gpuaddr, sizedwords, hostaddr);
+
+ mb();
+ while (dwords_left > 0) {
+ bool cur_ret = true;
+ int count = 0; /* dword count including packet header */
+
+ switch (*hostaddr >> 30) {
+ case 0x0: /* type-0 */
+ count = (*hostaddr >> 16)+2;
+ cur_ret = _handle_type0(dev_priv, hostaddr);
+ break;
+ case 0x1: /* type-1 */
+ count = 2;
+ break;
+ case 0x3: /* type-3 */
+ count = ((*hostaddr >> 16) & 0x3fff) + 2;
+ cur_ret = _handle_type3(dev_priv, hostaddr);
+ break;
+ default:
+ KGSL_CMD_ERR(dev_priv->device, "unexpected type: "
+ "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
+ *hostaddr >> 30, *hostaddr, hostaddr,
+ gpuaddr+4*(sizedwords-dwords_left));
+ cur_ret = false;
+ count = dwords_left;
+ break;
+ }
+
+ if (!cur_ret) {
+ KGSL_CMD_ERR(dev_priv->device,
+ "bad sub-type: #:%d/%d, v:0x%08x"
+ " @ 0x%p[gb:0x%08x], level:%d\n",
+ sizedwords-dwords_left, sizedwords, *hostaddr,
+ hostaddr, gpuaddr+4*(sizedwords-dwords_left),
+ level);
+
+ if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
+ >= 2)
+ print_hex_dump(KERN_ERR,
+ level == 1 ? "IB1:" : "IB2:",
+ DUMP_PREFIX_OFFSET, 32, 4, hoststart,
+ sizedwords*4, 0);
+ goto done;
+ }
+
+ /* jump to next packet */
+ dwords_left -= count;
+ hostaddr += count;
+ if (dwords_left < 0) {
+ KGSL_CMD_ERR(dev_priv->device,
+ "bad count: c:%d, #:%d/%d, "
+ "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
+ count, sizedwords-(dwords_left+count),
+ sizedwords, *(hostaddr-count), hostaddr-count,
+ gpuaddr+4*(sizedwords-(dwords_left+count)),
+ level);
+ if (ADRENO_DEVICE(dev_priv->device)->ib_check_level
+ >= 2)
+ print_hex_dump(KERN_ERR,
+ level == 1 ? "IB1:" : "IB2:",
+ DUMP_PREFIX_OFFSET, 32, 4, hoststart,
+ sizedwords*4, 0);
+ goto done;
+ }
+ }
+
+ ret = true;
+done:
+ if (!ret)
+ KGSL_DRV_ERR(dev_priv->device,
+ "parsing failed: gpuaddr:0x%08x, "
+ "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
+
+ level--;
+
+ return ret;
+}
+
int
adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
struct kgsl_context *context,
@@ -575,11 +768,12 @@
drawctxt);
return -EDEADLK;
}
- link = kzalloc(sizeof(unsigned int) * numibs * 3, GFP_KERNEL);
- cmds = link;
+
+ cmds = link = kzalloc(sizeof(unsigned int) * (numibs * 3 + 4),
+ GFP_KERNEL);
if (!link) {
- KGSL_MEM_ERR(device, "Failed to allocate memory for for command"
- " submission, size %x\n", numibs * 3);
+ KGSL_CORE_ERR("kzalloc(%d) failed\n",
+ sizeof(unsigned int) * (numibs * 3 + 4));
return -ENOMEM;
}
@@ -591,15 +785,31 @@
adreno_dev->drawctxt_active == drawctxt)
start_index = 1;
+ if (!start_index) {
+ *cmds++ = cp_nop_packet(1);
+ *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
+ } else {
+ *cmds++ = cp_nop_packet(4);
+ *cmds++ = KGSL_START_OF_IB_IDENTIFIER;
+ *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+ *cmds++ = ibdesc[0].gpuaddr;
+ *cmds++ = ibdesc[0].sizedwords;
+ }
for (i = start_index; i < numibs; i++) {
- (void)kgsl_cffdump_parse_ibs(dev_priv, NULL,
- ibdesc[i].gpuaddr, ibdesc[i].sizedwords, false);
-
+ if (unlikely(adreno_dev->ib_check_level >= 1 &&
+ !_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
+ ibdesc[i].sizedwords))) {
+ kfree(link);
+ return -EINVAL;
+ }
*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
*cmds++ = ibdesc[i].gpuaddr;
*cmds++ = ibdesc[i].sizedwords;
}
+ *cmds++ = cp_nop_packet(1);
+ *cmds++ = KGSL_END_OF_IB_IDENTIFIER;
+
kgsl_setstate(device,
kgsl_mmu_pt_get_flags(device->mmu.hwpagetable,
device->id));
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 0361387..d0110b9 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -13,10 +13,6 @@
#ifndef __ADRENO_RINGBUFFER_H
#define __ADRENO_RINGBUFFER_H
-#define GSL_RB_USE_MEM_RPTR
-#define GSL_RB_USE_MEM_TIMESTAMP
-#define GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
-
/*
* Adreno ringbuffer sizes in bytes - these are converted to
* the appropriate log2 values in the code
@@ -71,37 +67,16 @@
gpuaddr += sizeof(uint); \
} while (0)
-/* timestamp */
-#ifdef GSL_DEVICE_SHADOW_MEMSTORE_TO_USER
-#define GSL_RB_USE_MEM_TIMESTAMP
-#endif /* GSL_DEVICE_SHADOW_MEMSTORE_TO_USER */
-
-#ifdef GSL_RB_USE_MEM_TIMESTAMP
/* enable timestamp (...scratch0) memory shadowing */
#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x1
#define GSL_RB_INIT_TIMESTAMP(rb)
-#else
-#define GSL_RB_MEMPTRS_SCRATCH_MASK 0x0
-#define GSL_RB_INIT_TIMESTAMP(rb) \
- adreno_regwrite((rb)->device->id, REG_CP_TIMESTAMP, 0)
-
-#endif /* GSL_RB_USE_MEMTIMESTAMP */
-
/* mem rptr */
-#ifdef GSL_RB_USE_MEM_RPTR
#define GSL_RB_CNTL_NO_UPDATE 0x0 /* enable */
#define GSL_RB_GET_READPTR(rb, data) \
do { \
*(data) = rb->memptrs->rptr; \
} while (0)
-#else
-#define GSL_RB_CNTL_NO_UPDATE 0x1 /* disable */
-#define GSL_RB_GET_READPTR(rb, data) \
- do { \
- adreno_regread((rb)->device->id, REG_CP_RB_RPTR, (data)); \
- } while (0)
-#endif /* GSL_RB_USE_MEMRPTR */
#define GSL_RB_CNTL_POLL_EN 0x0 /* disable */
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 855db6d..bca7040 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -383,7 +383,7 @@
int offset = type0_pkt_offset(*ptr);
int i;
- for (i = 0; i < (size + 1); i++, offset++) {
+ for (i = 0; i < size; i++, offset++) {
/* Visiblity stream buffer */
@@ -403,9 +403,9 @@
* ...
*/
- if (index % 3 == 0)
+ if ((index % 3) == 0)
vsc_pipe[index / 3].base = ptr[i + 1];
- else if (index % 3 == 1)
+ else if ((index % 3) == 1)
vsc_pipe[index / 3].size = ptr[i + 1];
} else if ((offset >= A3XX_VFD_FETCH_INSTR_0_0) &&
(offset <= A3XX_VFD_FETCH_INSTR_1_F)) {
@@ -417,7 +417,7 @@
* in between
*/
- if (index % 2 == 0)
+ if ((index % 2) == 0)
vbo[index >> 1].stride =
(ptr[i + 1] >> 7) & 0x1FF;
else
@@ -522,13 +522,10 @@
unsigned int *data = snapshot + sizeof(*header);
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
- unsigned int rbbase, ptbase, rptr, *rbptr, ibbase;
- int start, stop, index;
- int numitems, size;
+ unsigned int ptbase, rptr, *rbptr, ibbase;
+ int index, size, i;
int parse_ibs = 0, ib_parse_start;
-
- /* Get the GPU address of the ringbuffer */
- kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
+ int skip_pktsize = 1;
/* Get the physical address of the MMU pagetable */
ptbase = kgsl_mmu_get_current_ptbase(device);
@@ -536,34 +533,77 @@
/* Get the current read pointers for the RB */
kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
- /*
- * Get the address of the last executed IB1 so we can be sure to
- * snapshot it
- */
-
+ /* Address of the last processed IB */
kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
- /* start the dump at the rptr minus some history */
- start = (int) rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY;
- if (start < 0)
- start += rb->sizedwords;
-
/*
- * Stop the dump at the point where the software last wrote. Don't use
- * the hardware value here on the chance that it didn't get properly
- * updated
+ * Figure out the window of ringbuffer data to dump. First we need to
+ * find where the last processed IB ws submitted
*/
- stop = (int) rb->wptr + 16;
- if (stop > rb->sizedwords)
- stop -= rb->sizedwords;
+ index = rptr;
+ rbptr = rb->buffer_desc.hostptr;
- /* Set up the header for the section */
+ while (index != rb->wptr) {
+ index--;
- numitems = (stop > start) ? stop - start :
- (rb->sizedwords - start) + stop;
+ if (index < 0) {
+ index = rb->sizedwords - 3;
- size = (numitems << 2);
+ /* We wrapped without finding what we wanted */
+ if (index < rb->wptr) {
+ index = rb->wptr;
+ break;
+ }
+ }
+
+ if (adreno_cmd_is_ib(rbptr[index]) &&
+ rbptr[index + 1] == ibbase)
+ break;
+ }
+
+ /*
+ * index points at the last submitted IB. We can only trust that the
+ * memory between the context switch and the hanging IB is valid, so
+ * the next step is to find the context switch before the submission
+ */
+
+ while (index != rb->wptr) {
+ index--;
+
+ if (index < 0) {
+ index = rb->sizedwords - 2;
+
+ /*
+ * Wrapped without finding the context switch. This is
+ * harmless - we should still have enough data to dump a
+ * valid state
+ */
+
+ if (index < rb->wptr) {
+ index = rb->wptr;
+ break;
+ }
+ }
+
+ /* Break if the current packet is a context switch identifier */
+ if (adreno_rb_ctxtswitch(&rbptr[index]))
+ break;
+ }
+
+ /*
+ * Index represents the start of the window of interest. We will try
+ * to dump all buffers between here and the rptr
+ */
+
+ ib_parse_start = index;
+
+ /*
+ * Dump the entire ringbuffer - the parser can choose how much of it to
+ * process
+ */
+
+ size = (rb->sizedwords << 2);
if (remain < size + sizeof(*header)) {
KGSL_DRV_ERR(device,
@@ -572,73 +612,48 @@
}
/* Write the sub-header for the section */
- header->start = start;
- header->end = stop;
+ header->start = rb->wptr;
+ header->end = rb->wptr;
header->wptr = rb->wptr;
header->rbsize = rb->sizedwords;
- header->count = numitems;
-
- /*
- * We can only reliably dump IBs from the beginning of the context,
- * and it turns out that for the vast majority of the time we really
- * only care about the current context when it comes to diagnosing
- * a hang. So, with an eye to limiting the buffer dumping to what is
- * really useful find the beginning of the context and only dump
- * IBs from that point
- */
-
- index = rptr;
- ib_parse_start = start;
- rbptr = rb->buffer_desc.hostptr;
-
- while (index != start) {
- index--;
-
- if (index < 0) {
- /*
- * The marker we are looking for is 2 dwords long, so
- * when wrapping, go back 2 from the end so we don't
- * access out of range in the if statement below
- */
- index = rb->sizedwords - 2;
-
- /*
- * Account for the possibility that start might be at
- * rb->sizedwords - 1
- */
-
- if (start == rb->sizedwords - 1)
- break;
- }
-
- /*
- * Look for a NOP packet with the context switch identifier in
- * the second dword
- */
-
- if (rbptr[index] == cp_nop_packet(1) &&
- rbptr[index + 1] == KGSL_CONTEXT_TO_MEM_IDENTIFIER) {
- ib_parse_start = index;
- break;
- }
- }
-
- index = start;
+ header->count = rb->sizedwords;
/*
* Loop through the RB, copying the data and looking for indirect
* buffers and MMU pagetable changes
*/
- while (index != rb->wptr) {
+ index = rb->wptr;
+ for (i = 0; i < rb->sizedwords; i++) {
*data = rbptr[index];
- /* Only parse IBs between the context start and the rptr */
+ /*
+ * Sometimes the rptr is located in the middle of a packet.
+ * try to adust for that by modifying the rptr to match a
+ * packet boundary. Unfortunately for us, it is hard to tell
+ * which dwords are legitimate type0 header and which are just
+ * random data so just walk over type0 packets until we get
+ * to the first type3, and from that point on start checking the
+ * size of the packet and adjusting accordingly
+ */
+
+ if (skip_pktsize && pkt_is_type3(rbptr[index]))
+ skip_pktsize = 0;
+
+ if (skip_pktsize == 0) {
+ unsigned int pktsize = type3_pkt_size(rbptr[index]);
+ if (index + pktsize > rptr)
+ rptr = (index + pktsize) % rb->sizedwords;
+ }
+
+ /*
+ * Only parse IBs between the start and the rptr or the next
+ * context switch, whichever comes first
+ */
if (index == ib_parse_start)
parse_ibs = 1;
-
- if (index == rptr)
+ else if (index == rptr || adreno_rb_ctxtswitch(&rbptr[index]))
parse_ibs = 0;
if (parse_ibs && adreno_cmd_is_ib(rbptr[index])) {
@@ -663,18 +678,6 @@
data++;
}
- /* Dump 16 dwords past the wptr, but don't bother interpeting it */
-
- while (index != stop) {
- *data = rbptr[index];
- index = index + 1;
-
- if (index == rb->sizedwords)
- index = 0;
-
- data++;
- }
-
/* Return the size of the section */
return size + sizeof(*header);
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 37d18bc..45bcf69 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -21,7 +21,7 @@
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include <linux/genlock.h>
-
+#include <linux/rbtree.h>
#include <linux/ashmem.h>
#include <linux/major.h>
#include <linux/ion.h>
@@ -224,8 +224,28 @@
void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
struct kgsl_process_private *process)
{
+ struct rb_node **node;
+ struct rb_node *parent = NULL;
+
spin_lock(&process->mem_lock);
- list_add(&entry->list, &process->mem_list);
+
+ node = &process->mem_rb.rb_node;
+
+ while (*node) {
+ struct kgsl_mem_entry *cur;
+
+ parent = *node;
+ cur = rb_entry(parent, struct kgsl_mem_entry, node);
+
+ if (entry->memdesc.gpuaddr < cur->memdesc.gpuaddr)
+ node = &parent->rb_left;
+ else
+ node = &parent->rb_right;
+ }
+
+ rb_link_node(&entry->node, parent, node);
+ rb_insert_color(&entry->node, &process->mem_rb);
+
spin_unlock(&process->mem_lock);
entry->priv = process;
@@ -593,8 +613,7 @@
spin_lock_init(&private->mem_lock);
private->refcnt = 1;
private->pid = task_tgid_nr(current);
-
- INIT_LIST_HEAD(&private->mem_list);
+ private->mem_rb = RB_ROOT;
if (kgsl_mmu_enabled())
{
@@ -623,7 +642,7 @@
struct kgsl_process_private *private)
{
struct kgsl_mem_entry *entry = NULL;
- struct kgsl_mem_entry *entry_tmp = NULL;
+ struct rb_node *node;
if (!private)
return;
@@ -637,11 +656,13 @@
list_del(&private->list);
- list_for_each_entry_safe(entry, entry_tmp, &private->mem_list, list) {
- list_del(&entry->list);
+ for (node = rb_first(&private->mem_rb); node; ) {
+ entry = rb_entry(node, struct kgsl_mem_entry, node);
+ node = rb_next(&entry->node);
+
+ rb_erase(&entry->node, &private->mem_rb);
kgsl_mem_entry_detach_process(entry);
}
-
kgsl_mmu_putpagetable(private->pagetable);
kfree(private);
unlock:
@@ -767,47 +788,43 @@
return result;
}
-
-/*call with private->mem_lock locked */
-static struct kgsl_mem_entry *
-kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
-{
- struct kgsl_mem_entry *entry = NULL, *result = NULL;
-
- BUG_ON(private == NULL);
-
- gpuaddr &= PAGE_MASK;
-
- list_for_each_entry(entry, &private->mem_list, list) {
- if (entry->memdesc.gpuaddr == gpuaddr) {
- result = entry;
- break;
- }
- }
- return result;
-}
-
/*call with private->mem_lock locked */
struct kgsl_mem_entry *
kgsl_sharedmem_find_region(struct kgsl_process_private *private,
- unsigned int gpuaddr,
- size_t size)
+ unsigned int gpuaddr, size_t size)
{
- struct kgsl_mem_entry *entry = NULL, *result = NULL;
+ struct rb_node *node = private->mem_rb.rb_node;
- BUG_ON(private == NULL);
+ while (node != NULL) {
+ struct kgsl_mem_entry *entry;
- list_for_each_entry(entry, &private->mem_list, list) {
- if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
- result = entry;
- break;
+ entry = rb_entry(node, struct kgsl_mem_entry, node);
+
+
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
+ return entry;
+
+ if (gpuaddr < entry->memdesc.gpuaddr)
+ node = node->rb_left;
+ else if (gpuaddr >=
+ (entry->memdesc.gpuaddr + entry->memdesc.size))
+ node = node->rb_right;
+ else {
+ return NULL;
}
}
- return result;
+ return NULL;
}
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
+/*call with private->mem_lock locked */
+static inline struct kgsl_mem_entry *
+kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
+{
+ return kgsl_sharedmem_find_region(private, gpuaddr, 1);
+}
+
/*call all ioctl sub functions with driver locked*/
static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
@@ -878,6 +895,21 @@
return result;
}
+static long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ int result = 0;
+ /* The getproperty struct is reused for setproperty too */
+ struct kgsl_device_getproperty *param = data;
+
+ if (dev_priv->device->ftbl->setproperty)
+ result = dev_priv->device->ftbl->setproperty(
+ dev_priv->device, param->type,
+ param->value, param->sizebytes);
+
+ return result;
+}
+
static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
*dev_priv, unsigned int cmd,
void *data)
@@ -906,40 +938,6 @@
return result;
}
-static bool check_ibdesc(struct kgsl_device_private *dev_priv,
- struct kgsl_ibdesc *ibdesc, unsigned int numibs,
- bool parse)
-{
- bool result = true;
- unsigned int i;
- for (i = 0; i < numibs; i++) {
- struct kgsl_mem_entry *entry;
- spin_lock(&dev_priv->process_priv->mem_lock);
- entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
- ibdesc[i].gpuaddr, ibdesc[i].sizedwords * sizeof(uint));
- spin_unlock(&dev_priv->process_priv->mem_lock);
- if (entry == NULL) {
- KGSL_DRV_ERR(dev_priv->device,
- "invalid cmd buffer gpuaddr %08x " \
- "sizedwords %d\n", ibdesc[i].gpuaddr,
- ibdesc[i].sizedwords);
- result = false;
- break;
- }
-
- if (parse && !kgsl_cffdump_parse_ibs(dev_priv, &entry->memdesc,
- ibdesc[i].gpuaddr, ibdesc[i].sizedwords, true)) {
- KGSL_DRV_ERR(dev_priv->device,
- "invalid cmd buffer gpuaddr %08x " \
- "sizedwords %d numibs %d/%d\n",
- ibdesc[i].gpuaddr,
- ibdesc[i].sizedwords, i+1, numibs);
- result = false;
- break;
- }
- }
- return result;
-}
static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
@@ -1005,12 +1003,6 @@
param->numibs = 1;
}
- if (!check_ibdesc(dev_priv, ibdesc, param->numibs, true)) {
- KGSL_DRV_ERR(dev_priv->device, "bad ibdesc");
- result = -EINVAL;
- goto free_ibdesc;
- }
-
result = dev_priv->device->ftbl->issueibcmds(dev_priv,
context,
ibdesc,
@@ -1020,18 +1012,6 @@
trace_kgsl_issueibcmds(dev_priv->device, param, result);
- if (result != 0)
- goto free_ibdesc;
-
- /* this is a check to try to detect if a command buffer was freed
- * during issueibcmds().
- */
- if (!check_ibdesc(dev_priv, ibdesc, param->numibs, false)) {
- KGSL_DRV_ERR(dev_priv->device, "bad ibdesc AFTER issue");
- result = -EINVAL;
- goto free_ibdesc;
- }
-
free_ibdesc:
kfree(ibdesc);
done:
@@ -1059,7 +1039,7 @@
{
struct kgsl_mem_entry *entry = priv;
spin_lock(&entry->priv->mem_lock);
- list_del(&entry->list);
+ rb_erase(&entry->node, &entry->priv->mem_rb);
spin_unlock(&entry->priv->mem_lock);
trace_kgsl_mem_timestamp_free(entry, timestamp);
kgsl_mem_entry_detach_process(entry);
@@ -1158,7 +1138,8 @@
spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
if (entry)
- list_del(&entry->list);
+ rb_erase(&entry->node, &private->mem_rb);
+
spin_unlock(&private->mem_lock);
if (entry) {
@@ -1195,6 +1176,8 @@
struct kgsl_mem_entry *entry = NULL;
struct vm_area_struct *vma;
+ KGSL_DEV_ERR_ONCE(dev_priv->device, "IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC"
+ " is deprecated\n");
if (!kgsl_mmu_enabled())
return -ENODEV;
@@ -1251,9 +1234,9 @@
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- result = remap_vmalloc_range(vma, (void *) entry->memdesc.hostptr, 0);
+ result = kgsl_sharedmem_map_vma(vma, &entry->memdesc);
if (result) {
- KGSL_CORE_ERR("remap_vmalloc_range failed: %d\n", result);
+ KGSL_CORE_ERR("kgsl_sharedmem_map_vma failed: %d\n", result);
goto error_free_vmalloc;
}
@@ -1393,7 +1376,8 @@
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
unsigned long paddr = (unsigned long) addr;
- memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist));
+ memdesc->sg = kgsl_sg_alloc(sglen);
+
if (memdesc->sg == NULL)
return -ENOMEM;
@@ -1433,7 +1417,7 @@
err:
spin_unlock(¤t->mm->page_table_lock);
- vfree(memdesc->sg);
+ kgsl_sg_free(memdesc->sg, sglen);
memdesc->sg = NULL;
return -EINVAL;
@@ -1637,6 +1621,8 @@
break;
case KGSL_USER_MEM_TYPE_ADDR:
+ KGSL_DEV_ERR_ONCE(dev_priv->device, "User mem type "
+ "KGSL_USER_MEM_TYPE_ADDR is deprecated\n");
if (!kgsl_mmu_enabled()) {
KGSL_DRV_ERR(dev_priv->device,
"Cannot map paged memory with the "
@@ -1959,6 +1945,8 @@
kgsl_ioctl_cff_user_event, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
kgsl_ioctl_timestamp_event, 1),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
+ kgsl_ioctl_device_setproperty, 1),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2111,7 +2099,7 @@
unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
struct kgsl_device_private *dev_priv = file->private_data;
struct kgsl_process_private *private = dev_priv->process_priv;
- struct kgsl_mem_entry *tmp, *entry = NULL;
+ struct kgsl_mem_entry *entry = NULL;
struct kgsl_device *device = dev_priv->device;
/* Handle leagacy behavior for memstore */
@@ -2122,13 +2110,11 @@
/* Find a chunk of GPU memory */
spin_lock(&private->mem_lock);
- list_for_each_entry(tmp, &private->mem_list, list) {
- if (vma_offset == tmp->memdesc.gpuaddr) {
- kgsl_mem_entry_get(tmp);
- entry = tmp;
- break;
- }
- }
+ entry = kgsl_sharedmem_find(private, vma_offset);
+
+ if (entry)
+ kgsl_mem_entry_get(entry);
+
spin_unlock(&private->mem_lock);
if (entry == NULL)
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 20ed808..87bba25 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -21,6 +21,7 @@
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/regulator/consumer.h>
+#include <linux/mm.h>
#define KGSL_NAME "kgsl"
@@ -98,7 +99,15 @@
extern struct kgsl_driver kgsl_driver;
struct kgsl_pagetable;
-struct kgsl_memdesc_ops;
+struct kgsl_memdesc;
+
+struct kgsl_memdesc_ops {
+ int (*vmflags)(struct kgsl_memdesc *);
+ int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *,
+ struct vm_fault *);
+ void (*free)(struct kgsl_memdesc *memdesc);
+ int (*map_kernel_mem)(struct kgsl_memdesc *);
+};
/* shared memory allocation */
struct kgsl_memdesc {
@@ -132,7 +141,7 @@
int memtype;
int flags;
void *priv_data;
- struct list_head list;
+ struct rb_node node;
uint32_t free_timestamp;
/* back pointer to private structure under whose context this
* allocation is made */
@@ -185,13 +194,15 @@
}
return 0;
}
-static inline uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
+static inline uint8_t *kgsl_gpuaddr_to_vaddr(struct kgsl_memdesc *memdesc,
unsigned int gpuaddr)
{
- if (memdesc->hostptr == NULL || memdesc->gpuaddr == 0 ||
- (gpuaddr < memdesc->gpuaddr ||
- gpuaddr >= memdesc->gpuaddr + memdesc->size))
- return NULL;
+ if (memdesc->gpuaddr == 0 ||
+ gpuaddr < memdesc->gpuaddr ||
+ gpuaddr >= (memdesc->gpuaddr + memdesc->size) ||
+ (NULL == memdesc->hostptr && memdesc->ops->map_kernel_mem &&
+ memdesc->ops->map_kernel_mem(memdesc)))
+ return NULL;
return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
}
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index a972f69..4e354d0 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -497,190 +497,6 @@
}
EXPORT_SYMBOL(kgsl_cffdump_waitirq);
-#define ADDRESS_STACK_SIZE 256
-#define GET_PM4_TYPE3_OPCODE(x) ((*(x) >> 8) & 0xFF)
-static unsigned int kgsl_cffdump_addr_count;
-
-static bool kgsl_cffdump_handle_type3(struct kgsl_device_private *dev_priv,
- uint *hostaddr, bool check_only)
-{
- static uint addr_stack[ADDRESS_STACK_SIZE];
- static uint size_stack[ADDRESS_STACK_SIZE];
-
- switch (GET_PM4_TYPE3_OPCODE(hostaddr)) {
- case CP_INDIRECT_BUFFER_PFD:
- case CP_INDIRECT_BUFFER:
- {
- /* traverse indirect buffers */
- int i;
- uint ibaddr = hostaddr[1];
- uint ibsize = hostaddr[2];
-
- /* is this address already in encountered? */
- for (i = 0;
- i < kgsl_cffdump_addr_count && addr_stack[i] != ibaddr;
- ++i)
- ;
-
- if (kgsl_cffdump_addr_count == i) {
- addr_stack[kgsl_cffdump_addr_count] = ibaddr;
- size_stack[kgsl_cffdump_addr_count++] = ibsize;
-
- if (kgsl_cffdump_addr_count >= ADDRESS_STACK_SIZE) {
- KGSL_CORE_ERR("stack overflow\n");
- return false;
- }
-
- return kgsl_cffdump_parse_ibs(dev_priv, NULL,
- ibaddr, ibsize, check_only);
- } else if (size_stack[i] != ibsize) {
- KGSL_CORE_ERR("gpuaddr: 0x%08x, "
- "wc: %u, with size wc: %u already on the "
- "stack\n", ibaddr, ibsize, size_stack[i]);
- return false;
- }
- }
- break;
- }
-
- return true;
-}
-
-/*
- * Traverse IBs and dump them to test vector. Detect swap by inspecting
- * register writes, keeping note of the current state, and dump
- * framebuffer config to test vector
- */
-bool kgsl_cffdump_parse_ibs(struct kgsl_device_private *dev_priv,
- const struct kgsl_memdesc *memdesc, uint gpuaddr, int sizedwords,
- bool check_only)
-{
- static uint level; /* recursion level */
- bool ret = true;
- uint *hostaddr, *hoststart;
- int dwords_left = sizedwords; /* dwords left in the current command
- buffer */
-
- if (level == 0)
- kgsl_cffdump_addr_count = 0;
-
- if (memdesc == NULL) {
- struct kgsl_mem_entry *entry;
- spin_lock(&dev_priv->process_priv->mem_lock);
- entry = kgsl_sharedmem_find_region(dev_priv->process_priv,
- gpuaddr, sizedwords * sizeof(uint));
- spin_unlock(&dev_priv->process_priv->mem_lock);
- if (entry == NULL) {
- KGSL_CORE_ERR("did not find mapping "
- "for gpuaddr: 0x%08x\n", gpuaddr);
- return true;
- }
- memdesc = &entry->memdesc;
- }
- hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
- if (hostaddr == NULL) {
- KGSL_CORE_ERR("no kernel mapping for "
- "gpuaddr: 0x%08x\n", gpuaddr);
- return true;
- }
-
- hoststart = hostaddr;
-
- level++;
-
- mb();
- kgsl_cache_range_op((struct kgsl_memdesc *)memdesc,
- KGSL_CACHE_OP_INV);
-#ifdef DEBUG
- pr_info("kgsl: cffdump: ib: gpuaddr:0x%08x, wc:%d, hptr:%p\n",
- gpuaddr, sizedwords, hostaddr);
-#endif
-
- while (dwords_left > 0) {
- int count = 0; /* dword count including packet header */
- bool cur_ret = true;
-
- switch (*hostaddr >> 30) {
- case 0x0: /* type-0 */
- count = (*hostaddr >> 16)+2;
- break;
- case 0x1: /* type-1 */
- count = 2;
- break;
- case 0x3: /* type-3 */
- count = ((*hostaddr >> 16) & 0x3fff) + 2;
- cur_ret = kgsl_cffdump_handle_type3(dev_priv,
- hostaddr, check_only);
- break;
- default:
- pr_warn("kgsl: cffdump: parse-ib: unexpected type: "
- "type:%d, word:0x%08x @ 0x%p, gpu:0x%08x\n",
- *hostaddr >> 30, *hostaddr, hostaddr,
- gpuaddr+4*(sizedwords-dwords_left));
- cur_ret = false;
- count = dwords_left;
- break;
- }
-
-#ifdef DEBUG
- if (!cur_ret) {
- pr_info("kgsl: cffdump: bad sub-type: #:%d/%d, v:0x%08x"
- " @ 0x%p[gb:0x%08x], level:%d\n",
- sizedwords-dwords_left, sizedwords, *hostaddr,
- hostaddr, gpuaddr+4*(sizedwords-dwords_left),
- level);
-
- print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
- DUMP_PREFIX_OFFSET, 32, 4, hoststart,
- sizedwords*4, 0);
- }
-#endif
- ret = ret && cur_ret;
-
- /* jump to next packet */
- dwords_left -= count;
- hostaddr += count;
- cur_ret = dwords_left >= 0;
-
-#ifdef DEBUG
- if (!cur_ret) {
- pr_info("kgsl: cffdump: bad count: c:%d, #:%d/%d, "
- "v:0x%08x @ 0x%p[gb:0x%08x], level:%d\n",
- count, sizedwords-(dwords_left+count),
- sizedwords, *(hostaddr-count), hostaddr-count,
- gpuaddr+4*(sizedwords-(dwords_left+count)),
- level);
-
- print_hex_dump(KERN_ERR, level == 1 ? "IB1:" : "IB2:",
- DUMP_PREFIX_OFFSET, 32, 4, hoststart,
- sizedwords*4, 0);
- }
-#endif
-
- ret = ret && cur_ret;
- }
-
- if (!ret)
- pr_info("kgsl: cffdump: parsing failed: gpuaddr:0x%08x, "
- "host:0x%p, wc:%d\n", gpuaddr, hoststart, sizedwords);
-
- if (!check_only) {
-#ifdef DEBUG
- uint offset = gpuaddr - memdesc->gpuaddr;
- pr_info("kgsl: cffdump: ib-dump: hostptr:%p, gpuaddr:%08x, "
- "physaddr:%08x, offset:%d, size:%d", hoststart,
- gpuaddr, memdesc->physaddr + offset, offset,
- sizedwords*4);
-#endif
- kgsl_cffdump_syncmem(dev_priv, memdesc, gpuaddr, sizedwords*4,
- false);
- }
-
- level--;
-
- return ret;
-}
-
static int subbuf_start_handler(struct rchan_buf *buf,
void *subbuf, void *prev_subbuf, uint prev_padding)
{
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2eacf22..feaf652 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -104,6 +104,9 @@
struct kgsl_context *context);
long (*ioctl) (struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data);
+ int (*setproperty) (struct kgsl_device *device,
+ enum kgsl_property_type type, void *value,
+ unsigned int sizebytes);
};
struct kgsl_memregion {
@@ -216,7 +219,7 @@
unsigned int refcnt;
pid_t pid;
spinlock_t mem_lock;
- struct list_head mem_list;
+ struct rb_root mem_rb;
struct kgsl_pagetable *pagetable;
struct list_head list;
struct kobject kobj;
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 03f8c42..d43b29b 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -903,17 +903,18 @@
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev;
struct drm_kgsl_gem_object *priv;
- unsigned long offset, pg;
+ unsigned long offset;
struct page *page;
+ int i;
mutex_lock(&dev->struct_mutex);
priv = obj->driver_private;
offset = (unsigned long) vmf->virtual_address - vma->vm_start;
- pg = (unsigned long) priv->memdesc.hostptr + offset;
+ i = offset >> PAGE_SHIFT;
+ page = sg_page(&(priv->memdesc.sg[i]));
- page = vmalloc_to_page((void *) pg);
if (!page) {
mutex_unlock(&dev->struct_mutex);
return VM_FAULT_SIGBUS;
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 942aa12..bbb5d46 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -357,8 +357,8 @@
int kgsl_gpummu_pt_equal(struct kgsl_pagetable *pt,
unsigned int pt_base)
{
- struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
- return pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
+ struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
+ return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
}
void kgsl_gpummu_destroy_pagetable(void *mmu_specific_pt)
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 194067b..ea11068 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -46,8 +46,8 @@
static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
unsigned int pt_base)
{
- struct iommu_domain *domain = pt->priv;
- return pt && pt_base && ((unsigned int)domain == pt_base);
+ struct iommu_domain *domain = pt ? pt->priv : NULL;
+ return domain && pt_base && ((unsigned int)domain == pt_base);
}
static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
diff --git a/drivers/gpu/msm/kgsl_log.h b/drivers/gpu/msm/kgsl_log.h
index 9fafcf4..6fd28ab 100644
--- a/drivers/gpu/msm/kgsl_log.h
+++ b/drivers/gpu/msm/kgsl_log.h
@@ -48,6 +48,16 @@
#define KGSL_LOG_DUMP(_dev, fmt, args...) dev_err(_dev->dev, fmt, ##args)
+#define KGSL_DEV_ERR_ONCE(_dev, fmt, args...) \
+({ \
+ static bool kgsl_dev_err_once; \
+ \
+ if (!kgsl_dev_err_once) { \
+ kgsl_dev_err_once = true; \
+ dev_crit(_dev->dev, "|%s| " fmt, __func__, ##args); \
+ } \
+})
+
#define KGSL_DRV_INFO(_dev, fmt, args...) \
KGSL_LOG_INFO(_dev->dev, _dev->drv_log, fmt, ##args)
#define KGSL_DRV_WARN(_dev, fmt, args...) \
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index ceb3212..7eb5ee9 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -35,6 +35,10 @@
static int kgsl_cleanup_pt(struct kgsl_pagetable *pt)
{
int i;
+ /* For IOMMU only unmap the global structures to global pt */
+ if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+ (KGSL_MMU_GLOBAL_PT != pt->name))
+ return 0;
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
struct kgsl_device *device = kgsl_driver.devp[i];
if (device)
@@ -57,6 +61,8 @@
kgsl_cleanup_pt(pagetable);
+ if (pagetable->kgsl_pool)
+ gen_pool_destroy(pagetable->kgsl_pool);
if (pagetable->pool)
gen_pool_destroy(pagetable->pool);
@@ -384,6 +390,10 @@
int i = 0;
int status = 0;
+ /* For IOMMU only map the global structures to global pt */
+ if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+ (KGSL_MMU_GLOBAL_PT != pt->name))
+ return 0;
for (i = 0; i < KGSL_DEVICE_MAX; i++) {
struct kgsl_device *device = kgsl_driver.devp[i];
if (device) {
@@ -427,10 +437,30 @@
pagetable->name = name;
pagetable->max_entries = KGSL_PAGETABLE_ENTRIES(ptsize);
+ /*
+ * create a separate kgsl pool for IOMMU, global mappings can be mapped
+ * just once from this pool of the defaultpagetable
+ */
+ if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
+ (KGSL_MMU_GLOBAL_PT == name)) {
+ pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
+ if (pagetable->kgsl_pool == NULL) {
+ KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
+ PAGE_SHIFT);
+ goto err_alloc;
+ }
+ if (gen_pool_add(pagetable->kgsl_pool,
+ KGSL_IOMMU_GLOBAL_MEM_BASE,
+ KGSL_IOMMU_GLOBAL_MEM_SIZE, -1)) {
+ KGSL_CORE_ERR("gen_pool_add failed\n");
+ goto err_kgsl_pool;
+ }
+ }
+
pagetable->pool = gen_pool_create(PAGE_SHIFT, -1);
if (pagetable->pool == NULL) {
KGSL_CORE_ERR("gen_pool_create(%d) failed\n", PAGE_SHIFT);
- goto err_alloc;
+ goto err_kgsl_pool;
}
if (gen_pool_add(pagetable->pool, KGSL_PAGETABLE_BASE,
@@ -465,6 +495,9 @@
pagetable->pt_ops->mmu_destroy_pagetable(pagetable->priv);
err_pool:
gen_pool_destroy(pagetable->pool);
+err_kgsl_pool:
+ if (pagetable->kgsl_pool)
+ gen_pool_destroy(pagetable->kgsl_pool);
err_alloc:
kfree(pagetable);
@@ -565,11 +598,21 @@
}
}
- memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->pool,
- memdesc->size, KGSL_MMU_ALIGN_SHIFT);
+ /* Allocate from kgsl pool if it exists for global mappings */
+ if (pagetable->kgsl_pool &&
+ (KGSL_MEMFLAGS_GLOBAL & memdesc->priv))
+ memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->kgsl_pool,
+ memdesc->size, KGSL_MMU_ALIGN_SHIFT);
+ else
+ memdesc->gpuaddr = gen_pool_alloc_aligned(pagetable->pool,
+ memdesc->size, KGSL_MMU_ALIGN_SHIFT);
if (memdesc->gpuaddr == 0) {
- KGSL_CORE_ERR("gen_pool_alloc(%d) failed\n", memdesc->size);
+ KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
+ memdesc->size,
+ ((pagetable->kgsl_pool &&
+ (KGSL_MEMFLAGS_GLOBAL & memdesc->priv)) ?
+ "kgsl_pool" : "general_pool"));
KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
pagetable->name, pagetable->stats.mapped,
pagetable->stats.entries);
@@ -627,7 +670,13 @@
spin_unlock(&pagetable->lock);
- gen_pool_free(pagetable->pool,
+ if (pagetable->kgsl_pool &&
+ (KGSL_MEMFLAGS_GLOBAL & memdesc->priv))
+ gen_pool_free(pagetable->kgsl_pool,
+ memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
+ memdesc->size);
+ else
+ gen_pool_free(pagetable->pool,
memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK,
memdesc->size);
@@ -656,6 +705,7 @@
return 0;
gpuaddr = memdesc->gpuaddr;
+ memdesc->priv |= KGSL_MEMFLAGS_GLOBAL;
result = kgsl_mmu_map(pagetable, memdesc, protflags);
if (result)
@@ -668,7 +718,6 @@
gpuaddr, memdesc->gpuaddr);
goto error_unmap;
}
- memdesc->priv |= KGSL_MEMFLAGS_GLOBAL;
return result;
error_unmap:
kgsl_mmu_unmap(pagetable, memdesc);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 0ff5881..bff41bf 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -13,6 +13,14 @@
#ifndef __KGSL_MMU_H
#define __KGSL_MMU_H
+/*
+ * These defines control the split between ttbr1 and ttbr0 pagetables of IOMMU
+ * and what ranges of memory we map to them
+ */
+#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xC0000000
+#define KGSL_IOMMU_GLOBAL_MEM_SIZE SZ_4M
+#define KGSL_IOMMU_TTBR1_SPLIT 2
+
#define KGSL_MMU_ALIGN_SHIFT 13
#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
@@ -92,6 +100,7 @@
struct kref refcount;
unsigned int max_entries;
struct gen_pool *pool;
+ struct gen_pool *kgsl_pool;
struct list_head list;
unsigned int name;
struct kobject *kobj;
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index a03e530..7c451a9 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -334,7 +334,8 @@
do_gettimeofday(&(b->start));
}
-void kgsl_pwrctrl_clk(struct kgsl_device *device, int state)
+void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+ int requested_state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int i = 0;
@@ -346,7 +347,7 @@
if (pwr->grp_clks[i])
clk_disable(pwr->grp_clks[i]);
if ((pwr->pwrlevels[0].gpu_freq > 0) &&
- (device->requested_state != KGSL_STATE_NAP))
+ (requested_state != KGSL_STATE_NAP))
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
@@ -509,6 +510,7 @@
pwr->nap_allowed = pdata->nap_allowed;
pwr->idle_needed = pdata->idle_needed;
pwr->interval_timeout = pdata->idle_timeout;
+ pwr->strtstp_sleepwake = pdata->strtstp_sleepwake;
pwr->ebi1_clk = clk_get(&pdev->dev, "bus_clk");
if (IS_ERR(pwr->ebi1_clk))
pwr->ebi1_clk = NULL;
@@ -601,9 +603,7 @@
mutex_lock(&device->mutex);
if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
- if ((device->requested_state != KGSL_STATE_SLEEP) &&
- (device->requested_state != KGSL_STATE_SLUMBER))
- kgsl_pwrscale_idle(device);
+ kgsl_pwrscale_idle(device);
if (kgsl_pwrctrl_sleep(device) != 0) {
mod_timer(&device->idle_timer,
@@ -631,7 +631,8 @@
KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
if (device->requested_state != KGSL_STATE_SUSPEND) {
- if (device->pwrctrl.restore_slumber)
+ if (device->pwrctrl.restore_slumber ||
+ device->pwrctrl.strtstp_sleepwake)
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
else
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
@@ -698,7 +699,7 @@
return -EBUSY;
}
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
if (device->idle_wakelock.name)
wake_unlock(&device->idle_wakelock);
@@ -741,7 +742,7 @@
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
_sleep_accounting(device);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
wake_unlock(&device->idle_wakelock);
pm_qos_update_request(&device->pm_qos_req_dma,
@@ -772,7 +773,9 @@
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
del_timer_sync(&device->idle_timer);
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
+ if (!device->pwrctrl.strtstp_sleepwake)
+ kgsl_pwrctrl_pwrlevel_change(device,
+ KGSL_PWRLEVEL_NOMINAL);
device->pwrctrl.restore_slumber = true;
device->ftbl->suspend_context(device);
device->ftbl->stop(device);
@@ -843,7 +846,7 @@
/* fall through */
case KGSL_STATE_NAP:
/* Turn on the core clocks */
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
/* Enable state before turning on irq */
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
@@ -869,7 +872,7 @@
{
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
}
EXPORT_SYMBOL(kgsl_pwrctrl_enable);
@@ -878,7 +881,7 @@
{
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
}
EXPORT_SYMBOL(kgsl_pwrctrl_disable);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index f474c21..7dd429f 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,7 @@
#define KGSL_PWRLEVEL_TURBO 0
#define KGSL_PWRLEVEL_NOMINAL 1
+#define KGSL_PWRLEVEL_LAST_OFFSET 2
#define KGSL_MAX_CLKS 5
@@ -47,6 +48,7 @@
int thermal_pwrlevel;
unsigned int num_pwrlevels;
unsigned int interval_timeout;
+ bool strtstp_sleepwake;
struct regulator *gpu_reg;
uint32_t pcl;
unsigned int nap_allowed;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index d0b2a41..1cecbc7 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -45,6 +45,9 @@
#ifdef CONFIG_MSM_SLEEP_STATS_DEVICE
&kgsl_pwrscale_policy_idlestats,
#endif
+#ifdef CONFIG_MSM_DCVS
+ &kgsl_pwrscale_policy_msm,
+#endif
NULL
};
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index b4f831e..6023476 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -54,6 +54,7 @@
extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz;
extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_idlestats;
+extern struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm;
int kgsl_pwrscale_init(struct kgsl_device *device);
void kgsl_pwrscale_close(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index 2976b0b..71af893 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
@@ -153,6 +153,14 @@
MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED);
}
+static void idlestats_wake(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ /* Use highest perf level on wake-up from
+ sleep for better performance */
+ kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
+}
+
static int idlestats_init(struct kgsl_device *device,
struct kgsl_pwrscale *pwrscale)
{
@@ -218,5 +226,6 @@
.idle = idlestats_idle,
.busy = idlestats_busy,
.sleep = idlestats_sleep,
+ .wake = idlestats_wake,
.close = idlestats_close
};
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
new file mode 100644
index 0000000..f77a02b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -0,0 +1,195 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/slab.h>
+#include <mach/msm_dcvs.h>
+#include "kgsl.h"
+#include "kgsl_pwrscale.h"
+#include "kgsl_device.h"
+
+struct msm_priv {
+ struct kgsl_device *device;
+ int enabled;
+ int handle;
+ unsigned int cur_freq;
+ struct msm_dcvs_idle idle_source;
+ struct msm_dcvs_freq freq_sink;
+ struct msm_dcvs_core_info *core_info;
+};
+
+static int msm_idle_enable(struct msm_dcvs_idle *self,
+ enum msm_core_control_event event)
+{
+ struct msm_priv *priv = container_of(self, struct msm_priv,
+ idle_source);
+
+ switch (event) {
+ case MSM_DCVS_ENABLE_IDLE_PULSE:
+ priv->enabled = true;
+ break;
+ case MSM_DCVS_DISABLE_IDLE_PULSE:
+ priv->enabled = false;
+ break;
+ case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
+ case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
+ break;
+ }
+ return 0;
+}
+
+/* Set the requested frequency if it is within 5MHz (delta) of a
+ * supported frequency.
+ */
+static int msm_set_freq(struct msm_dcvs_freq *self,
+ unsigned int freq)
+{
+ int i, delta = 5000000;
+ struct msm_priv *priv = container_of(self, struct msm_priv,
+ freq_sink);
+ struct kgsl_device *device = priv->device;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+ /* msm_dcvs manager uses frequencies in kHz */
+ freq *= 1000;
+ for (i = 0; i < pwr->num_pwrlevels; i++)
+ if (abs(pwr->pwrlevels[i].gpu_freq - freq) < delta)
+ break;
+ if (i == pwr->num_pwrlevels)
+ return 0;
+
+ mutex_lock(&device->mutex);
+ kgsl_pwrctrl_pwrlevel_change(device, i);
+ priv->cur_freq = pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
+ mutex_unlock(&device->mutex);
+
+ /* return current frequency in kHz */
+ return priv->cur_freq / 1000;
+}
+
+static unsigned int msm_get_freq(struct msm_dcvs_freq *self)
+{
+ struct msm_priv *priv = container_of(self, struct msm_priv,
+ freq_sink);
+ /* return current frequency in kHz */
+ return priv->cur_freq / 1000;
+}
+
+static void msm_busy(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ struct msm_priv *priv = pwrscale->priv;
+ if (priv->enabled)
+ msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
+ return;
+}
+
+static void msm_idle(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ struct msm_priv *priv = pwrscale->priv;
+ if (priv->enabled && pwrscale->gpu_busy)
+ msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+
+ return;
+}
+
+static void msm_sleep(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ /* do we need to reset any parameters here? */
+}
+
+static int msm_init(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ struct msm_priv *priv;
+ struct msm_dcvs_freq_entry *tbl;
+ int i, ret, low_level;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct platform_device *pdev =
+ container_of(device->parentdev, struct platform_device, dev);
+ struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+
+ priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
+ GFP_KERNEL);
+ if (pwrscale->priv == NULL)
+ return -ENOMEM;
+
+ priv->core_info = pdata->core_info;
+ tbl = priv->core_info->freq_tbl;
+ /* Fill in frequency table from low to high, reversing order. */
+ low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
+ for (i = 0; i <= low_level; i++)
+ tbl[i].freq =
+ pwr->pwrlevels[low_level - i].gpu_freq / 1000;
+ ret = msm_dcvs_register_core(device->name, 0, priv->core_info);
+ if (ret) {
+ KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
+ goto err;
+ }
+
+ priv->device = device;
+ priv->idle_source.enable = msm_idle_enable;
+ priv->idle_source.core_name = device->name;
+ priv->handle = msm_dcvs_idle_source_register(&priv->idle_source);
+ if (priv->handle < 0) {
+ ret = priv->handle;
+ KGSL_PWR_ERR(device, "msm_dcvs_idle_source_register failed\n");
+ goto err;
+ }
+
+ priv->freq_sink.core_name = device->name;
+ priv->freq_sink.set_frequency = msm_set_freq;
+ priv->freq_sink.get_frequency = msm_get_freq;
+ ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+ if (ret >= 0) {
+ if (device->ftbl->isidle(device)) {
+ device->pwrscale.gpu_busy = 0;
+ msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ } else {
+ device->pwrscale.gpu_busy = 1;
+ }
+ return 0;
+ }
+
+ KGSL_PWR_ERR(device, "msm_dcvs_freq_sink_register failed\n");
+ msm_dcvs_idle_source_unregister(&priv->idle_source);
+
+err:
+ kfree(pwrscale->priv);
+ pwrscale->priv = NULL;
+
+ return ret;
+}
+
+static void msm_close(struct kgsl_device *device,
+ struct kgsl_pwrscale *pwrscale)
+{
+ struct msm_priv *priv = pwrscale->priv;
+
+ if (pwrscale->priv == NULL)
+ return;
+ msm_dcvs_idle_source_unregister(&priv->idle_source);
+ msm_dcvs_freq_sink_unregister(&priv->freq_sink);
+ kfree(pwrscale->priv);
+ pwrscale->priv = NULL;
+}
+
+struct kgsl_pwrscale_policy kgsl_pwrscale_policy_msm = {
+ .name = "msm",
+ .init = msm_init,
+ .idle = msm_idle,
+ .busy = msm_busy,
+ .sleep = msm_sleep,
+ .close = msm_close,
+};
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 931ef48..eef80d3 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -180,7 +180,7 @@
struct tz_priv *priv;
/* Trustzone is only valid for some SOCs */
- if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_msm8930()))
+ if (!(cpu_is_msm8x60() || cpu_is_msm8960()))
return -EINVAL;
priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index d083702..63c24f1 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -299,13 +299,14 @@
struct vm_area_struct *vma,
struct vm_fault *vmf)
{
- unsigned long offset, pg;
+ unsigned long offset;
struct page *page;
+ int i;
offset = (unsigned long) vmf->virtual_address - vma->vm_start;
- pg = (unsigned long) memdesc->hostptr + offset;
- page = vmalloc_to_page((void *) pg);
+ i = offset >> PAGE_SHIFT;
+ page = sg_page(&memdesc->sg[i]);
if (page == NULL)
return VM_FAULT_SIGBUS;
@@ -322,8 +323,14 @@
static void kgsl_vmalloc_free(struct kgsl_memdesc *memdesc)
{
+ int i = 0;
+ struct scatterlist *sg;
kgsl_driver.stats.vmalloc -= memdesc->size;
- vfree(memdesc->hostptr);
+ if (memdesc->hostptr)
+ vunmap(memdesc->hostptr);
+ if (memdesc->sg)
+ for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+ __free_page(sg_page(sg));
}
static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc)
@@ -331,6 +338,39 @@
return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
}
+/*
+ * kgsl_vmalloc_map_kernel - Map the memory in memdesc to kernel address space
+ *
+ * @memdesc - The memory descriptor which contains information about the memory
+ *
+ * Return: 0 on success else error code
+ */
+static int kgsl_vmalloc_map_kernel(struct kgsl_memdesc *memdesc)
+{
+ if (!memdesc->hostptr) {
+ pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
+ struct page **pages = NULL;
+ struct scatterlist *sg;
+ int i;
+ /* create a list of pages to call vmap */
+ pages = vmalloc(memdesc->sglen * sizeof(struct page *));
+ if (!pages) {
+ KGSL_CORE_ERR("vmalloc(%d) failed\n",
+ memdesc->sglen * sizeof(struct page *));
+ return -ENOMEM;
+ }
+ for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+ pages[i] = sg_page(sg);
+ memdesc->hostptr = vmap(pages, memdesc->sglen,
+ VM_IOREMAP, page_prot);
+ vfree(pages);
+ }
+ if (!memdesc->hostptr)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
struct vm_area_struct *vma,
struct vm_fault *vmf)
@@ -374,6 +414,7 @@
.free = kgsl_vmalloc_free,
.vmflags = kgsl_vmalloc_vmflags,
.vmfault = kgsl_vmalloc_vmfault,
+ .map_kernel_mem = kgsl_vmalloc_map_kernel,
};
EXPORT_SYMBOL(kgsl_vmalloc_ops);
@@ -411,7 +452,7 @@
static int
_kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- void *ptr, size_t size, unsigned int protflags)
+ size_t size, unsigned int protflags)
{
int order, ret = 0;
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
@@ -421,9 +462,9 @@
memdesc->pagetable = pagetable;
memdesc->priv = KGSL_MEMFLAGS_CACHED;
memdesc->ops = &kgsl_vmalloc_ops;
- memdesc->hostptr = (void *) ptr;
- memdesc->sg = vmalloc(sglen * sizeof(struct scatterlist));
+ memdesc->sg = kgsl_sg_alloc(sglen);
+
if (memdesc->sg == NULL) {
ret = -ENOMEM;
goto done;
@@ -434,16 +475,19 @@
memdesc->sglen = sglen;
sg_init_table(memdesc->sg, sglen);
- for (i = 0; i < memdesc->sglen; i++, ptr += PAGE_SIZE) {
- struct page *page = vmalloc_to_page(ptr);
+ for (i = 0; i < memdesc->sglen; i++) {
+ struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+ __GFP_HIGHMEM);
if (!page) {
- ret = -EINVAL;
+ ret = -ENOMEM;
+ memdesc->sglen = i;
goto done;
}
+ flush_dcache_page(page);
sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
}
-
- kgsl_cache_range_op(memdesc, KGSL_CACHE_OP_INV);
+ outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
+ KGSL_CACHE_OP_FLUSH);
ret = kgsl_mmu_map(pagetable, memdesc, protflags);
@@ -469,20 +513,18 @@
kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable, size_t size)
{
- void *ptr;
-
+ int ret = 0;
BUG_ON(size == 0);
size = ALIGN(size, PAGE_SIZE * 2);
- ptr = vmalloc(size);
- if (ptr == NULL) {
- KGSL_CORE_ERR("vmalloc(%d) failed\n", size);
- return -ENOMEM;
- }
-
- return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
+ ret = _kgsl_sharedmem_vmalloc(memdesc, pagetable, size,
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ if (!ret)
+ ret = kgsl_vmalloc_map_kernel(memdesc);
+ if (ret)
+ kgsl_sharedmem_free(memdesc);
+ return ret;
}
EXPORT_SYMBOL(kgsl_sharedmem_vmalloc);
@@ -491,25 +533,15 @@
struct kgsl_pagetable *pagetable,
size_t size, int flags)
{
- void *ptr;
unsigned int protflags;
BUG_ON(size == 0);
- ptr = vmalloc_user(size);
-
- if (ptr == NULL) {
- KGSL_CORE_ERR("vmalloc_user(%d) failed: allocated=%d\n",
- size, kgsl_driver.stats.vmalloc);
- return -ENOMEM;
- }
-
- kmemleak_not_leak(ptr);
protflags = GSL_PT_PAGE_RV;
if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
protflags |= GSL_PT_PAGE_WV;
- return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
+ return _kgsl_sharedmem_vmalloc(memdesc, pagetable, size,
protflags);
}
EXPORT_SYMBOL(kgsl_sharedmem_vmalloc_user);
@@ -560,7 +592,7 @@
if (memdesc->ops && memdesc->ops->free)
memdesc->ops->free(memdesc);
- vfree(memdesc->sg);
+ kgsl_sg_free(memdesc->sg, memdesc->sglen);
memset(memdesc, 0, sizeof(*memdesc));
}
@@ -692,3 +724,33 @@
return 0;
}
EXPORT_SYMBOL(kgsl_sharedmem_set);
+
+/*
+ * kgsl_sharedmem_map_vma - Map a user vma to physical memory
+ *
+ * @vma - The user vma to map
+ * @memdesc - The memory descriptor which contains information about the
+ * physical memory
+ *
+ * Return: 0 on success else error code
+ */
+int
+kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
+ const struct kgsl_memdesc *memdesc)
+{
+ unsigned long addr = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ int ret, i = 0;
+
+ if (!memdesc->sg || (size != memdesc->size) ||
+ (memdesc->sglen != (size / PAGE_SIZE)))
+ return -EINVAL;
+
+ for (; addr < vma->vm_end; addr += PAGE_SIZE, i++) {
+ ret = vm_insert_page(vma, addr, sg_page(&memdesc->sg[i]));
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(kgsl_sharedmem_map_vma);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index a1e4c91..def29b3 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -32,13 +32,6 @@
/** Set if the memdesc is mapped into all pagetables */
#define KGSL_MEMFLAGS_GLOBAL 0x00000002
-struct kgsl_memdesc_ops {
- int (*vmflags)(struct kgsl_memdesc *);
- int (*vmfault)(struct kgsl_memdesc *, struct vm_area_struct *,
- struct vm_fault *);
- void (*free)(struct kgsl_memdesc *memdesc);
-};
-
extern struct kgsl_memdesc_ops kgsl_vmalloc_ops;
int kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
@@ -92,13 +85,38 @@
return pa;
}
+int
+kgsl_sharedmem_map_vma(struct vm_area_struct *vma,
+ const struct kgsl_memdesc *memdesc);
+
+/*
+ * For relatively small sglists, it is preferable to use kzalloc
+ * rather than going down the vmalloc rat hole. If the size of
+ * the sglist is < PAGE_SIZE use kzalloc otherwise fallback to
+ * vmalloc
+ */
+
+static inline void *kgsl_sg_alloc(unsigned int sglen)
+{
+ if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
+ return kzalloc(sglen * sizeof(struct scatterlist), GFP_KERNEL);
+ else
+ return vmalloc(sglen * sizeof(struct scatterlist));
+}
+
+static inline void kgsl_sg_free(void *ptr, unsigned int sglen)
+{
+ if ((sglen * sizeof(struct scatterlist)) < PAGE_SIZE)
+ kfree(ptr);
+ else
+ vfree(ptr);
+}
+
static inline int
memdesc_sg_phys(struct kgsl_memdesc *memdesc,
unsigned int physaddr, unsigned int size)
{
- memdesc->sg = vmalloc(sizeof(struct scatterlist) * 1);
- if (memdesc->sg == NULL)
- return -ENOMEM;
+ memdesc->sg = kgsl_sg_alloc(1);
kmemleak_not_leak(memdesc->sg);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 6c43a75..41f4435 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -409,7 +409,7 @@
unsigned int index = 0;
unsigned int nextindex;
unsigned int nextcnt = Z180_STREAM_END_CMD | 5;
- struct kgsl_memdesc tmp = {0};
+ struct kgsl_mem_entry *entry = NULL;
unsigned int cmd;
struct kgsl_device *device = dev_priv->device;
struct kgsl_pagetable *pagetable = dev_priv->process_priv->pagetable;
@@ -427,8 +427,30 @@
}
cmd = ibdesc[0].gpuaddr;
sizedwords = ibdesc[0].sizedwords;
-
- tmp.hostptr = (void *)*timestamp;
+ /*
+ * Get a kernel mapping to the IB for monkey patching.
+ * See the end of this function.
+ */
+ entry = kgsl_sharedmem_find_region(dev_priv->process_priv, cmd,
+ sizedwords);
+ if (entry == NULL) {
+ KGSL_DRV_ERR(device, "Bad ibdesc: gpuaddr 0x%x size %d\n",
+ cmd, sizedwords);
+ result = -EINVAL;
+ goto error;
+ }
+ /*
+ * This will only map memory if it exists, otherwise it will reuse the
+ * mapping. And the 2d userspace reuses IBs so we likely won't create
+ * too many mappings.
+ */
+ if (kgsl_gpuaddr_to_vaddr(&entry->memdesc, cmd) == NULL) {
+ KGSL_DRV_ERR(device,
+ "Cannot make kernel mapping for gpuaddr 0x%x\n",
+ cmd);
+ result = -EINVAL;
+ goto error;
+ }
KGSL_CMD_INFO(device, "ctxt %d ibaddr 0x%08x sizedwords %d\n",
context->id, cmd, sizedwords);
@@ -470,12 +492,13 @@
nextaddr = z180_dev->ringbuffer.cmdbufdesc.gpuaddr
+ rb_offset(nextindex);
- tmp.hostptr = (void *)(tmp.hostptr +
- (sizedwords * sizeof(unsigned int)));
- tmp.size = 12;
-
- kgsl_sharedmem_writel(&tmp, 4, nextaddr);
- kgsl_sharedmem_writel(&tmp, 8, nextcnt);
+ /* monkey patch the IB so that it jumps back to the ringbuffer */
+ kgsl_sharedmem_writel(&entry->memdesc,
+ ((sizedwords + 1) * sizeof(unsigned int)),
+ nextaddr);
+ kgsl_sharedmem_writel(&entry->memdesc,
+ ((sizedwords + 2) * sizeof(unsigned int)),
+ nextcnt);
/* sync memory before activating the hardware for the new command*/
mb();
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 2f59235..6bef3d3 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -239,6 +239,7 @@
if (arb_cntrl) {
data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_REQ;
+ INIT_COMPLETION(adc_pmic->adc_rslt_completion);
rc = pm8xxx_writeb(adc_pmic->dev->parent,
PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
} else
@@ -336,7 +337,6 @@
static int32_t pm8xxx_adc_configure(
struct pm8xxx_adc_amux_properties *chan_prop)
{
- struct pm8xxx_adc *adc_pmic = pmic_adc;
u8 data_amux_chan = 0, data_arb_rsv = 0, data_dig_param = 0;
int rc;
@@ -395,9 +395,6 @@
if (rc < 0)
return rc;
- if (!pm8xxx_adc_calib_first_adc)
- enable_irq(adc_pmic->adc_irq);
-
rc = pm8xxx_adc_arb_cntrl(1, data_amux_chan);
if (rc < 0) {
pr_err("Configuring ADC Arbiter"
@@ -476,16 +473,21 @@
spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
}
+void trigger_completion(struct work_struct *work)
+{
+ struct pm8xxx_adc *adc_8xxx = pmic_adc;
+
+ complete(&adc_8xxx->adc_rslt_completion);
+}
+DECLARE_WORK(trigger_completion_work, trigger_completion);
+
static irqreturn_t pm8xxx_adc_isr(int irq, void *dev_id)
{
- struct pm8xxx_adc *adc_8xxx = dev_id;
-
- disable_irq_nosync(adc_8xxx->adc_irq);
if (pm8xxx_adc_calib_first_adc)
return IRQ_HANDLED;
- /* TODO Handle spurius interrupt condition */
- complete(&adc_8xxx->adc_rslt_completion);
+
+ schedule_work(&trigger_completion_work);
return IRQ_HANDLED;
}
@@ -1214,10 +1216,10 @@
if (rc) {
dev_err(&pdev->dev, "failed to request adc irq "
"with error %d\n", rc);
+ } else {
+ enable_irq_wake(adc_pmic->adc_irq);
}
- disable_irq_nosync(adc_pmic->adc_irq);
-
adc_pmic->btm_warm_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_1);
if (adc_pmic->btm_warm_irq < 0)
return adc_pmic->btm_warm_irq;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 8476033..195c99b 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -761,16 +761,9 @@
return -EIO;
}
- if (dev->clk_state == 0) {
- if (dev->clk_ctl == 0) {
- if (dev->pdata->src_clk_rate > 0)
- clk_set_rate(dev->clk,
- dev->pdata->src_clk_rate);
- else
- dev->pdata->src_clk_rate = 19200000;
- }
+ if (dev->clk_state == 0)
qup_i2c_pwr_mgmt(dev, 1);
- }
+
/* Initialize QUP registers during first transfer */
if (dev->clk_ctl == 0) {
int fs_div;
@@ -1257,6 +1250,12 @@
* If bootloaders leave a pending interrupt on certain GSBI's,
* then we reset the core before registering for interrupts.
*/
+
+ if (dev->pdata->src_clk_rate > 0)
+ clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
+ else
+ dev->pdata->src_clk_rate = 19200000;
+
clk_prepare_enable(dev->clk);
clk_prepare_enable(dev->pclk);
writel_relaxed(1, dev->base + QUP_SW_RESET);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 39c158d..bda7cb2 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -274,6 +274,10 @@
#define T7_DATA_SIZE 3
#define MXT_MAX_RW_TRIES 3
#define MXT_BLOCK_SIZE 256
+#define MXT_CFG_VERSION_LEN 3
+#define MXT_CFG_VERSION_EQUAL 0
+#define MXT_CFG_VERSION_LESS 1
+#define MXT_CFG_VERSION_GREATER 2
#define MXT_DEBUGFS_DIR "atmel_mxt_ts"
#define MXT_DEBUGFS_FILE "object"
@@ -340,8 +344,10 @@
u8 t9_min_reportid;
u8 t15_max_reportid;
u8 t15_min_reportid;
- u8 curr_cfg_version;
+ u8 cfg_version[MXT_CFG_VERSION_LEN];
int cfg_version_idx;
+ int t38_start_addr;
+ bool update_cfg;
const char *fw_name;
};
@@ -1047,8 +1053,10 @@
/* Calculate index for config major version in config array.
* Major version is the first byte in object T38.
*/
- if (object->type == MXT_SPT_USERDATA_T38)
+ if (object->type == MXT_SPT_USERDATA_T38) {
+ data->t38_start_addr = object->start_address;
found_t38 = true;
+ }
if (!found_t38 && mxt_object_writable(object->type))
data->cfg_version_idx += object->size + 1;
}
@@ -1056,14 +1064,85 @@
return 0;
}
-static int mxt_search_config_array(struct mxt_data *data, bool version_match)
+static int compare_versions(const u8 *v1, const u8 *v2)
+{
+ int i;
+
+ if (!v1 || !v2)
+ return -EINVAL;
+
+ /* The major version number stays the same across different versions for
+ * a particular controller on a target. The minor and sub-minor version
+ * numbers indicate which version is newer.
+ */
+ if (v1[0] != v2[0])
+ return -EINVAL;
+
+ for (i = 1; i < MXT_CFG_VERSION_LEN; i++) {
+ if (v1[i] > v2[i])
+ return MXT_CFG_VERSION_LESS; /* v2 is older */
+
+ if (v1[i] < v2[i])
+ return MXT_CFG_VERSION_GREATER; /* v2 is newer */
+ }
+
+ return MXT_CFG_VERSION_EQUAL; /* v1 and v2 are equal */
+}
+
+static void mxt_check_config_version(struct mxt_data *data,
+ const struct mxt_config_info *cfg_info,
+ bool match_major,
+ const u8 **cfg_version_found,
+ bool *found_cfg_major_match)
+{
+ const u8 *cfg_version;
+ int result = -EINVAL;
+
+ cfg_version = cfg_info->config + data->cfg_version_idx;
+
+ if (*cfg_version_found)
+ result = compare_versions(*cfg_version_found, cfg_version);
+
+ if (match_major) {
+ if (result >= MXT_CFG_VERSION_EQUAL)
+ *found_cfg_major_match = true;
+
+ if (result == MXT_CFG_VERSION_EQUAL ||
+ result == MXT_CFG_VERSION_GREATER) {
+ data->config_info = cfg_info;
+ data->fw_name = cfg_info->fw_name;
+ *cfg_version_found = cfg_version;
+ }
+
+ if (result == MXT_CFG_VERSION_GREATER)
+ data->update_cfg = true;
+ } else if (!*cfg_version_found || result == MXT_CFG_VERSION_GREATER) {
+ data->config_info = cfg_info;
+ data->fw_name = cfg_info->fw_name;
+ data->update_cfg = true;
+ *cfg_version_found = cfg_version;
+ }
+}
+
+/* If the controller's config version has a non-zero major number, call this
+ * function with match_major = true to look for the latest config present in
+ * the pdata based on matching family id, variant id, f/w version, build, and
+ * config major number. If the controller is programmed with wrong config data
+ * previously, call this function with match_major = false to look for latest
+ * config based on based on matching family id, variant id, f/w version and
+ * build only.
+ */
+static int mxt_search_config_array(struct mxt_data *data, bool match_major)
{
const struct mxt_platform_data *pdata = data->pdata;
const struct mxt_config_info *cfg_info;
- struct mxt_info *info = &data->info;
+ const struct mxt_info *info = &data->info;
+ const u8 *cfg_version_found;
+ bool found_cfg_major_match = false;
int i;
- u8 cfg_version;
+
+ cfg_version_found = match_major ? data->cfg_version : NULL;
for (i = 0; i < pdata->config_array_size; i++) {
@@ -1077,22 +1156,17 @@
info->version == cfg_info->version &&
info->build == cfg_info->build) {
- cfg_version = cfg_info->config[data->cfg_version_idx];
- if (data->curr_cfg_version == cfg_version ||
- !version_match) {
- data->config_info = cfg_info;
- data->fw_name = pdata->config_array[i].fw_name;
- return 0;
- }
+ mxt_check_config_version(data, cfg_info, match_major,
+ &cfg_version_found, &found_cfg_major_match);
}
}
+ if (data->config_info || found_cfg_major_match)
+ return 0;
+
+ data->config_info = NULL;
data->fw_name = NULL;
- dev_info(&data->client->dev,
- "Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
- info->family_id, info->variant_id,
- info->version >> 4, info->version & 0xF, info->build,
- data->curr_cfg_version);
+
return -EINVAL;
}
@@ -1115,24 +1189,40 @@
return -EINVAL;
}
- error = mxt_read_reg(data->client, object->start_address,
- &data->curr_cfg_version);
+ error = __mxt_read_reg(data->client, object->start_address,
+ sizeof(data->cfg_version), data->cfg_version);
if (error) {
dev_err(dev, "Unable to read config version\n");
return error;
}
+ dev_info(dev, "Current config version on the controller is %d.%d.%d\n",
+ data->cfg_version[0], data->cfg_version[1],
+ data->cfg_version[2]);
/* It is possible that the config data on the controller is not
* versioned and the version number returns 0. In this case,
* find a match without the config version checking.
*/
error = mxt_search_config_array(data,
- data->curr_cfg_version != 0 ? true : false);
- if (error)
- return error;
+ data->cfg_version[0] != 0 ? true : false);
+ if (error) {
+ /* If a match wasn't found for a non-zero config version,
+ * it means the controller has the wrong config data. Search
+ * for a best match based on controller and firmware version,
+ * but not config version.
+ */
+ if (data->cfg_version[0])
+ error = mxt_search_config_array(data, false);
+ if (error) {
+ dev_err(dev,
+ "Unable to find matching config in pdata\n");
+ return error;
+ }
+ }
return 0;
}
+
static void mxt_reset_delay(struct mxt_data *data)
{
struct mxt_info *info = &data->info;
@@ -1152,17 +1242,104 @@
}
}
+static int mxt_backup_nv(struct mxt_data *data)
+{
+ int error;
+ u8 command_register;
+ int timeout_counter = 0;
+
+ /* Backup to memory */
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_BACKUPNV,
+ MXT_BACKUP_VALUE);
+ msleep(MXT_BACKUP_TIME);
+
+ do {
+ error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_BACKUPNV,
+ &command_register);
+ if (error)
+ return error;
+
+ usleep_range(1000, 2000);
+
+ } while ((command_register != 0) && (++timeout_counter <= 100));
+
+ if (timeout_counter > 100) {
+ dev_err(&data->client->dev, "No response after backup!\n");
+ return -EIO;
+ }
+
+ /* Soft reset */
+ mxt_write_object(data, MXT_GEN_COMMAND_T6, MXT_COMMAND_RESET, 1);
+
+ mxt_reset_delay(data);
+
+ return 0;
+}
+
+static int mxt_save_objects(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct mxt_object *t7_object;
+ struct mxt_object *t9_object;
+ struct mxt_object *t15_object;
+ int error;
+
+ /* Store T7 and T9 locally, used in suspend/resume operations */
+ t7_object = mxt_get_object(data, MXT_GEN_POWER_T7);
+ if (!t7_object) {
+ dev_err(&client->dev, "Failed to get T7 object\n");
+ return -EINVAL;
+ }
+
+ data->t7_start_addr = t7_object->start_address;
+ error = __mxt_read_reg(client, data->t7_start_addr,
+ T7_DATA_SIZE, data->t7_data);
+ if (error < 0) {
+ dev_err(&client->dev,
+ "Failed to save current power state\n");
+ return error;
+ }
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL,
+ &data->t9_ctrl);
+ if (error < 0) {
+ dev_err(&client->dev, "Failed to save current touch object\n");
+ return error;
+ }
+
+ /* Store T9, T15's min and max report ids */
+ t9_object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
+ if (!t9_object) {
+ dev_err(&client->dev, "Failed to get T9 object\n");
+ return -EINVAL;
+ }
+ data->t9_max_reportid = t9_object->max_reportid;
+ data->t9_min_reportid = t9_object->max_reportid -
+ t9_object->num_report_ids + 1;
+
+ if (data->pdata->key_codes) {
+ t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
+ if (!t15_object)
+ dev_dbg(&client->dev, "T15 object is not available\n");
+ else {
+ data->t15_max_reportid = t15_object->max_reportid;
+ data->t15_min_reportid = t15_object->max_reportid -
+ t15_object->num_report_ids + 1;
+ }
+ }
+
+ return 0;
+}
+
static int mxt_initialize(struct mxt_data *data)
{
struct i2c_client *client = data->client;
struct mxt_info *info = &data->info;
int error;
- int timeout_counter = 0;
u8 val;
- u8 command_register;
- struct mxt_object *t7_object;
- struct mxt_object *t9_object;
- struct mxt_object *t15_object;
+ const u8 *cfg_ver;
error = mxt_get_info(data);
if (error) {
@@ -1209,81 +1386,40 @@
dev_dbg(&client->dev, "Config info not found.\n");
/* Check register init values */
- error = mxt_check_reg_init(data);
+ if (data->config_info && data->config_info->config) {
+ if (data->update_cfg) {
+ error = mxt_check_reg_init(data);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to check reg init value\n");
+ goto free_object_table;
+ }
+
+ error = mxt_backup_nv(data);
+ if (error) {
+ dev_err(&client->dev, "Failed to back up NV\n");
+ goto free_object_table;
+ }
+
+ cfg_ver = data->config_info->config +
+ data->cfg_version_idx;
+ dev_info(&client->dev,
+ "Config updated from %d.%d.%d to %d.%d.%d\n",
+ data->cfg_version[0], data->cfg_version[1],
+ data->cfg_version[2],
+ cfg_ver[0], cfg_ver[1], cfg_ver[2]);
+
+ memcpy(data->cfg_version, cfg_ver, MXT_CFG_VERSION_LEN);
+ }
+ } else {
+ dev_info(&client->dev,
+ "No cfg data defined, skipping check reg init\n");
+ }
+
+ error = mxt_save_objects(data);
if (error)
goto free_object_table;
- /* Store T7 and T9 locally, used in suspend/resume operations */
- t7_object = mxt_get_object(data, MXT_GEN_POWER_T7);
- if (!t7_object) {
- dev_err(&client->dev, "Failed to get T7 object\n");
- error = -EINVAL;
- goto free_object_table;
- }
-
- data->t7_start_addr = t7_object->start_address;
- error = __mxt_read_reg(client, data->t7_start_addr,
- T7_DATA_SIZE, data->t7_data);
- if (error < 0) {
- dev_err(&client->dev,
- "Failed to save current power state\n");
- goto free_object_table;
- }
- error = mxt_read_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL,
- &data->t9_ctrl);
- if (error < 0) {
- dev_err(&client->dev, "Failed to save current touch object\n");
- goto free_object_table;
- }
-
- /* Store T9, T15's min and max report ids */
- t9_object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
- if (!t9_object) {
- dev_err(&client->dev, "Failed to get T9 object\n");
- error = -EINVAL;
- goto free_object_table;
- }
- data->t9_max_reportid = t9_object->max_reportid;
- data->t9_min_reportid = t9_object->max_reportid -
- t9_object->num_report_ids + 1;
-
- if (data->pdata->key_codes) {
- t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
- if (!t15_object)
- dev_dbg(&client->dev, "T15 object is not available\n");
- else {
- data->t15_max_reportid = t15_object->max_reportid;
- data->t15_min_reportid = t15_object->max_reportid -
- t15_object->num_report_ids + 1;
- }
- }
-
- /* Backup to memory */
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_BACKUPNV,
- MXT_BACKUP_VALUE);
- msleep(MXT_BACKUP_TIME);
- do {
- error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_BACKUPNV,
- &command_register);
- if (error)
- goto free_object_table;
- usleep_range(1000, 2000);
- } while ((command_register != 0) && (++timeout_counter <= 100));
- if (timeout_counter > 100) {
- dev_err(&client->dev, "No response after backup!\n");
- error = -EIO;
- goto free_object_table;
- }
-
-
- /* Soft reset */
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_RESET, 1);
-
- mxt_reset_delay(data);
-
/* Update matrix size at info struct */
error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
if (error)
@@ -1518,6 +1654,7 @@
int error;
const char *fw_name;
u8 bootldr_id;
+ u8 cfg_version[MXT_CFG_VERSION_LEN] = {0};
/* If fw_name is set, then the existing firmware has an upgrade */
if (!data->fw_name) {
@@ -1566,6 +1703,13 @@
kfree(data->object_table);
data->object_table = NULL;
data->cfg_version_idx = 0;
+ data->update_cfg = false;
+
+ error = __mxt_write_reg(data->client, data->t38_start_addr,
+ sizeof(cfg_version), cfg_version);
+ if (error)
+ dev_err(dev,
+ "Unable to zero out config version after fw upgrade\n");
mxt_initialize(data);
}
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 46199d8..fa42c2c 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -71,7 +71,7 @@
#define WLED_OP_FDBCK_MASK 0x1C
#define WLED_OP_FDBCK_BIT_SHFT 0x02
-#define WLED_MAX_LEVEL 100
+#define WLED_MAX_LEVEL 255
#define WLED_8_BIT_MASK 0xFF
#define WLED_8_BIT_SHFT 0x08
#define WLED_MAX_DUTY_CYCLE 0xFFF
@@ -79,6 +79,13 @@
#define WLED_SYNC_VAL 0x07
#define WLED_SYNC_RESET_VAL 0x00
+#define SSBI_REG_ADDR_RGB_CNTL1 0x12D
+#define SSBI_REG_ADDR_RGB_CNTL2 0x12E
+
+#define PM8XXX_DRV_RGB_RED_LED BIT(2)
+#define PM8XXX_DRV_RGB_GREEN_LED BIT(1)
+#define PM8XXX_DRV_RGB_BLUE_LED BIT(0)
+
#define MAX_FLASH_LED_CURRENT 300
#define MAX_LC_LED_CURRENT 40
#define MAX_KP_BL_LED_CURRENT 300
@@ -98,6 +105,40 @@
#define PM8XXX_LED_PWM_FLAGS (PM_PWM_LUT_LOOP | PM_PWM_LUT_RAMP_UP)
+#define LED_MAP(_version, _kb, _led0, _led1, _led2, _flash_led0, _flash_led1, \
+ _wled, _rgb_led_red, _rgb_led_green, _rgb_led_blue)\
+ {\
+ .version = _version,\
+ .supported = _kb << PM8XXX_ID_LED_KB_LIGHT | \
+ _led0 << PM8XXX_ID_LED_0 | _led1 << PM8XXX_ID_LED_1 | \
+ _led2 << PM8XXX_ID_LED_2 | \
+ _flash_led0 << PM8XXX_ID_FLASH_LED_0 | \
+ _flash_led1 << PM8XXX_ID_FLASH_LED_1 | \
+ _wled << PM8XXX_ID_WLED | \
+ _rgb_led_red << PM8XXX_ID_RGB_LED_RED | \
+ _rgb_led_green << PM8XXX_ID_RGB_LED_GREEN | \
+ _rgb_led_blue << PM8XXX_ID_RGB_LED_BLUE, \
+ }
+
+/**
+ * supported_leds - leds supported for each PMIC version
+ * @version - version of PMIC
+ * @supported - which leds are supported on version
+ */
+
+struct supported_leds {
+ enum pm8xxx_version version;
+ u32 supported;
+};
+
+static const struct supported_leds led_map[] = {
+ LED_MAP(PM8XXX_VERSION_8058, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
+ LED_MAP(PM8XXX_VERSION_8921, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0),
+ LED_MAP(PM8XXX_VERSION_8018, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ LED_MAP(PM8XXX_VERSION_8922, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1),
+ LED_MAP(PM8XXX_VERSION_8038, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1),
+};
+
/**
* struct pm8xxx_led_data - internal led data structure
* @led_classdev - led class device
@@ -260,6 +301,44 @@
}
}
+static void
+led_rgb_set(struct pm8xxx_led_data *led, enum led_brightness value)
+{
+ int rc;
+ u8 val, mask;
+
+ rc = pm8xxx_readb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL2, &val);
+ if (rc) {
+ dev_err(led->cdev.dev, "can't read rgb ctrl register rc=%d\n",
+ rc);
+ return;
+ }
+
+ switch (led->id) {
+ case PM8XXX_ID_RGB_LED_RED:
+ mask = PM8XXX_DRV_RGB_RED_LED;
+ break;
+ case PM8XXX_ID_RGB_LED_GREEN:
+ mask = PM8XXX_DRV_RGB_GREEN_LED;
+ break;
+ case PM8XXX_ID_RGB_LED_BLUE:
+ mask = PM8XXX_DRV_RGB_BLUE_LED;
+ break;
+ default:
+ return;
+ }
+
+ if (value)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ rc = pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL2, val);
+ if (rc < 0)
+ dev_err(led->cdev.dev, "can't set rgb led %d level rc=%d\n",
+ led->id, rc);
+}
+
static int pm8xxx_led_pwm_work(struct pm8xxx_led_data *led)
{
int duty_us;
@@ -305,6 +384,11 @@
if (rc < 0)
pr_err("wled brightness set failed %d\n", rc);
break;
+ case PM8XXX_ID_RGB_LED_RED:
+ case PM8XXX_ID_RGB_LED_GREEN:
+ case PM8XXX_ID_RGB_LED_BLUE:
+ led_rgb_set(led, level);
+ break;
default:
dev_err(led->cdev.dev, "unknown led id %d", led->id);
break;
@@ -349,8 +433,6 @@
static int pm8xxx_set_led_mode_and_max_brightness(struct pm8xxx_led_data *led,
enum pm8xxx_led_modes led_mode, int max_current)
{
- int rc = 0;
-
switch (led->id) {
case PM8XXX_ID_LED_0:
case PM8XXX_ID_LED_1:
@@ -389,13 +471,17 @@
case PM8XXX_ID_WLED:
led->cdev.max_brightness = WLED_MAX_LEVEL;
break;
- default:
- rc = -EINVAL;
- pr_err("LED Id is invalid");
+ case PM8XXX_ID_RGB_LED_RED:
+ case PM8XXX_ID_RGB_LED_GREEN:
+ case PM8XXX_ID_RGB_LED_BLUE:
+ led->cdev.max_brightness = LED_FULL;
break;
+ default:
+ dev_err(led->cdev.dev, "LED Id is invalid");
+ return -EINVAL;
}
- return rc;
+ return 0;
}
static enum led_brightness pm8xxx_led_get(struct led_classdev *led_cdev)
@@ -550,6 +636,35 @@
return 0;
}
+static int __devinit init_rgb_led(struct pm8xxx_led_data *led)
+{
+ int rc;
+ u8 val;
+
+ rc = pm8xxx_readb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL1, &val);
+ if (rc) {
+ dev_err(led->cdev.dev, "can't read rgb ctrl1 register rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ switch (led->id) {
+ case PM8XXX_ID_RGB_LED_RED:
+ val |= PM8XXX_DRV_RGB_RED_LED;
+ break;
+ case PM8XXX_ID_RGB_LED_GREEN:
+ val |= PM8XXX_DRV_RGB_GREEN_LED;
+ break;
+ case PM8XXX_ID_RGB_LED_BLUE:
+ val |= PM8XXX_DRV_RGB_BLUE_LED;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return pm8xxx_writeb(led->dev->parent, SSBI_REG_ADDR_RGB_CNTL1, val);
+}
+
static int __devinit get_init_value(struct pm8xxx_led_data *led, u8 *val)
{
int rc, offset;
@@ -577,6 +692,17 @@
dev_err(led->cdev.dev, "can't initialize wled rc=%d\n",
rc);
return rc;
+ case PM8XXX_ID_RGB_LED_RED:
+ case PM8XXX_ID_RGB_LED_GREEN:
+ case PM8XXX_ID_RGB_LED_BLUE:
+ rc = init_rgb_led(led);
+ if (rc) {
+ dev_err(led->cdev.dev, "can't initialize rgb rc=%d\n",
+ rc);
+ return rc;
+ }
+ addr = SSBI_REG_ADDR_RGB_CNTL1;
+ break;
default:
dev_err(led->cdev.dev, "unknown led id %d", led->id);
return -EINVAL;
@@ -639,7 +765,9 @@
struct led_info *curr_led;
struct pm8xxx_led_data *led, *led_dat;
struct pm8xxx_led_config *led_cfg;
- int rc, i;
+ enum pm8xxx_version version;
+ bool found = false;
+ int rc, i, j;
if (pdata == NULL) {
dev_err(&pdev->dev, "platform data not supplied\n");
@@ -674,8 +802,26 @@
if (!((led_dat->id >= PM8XXX_ID_LED_KB_LIGHT) &&
(led_dat->id < PM8XXX_ID_MAX))) {
- dev_err(&pdev->dev, "invalid LED ID (%d) specified\n",
- led_dat->id);
+ dev_err(&pdev->dev, "invalid LED ID(%d) specified\n",
+ led_dat->id);
+ rc = -EINVAL;
+ goto fail_id_check;
+
+ }
+
+ found = false;
+ version = pm8xxx_get_version(pdev->dev.parent);
+ for (j = 0; j < ARRAY_SIZE(led_map); j++) {
+ if (version == led_map[j].version
+ && (led_map[j].supported & (1 << led_dat->id))) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ dev_err(&pdev->dev, "invalid LED ID(%d) specified\n",
+ led_dat->id);
rc = -EINVAL;
goto fail_id_check;
}
@@ -714,7 +860,12 @@
led->cdev.brightness = LED_OFF;
if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL) {
- __pm8xxx_led_work(led_dat,
+ if (led_dat->id == PM8XXX_ID_RGB_LED_RED ||
+ led_dat->id == PM8XXX_ID_RGB_LED_GREEN ||
+ led_dat->id == PM8XXX_ID_RGB_LED_BLUE)
+ __pm8xxx_led_work(led_dat, 0);
+ else
+ __pm8xxx_led_work(led_dat,
led_dat->cdev.max_brightness);
if (led_dat->pwm_channel != -1) {
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index c8827ff..ba510a2 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -18,7 +18,6 @@
#include <linux/crypto.h>
#include <linux/workqueue.h>
#include <linux/backing-dev.h>
-#include <linux/percpu.h>
#include <asm/atomic.h>
#include <linux/scatterlist.h>
#include <asm/page.h>
@@ -44,7 +43,8 @@
unsigned int idx_in;
unsigned int idx_out;
sector_t sector;
- atomic_t pending;
+ atomic_t cc_pending;
+ struct ablkcipher_request *req;
};
/*
@@ -57,7 +57,7 @@
struct convert_context ctx;
- atomic_t pending;
+ atomic_t io_pending;
int error;
sector_t sector;
struct dm_crypt_io *base_io;
@@ -106,18 +106,7 @@
enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
/*
- * Duplicated per-CPU state for cipher.
- */
-struct crypt_cpu {
- struct ablkcipher_request *req;
- /* ESSIV: struct crypto_cipher *essiv_tfm */
- void *iv_private;
- struct crypto_ablkcipher *tfms[0];
-};
-
-/*
* The fields in here must be read only after initialization,
- * changing state should be in crypt_cpu.
*/
struct crypt_config {
struct dm_dev *dev;
@@ -147,11 +136,9 @@
sector_t iv_offset;
unsigned int iv_size;
- /*
- * Duplicated per cpu state. Access through
- * per_cpu_ptr() only.
- */
- struct crypt_cpu __percpu *cpu;
+ /* ESSIV: struct crypto_cipher *essiv_tfm */
+ void *iv_private;
+ struct crypto_ablkcipher **tfms;
unsigned tfms_count;
/*
@@ -185,17 +172,12 @@
static void kcryptd_queue_crypt(struct dm_crypt_io *io);
static u8 *iv_of_dmreq(struct crypt_config *cc, struct dm_crypt_request *dmreq);
-static struct crypt_cpu *this_crypt_config(struct crypt_config *cc)
-{
- return this_cpu_ptr(cc->cpu);
-}
-
/*
* Use this to access cipher attributes that are the same for each CPU.
*/
static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
{
- return __this_cpu_ptr(cc->cpu)->tfms[0];
+ return cc->tfms[0];
}
/*
@@ -260,7 +242,7 @@
struct hash_desc desc;
struct scatterlist sg;
struct crypto_cipher *essiv_tfm;
- int err, cpu;
+ int err;
sg_init_one(&sg, cc->key, cc->key_size);
desc.tfm = essiv->hash_tfm;
@@ -270,14 +252,12 @@
if (err)
return err;
- for_each_possible_cpu(cpu) {
- essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private,
+ essiv_tfm = cc->iv_private;
- err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
- crypto_hash_digestsize(essiv->hash_tfm));
- if (err)
- return err;
- }
+ err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
+ crypto_hash_digestsize(essiv->hash_tfm));
+ if (err)
+ return err;
return 0;
}
@@ -288,16 +268,14 @@
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
unsigned salt_size = crypto_hash_digestsize(essiv->hash_tfm);
struct crypto_cipher *essiv_tfm;
- int cpu, r, err = 0;
+ int r, err = 0;
memset(essiv->salt, 0, salt_size);
- for_each_possible_cpu(cpu) {
- essiv_tfm = per_cpu_ptr(cc->cpu, cpu)->iv_private;
- r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size);
- if (r)
- err = r;
- }
+ essiv_tfm = cc->iv_private;
+ r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size);
+ if (r)
+ err = r;
return err;
}
@@ -337,8 +315,6 @@
static void crypt_iv_essiv_dtr(struct crypt_config *cc)
{
- int cpu;
- struct crypt_cpu *cpu_cc;
struct crypto_cipher *essiv_tfm;
struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
@@ -348,15 +324,13 @@
kzfree(essiv->salt);
essiv->salt = NULL;
- for_each_possible_cpu(cpu) {
- cpu_cc = per_cpu_ptr(cc->cpu, cpu);
- essiv_tfm = cpu_cc->iv_private;
+ essiv_tfm = cc->iv_private;
- if (essiv_tfm)
- crypto_free_cipher(essiv_tfm);
+ if (essiv_tfm)
+ crypto_free_cipher(essiv_tfm);
- cpu_cc->iv_private = NULL;
- }
+ cc->iv_private = NULL;
+
}
static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
@@ -365,7 +339,7 @@
struct crypto_cipher *essiv_tfm = NULL;
struct crypto_hash *hash_tfm = NULL;
u8 *salt = NULL;
- int err, cpu;
+ int err;
if (!opts) {
ti->error = "Digest algorithm missing for ESSIV mode";
@@ -390,15 +364,13 @@
cc->iv_gen_private.essiv.salt = salt;
cc->iv_gen_private.essiv.hash_tfm = hash_tfm;
- for_each_possible_cpu(cpu) {
- essiv_tfm = setup_essiv_cpu(cc, ti, salt,
- crypto_hash_digestsize(hash_tfm));
- if (IS_ERR(essiv_tfm)) {
- crypt_iv_essiv_dtr(cc);
- return PTR_ERR(essiv_tfm);
- }
- per_cpu_ptr(cc->cpu, cpu)->iv_private = essiv_tfm;
+ essiv_tfm = setup_essiv_cpu(cc, ti, salt,
+ crypto_hash_digestsize(hash_tfm));
+ if (IS_ERR(essiv_tfm)) {
+ crypt_iv_essiv_dtr(cc);
+ return PTR_ERR(essiv_tfm);
}
+ cc->iv_private = essiv_tfm;
return 0;
@@ -412,7 +384,8 @@
static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
struct dm_crypt_request *dmreq)
{
- struct crypto_cipher *essiv_tfm = this_crypt_config(cc)->iv_private;
+
+ struct crypto_cipher *essiv_tfm = cc->iv_private;
memset(iv, 0, cc->iv_size);
*(u64 *)iv = cpu_to_le64(dmreq->iv_sector);
@@ -750,16 +723,15 @@
static void crypt_alloc_req(struct crypt_config *cc,
struct convert_context *ctx)
{
- struct crypt_cpu *this_cc = this_crypt_config(cc);
unsigned key_index = ctx->sector & (cc->tfms_count - 1);
- if (!this_cc->req)
- this_cc->req = mempool_alloc(cc->req_pool, GFP_NOIO);
+ if (!ctx->req)
+ ctx->req = mempool_alloc(cc->req_pool, GFP_NOIO);
- ablkcipher_request_set_tfm(this_cc->req, this_cc->tfms[key_index]);
- ablkcipher_request_set_callback(this_cc->req,
+ ablkcipher_request_set_tfm(ctx->req, cc->tfms[key_index]);
+ ablkcipher_request_set_callback(ctx->req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
- kcryptd_async_done, dmreq_of_req(cc, this_cc->req));
+ kcryptd_async_done, dmreq_of_req(cc, ctx->req));
}
/*
@@ -768,19 +740,18 @@
static int crypt_convert(struct crypt_config *cc,
struct convert_context *ctx)
{
- struct crypt_cpu *this_cc = this_crypt_config(cc);
int r;
- atomic_set(&ctx->pending, 1);
+ atomic_set(&ctx->cc_pending, 1);
while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
ctx->idx_out < ctx->bio_out->bi_vcnt) {
crypt_alloc_req(cc, ctx);
- atomic_inc(&ctx->pending);
+ atomic_inc(&ctx->cc_pending);
- r = crypt_convert_block(cc, ctx, this_cc->req);
+ r = crypt_convert_block(cc, ctx, ctx->req);
switch (r) {
/* async */
@@ -789,20 +760,20 @@
INIT_COMPLETION(ctx->restart);
/* fall through*/
case -EINPROGRESS:
- this_cc->req = NULL;
+ ctx->req = NULL;
ctx->sector++;
continue;
/* sync */
case 0:
- atomic_dec(&ctx->pending);
+ atomic_dec(&ctx->cc_pending);
ctx->sector++;
cond_resched();
continue;
/* error */
default:
- atomic_dec(&ctx->pending);
+ atomic_dec(&ctx->cc_pending);
return r;
}
}
@@ -853,8 +824,7 @@
* return a partially allocated bio, the caller will then try
* to allocate additional bios while submitting this partial bio
*/
- if (i == (MIN_BIO_PAGES - 1))
- gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+ gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
@@ -899,14 +869,15 @@
io->sector = sector;
io->error = 0;
io->base_io = NULL;
- atomic_set(&io->pending, 0);
+ io->ctx.req = NULL;
+ atomic_set(&io->io_pending, 0);
return io;
}
static void crypt_inc_pending(struct dm_crypt_io *io)
{
- atomic_inc(&io->pending);
+ atomic_inc(&io->io_pending);
}
/*
@@ -921,9 +892,11 @@
struct dm_crypt_io *base_io = io->base_io;
int error = io->error;
- if (!atomic_dec_and_test(&io->pending))
+ if (!atomic_dec_and_test(&io->io_pending))
return;
+ if (io->ctx.req)
+ mempool_free(io->ctx.req, cc->req_pool);
mempool_free(io, cc->io_pool);
if (likely(!base_io))
@@ -1047,16 +1020,14 @@
queue_work(cc->io_queue, &io->work);
}
-static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io,
- int error, int async)
+static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
{
struct bio *clone = io->ctx.bio_out;
struct crypt_config *cc = io->target->private;
- if (unlikely(error < 0)) {
+ if (unlikely(io->error < 0)) {
crypt_free_buffer_pages(cc, clone);
bio_put(clone);
- io->error = -EIO;
crypt_dec_pending(io);
return;
}
@@ -1108,11 +1079,13 @@
crypt_inc_pending(io);
r = crypt_convert(cc, &io->ctx);
- crypt_finished = atomic_dec_and_test(&io->ctx.pending);
+ if (r < 0)
+ io->error = -EIO;
+ crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
/* Encryption was already finished, submit io now */
if (crypt_finished) {
- kcryptd_crypt_write_io_submit(io, r, 0);
+ kcryptd_crypt_write_io_submit(io, 0);
/*
* If there was an error, do not try next fragments.
@@ -1163,11 +1136,8 @@
crypt_dec_pending(io);
}
-static void kcryptd_crypt_read_done(struct dm_crypt_io *io, int error)
+static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
{
- if (unlikely(error < 0))
- io->error = -EIO;
-
crypt_dec_pending(io);
}
@@ -1183,8 +1153,11 @@
r = crypt_convert(cc, &io->ctx);
- if (atomic_dec_and_test(&io->ctx.pending))
- kcryptd_crypt_read_done(io, r);
+ if (r < 0)
+ io->error = -EIO;
+
+ if (atomic_dec_and_test(&io->ctx.cc_pending))
+ kcryptd_crypt_read_done(io);
crypt_dec_pending(io);
}
@@ -1205,15 +1178,18 @@
if (!error && cc->iv_gen_ops && cc->iv_gen_ops->post)
error = cc->iv_gen_ops->post(cc, iv_of_dmreq(cc, dmreq), dmreq);
+ if (error < 0)
+ io->error = -EIO;
+
mempool_free(req_of_dmreq(cc, dmreq), cc->req_pool);
- if (!atomic_dec_and_test(&ctx->pending))
+ if (!atomic_dec_and_test(&ctx->cc_pending))
return;
if (bio_data_dir(io->base_bio) == READ)
- kcryptd_crypt_read_done(io, error);
+ kcryptd_crypt_read_done(io);
else
- kcryptd_crypt_write_io_submit(io, error, 1);
+ kcryptd_crypt_write_io_submit(io, 1);
}
static void kcryptd_crypt(struct work_struct *work)
@@ -1275,29 +1251,35 @@
}
}
-static void crypt_free_tfms(struct crypt_config *cc, int cpu)
+static void crypt_free_tfms(struct crypt_config *cc)
{
- struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu);
unsigned i;
+ if (!cc->tfms)
+ return;
+
for (i = 0; i < cc->tfms_count; i++)
- if (cpu_cc->tfms[i] && !IS_ERR(cpu_cc->tfms[i])) {
- crypto_free_ablkcipher(cpu_cc->tfms[i]);
- cpu_cc->tfms[i] = NULL;
+ if (cc->tfms[i] && !IS_ERR(cc->tfms[i])) {
+ crypto_free_ablkcipher(cc->tfms[i]);
+ cc->tfms[i] = NULL;
}
}
-static int crypt_alloc_tfms(struct crypt_config *cc, int cpu, char *ciphermode)
+static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode)
{
- struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu);
unsigned i;
int err;
+ cc->tfms = kmalloc(cc->tfms_count * sizeof(struct crypto_ablkcipher *),
+ GFP_KERNEL);
+ if (!cc->tfms)
+ return -ENOMEM;
+
for (i = 0; i < cc->tfms_count; i++) {
- cpu_cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0);
- if (IS_ERR(cpu_cc->tfms[i])) {
- err = PTR_ERR(cpu_cc->tfms[i]);
- crypt_free_tfms(cc, cpu);
+ cc->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0);
+ if (IS_ERR(cc->tfms[i])) {
+ err = PTR_ERR(cc->tfms[i]);
+ crypt_free_tfms(cc);
return err;
}
}
@@ -1308,15 +1290,14 @@
static int crypt_setkey_allcpus(struct crypt_config *cc)
{
unsigned subkey_size = cc->key_size >> ilog2(cc->tfms_count);
- int cpu, err = 0, i, r;
+ int err = 0, i, r;
- for_each_possible_cpu(cpu) {
- for (i = 0; i < cc->tfms_count; i++) {
- r = crypto_ablkcipher_setkey(per_cpu_ptr(cc->cpu, cpu)->tfms[i],
- cc->key + (i * subkey_size), subkey_size);
- if (r)
- err = r;
- }
+ for (i = 0; i < cc->tfms_count; i++) {
+ r = crypto_ablkcipher_setkey(cc->tfms[i],
+ cc->key + (i * subkey_size),
+ subkey_size);
+ if (r)
+ err = r;
}
return err;
@@ -1360,8 +1341,6 @@
static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = ti->private;
- struct crypt_cpu *cpu_cc;
- int cpu;
ti->private = NULL;
@@ -1373,13 +1352,7 @@
if (cc->crypt_queue)
destroy_workqueue(cc->crypt_queue);
- if (cc->cpu)
- for_each_possible_cpu(cpu) {
- cpu_cc = per_cpu_ptr(cc->cpu, cpu);
- if (cpu_cc->req)
- mempool_free(cpu_cc->req, cc->req_pool);
- crypt_free_tfms(cc, cpu);
- }
+ crypt_free_tfms(cc);
if (cc->bs)
bioset_free(cc->bs);
@@ -1397,9 +1370,6 @@
if (cc->dev)
dm_put_device(ti, cc->dev);
- if (cc->cpu)
- free_percpu(cc->cpu);
-
kzfree(cc->cipher);
kzfree(cc->cipher_string);
@@ -1413,7 +1383,7 @@
struct crypt_config *cc = ti->private;
char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount;
char *cipher_api = NULL;
- int cpu, ret = -EINVAL;
+ int ret = -EINVAL;
/* Convert to crypto api definition? */
if (strchr(cipher_in, '(')) {
@@ -1453,14 +1423,6 @@
if (tmp)
DMWARN("Ignoring unexpected additional cipher options");
- cc->cpu = __alloc_percpu(sizeof(*(cc->cpu)) +
- cc->tfms_count * sizeof(*(cc->cpu->tfms)),
- __alignof__(struct crypt_cpu));
- if (!cc->cpu) {
- ti->error = "Cannot allocate per cpu state";
- goto bad_mem;
- }
-
/*
* For compatibility with the original dm-crypt mapping format, if
* only the cipher name is supplied, use cbc-plain.
@@ -1487,12 +1449,10 @@
}
/* Allocate cipher */
- for_each_possible_cpu(cpu) {
- ret = crypt_alloc_tfms(cc, cpu, cipher_api);
- if (ret < 0) {
- ti->error = "Error allocating crypto tfm";
- goto bad;
- }
+ ret = crypt_alloc_tfms(cc, cipher_api);
+ if (ret < 0) {
+ ti->error = "Error allocating crypto tfm";
+ goto bad;
}
/* Initialize and set key */
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index ab732b2..a276e84 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -99,6 +99,7 @@
struct hci_fm_ssbi_peek ssbi_peek_reg;
struct hci_fm_sig_threshold_rsp sig_th;
struct hci_fm_ch_det_threshold ch_det_threshold;
+ struct hci_fm_data_rd_rsp default_data;
};
static struct video_device *priv_videodev;
@@ -1769,23 +1770,15 @@
struct iris_device *radio = video_get_drvdata(video_get_dev());
__u8 status = *((__u8 *) skb->data);
__u8 len;
- char *data;
if (status)
return;
len = skb->data[1];
- data = kmalloc(len+2, GFP_ATOMIC);
- if (!data) {
- FMDERR("Memory allocation failed");
- return;
- }
- data[0] = status;
- data[1] = len;
- memcpy(&data[2], &skb->data[DEFAULT_DATA_OFFSET], len);
- iris_q_evt_data(radio, data, len+2, IRIS_BUF_RD_DEFAULT);
+ memset(&radio->default_data, 0 , sizeof(struct hci_fm_data_rd_rsp));
+ memcpy(&radio->default_data, &skb->data[0], len+2);
+ iris_q_evt_data(radio, &skb->data[0], len+2, IRIS_BUF_RD_DEFAULT);
radio_hci_req_complete(hdev, status);
- kfree(data);
}
static void hci_cc_ssbi_peek_rsp(struct radio_hci_dev *hdev,
@@ -2773,6 +2766,8 @@
unsigned long arg = 0;
struct hci_fm_tx_ps tx_ps = {0};
struct hci_fm_tx_rt tx_rt = {0};
+ struct hci_fm_def_data_rd_req rd_txgain;
+ struct hci_fm_def_data_wr_req wr_txgain;
switch (ctrl->id) {
case V4L2_CID_PRIVATE_IRIS_TX_TONE:
@@ -3055,6 +3050,32 @@
radio->ps_repeatcount = ctrl->value;
break;
case V4L2_CID_TUNE_POWER_LEVEL:
+ if (ctrl->value > FM_TX_PWR_LVL_MAX)
+ ctrl->value = FM_TX_PWR_LVL_MAX;
+ if (ctrl->value < FM_TX_PWR_LVL_0)
+ ctrl->value = FM_TX_PWR_LVL_0;
+ rd_txgain.mode = FM_TX_PHY_CFG_MODE;
+ rd_txgain.length = FM_TX_PHY_CFG_LEN;
+ rd_txgain.param_len = 0x00;
+ rd_txgain.param = 0x00;
+
+ retval = hci_def_data_read(&rd_txgain, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Default data read failed for PHY_CFG %d\n",
+ retval);
+ break;
+ }
+ memset(&wr_txgain, 0, sizeof(wr_txgain));
+ wr_txgain.mode = FM_TX_PHY_CFG_MODE;
+ wr_txgain.length = FM_TX_PHY_CFG_LEN;
+ memcpy(&wr_txgain.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wr_txgain.data[FM_TX_PWR_GAIN_OFFSET] =
+ (ctrl->value) * FM_TX_PWR_LVL_STEP_SIZE;
+ retval = hci_def_data_write(&wr_txgain, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("Default write failed for PHY_TXGAIN %d\n",
+ retval);
break;
case V4L2_CID_PRIVATE_IRIS_SOFT_MUTE:
radio->mute_mode.soft_mute = ctrl->value;
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index fb73321..212e5d5 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1078,6 +1078,10 @@
{
struct tavarua_device *radio = container_of(work,
struct tavarua_device, work.work);
+ FMDERR("%s: Releasing the FM I2S GPIO\n", __func__);
+ if (radio->pdata->config_i2s_gpio != NULL)
+ radio->pdata->config_i2s_gpio(FM_I2S_OFF);
+ FMDERR("%s: Shutting down FM SOC\n", __func__);
radio->pdata->fm_shutdown(radio->pdata);
complete(&radio->shutdown_done);
}
@@ -1163,8 +1167,9 @@
return -EINVAL;
irq = radio->pdata->irq;
disable_irq_wake(irq);
- flush_workqueue(radio->wqueue);
free_irq(irq, radio);
+ cancel_delayed_work_sync(&radio->work);
+ flush_workqueue(radio->wqueue);
return 0;
}
@@ -2043,10 +2048,7 @@
FMDBG("In %s", __func__);
- /* disable radio ctrl */
- retval = tavarua_write_register(radio, RDCTRL, 0x00);
-
- FMDBG("%s, Disable IRQs\n", __func__);
+ FMDBG("%s, Disabling the IRQs\n", __func__);
/* disable irq */
retval = tavarua_disable_irq(radio);
if (retval < 0) {
@@ -2054,6 +2056,13 @@
return retval;
}
+ /* disable radio ctrl */
+ retval = tavarua_write_register(radio, RDCTRL, 0x00);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: failed to disable FM\n", __func__);
+ return retval;
+ }
+
init_completion(&radio->shutdown_done);
bahama_present = is_bahama();
@@ -2146,8 +2155,6 @@
/* teardown gpio and pmic */
marimba_set_fm_status(radio->marimba, false);
wait_for_completion(&radio->shutdown_done);
- if (radio->pdata->config_i2s_gpio != NULL)
- radio->pdata->config_i2s_gpio(FM_I2S_OFF);
radio->handle_irq = 1;
atomic_inc(&radio->users);
radio->marimba->mod_id = SLAVE_ID_BAHAMA;
@@ -2992,7 +2999,7 @@
}
/* check if off */
else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
- FMDBG("turning off...\n");
+ FMDBG("%s: turning off...\n", __func__);
tavarua_write_register(radio, RDCTRL, ctrl->value);
/* flush the event and work queues */
kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
@@ -3624,13 +3631,8 @@
struct v4l2_hw_freq_seek *seek)
{
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
- int dir;
- if (seek->seek_upward)
- dir = SRCH_DIR_UP;
- else
- dir = SRCH_DIR_DOWN;
FMDBG("starting search\n");
- return tavarua_search(radio, CTRL_ON, dir);
+ return tavarua_search(radio, CTRL_ON, seek->seek_upward);
}
/*
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index a9b8e40..6744479 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -21,27 +21,22 @@
#include <media/rc-core.h>
#include <media/gpio-ir-recv.h>
-#define TSOP_DRIVER_NAME "gpio-rc-recv"
-#define TSOP_DEVICE_NAME "gpio_ir_recv"
+#define GPIO_IR_DRIVER_NAME "gpio-rc-recv"
+#define GPIO_IR_DEVICE_NAME "gpio_ir_recv"
struct gpio_rc_dev {
struct rc_dev *rcdev;
- struct mutex lock;
unsigned int gpio_nr;
bool active_low;
- bool can_wakeup;
- struct work_struct work;
};
-static void ir_decoder_work(struct work_struct *work)
+static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
- struct gpio_rc_dev *gpio_dev = container_of(work,
- struct gpio_rc_dev, work);
+ struct gpio_rc_dev *gpio_dev = dev_id;
unsigned int gval;
int rc = 0;
enum raw_event_type type = IR_SPACE;
- mutex_lock(&gpio_dev->lock);
gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
if (gval < 0)
@@ -60,15 +55,6 @@
ir_raw_event_handle(gpio_dev->rcdev);
err_get_value:
- mutex_unlock(&gpio_dev->lock);
-}
-
-static irqreturn_t gpio_ir_recv_irq_handler(int irq, void *data)
-{
- struct gpio_rc_dev *gpio_dev = data;
-
- schedule_work(&gpio_dev->work);
-
return IRQ_HANDLED;
}
@@ -78,7 +64,7 @@
struct rc_dev *rcdev;
const struct gpio_ir_recv_platform_data *pdata =
pdev->dev.platform_data;
- int rc = 0;
+ int rc;
if (!pdata)
return -EINVAL;
@@ -90,8 +76,6 @@
if (!gpio_dev)
return -ENOMEM;
- mutex_init(&gpio_dev->lock);
-
rcdev = rc_allocate_device();
if (!rcdev) {
rc = -ENOMEM;
@@ -99,18 +83,15 @@
}
rcdev->driver_type = RC_DRIVER_IR_RAW;
- rcdev->allowed_protos = RC_TYPE_NEC;
- rcdev->input_name = TSOP_DEVICE_NAME;
+ rcdev->allowed_protos = RC_TYPE_ALL;
+ rcdev->input_name = GPIO_IR_DEVICE_NAME;
rcdev->input_id.bustype = BUS_HOST;
- rcdev->driver_name = TSOP_DRIVER_NAME;
- rcdev->map_name = RC_MAP_SAMSUNG_NECX;
+ rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+ rcdev->map_name = RC_MAP_EMPTY;
gpio_dev->rcdev = rcdev;
gpio_dev->gpio_nr = pdata->gpio_nr;
gpio_dev->active_low = pdata->active_low;
- gpio_dev->can_wakeup = pdata->can_wakeup;
-
- INIT_WORK(&gpio_dev->work, ir_decoder_work);
rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
if (rc < 0)
@@ -127,22 +108,15 @@
platform_set_drvdata(pdev, gpio_dev);
- rc = request_irq(gpio_to_irq(pdata->gpio_nr), gpio_ir_recv_irq_handler,
+ rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
+ gpio_ir_recv_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "gpio-ir-recv-irq", gpio_dev);
+ "gpio-ir-recv-irq", gpio_dev);
if (rc < 0)
goto err_request_irq;
- if (pdata->can_wakeup == true) {
- rc = enable_irq_wake(gpio_to_irq(pdata->gpio_nr));
- if (rc < 0)
- goto err_enable_irq_wake;
- }
-
return 0;
-err_enable_irq_wake:
- free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
err_request_irq:
platform_set_drvdata(pdev, NULL);
rc_unregister_device(rcdev);
@@ -153,7 +127,6 @@
rc_free_device(rcdev);
rcdev = NULL;
err_allocate_device:
- mutex_destroy(&gpio_dev->lock);
kfree(gpio_dev);
return rc;
}
@@ -162,24 +135,57 @@
{
struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
- flush_work_sync(&gpio_dev->work);
- disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
platform_set_drvdata(pdev, NULL);
rc_unregister_device(gpio_dev->rcdev);
gpio_free(gpio_dev->gpio_nr);
rc_free_device(gpio_dev->rcdev);
- mutex_destroy(&gpio_dev->lock);
kfree(gpio_dev);
return 0;
}
+#ifdef CONFIG_PM
+static int gpio_ir_recv_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+ else
+ disable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+ return 0;
+}
+
+static int gpio_ir_recv_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
+ else
+ enable_irq(gpio_to_irq(gpio_dev->gpio_nr));
+
+ return 0;
+}
+
+static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
+ .suspend = gpio_ir_recv_suspend,
+ .resume = gpio_ir_recv_resume,
+};
+#endif
+
static struct platform_driver gpio_ir_recv_driver = {
.probe = gpio_ir_recv_probe,
.remove = __devexit_p(gpio_ir_recv_remove),
.driver = {
- .name = TSOP_DRIVER_NAME,
+ .name = GPIO_IR_DRIVER_NAME,
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &gpio_ir_recv_pm_ops,
+#endif
},
};
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 45b0134..198298b 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -56,6 +56,7 @@
rc-norwood.o \
rc-npgtech.o \
rc-pctv-sedna.o \
+ rc-philips.o \
rc-pinnacle-color.o \
rc-pinnacle-grey.o \
rc-pinnacle-pctv-hd.o \
diff --git a/drivers/media/rc/keymaps/rc-philips.c b/drivers/media/rc/keymaps/rc-philips.c
new file mode 100644
index 0000000..ff2caf9
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-philips.c
@@ -0,0 +1,81 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 <media/rc-map.h>
+
+static struct rc_map_table philips[] = {
+
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
+ { 0xF4, KEY_SOUND },
+ { 0xF3, KEY_SCREEN }, /* Picture */
+
+ { 0x10, KEY_VOLUMEUP },
+ { 0x11, KEY_VOLUMEDOWN },
+ { 0x0d, KEY_MUTE },
+ { 0x20, KEY_CHANNELUP },
+ { 0x21, KEY_CHANNELDOWN },
+ { 0x0A, KEY_BACK },
+ { 0x0f, KEY_INFO },
+ { 0x5c, KEY_OK },
+ { 0x58, KEY_UP },
+ { 0x59, KEY_DOWN },
+ { 0x5a, KEY_LEFT },
+ { 0x5b, KEY_RIGHT },
+ { 0xcc, KEY_PAUSE },
+ { 0x6d, KEY_PVR }, /* Demo */
+ { 0x40, KEY_EXIT },
+ { 0x6e, KEY_PROG1 }, /* Scenea */
+ { 0x6f, KEY_MODE }, /* Dual */
+ { 0x70, KEY_SLEEP },
+ { 0xf5, KEY_TUNER }, /* Format */
+
+ { 0x4f, KEY_TV },
+ { 0x3c, KEY_NEW }, /* USB */
+ { 0x38, KEY_COMPOSE }, /* Source */
+ { 0x54, KEY_MENU },
+
+ { 0x0C, KEY_POWER },
+};
+
+static struct rc_map_list rc6_philips_map = {
+ .map = {
+ .scan = philips,
+ .size = ARRAY_SIZE(philips),
+ .rc_type = RC_TYPE_RC6,
+ .name = RC_MAP_RC6_PHILIPS,
+ }
+};
+
+static int __init init_rc_map_rc6_philips(void)
+{
+ return rc_map_register(&rc6_philips_map);
+}
+
+static void __exit exit_rc_map_rc6_philips(void)
+{
+ rc_map_unregister(&rc6_philips_map);
+}
+
+module_init(init_rc_map_rc6_philips)
+module_exit(exit_rc_map_rc6_philips)
+
+MODULE_DESCRIPTION("Philips Remote Keymap ");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index a93031e..c00f4c6 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -82,7 +82,7 @@
# This uses the CSI interface.
config VX6953
bool "Sensor VX6953 (BAYER 5M)"
- depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
+ depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60) && !MSM_CAMERA_V4L2
default y
---help---
STM 5M Bayer Sensor with EDOF
@@ -251,3 +251,11 @@
---help---
Sony 13MP sensor back camera that uses 4 mipi lanes,
runs at 30 fps preview and 14 fps snapshot
+
+config MSM_V4L2_VIDEO_OVERLAY_DEVICE
+ tristate "Qualcomm MSM V4l2 video overlay device"
+ ---help---
+ Enables support for the MSM V4L2 video
+ overlay driver. This allows video rendering
+ apps to render overlaid video using Video4Linux2
+ APIs, by using /dev/videoX device
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 2843d30..ca80fc1 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -20,9 +20,14 @@
else
obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o
endif
-obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o
obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o
-obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+ obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o msm_vfe31_v4l2.o msm_vpe.o
+ obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o msm_vfe31_v4l2.o msm_vpe.o msm_axi_qos.o
+else
+ obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o
+ obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o
+endif
obj-$(CONFIG_ARCH_MSM8960) += msm_io_8960.o msm_vfe32.o msm_vpe.o
obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o
obj-$(CONFIG_SN12M0PZ) += sn12m0pz.o sn12m0pz_reg.o
@@ -32,9 +37,7 @@
obj-$(CONFIG_MT9P012_KM) += mt9p012_km.o mt9p012_km_reg.o
obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
#FIXME: Merge the two ifeq causes VX6953 preview not coming up.
-ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_VX6953) += vx6953_v4l2.o vx6953_reg_v4l2.o
-else
+ifneq ($(CONFIG_MSM_CAMERA_V4L2),y)
obj-$(CONFIG_VX6953) += vx6953.o vx6953_reg.o
obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
@@ -52,3 +55,4 @@
obj-$(CONFIG_MT9D113) += mt9d113.o mt9d113_reg.o
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += wfd/
+obj-$(CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE) += msm_v4l2_video.o
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 6e8eb122..e5d5966 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -2,3 +2,5 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm
obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o msm_csid.o msm_ispif.o
obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic.o
+obj-$(CONFIG_ARCH_MSM8X60) += msm_csic.o
+obj-$(CONFIG_ARCH_MSM7X30) += msm_csic.o
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index 3a642c7..1ca4fa3 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <mach/clk.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <media/msm_isp.h>
@@ -54,7 +55,7 @@
/* Data format for unpacking purpose */
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13
/* Enable decoding of payload based on data type filed of packet hdr */
-#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x00000
+#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x40000
/* Enable error correction on packet headers */
#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000
@@ -132,7 +133,7 @@
#define MSM_AXI_QOS_SNAPSHOT 200000
#define MSM_AXI_QOS_RECORDING 200000
-#define MIPI_PWR_CNTL_ENA 0x07
+#define MIPI_PWR_CNTL_EN 0x07
#define MIPI_PWR_CNTL_DIS 0x0
static int msm_csic_config(struct csic_cfg_params *cfg_params)
@@ -210,9 +211,9 @@
break;
}
- msm_io_w(0xFFFFF3FF, csicbase + MIPI_INTERRUPT_MASK);
- /*clear IRQ bits - write 1 clears the status*/
- msm_io_w(0xFFFFF3FF, csicbase + MIPI_INTERRUPT_STATUS);
+ msm_io_w(0xF077F3C0, csicbase + MIPI_INTERRUPT_MASK);
+ /*clear IRQ bits*/
+ msm_io_w(0xF077F3C0, csicbase + MIPI_INTERRUPT_STATUS);
return rc;
}
@@ -244,7 +245,14 @@
return 0;
}
-static struct msm_cam_clk_info csic_clk_info[] = {
+static struct msm_cam_clk_info csic_8x_clk_info[] = {
+ {"csi_src_clk", 384000000},
+ {"csi_clk", -1},
+ {"csi_vfe_clk", -1},
+ {"csi_pclk", -1},
+};
+
+static struct msm_cam_clk_info csic_7x_clk_info[] = {
{"csi_clk", 400000000},
{"csi_vfe_clk", -1},
{"csi_pclk", -1},
@@ -267,12 +275,18 @@
return rc;
}
- pr_info("msm_cam_clk_enable: enable csi_pclk, csi_clk, csi_vfe_clk\n");
- rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_clk_info,
- csic_dev->csic_clk, ARRAY_SIZE(csic_clk_info), 1);
+ csic_dev->hw_version = CSIC_8X;
+ rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_8x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_8x_clk_info), 1);
if (rc < 0) {
- iounmap(csic_dev->base);
- return rc;
+ csic_dev->hw_version = CSIC_7X;
+ rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_7x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_7x_clk_info), 1);
+ if (rc < 0) {
+ csic_dev->hw_version = 0;
+ iounmap(csic_dev->base);
+ return rc;
+ }
}
#if DBG_CSIC
@@ -282,20 +296,58 @@
return 0;
}
+static void msm_csic_disable(struct v4l2_subdev *sd)
+{
+ uint32_t val;
+ struct csic_device *csic_dev;
+ csic_dev = v4l2_get_subdevdata(sd);
+
+ val = 0x0;
+ if (csic_dev->base != NULL) {
+ CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D0_CONTROL2);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D1_CONTROL2);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D2_CONTROL2);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D3_CONTROL2);
+ CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_CL_CONTROL);
+ msleep(20);
+ val = msm_io_r(csic_dev->base + MIPI_PHY_D1_CONTROL);
+ val &=
+ ~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT)
+ |(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT));
+ CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D1_CONTROL);
+ usleep_range(5000, 6000);
+ msm_io_w(0x0, csic_dev->base + MIPI_INTERRUPT_MASK);
+ msm_io_w(0x0, csic_dev->base + MIPI_INTERRUPT_STATUS);
+ msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+ csic_dev->base + MIPI_PROTOCOL_CONTROL);
+
+ msm_io_w(0xE400, csic_dev->base + MIPI_CAMERA_CNTL);
+ }
+}
+
static int msm_csic_release(struct v4l2_subdev *sd)
{
struct csic_device *csic_dev;
csic_dev = v4l2_get_subdevdata(sd);
+ msm_csic_disable(sd);
#if DBG_CSIC
disable_irq(csic_dev->irq->start);
#endif
- pr_info("msm_cam_clk_enable: disble csi_pclk, csi_clk, csi_vfe_clk\n");
- msm_cam_clk_enable(&csic_dev->pdev->dev, csic_clk_info,
- csic_dev->csic_clk, ARRAY_SIZE(csic_clk_info), 0);
+ if (csic_dev->hw_version == CSIC_8X) {
+ msm_cam_clk_enable(&csic_dev->pdev->dev, csic_8x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_8x_clk_info), 0);
+ } else if (csic_dev->hw_version == CSIC_7X) {
+ msm_cam_clk_enable(&csic_dev->pdev->dev, csic_7x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_7x_clk_info), 0);
+ }
iounmap(csic_dev->base);
+ csic_dev->base = NULL;
return 0;
}
@@ -365,7 +417,7 @@
}
rc = request_irq(new_csic_dev->irq->start, msm_csic_irq,
- IRQF_TRIGGER_HIGH, "csic", new_csic_dev);
+ IRQF_TRIGGER_HIGH, "csic", new_csic_dev);
if (rc < 0) {
release_mem_region(new_csic_dev->mem->start,
resource_size(new_csic_dev->mem));
@@ -374,20 +426,6 @@
goto csic_no_resource;
}
disable_irq(new_csic_dev->irq->start);
- pr_info("msm_cam_clk_enable: enable csi_pclk\n");
- msm_cam_clk_enable(&pdev->dev, &csic_clk_info[2],
- new_csic_dev->csic_clk, 1, 1);
- new_csic_dev->base = ioremap(new_csic_dev->mem->start,
- resource_size(new_csic_dev->mem));
- if (!new_csic_dev->base) {
- rc = -ENOMEM;
- goto csic_no_resource;
- }
-
- msm_io_w(MIPI_PWR_CNTL_DIS, new_csic_dev->base + MIPI_PWR_CNTL_DIS);
- pr_info("msm_cam_clk_enable: disable csi_pclk\n");
- msm_cam_clk_enable(&pdev->dev, &csic_clk_info[2],
- new_csic_dev->csic_clk, 1, 0);
iounmap(new_csic_dev->base);
new_csic_dev->pdev = pdev;
diff --git a/drivers/media/video/msm/csi/msm_csic.h b/drivers/media/video/msm/csi/msm_csic.h
index 08dde52..177e9d1 100644
--- a/drivers/media/video/msm/csi/msm_csic.h
+++ b/drivers/media/video/msm/csi/msm_csic.h
@@ -17,6 +17,9 @@
#include <linux/io.h>
#include <media/v4l2-subdev.h>
+#define CSIC_7X 0x1
+#define CSIC_8X (0x1 << 1)
+
struct csic_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 6985f3c..a86e5c4 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -212,6 +212,66 @@
#endif /* CONFIG_LEDS_PMIC8058 */
return rc;
}
+
+int msm_camera_flash_led(
+ struct msm_camera_sensor_flash_external *external,
+ unsigned led_state)
+{
+ int rc = 0;
+
+ CDBG("msm_camera_flash_led: %d\n", led_state);
+ switch (led_state) {
+ case MSM_CAMERA_LED_INIT:
+ rc = gpio_request(external->led_en, "sgm3141");
+ CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
+ external->led_en, rc);
+ if (!rc)
+ gpio_direction_output(external->led_en, 0);
+ else
+ return 0;
+
+ rc = gpio_request(external->led_flash_en, "sgm3141");
+ CDBG("MSM_CAMERA_LED_INIT: gpio_req: %d %d\n",
+ external->led_flash_en, rc);
+ if (!rc)
+ gpio_direction_output(external->led_flash_en, 0);
+
+ break;
+
+ case MSM_CAMERA_LED_RELEASE:
+ CDBG("MSM_CAMERA_LED_RELEASE\n");
+ gpio_set_value_cansleep(external->led_en, 0);
+ gpio_free(external->led_en);
+ gpio_set_value_cansleep(external->led_flash_en, 0);
+ gpio_free(external->led_flash_en);
+ break;
+
+ case MSM_CAMERA_LED_OFF:
+ CDBG("MSM_CAMERA_LED_OFF\n");
+ gpio_set_value_cansleep(external->led_en, 0);
+ gpio_set_value_cansleep(external->led_flash_en, 0);
+ break;
+
+ case MSM_CAMERA_LED_LOW:
+ CDBG("MSM_CAMERA_LED_LOW\n");
+ gpio_set_value_cansleep(external->led_en, 1);
+ gpio_set_value_cansleep(external->led_flash_en, 1);
+ break;
+
+ case MSM_CAMERA_LED_HIGH:
+ CDBG("MSM_CAMERA_LED_HIGH\n");
+ gpio_set_value_cansleep(external->led_en, 1);
+ gpio_set_value_cansleep(external->led_flash_en, 1);
+ break;
+
+ default:
+ rc = -EFAULT;
+ break;
+ }
+
+ return rc;
+}
+
int msm_camera_flash_external(
struct msm_camera_sensor_flash_external *external,
unsigned led_state)
@@ -439,6 +499,12 @@
led_state);
break;
+ case MSM_CAMERA_FLASH_SRC_LED1:
+ rc = msm_camera_flash_led(
+ &fdata->flash_src->_fsrc.ext_driver_src,
+ led_state);
+ break;
+
default:
rc = -ENODEV;
break;
diff --git a/drivers/media/video/msm/gemini/msm_gemini_core.c b/drivers/media/video/msm/gemini/msm_gemini_core.c
index 480500b..45d3937 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_core.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -71,7 +71,6 @@
for (i = 0; i < 2; i++) {
if (we_pingpong_buf.buf_status[i] && release_buf)
msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file,
- &we_pingpong_buf.buf[i].msm_buffer,
&we_pingpong_buf.buf[i].handle);
we_pingpong_buf.buf_status[i] = 0;
}
diff --git a/drivers/media/video/msm/gemini/msm_gemini_hw.h b/drivers/media/video/msm/gemini/msm_gemini_hw.h
index 3c2fc6a..e1702a5 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_hw.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -27,8 +27,6 @@
uint32_t cbcr_buffer_addr;
uint32_t cbcr_len;
uint32_t num_of_mcu_rows;
- struct msm_mapped_buffer *msm_buffer;
- int *subsystem_id;
struct ion_handle *handle;
};
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index e81215e..ee0ff2f 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -28,14 +28,10 @@
struct ion_client *gemini_client;
void msm_gemini_platform_p2v(struct file *file,
- struct msm_mapped_buffer **msm_buffer,
struct ion_handle **ionhandle)
{
- if (msm_subsystem_unmap_buffer(
- (struct msm_mapped_buffer *)*msm_buffer) < 0)
- pr_err("%s: umapped stat memory\n", __func__);
- *msm_buffer = NULL;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
ion_free(gemini_client, *ionhandle);
*ionhandle = NULL;
#elif CONFIG_ANDROID_PMEM
@@ -44,18 +40,18 @@
}
uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
- struct msm_mapped_buffer **msm_buffer,
- int *subsys_id, struct ion_handle **ionhandle)
+ struct ion_handle **ionhandle)
{
unsigned long paddr;
unsigned long size;
int rc;
- int flags;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
*ionhandle = ion_import_fd(gemini_client, fd);
if (IS_ERR_OR_NULL(*ionhandle))
return 0;
- rc = ion_phys(gemini_client, *ionhandle, &paddr, (size_t *)&size);
+
+ rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
+ SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
#elif CONFIG_ANDROID_PMEM
unsigned long kvstart;
rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
@@ -67,31 +63,21 @@
if (rc < 0) {
GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
rc);
- return 0;
+ goto error1;
}
/* validate user input */
if (len > size) {
GMN_PR_ERR("%s: invalid offset + len\n", __func__);
- return 0;
+ goto error1;
}
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- *subsys_id = MSM_SUBSYSTEM_CAMERA;
- *msm_buffer = msm_subsystem_map_buffer(paddr, size,
- flags, subsys_id, 1);
- if (IS_ERR((void *)*msm_buffer)) {
- pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_free(gemini_client, *ionhandle);
- *ionhandle = NULL;
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(*file_p);
-#endif
- return 0;
- }
- paddr = ((struct msm_mapped_buffer *)*msm_buffer)->iova[0];
return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_free(gemini_client, *ionhandle);
+#endif
+ return 0;
}
int msm_gemini_platform_init(struct platform_device *pdev,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.h b/drivers/media/video/msm/gemini/msm_gemini_platform.h
index c54d7df..4542129 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -17,11 +17,9 @@
#include <linux/platform_device.h>
#include <linux/ion.h>
void msm_gemini_platform_p2v(struct file *file,
- struct msm_mapped_buffer **msm_buffer,
struct ion_handle **ionhandle);
uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
- struct msm_mapped_buffer **msm_buffer,
- int *subsys_id, struct ion_handle **ionhandle);
+ struct ion_handle **ionhandle);
int msm_gemini_platform_clk_enable(void);
int msm_gemini_platform_clk_disable(void);
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index f035ad6..fe7c99f 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -151,9 +151,8 @@
buf_p = msm_gemini_q_out(q_p);
if (buf_p) {
msm_gemini_platform_p2v(buf_p->file,
- &buf_p->msm_buffer, &buf_p->handle);
+ &buf_p->handle);
GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
- kfree(buf_p->subsystem_id);
kfree(buf_p);
}
} while (buf_p);
@@ -317,9 +316,7 @@
}
buf_cmd = buf_p->vbuf;
- msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
- &buf_p->handle);
- kfree(buf_p->subsystem_id);
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
kfree(buf_p);
GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
@@ -361,18 +358,10 @@
GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr,
buf_cmd.y_len);
- buf_p->subsystem_id = kmalloc(sizeof(int), GFP_ATOMIC);
- if (!buf_p->subsystem_id) {
- GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
- kfree(buf_p);
- return -ENOMEM;
- }
buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
- buf_cmd.y_len, &buf_p->file, &buf_p->msm_buffer,
- buf_p->subsystem_id, &buf_p->handle);
+ buf_cmd.y_len, &buf_p->file, &buf_p->handle);
if (!buf_p->y_buffer_addr) {
GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
- kfree(buf_p->subsystem_id);
kfree(buf_p);
return -1;
}
@@ -437,10 +426,8 @@
buf_cmd = buf_p->vbuf;
if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
- msm_gemini_platform_p2v(buf_p->file, &buf_p->msm_buffer,
- &buf_p->handle);
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
}
- kfree(buf_p->subsystem_id);
kfree(buf_p);
GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
@@ -481,19 +468,12 @@
GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
(int) buf_cmd.vaddr, buf_cmd.y_len);
- buf_p->subsystem_id = kmalloc(sizeof(int), GFP_ATOMIC);
- if (!buf_p->subsystem_id) {
- GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
- kfree(buf_p);
- return -ENOMEM;
- }
if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
buf_p->y_buffer_addr = buf_cmd.y_off;
} else {
buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
- &buf_p->msm_buffer, buf_p->subsystem_id, &buf_p->handle)
- + buf_cmd.offset;
+ &buf_p->handle) + buf_cmd.offset;
}
buf_p->y_len = buf_cmd.y_len;
@@ -507,7 +487,6 @@
if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
- kfree(buf_p->subsystem_id);
kfree(buf_p);
return -1;
}
diff --git a/drivers/media/video/msm/io/msm_io_util.c b/drivers/media/video/msm/io/msm_io_util.c
index a04d6fd..cc6bab2 100644
--- a/drivers/media/video/msm/io/msm_io_util.c
+++ b/drivers/media/video/msm/io/msm_io_util.c
@@ -111,15 +111,15 @@
curr_vreg->reg_name);
goto vreg_set_voltage_fail;
}
- if (curr_vreg->op_mode) {
+ if (curr_vreg->op_mode >= 0) {
rc = regulator_set_optimum_mode(
reg_ptr[i],
curr_vreg->op_mode);
if (rc < 0) {
- pr_err("%s: %s set optimum"
- "mode failed\n",
- __func__,
- curr_vreg->reg_name);
+ pr_err(
+ "%s: %s set optimum mode failed\n",
+ __func__,
+ curr_vreg->reg_name);
goto vreg_set_opt_mode_fail;
}
}
@@ -130,9 +130,10 @@
curr_vreg = &cam_vreg[i];
if (reg_ptr[i]) {
if (curr_vreg->type == REG_LDO) {
- if (curr_vreg->op_mode)
+ if (curr_vreg->op_mode >= 0) {
regulator_set_optimum_mode(
reg_ptr[i], 0);
+ }
regulator_set_voltage(
reg_ptr[i], 0, curr_vreg->
max_voltage);
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 175a441..d12d65e 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -484,8 +484,11 @@
uint8_t ctrl_data[max_control_command_size];
WARN_ON(ctrl == NULL);
-
- if (ctrl && ctrl->id == MSM_V4L2_PID_CTRL_CMD)
+ if (ctrl == NULL) {
+ pr_err("%s Invalid control\n", __func__);
+ return -EINVAL;
+ }
+ if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
return msm_server_proc_ctrl_cmd(pcam, ctrl, 1);
memset(ctrl_data, 0, sizeof(ctrl_data));
@@ -512,7 +515,11 @@
uint8_t ctrl_data[max_control_command_size];
WARN_ON(ctrl == NULL);
- if (ctrl && ctrl->id == MSM_V4L2_PID_CTRL_CMD)
+ if (ctrl == NULL) {
+ pr_err("%s Invalid control\n", __func__);
+ return -EINVAL;
+ }
+ if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
return msm_server_proc_ctrl_cmd(pcam, ctrl, 0);
memset(ctrl_data, 0, sizeof(ctrl_data));
@@ -1366,6 +1373,14 @@
return rc;
}
+ /* The number of camera instance should be controlled by the
+ resource manager. Currently supporting one active instance
+ until multiple instances are supported */
+ if (atomic_read(&ps->number_pcam_active) > 0) {
+ pr_err("%s Cannot have more than one active camera %d\n",
+ __func__, atomic_read(&ps->number_pcam_active));
+ return -EINVAL;
+ }
/* book keeping this camera session*/
ps->pcam_active = pcam;
atomic_inc(&ps->number_pcam_active);
@@ -1411,6 +1426,9 @@
{
int i;
int rc = -EINVAL;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ int ion_client_created = 0;
+#endif
/*struct msm_isp_ops *p_isp = 0;*/
/* get the video device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
@@ -1442,7 +1460,9 @@
pcam_inst->pcam = pcam;
pcam->dev_inst[i] = pcam_inst;
- D("%s for %s\n", __func__, pcam->pdev->name);
+ D("%s index %d nodeid %d count %d\n", __func__,
+ pcam_inst->my_index,
+ pcam->vnode_id, pcam->use_count);
pcam->use_count++;
if (pcam->use_count == 1) {
@@ -1450,19 +1470,19 @@
if (rc < 0) {
pr_err("%s: cam_server_open_session failed %d\n",
__func__, rc);
- mutex_unlock(&pcam->vid_lock);
- return rc;
+ goto err;
}
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
pcam->mctl.client = msm_ion_client_create(-1, "camera");
kref_init(&pcam->mctl.refcount);
+ ion_client_created = 1;
#endif
/* Should be set to sensor ops if any but right now its OK!! */
if (!pcam->mctl.mctl_open) {
D("%s: media contoller is not inited\n",
__func__);
- mutex_unlock(&pcam->vid_lock);
- return -ENODEV;
+ rc = -ENODEV;
+ goto err;
}
/* Now we really have to activate the camera */
@@ -1470,9 +1490,8 @@
rc = pcam->mctl.mctl_open(&(pcam->mctl), MSM_APPS_ID_V4L2);
if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
pr_err("%s: HW open failed rc = 0x%x\n", __func__, rc);
- return rc;
+ goto err;
}
pcam->mctl.sync.pcam_sync = pcam;
@@ -1480,24 +1499,21 @@
rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
pcam->mctl.isp_sdev->sd);
if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
pr_err("%s: v4l2_device_register_subdev failed rc = %d\n",
__func__, rc);
- return rc;
+ goto err;
}
if (pcam->mctl.isp_sdev->sd_vpe) {
rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
pcam->mctl.isp_sdev->sd_vpe);
if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
- return rc;
+ goto err;
}
}
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->pvdev);
if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
- return rc;
+ goto err;
}
}
pcam_inst->vbqueue_initialized = 0;
@@ -1522,6 +1538,21 @@
D("%s: end", __func__);
/* rc = msm_cam_server_open_session(g_server_dev, pcam);*/
return rc;
+
+err:
+ if (pcam->use_count == 1) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ if (ion_client_created) {
+ pr_err("%s: destroy ion client", __func__);
+ kref_put(&pcam->mctl.refcount, msm_release_ion_client);
+ }
+#endif
+ pcam->dev_inst[i] = NULL;
+ pcam->use_count = 0;
+ }
+ mutex_unlock(&pcam->vid_lock);
+ kfree(pcam_inst);
+ return rc;
}
static int msm_addr_remap(struct msm_cam_v4l2_dev_inst *pcam_inst,
@@ -1622,6 +1653,8 @@
if (pcam_inst->vbqueue_initialized)
vb2_queue_release(&pcam_inst->vid_bufq);
D("%s Closing down instance %p ", __func__, pcam_inst);
+ D("%s index %d nodeid %d count %d\n", __func__, pcam_inst->my_index,
+ pcam->vnode_id, pcam->use_count);
pcam->dev_inst[pcam_inst->my_index] = NULL;
if (pcam_inst->my_index == 0) {
v4l2_fh_del(&pcam_inst->eventHandle);
@@ -2296,7 +2329,7 @@
if (IS_ERR(device_config)) {
rc = PTR_ERR(device_config);
pr_err("%s: error creating device: %d\n", __func__, rc);
- return rc;
+ goto config_setup_fail;
}
cdev_init(&config_cam->config_cdev,
@@ -2307,7 +2340,7 @@
if (rc < 0) {
pr_err("%s: error adding cdev: %d\n", __func__, rc);
device_destroy(msm_class, devno);
- return rc;
+ goto config_setup_fail;
}
g_server_dev.config_info.config_dev_name[dev_num]
= dev_name(device_config);
@@ -2319,16 +2352,23 @@
config_cam->config_stat_event_queue.pvdev = video_device_alloc();
if (config_cam->config_stat_event_queue.pvdev == NULL) {
pr_err("%s: video_device_alloc failed\n", __func__);
- return -ENOMEM;
+ goto config_setup_fail;
}
rc = msm_setup_v4l2_event_queue(
&config_cam->config_stat_event_queue.eventHandle,
config_cam->config_stat_event_queue.pvdev);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s failed to initialize event queue\n", __func__);
+ goto config_setup_fail;
+ }
return rc;
+
+config_setup_fail:
+ kfree(config_cam);
+ return rc;
+
}
static int msm_setup_server_dev(int node, char *device_name)
@@ -2638,7 +2678,7 @@
D("%s done, rc = %d\n", __func__, rc);
D("%s number of sensors connected is %d\n", __func__,
- g_server_dev.camera_info.num_cameras);
+ g_server_dev.camera_info.num_cameras);
/* register the subdevice, must be done for callbacks */
rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sensor_sd);
diff --git a/drivers/media/video/msm/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/msm_io_vfe31_v4l2.c
new file mode 100644
index 0000000..03810f4
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_vfe31_v4l2.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+#include <linux/pm_qos_params.h>
+
+/* AXI rates in KHz */
+#define MSM_AXI_QOS_PREVIEW 192000
+#define MSM_AXI_QOS_SNAPSHOT 192000
+#define MSM_AXI_QOS_RECORDING 192000
+
+#define BUFF_SIZE_128 128
+
+static struct clk *camio_jpeg_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_jpeg_pclk;
+static struct clk *camio_vpe_clk;
+static struct clk *camio_vpe_pclk;
+static struct regulator *fs_ijpeg;
+static struct regulator *fs_vpe;
+
+static int vpe_clk_rate;
+void msm_io_w(u32 data, void __iomem *addr)
+{
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ writel_relaxed((data), (addr));
+}
+
+void msm_io_w_mb(u32 data, void __iomem *addr)
+{
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ wmb();
+ writel_relaxed((data), (addr));
+ wmb();
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+ uint32_t data = readl_relaxed(addr);
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ return data;
+}
+
+u32 msm_io_r_mb(void __iomem *addr)
+{
+ uint32_t data;
+ rmb();
+ data = readl_relaxed(addr);
+ rmb();
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ return data;
+}
+
+void msm_io_memcpy_toio(void __iomem *dest_addr,
+ void __iomem *src_addr, u32 len)
+{
+ int i;
+ u32 *d = (u32 *) dest_addr;
+ u32 *s = (u32 *) src_addr;
+ /* memcpy_toio does not work. Use writel for now */
+ for (i = 0; i < len; i++)
+ writel_relaxed(*s++, d++);
+}
+
+void msm_io_dump(void __iomem *addr, int size)
+{
+ char line_str[BUFF_SIZE_128], *p_str;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ CDBG("%s: %p %d\n", __func__, addr, size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ CDBG("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ CDBG("%s\n", line_str);
+}
+
+void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len)
+{
+ CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len);
+ msm_io_memcpy_toio(dest_addr, src_addr, len / 4);
+ msm_io_dump(dest_addr, len);
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ switch (clktype) {
+ case CAMIO_JPEG_CLK:
+ camio_jpeg_clk =
+ clk = clk_get(NULL, "ijpeg_clk");
+ rc = clk_set_rate(clk, 228571000);
+ if (rc < 0)
+ rc = clk_set_rate(clk, 153600000);
+ break;
+
+ case CAMIO_JPEG_PCLK:
+ camio_jpeg_pclk =
+ clk = clk_get(NULL, "ijpeg_pclk");
+ break;
+
+ case CAMIO_VPE_CLK:
+ camio_vpe_clk =
+ clk = clk_get(NULL, "vpe_clk");
+ vpe_clk_rate = clk_round_rate(camio_vpe_clk, vpe_clk_rate);
+ clk_set_rate(camio_vpe_clk, vpe_clk_rate);
+ break;
+
+ case CAMIO_VPE_PCLK:
+ camio_vpe_pclk =
+ clk = clk_get(NULL, "vpe_pclk");
+ break;
+
+ default:
+ break;
+ }
+
+ if (!IS_ERR(clk)) {
+ clk_prepare(clk);
+ clk_enable(clk);
+ } else {
+ rc = -1;
+ }
+ return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ switch (clktype) {
+ case CAMIO_JPEG_CLK:
+ clk = camio_jpeg_clk;
+ break;
+
+ case CAMIO_JPEG_PCLK:
+ clk = camio_jpeg_pclk;
+ break;
+
+ case CAMIO_VPE_CLK:
+ clk = camio_vpe_clk;
+ break;
+
+ case CAMIO_VPE_PCLK:
+ clk = camio_vpe_pclk;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!IS_ERR(clk)) {
+ clk_disable(clk);
+ clk_unprepare(clk);
+ clk_put(clk);
+ } else {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+int msm_camio_vfe_clk_rate_set(int rate)
+{
+ int rc = 0;
+ struct clk *clk = camio_vfe_clk;
+ if (rate > clk_get_rate(clk))
+ rc = clk_set_rate(clk, rate);
+ return rc;
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+ clk_set_rate(clk, rate);
+}
+
+int msm_camio_jpeg_clk_disable(void)
+{
+ int rc = 0;
+ if (fs_ijpeg) {
+ rc = regulator_disable(fs_ijpeg);
+ if (rc < 0) {
+ CDBG("%s: Regulator disable failed %d\n", __func__, rc);
+ return rc;
+ }
+ regulator_put(fs_ijpeg);
+ }
+ rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+ CDBG("%s: exit %d\n", __func__, rc);
+ return rc;
+}
+
+int msm_camio_jpeg_clk_enable(void)
+{
+ int rc = 0;
+ rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
+ if (rc < 0)
+ return rc;
+ fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
+ if (IS_ERR(fs_ijpeg)) {
+ CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
+ PTR_ERR(fs_ijpeg));
+ fs_ijpeg = NULL;
+ } else if (regulator_enable(fs_ijpeg)) {
+ CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
+ regulator_put(fs_ijpeg);
+ }
+ CDBG("%s: exit %d\n", __func__, rc);
+ return rc;
+}
+
+int msm_camio_vpe_clk_disable(void)
+{
+ int rc = 0;
+ if (fs_vpe) {
+ regulator_disable(fs_vpe);
+ regulator_put(fs_vpe);
+ }
+
+ rc = msm_camio_clk_disable(CAMIO_VPE_CLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_disable(CAMIO_VPE_PCLK);
+ return rc;
+}
+
+int msm_camio_vpe_clk_enable(uint32_t clk_rate)
+{
+ int rc = 0;
+ fs_vpe = regulator_get(NULL, "fs_vpe");
+ if (IS_ERR(fs_vpe)) {
+ CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__,
+ PTR_ERR(fs_vpe));
+ fs_vpe = NULL;
+ } else if (regulator_enable(fs_vpe)) {
+ CDBG("%s: Regulator FS_VPE enable failed\n", __func__);
+ regulator_put(fs_vpe);
+ }
+
+ vpe_clk_rate = clk_rate;
+ rc = msm_camio_clk_enable(CAMIO_VPE_CLK);
+ if (rc < 0)
+ return rc;
+
+ rc = msm_camio_clk_enable(CAMIO_VPE_PCLK);
+ return rc;
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+ return;
+}
+
+static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
+{
+ switch (perf_setting) {
+ case S_INIT:
+ add_axi_qos();
+ break;
+ case S_PREVIEW:
+ update_axi_qos(MSM_AXI_QOS_PREVIEW);
+ break;
+ case S_VIDEO:
+ update_axi_qos(MSM_AXI_QOS_RECORDING);
+ break;
+ case S_CAPTURE:
+ update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
+ break;
+ case S_DEFAULT:
+ update_axi_qos(PM_QOS_DEFAULT_VALUE);
+ break;
+ case S_EXIT:
+ release_axi_qos();
+ break;
+ default:
+ CDBG("%s: INVALID CASE\n", __func__);
+ }
+}
+
+void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
+ enum msm_bus_perf_setting perf_setting)
+{
+ static uint32_t bus_perf_client;
+ int rc = 0;
+ if (cam_bus_scale_table == NULL) {
+ msm_camio_axi_cfg(perf_setting);
+ return;
+ }
+
+ switch (perf_setting) {
+ case S_INIT:
+ bus_perf_client =
+ msm_bus_scale_register_client(cam_bus_scale_table);
+ if (!bus_perf_client) {
+ pr_err("%s: Registration Failed!!!\n", __func__);
+ bus_perf_client = 0;
+ return;
+ }
+ CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
+ break;
+ case S_EXIT:
+ if (bus_perf_client) {
+ CDBG("%s: S_EXIT\n", __func__);
+ msm_bus_scale_unregister_client(bus_perf_client);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_PREVIEW:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 1);
+ CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_VIDEO:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 2);
+ CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_CAPTURE:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 3);
+ CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+
+ case S_ZSL:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 4);
+ CDBG("%s: S_ZSL rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_STEREO_VIDEO:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 5);
+ CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_STEREO_CAPTURE:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 6);
+ CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_DEFAULT:
+ break;
+ default:
+ pr_warning("%s: INVALID CASE\n", __func__);
+ }
+}
+
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 628fa62..3031e1f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -194,8 +194,11 @@
info.pxlcode = pcam->usr_fmts[0].pxlcode;
info.flashtype = sdata->flash_type; /* two flash_types here? */
info.camera_type = sdata->camera_type;
- info.sensor_type = 0; /* need to add YUV/SOC in probing */
+ /* sensor_type needed to add YUV/SOC in probing */
+ info.sensor_type = sdata->sensor_type;
info.mount_angle = sdata->sensor_platform_info->mount_angle;
+ info.actuator_enabled = sdata->actuator_info ? 1 : 0;
+ info.strobe_flash_enabled = sdata->strobe_flash_data ? 1 : 0;
/* copy back to user space */
if (copy_to_user((void *)arg,
&info,
@@ -629,6 +632,22 @@
goto msm_open_done;
}
+ /* then sensor - move sub dev later*/
+ rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
+
+ if (rc < 0) {
+ pr_err("%s: isp init failed: %d\n", __func__, rc);
+ goto msm_open_done;
+ }
+ if (sync->actctrl.a_power_up)
+ rc = sync->actctrl.a_power_up(
+ sync->sdata->actuator_info);
+
+ if (rc < 0) {
+ pr_err("%s: act power failed:%d\n", __func__, rc);
+ goto msm_open_done;
+ }
+
if (camdev->is_csiphy) {
rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_INIT, NULL);
@@ -680,22 +699,6 @@
}
}
- /* then sensor - move sub dev later*/
- rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
-
- if (rc < 0) {
- pr_err("%s: isp init failed: %d\n", __func__, rc);
- goto msm_open_done;
- }
- if (sync->actctrl.a_power_up)
- rc = sync->actctrl.a_power_up(
- sync->sdata->actuator_info);
-
- if (rc < 0) {
- pr_err("%s: act power failed:%d\n", __func__, rc);
- goto msm_open_done;
- }
-
if (camdev->is_ispif) {
pm_qos_add_request(&p_mctl->pm_qos_req_list,
PM_QOS_CPU_DMA_LATENCY,
@@ -725,6 +728,11 @@
VIDIOC_MSM_ISPIF_RELEASE, NULL);
}
+ if (camdev->is_csic) {
+ v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+ VIDIOC_MSM_CSIC_RELEASE, NULL);
+ }
+
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
p_mctl->isp_sdev->isp_release(&p_mctl->sync,
p_mctl->gemini_sdev);
@@ -734,26 +742,22 @@
VIDIOC_MSM_CSID_RELEASE, NULL);
}
- if (camdev->is_csic) {
- v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
- VIDIOC_MSM_CSIC_RELEASE, NULL);
- }
-
if (camdev->is_csiphy) {
v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_RELEASE, NULL);
}
- if (p_mctl->sync.actctrl.a_power_down)
- p_mctl->sync.actctrl.a_power_down(
- p_mctl->sync.sdata->actuator_info);
-
- v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
if (camdev->is_ispif) {
pm_qos_update_request(&p_mctl->pm_qos_req_list,
PM_QOS_DEFAULT_VALUE);
pm_qos_remove_request(&p_mctl->pm_qos_req_list);
}
+ if (p_mctl->sync.actctrl.a_power_down)
+ p_mctl->sync.actctrl.a_power_down(
+ p_mctl->sync.sdata->actuator_info);
+
+ v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
+
wake_unlock(&p_mctl->sync.wake_lock);
return rc;
}
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 54b4efb..4f7e5d2 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -26,7 +26,6 @@
#include <media/v4l2-device.h>
#include <linux/android_pmem.h>
-#include <mach/msm_subsystem_map.h>
#include "msm.h"
@@ -120,7 +119,6 @@
struct msm_pmem_info *info, struct ion_client *client)
{
unsigned long paddr;
- unsigned int flags;
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
unsigned long kvstart;
struct file *file;
@@ -137,7 +135,9 @@
region->handle = ion_import_fd(client, info->fd);
if (IS_ERR_OR_NULL(region->handle))
goto out1;
- ion_phys(client, region->handle, &paddr, (size_t *)&len);
+ if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL,
+ SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
+ goto out2;
#elif CONFIG_ANDROID_PMEM
rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
if (rc < 0) {
@@ -155,13 +155,13 @@
info->len = len;
rc = check_pmem_info(info, len);
if (rc < 0)
- goto out2;
+ goto out3;
paddr += info->offset;
len = info->len;
if (check_overlap(ptype, paddr, len) < 0) {
rc = -EINVAL;
- goto out2;
+ goto out3;
}
CDBG("%s: type %d, active flag %d, paddr 0x%lx, vaddr 0x%lx\n",
@@ -169,16 +169,6 @@
(unsigned long)info->vaddr);
INIT_HLIST_NODE(®ion->list);
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- region->subsys_id = MSM_SUBSYSTEM_CAMERA;
- region->msm_buffer = msm_subsystem_map_buffer(paddr, len,
- flags, &(region->subsys_id), 1);
- if (IS_ERR((void *)region->msm_buffer)) {
- pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
- rc = PTR_ERR((void *)region->msm_buffer);
- goto out2;
- }
- paddr = region->msm_buffer->iova[0];
region->paddr = paddr;
region->len = len;
memcpy(®ion->info, info, sizeof(region->info));
@@ -188,8 +178,12 @@
hlist_add_head(&(region->list), ptype);
return 0;
-out2:
+out3:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL);
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+out2:
ion_free(client, region->handle);
#elif CONFIG_ANDROID_PMEM
put_pmem_file(region->file);
@@ -248,12 +242,9 @@
pinfo->vaddr == region->info.vaddr &&
pinfo->fd == region->info.fd) {
hlist_del(node);
- if (msm_subsystem_unmap_buffer
- (region->msm_buffer) < 0)
- pr_err(
- "%s: unmapped stat memory\n",
- __func__);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, region->handle,
+ CAMERA_DOMAIN, GEN_POOL);
ion_free(client, region->handle);
#else
put_pmem_file(region->file);
diff --git a/drivers/media/video/msm/msm_v4l2_video.c b/drivers/media/video/msm/msm_v4l2_video.c
new file mode 100644
index 0000000..c4e6c62
--- /dev/null
+++ b/drivers/media/video/msm/msm_v4l2_video.c
@@ -0,0 +1,947 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/msm_mdp.h>
+#include <linux/sched.h>
+#include <linux/capability.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-dev.h>
+#include <media/msm_v4l2_overlay.h>
+
+#include <mach/board.h>
+#include <mach/msm_fb.h>
+
+#include "msm_v4l2_video.h"
+
+#define MSM_VIDEO -1
+
+static struct msm_v4l2_overlay_device *saved_vout0;
+
+static struct mutex msmfb_lock;
+static char *v4l2_ram_phys;
+static unsigned int v4l2_ram_size;
+
+static int msm_v4l2_overlay_mapformat(uint32_t pixelformat);
+
+static int msm_v4l2_overlay_startstreaming(struct msm_v4l2_overlay_device *vout)
+{
+ vout->req.src.width = vout->pix.width;
+ vout->req.src.height = vout->pix.height;
+
+ vout->req.src_rect.x = vout->crop_rect.left;
+ vout->req.src_rect.y = vout->crop_rect.top;
+ vout->req.src_rect.w = vout->crop_rect.width;
+ vout->req.src_rect.h = vout->crop_rect.height;
+
+ vout->req.src.format =
+ msm_v4l2_overlay_mapformat(vout->pix.pixelformat);
+
+ vout->req.dst_rect.x = vout->win.w.left;
+ vout->req.dst_rect.y = vout->win.w.top;
+ vout->req.dst_rect.w = vout->win.w.width;
+ vout->req.dst_rect.h = vout->win.w.height;
+
+ vout->req.alpha = MDP_ALPHA_NOP;
+ vout->req.transp_mask = MDP_TRANSP_NOP;
+
+ pr_debug("msm_v4l2_overlay:startstreaming:enabling fb\n");
+ mutex_lock(&msmfb_lock);
+ msm_fb_v4l2_enable(&vout->req, true, &vout->par);
+ mutex_unlock(&msmfb_lock);
+
+ vout->streaming = 1;
+
+ return 0;
+}
+
+static int msm_v4l2_overlay_stopstreaming(struct msm_v4l2_overlay_device *vout)
+{
+ if (!vout->streaming)
+ return 0;
+
+ pr_debug("msm_v4l2_overlay:startstreaming:disabling fb\n");
+ mutex_lock(&msmfb_lock);
+ msm_fb_v4l2_enable(&vout->req, false, &vout->par);
+ mutex_unlock(&msmfb_lock);
+
+ vout->streaming = 0;
+
+ return 0;
+}
+
+static int msm_v4l2_overlay_mapformat(uint32_t pixelformat)
+{
+ int mdp_format;
+
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ mdp_format = MDP_RGB_565;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ mdp_format = MDP_ARGB_8888;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ mdp_format = MDP_RGB_888;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ mdp_format = MDP_Y_CRCB_H2V2;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ mdp_format = MDP_Y_CBCR_H2V2;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ mdp_format = MDP_Y_CR_CB_H2V2;
+ break;
+ default:
+ pr_err("%s:Unrecognized format %u\n", __func__, pixelformat);
+ mdp_format = MDP_Y_CBCR_H2V2;
+ break;
+ }
+
+ return mdp_format;
+}
+
+static int
+msm_v4l2_overlay_fb_update(struct msm_v4l2_overlay_device *vout,
+ struct v4l2_buffer *buffer)
+{
+ int ret;
+ unsigned long src_addr, src_size;
+ struct msm_v4l2_overlay_userptr_buffer up_buffer;
+
+ if (!buffer ||
+ (buffer->memory == V4L2_MEMORY_MMAP &&
+ buffer->index >= vout->numbufs))
+ return -EINVAL;
+
+ mutex_lock(&msmfb_lock);
+ switch (buffer->memory) {
+ case V4L2_MEMORY_MMAP:
+ src_addr = (unsigned long)v4l2_ram_phys
+ + vout->bufs[buffer->index].offset;
+ src_size = buffer->bytesused;
+ ret = msm_fb_v4l2_update(vout->par, src_addr, src_size,
+ 0, 0, 0, 0);
+ break;
+ case V4L2_MEMORY_USERPTR:
+ if (copy_from_user(&up_buffer,
+ (void __user *)buffer->m.userptr,
+ sizeof(struct msm_v4l2_overlay_userptr_buffer))) {
+ mutex_unlock(&msmfb_lock);
+ return -EINVAL;
+ }
+ ret = msm_fb_v4l2_update(vout->par,
+ (unsigned long)up_buffer.base[0], up_buffer.length[0],
+ (unsigned long)up_buffer.base[1], up_buffer.length[1],
+ (unsigned long)up_buffer.base[2], up_buffer.length[2]);
+ break;
+ default:
+ mutex_unlock(&msmfb_lock);
+ return -EINVAL;
+ }
+ mutex_unlock(&msmfb_lock);
+
+ if (buffer->memory == V4L2_MEMORY_MMAP) {
+ vout->bufs[buffer->index].queued = 1;
+ buffer->flags |= V4L2_BUF_FLAG_MAPPED;
+ }
+ buffer->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ return ret;
+}
+
+static int
+msm_v4l2_overlay_vidioc_dqbuf(struct file *file,
+ struct msm_v4l2_overlay_fh *fh, void *arg)
+{
+ struct msm_v4l2_overlay_device *vout = fh->vout;
+ struct v4l2_buffer *buffer = arg;
+ int i;
+
+ if (!vout->streaming) {
+ pr_err("%s: Video Stream not enabled\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!buffer || buffer->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (buffer->memory == V4L2_MEMORY_MMAP) {
+ for (i = 0; i < vout->numbufs; i++) {
+ if (vout->bufs[i].queued == 1) {
+ vout->bufs[i].queued = 0;
+ /* Call into fb to remove this buffer? */
+ break;
+ }
+ }
+
+ /*
+ * This should actually block, unless O_NONBLOCK was
+ * specified in open, but fine for now, especially
+ * since this is not a capturing device
+ */
+ if (i == vout->numbufs)
+ return -EAGAIN;
+ }
+
+ buffer->flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+ return 0;
+}
+
+
+static int
+msm_v4l2_overlay_vidioc_qbuf(struct file *file, struct msm_v4l2_overlay_fh* fh,
+ void *arg, bool bUserPtr)
+{
+ struct msm_v4l2_overlay_device *vout = fh->vout;
+ struct v4l2_buffer *buffer = arg;
+ int ret;
+
+ if (!bUserPtr && buffer->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if (!vout->streaming) {
+ pr_err("%s: Video Stream not enabled\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!buffer || buffer->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ /* maybe allow only one qbuf at a time? */
+ ret = msm_v4l2_overlay_fb_update(vout, buffer);
+
+ return 0;
+}
+
+static int
+msm_v4l2_overlay_vidioc_querycap(struct file *file, void *arg)
+{
+ struct v4l2_capability *buffer = arg;
+
+ memset(buffer, 0, sizeof(struct v4l2_capability));
+ strlcpy(buffer->driver, "msm_v4l2_video_overlay",
+ ARRAY_SIZE(buffer->driver));
+ strlcpy(buffer->card, "MSM MDP",
+ ARRAY_SIZE(buffer->card));
+ buffer->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_VIDEO_OVERLAY;
+ return 0;
+}
+
+static int
+msm_v4l2_overlay_vidioc_fbuf(struct file *file,
+ struct msm_v4l2_overlay_device *vout, void *arg, bool get)
+{
+ struct v4l2_framebuffer *fb = arg;
+
+ if (fb == NULL)
+ return -EINVAL;
+
+ if (get) {
+ mutex_lock(&vout->update_lock);
+ memcpy(&fb->fmt, &vout->pix, sizeof(struct v4l2_pix_format));
+ mutex_unlock(&vout->update_lock);
+ }
+ /* The S_FBUF request does not store anything right now */
+ return 0;
+}
+
+static long msm_v4l2_overlay_calculate_bufsize(struct v4l2_pix_format *pix)
+{
+ int bpp;
+ long bufsize;
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ bpp = 12;
+ break;
+
+ case V4L2_PIX_FMT_RGB565:
+ bpp = 16;
+ break;
+
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_YUV444:
+ bpp = 24;
+ break;
+
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ bpp = 32;
+ break;
+ default:
+ pr_err("%s: Unrecognized format %u\n", __func__,
+ pix->pixelformat);
+ bpp = 0;
+ }
+
+ bufsize = (pix->width * pix->height * bpp)/8;
+
+ return bufsize;
+}
+
+static long
+msm_v4l2_overlay_vidioc_reqbufs(struct file *file,
+ struct msm_v4l2_overlay_device *vout, void *arg)
+
+{
+ struct v4l2_requestbuffers *rqb = arg;
+ long bufsize;
+ int i;
+
+ if (rqb == NULL || rqb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (rqb->memory == V4L2_MEMORY_MMAP) {
+ if (rqb->count == 0) {
+ /* Deallocate allocated buffers */
+ mutex_lock(&vout->update_lock);
+ vout->numbufs = 0;
+ kfree(vout->bufs);
+ /*
+ * There should be a way to look at bufs[i]->mapped,
+ * and prevent userspace from mmaping and directly
+ * calling this ioctl without unmapping. Maybe kernel
+ * handles for us, but needs to be checked out
+ */
+ mutex_unlock(&vout->update_lock);
+ } else {
+ /*
+ * Keep it simple for now - need to deallocate
+ * before reallocate
+ */
+ if (vout->bufs)
+ return -EINVAL;
+
+ mutex_lock(&vout->update_lock);
+ bufsize =
+ msm_v4l2_overlay_calculate_bufsize(&vout->pix);
+ mutex_unlock(&vout->update_lock);
+
+ if (bufsize == 0
+ || (bufsize * rqb->count) > v4l2_ram_size) {
+ pr_err("%s: Unsupported format or buffer size too large\n",
+ __func__);
+ pr_err("%s: bufsize %lu ram_size %u count %u\n",
+ __func__, bufsize, v4l2_ram_size, rqb->count);
+ return -EINVAL;
+ }
+
+ /*
+ * We don't support multiple open of one vout,
+ * but there are probably still some MT problems here,
+ * (what if same fh is shared between two userspace
+ * threads and they both call REQBUFS etc)
+ */
+
+ mutex_lock(&vout->update_lock);
+ vout->numbufs = rqb->count;
+ vout->bufs =
+ kmalloc(rqb->count *
+ sizeof(struct msm_v4l2_overlay_buffer),
+ GFP_KERNEL);
+
+ for (i = 0; i < rqb->count; i++) {
+ struct msm_v4l2_overlay_buffer *b =
+ (struct msm_v4l2_overlay_buffer *)vout->bufs
+ + i;
+ b->mapped = 0;
+ b->queued = 0;
+ b->offset = PAGE_ALIGN(bufsize*i);
+ b->bufsize = bufsize;
+ }
+
+ mutex_unlock(&vout->update_lock);
+
+ }
+ }
+
+ return 0;
+}
+
+static long
+msm_v4l2_overlay_vidioc_querybuf(struct file *file,
+ struct msm_v4l2_overlay_device *vout,
+ void *arg)
+{
+ struct v4l2_buffer *buf = arg;
+ struct msm_v4l2_overlay_buffer *mbuf;
+
+ if (buf == NULL || buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT
+ || buf->memory == V4L2_MEMORY_USERPTR
+ || buf->index >= vout->numbufs)
+ return -EINVAL;
+
+ mutex_lock(&vout->update_lock);
+
+ mbuf = (struct msm_v4l2_overlay_buffer *)vout->bufs + buf->index;
+ buf->flags = 0;
+ if (mbuf->mapped)
+ buf->flags |= V4L2_BUF_FLAG_MAPPED;
+ if (mbuf->queued)
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->length = mbuf->bufsize;
+ buf->m.offset = mbuf->offset;
+
+ mutex_unlock(&vout->update_lock);
+
+ return 0;
+}
+
+static long
+msm_v4l2_overlay_do_ioctl(struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct msm_v4l2_overlay_fh *fh = file->private_data;
+ struct msm_v4l2_overlay_device *vout = fh->vout;
+ int ret;
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ return msm_v4l2_overlay_vidioc_querycap(file, arg);
+
+ case VIDIOC_G_FBUF:
+ return msm_v4l2_overlay_vidioc_fbuf(file, vout, arg, true);
+
+ case VIDIOC_S_FBUF:
+ return msm_v4l2_overlay_vidioc_fbuf(file, vout, arg, false);
+
+ case VIDIOC_REQBUFS:
+ return msm_v4l2_overlay_vidioc_reqbufs(file, vout, arg);
+
+ case VIDIOC_QUERYBUF:
+ return msm_v4l2_overlay_vidioc_querybuf(file, vout, arg);
+
+ case VIDIOC_QBUF:
+ mutex_lock(&vout->update_lock);
+ ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, false);
+ mutex_unlock(&vout->update_lock);
+
+ return ret;
+
+ case VIDIOC_MSM_USERPTR_QBUF:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ mutex_lock(&vout->update_lock);
+ ret = msm_v4l2_overlay_vidioc_qbuf(file, fh, arg, true);
+ mutex_unlock(&vout->update_lock);
+
+ return ret;
+
+ case VIDIOC_DQBUF:
+ mutex_lock(&vout->update_lock);
+ ret = msm_v4l2_overlay_vidioc_dqbuf(file, fh, arg);
+ mutex_unlock(&vout->update_lock);
+ break;
+
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *f = arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ mutex_lock(&vout->update_lock);
+ memcpy(&vout->win, &f->fmt.win,
+ sizeof(struct v4l2_window));
+ mutex_unlock(&vout->update_lock);
+ break;
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ mutex_lock(&vout->update_lock);
+ memcpy(&vout->pix, &f->fmt.pix,
+ sizeof(struct v4l2_pix_format));
+ mutex_unlock(&vout->update_lock);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_G_FMT: {
+ struct v4l2_format *f = arg;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT: {
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ memset(pix, 0, sizeof(*pix));
+ *pix = vout->pix;
+ break;
+ }
+
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY: {
+ struct v4l2_window *win = &f->fmt.win;
+ memset(win, 0, sizeof(*win));
+ win->w = vout->win.w;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_CROPCAP: {
+ struct v4l2_cropcap *cr = arg;
+ if (cr->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = vout->crop_rect.width;
+ cr->bounds.height = vout->crop_rect.height;
+
+ cr->defrect.left = 0;
+ cr->defrect.top = 0;
+ cr->defrect.width = vout->crop_rect.width;
+ cr->defrect.height = vout->crop_rect.height;
+
+ cr->pixelaspect.numerator = 1;
+ cr->pixelaspect.denominator = 1;
+ break;
+ }
+
+ case VIDIOC_S_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ switch (crop->type) {
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+
+ mutex_lock(&vout->update_lock);
+ memcpy(&vout->crop_rect, &crop->c,
+ sizeof(struct v4l2_rect));
+ mutex_unlock(&vout->update_lock);
+
+ break;
+
+ default:
+
+ return -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_G_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ switch (crop->type) {
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ memcpy(&crop->c, &vout->crop_rect,
+ sizeof(struct v4l2_rect));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_S_CTRL: {
+ struct v4l2_control *ctrl = arg;
+ int32_t rotflag;
+
+ switch (ctrl->id) {
+
+ case V4L2_CID_ROTATE:
+ switch (ctrl->value) {
+ case 0:
+ rotflag = MDP_ROT_NOP;
+ break;
+ case 90:
+ rotflag = MDP_ROT_90;
+ break;
+ case 180:
+ rotflag = MDP_ROT_180;
+ break;
+ case 270:
+ rotflag = MDP_ROT_270;
+ break;
+ default:
+ pr_err("%s: V4L2_CID_ROTATE invalid rotation value %d.\n",
+ __func__, ctrl->value);
+ return -ERANGE;
+ }
+
+ mutex_lock(&vout->update_lock);
+ /* Clear the rotation flags */
+ vout->req.flags &= ~MDP_ROT_NOP;
+ vout->req.flags &= ~MDP_ROT_90;
+ vout->req.flags &= ~MDP_ROT_180;
+ vout->req.flags &= ~MDP_ROT_270;
+ /* Set the new rotation flag */
+ vout->req.flags |= rotflag;
+ mutex_unlock(&vout->update_lock);
+
+ break;
+
+ case V4L2_CID_HFLIP:
+ mutex_lock(&vout->update_lock);
+ /* Clear the flip flag */
+ vout->req.flags &= ~MDP_FLIP_LR;
+ if (true == ctrl->value)
+ vout->req.flags |= MDP_FLIP_LR;
+ mutex_unlock(&vout->update_lock);
+
+ break;
+
+ case V4L2_CID_VFLIP:
+ mutex_lock(&vout->update_lock);
+ /* Clear the flip flag */
+ vout->req.flags &= ~MDP_FLIP_UD;
+ if (true == ctrl->value)
+ vout->req.flags |= MDP_FLIP_UD;
+ mutex_unlock(&vout->update_lock);
+
+ break;
+
+ default:
+ pr_err("%s: VIDIOC_S_CTRL invalid control ID %d.\n",
+ __func__, ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_G_CTRL: {
+ struct v4l2_control *ctrl = arg;
+ __s32 rotation;
+
+ switch (ctrl->id) {
+
+ case V4L2_CID_ROTATE:
+ if (MDP_ROT_NOP == (vout->req.flags & MDP_ROT_NOP))
+ rotation = 0;
+ if (MDP_ROT_90 == (vout->req.flags & MDP_ROT_90))
+ rotation = 90;
+ if (MDP_ROT_180 == (vout->req.flags & MDP_ROT_180))
+ rotation = 180;
+ if (MDP_ROT_270 == (vout->req.flags & MDP_ROT_270))
+ rotation = 270;
+
+ ctrl->value = rotation;
+ break;
+
+ case V4L2_CID_HFLIP:
+ if (MDP_FLIP_LR == (vout->req.flags & MDP_FLIP_LR))
+ ctrl->value = true;
+ break;
+
+ case V4L2_CID_VFLIP:
+ if (MDP_FLIP_UD == (vout->req.flags & MDP_FLIP_UD))
+ ctrl->value = true;
+ break;
+
+ default:
+ pr_err("%s: VIDIOC_G_CTRL invalid control ID %d.\n",
+ __func__, ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_STREAMON: {
+
+ if (vout->streaming) {
+ pr_err("%s: VIDIOC_STREAMON: already streaming.\n",
+ __func__);
+ return -EBUSY;
+ }
+
+ mutex_lock(&vout->update_lock);
+ msm_v4l2_overlay_startstreaming(vout);
+ mutex_unlock(&vout->update_lock);
+
+ break;
+ }
+
+ case VIDIOC_STREAMOFF: {
+
+ if (!vout->streaming) {
+ pr_err("%s: VIDIOC_STREAMOFF: not currently streaming.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&vout->update_lock);
+ msm_v4l2_overlay_stopstreaming(vout);
+ mutex_unlock(&vout->update_lock);
+
+ break;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+
+ } /* switch */
+
+ return 0;
+}
+
+static long
+msm_v4l2_overlay_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, msm_v4l2_overlay_do_ioctl);
+}
+
+static int
+msm_v4l2_overlay_mmap(struct file *filp, struct vm_area_struct * vma)
+{
+ unsigned long start = (unsigned long)v4l2_ram_phys;
+
+ /*
+ * vm_pgoff is the offset (>>PAGE_SHIFT) that we provided
+ * during REQBUFS. off therefore should equal the offset we
+ * provided in REQBUFS, since last (PAGE_SHIFT) bits of off
+ * should be 0
+ */
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+ u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + v4l2_ram_size);
+
+ /*
+ * This is probably unnecessary now - the last PAGE_SHIFT
+ * bits of start should be 0 now, since we are page aligning
+ * v4l2_ram_phys
+ */
+ start &= PAGE_MASK;
+
+ pr_debug("v4l2 map req for phys(%p,%p) offset %u to virt (%p,%p)\n",
+ (void *)(start+off), (void *)(start+off+(vma->vm_end - vma->vm_start)),
+ (unsigned int)off, (void *)vma->vm_start, (void *)vma->vm_end);
+
+ if ((vma->vm_end - vma->vm_start + off) > len) {
+ pr_err("v4l2 map request, memory requested too big\n");
+ return -EINVAL;
+ }
+
+ start += off;
+ vma->vm_pgoff = start >> PAGE_SHIFT;
+ /* This is an IO map - tell maydump to skip this VMA */
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* Remap the frame buffer I/O range */
+ if (io_remap_pfn_range(vma, vma->vm_start, start >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int
+msm_v4l2_overlay_release(struct file *file)
+{
+ struct msm_v4l2_overlay_fh *fh = file->private_data;
+ struct msm_v4l2_overlay_device *vout = fh->vout;
+
+ if (vout->streaming)
+ msm_v4l2_overlay_stopstreaming(vout);
+
+ vout->ref_count--;
+
+ kfree(vout->bufs);
+ vout->numbufs = 0;
+ kfree(fh);
+
+ return 0;
+}
+
+static int
+msm_v4l2_overlay_open(struct file *file)
+{
+ struct msm_v4l2_overlay_device *vout = NULL;
+ struct v4l2_pix_format *pix = NULL;
+ struct msm_v4l2_overlay_fh *fh;
+
+ vout = saved_vout0;
+ vout->id = 0;
+
+ if (vout->ref_count) {
+ pr_err("%s: multiple open currently is not"
+ "supported!\n", __func__);
+ return -EBUSY;
+ }
+
+ vout->ref_count++;
+
+ /* allocate per-filehandle data */
+ fh = kmalloc(sizeof(struct msm_v4l2_overlay_fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+
+ fh->vout = vout;
+ fh->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ file->private_data = fh;
+
+ vout->streaming = 0;
+ vout->crop_rect.left = vout->crop_rect.top = 0;
+ vout->crop_rect.width = vout->screen_width;
+ vout->crop_rect.height = vout->screen_height;
+
+ pix = &vout->pix;
+ pix->width = vout->screen_width;
+ pix->height = vout->screen_height;
+ pix->pixelformat = V4L2_PIX_FMT_RGB32;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = pix->width * 4;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->priv = 0;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+
+ vout->win.w.left = 0;
+ vout->win.w.top = 0;
+ vout->win.w.width = vout->screen_width;
+ vout->win.w.height = vout->screen_height;
+
+ vout->fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY
+ | V4L2_FBUF_CAP_LOCAL_ALPHA;
+ vout->fb.flags = V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ vout->fb.base = 0;
+ memcpy(&vout->fb.fmt, pix, sizeof(struct v4l2_format));
+
+ vout->bufs = 0;
+ vout->numbufs = 0;
+
+ mutex_init(&vout->update_lock);
+
+ return 0;
+}
+
+
+static int __devinit
+msm_v4l2_overlay_probe(struct platform_device *pdev)
+{
+ char *v4l2_ram_phys_unaligned;
+ if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+ v4l2_ram_size =
+ pdev->resource[0].end - pdev->resource[0].start + 1;
+ v4l2_ram_phys_unaligned = (char *)pdev->resource[0].start;
+ v4l2_ram_phys =
+ (char *)PAGE_ALIGN((unsigned int)v4l2_ram_phys_unaligned);
+ /*
+ * We are (fwd) page aligning the start of v4l2 memory.
+ * Therefore we have that much less physical memory available
+ */
+ v4l2_ram_size -= (unsigned int)v4l2_ram_phys
+ - (unsigned int)v4l2_ram_phys_unaligned;
+
+
+ }
+ return 0;
+}
+
+static int __devexit
+msm_v4l2_overlay_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static void msm_v4l2_overlay_videodev_release(struct video_device *vfd)
+{
+ return;
+}
+
+static const struct v4l2_file_operations msm_v4l2_overlay_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_v4l2_overlay_open,
+ .release = msm_v4l2_overlay_release,
+ .mmap = msm_v4l2_overlay_mmap,
+ .ioctl = msm_v4l2_overlay_ioctl,
+};
+
+static struct video_device msm_v4l2_overlay_vid_device0 = {
+ .name = "msm_v4l2_overlay",
+ .fops = &msm_v4l2_overlay_fops,
+ .minor = -1,
+ .release = msm_v4l2_overlay_videodev_release,
+};
+
+static struct platform_driver msm_v4l2_overlay_platform_driver = {
+ .probe = msm_v4l2_overlay_probe,
+ .remove = msm_v4l2_overlay_remove,
+ .driver = {
+ .name = "msm_v4l2_overlay_pd",
+ },
+};
+
+static int __init msm_v4l2_overlay_init(void)
+{
+ int ret;
+
+
+ saved_vout0 = kzalloc(sizeof(struct msm_v4l2_overlay_device),
+ GFP_KERNEL);
+
+ if (!saved_vout0)
+ return -ENOMEM;
+
+ ret = platform_driver_register(&msm_v4l2_overlay_platform_driver);
+ if (ret < 0)
+ goto end;
+
+ /*
+ * Register the device with videodev.
+ * Videodev will make IOCTL calls on application requests
+ */
+ ret = video_register_device(&msm_v4l2_overlay_vid_device0,
+ VFL_TYPE_GRABBER, MSM_VIDEO);
+
+ if (ret < 0) {
+ pr_err("%s: V4L2 video overlay device registration failure(%d)\n",
+ __func__, ret);
+ goto end_unregister;
+ }
+
+ mutex_init(&msmfb_lock);
+
+ return 0;
+
+end_unregister:
+ platform_driver_unregister(&msm_v4l2_overlay_platform_driver);
+
+end:
+ kfree(saved_vout0);
+ return ret;
+}
+
+static void __exit msm_v4l2_overlay_exit(void)
+{
+ video_unregister_device(&msm_v4l2_overlay_vid_device0);
+ platform_driver_unregister(&msm_v4l2_overlay_platform_driver);
+ mutex_destroy(&msmfb_lock);
+ kfree(saved_vout0);
+}
+
+module_init(msm_v4l2_overlay_init);
+module_exit(msm_v4l2_overlay_exit);
+
+MODULE_DESCRIPTION("MSM V4L2 Video Overlay Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_v4l2_video.h b/drivers/media/video/msm/msm_v4l2_video.h
new file mode 100644
index 0000000..a7baa75
--- /dev/null
+++ b/drivers/media/video/msm/msm_v4l2_video.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef MSM_V4L2_VIDEO_H
+#define MSM_V4L2_VIDEO_H
+
+#include <linux/mm.h>
+#include <linux/msm_mdp.h>
+#include <linux/videodev2.h>
+
+
+struct msm_v4l2_overlay_buffer {
+ int mapped;
+ int queued;
+ int offset;
+ int bufsize;
+};
+
+struct msm_v4l2_overlay_device {
+ struct device dev;
+
+ int ref_count;
+ int id;
+
+ int screen_width;
+ int screen_height;
+ int streaming;
+
+ struct v4l2_pix_format pix;
+ struct v4l2_window win;
+ struct v4l2_rect crop_rect;
+ struct v4l2_framebuffer fb;
+ struct msm_v4l2_overlay_buffer *bufs;
+ int numbufs;
+ struct mdp_overlay req;
+ void *par;
+
+ struct mutex update_lock;
+};
+
+struct msm_v4l2_overlay_fh {
+ struct msm_v4l2_overlay_device *vout;
+ enum v4l2_buf_type type;
+};
+
+struct msm_v4l2_overlay_userptr_buffer {
+ uint base[3];
+ size_t length[3];
+};
+
+#endif
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
new file mode 100644
index 0000000..1f17ebe
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -0,0 +1,3850 @@
+/* Copyright (c) 2012 Code Aurora Forum. 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/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+
+#include "msm.h"
+#include "msm_vfe31_v4l2.h"
+
+atomic_t irq_cnt;
+
+#define BUFF_SIZE_128 128
+
+#define VFE31_AXI_OFFSET 0x0050
+#define vfe31_get_ch_ping_addr(chn) \
+ (msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe31_get_ch_pong_addr(chn) \
+ (msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe31_get_ch_addr(ping_pong, chn) \
+ (((ping_pong) & (1 << (chn))) == 0 ? \
+ vfe31_get_ch_pong_addr(chn) : vfe31_get_ch_ping_addr(chn))
+
+#define vfe31_put_ch_ping_addr(chn, addr) \
+ (msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe31_put_ch_pong_addr(chn, addr) \
+ (msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe31_put_ch_addr(ping_pong, chn, addr) \
+ (((ping_pong) & (1 << (chn))) == 0 ? \
+ vfe31_put_ch_pong_addr((chn), (addr)) : \
+ vfe31_put_ch_ping_addr((chn), (addr)))
+
+#define VFE_CLK_RATE 153600000
+#define CAMIF_CFG_RMSK 0x1fffff
+
+static struct vfe31_ctrl_type *vfe31_ctrl;
+static void *vfe_syncdata;
+static uint32_t vfe_clk_rate;
+
+struct vfe31_isr_queue_cmd {
+ struct list_head list;
+ uint32_t vfeInterruptStatus0;
+ uint32_t vfeInterruptStatus1;
+};
+
+/*TODO: Why is V32 reference in arch/arm/mach-msm/include/mach/camera.h?*/
+#define VFE_MSG_V31_START VFE_MSG_V32_START
+#define VFE_MSG_V31_CAPTURE VFE_MSG_V32_CAPTURE
+#define VFE_MSG_V31_JPEG_CAPTURE VFE_MSG_V32_JPEG_CAPTURE
+#define VFE_MSG_V31_START_RECORDING VFE_MSG_V32_START_RECORDING
+
+static struct vfe31_cmd_type vfe31_cmd[] = {
+/* 0*/ {VFE_CMD_DUMMY_0},
+ {VFE_CMD_SET_CLK},
+ {VFE_CMD_RESET},
+ {VFE_CMD_START},
+ {VFE_CMD_TEST_GEN_START},
+/* 5*/ {VFE_CMD_OPERATION_CFG, V31_OPERATION_CFG_LEN},
+ {VFE_CMD_AXI_OUT_CFG, V31_AXI_OUT_LEN, V31_AXI_OUT_OFF, 0xFF},
+ {VFE_CMD_CAMIF_CFG, V31_CAMIF_LEN, V31_CAMIF_OFF, 0xFF},
+ {VFE_CMD_AXI_INPUT_CFG},
+ {VFE_CMD_BLACK_LEVEL_CFG, V31_BLACK_LEVEL_LEN,
+ V31_BLACK_LEVEL_OFF,
+ 0xFF},
+/*10*/ {VFE_CMD_MESH_ROLL_OFF_CFG, V31_MESH_ROLL_OFF_CFG_LEN,
+ V31_MESH_ROLL_OFF_CFG_OFF, 0xFF},
+ {VFE_CMD_DEMUX_CFG, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+ {VFE_CMD_FOV_CFG, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+ {VFE_CMD_MAIN_SCALER_CFG, V31_MAIN_SCALER_LEN,
+ V31_MAIN_SCALER_OFF, 0xFF},
+ {VFE_CMD_WB_CFG, V31_WB_LEN, V31_WB_OFF, 0xFF},
+/*15*/ {VFE_CMD_COLOR_COR_CFG, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF, 0xFF},
+ {VFE_CMD_RGB_G_CFG, V31_RGB_G_LEN, V31_RGB_G_OFF, 0xFF},
+ {VFE_CMD_LA_CFG, V31_LA_LEN, V31_LA_OFF, 0xFF },
+ {VFE_CMD_CHROMA_EN_CFG, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF,
+ 0xFF},
+ {VFE_CMD_CHROMA_SUP_CFG, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF,
+ 0xFF},
+/*20*/ {VFE_CMD_MCE_CFG, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+ {VFE_CMD_SK_ENHAN_CFG, V31_SCE_LEN, V31_SCE_OFF, 0xFF},
+ {VFE_CMD_ASF_CFG, V31_ASF_LEN, V31_ASF_OFF, 0xFF},
+ {VFE_CMD_S2Y_CFG, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+ {VFE_CMD_S2CbCr_CFG, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+/*25*/ {VFE_CMD_CHROMA_SUBS_CFG, V31_CHROMA_SUBS_LEN, V31_CHROMA_SUBS_OFF,
+ 0xFF},
+ {VFE_CMD_OUT_CLAMP_CFG, V31_OUT_CLAMP_LEN, V31_OUT_CLAMP_OFF,
+ 0xFF},
+ {VFE_CMD_FRAME_SKIP_CFG, V31_FRAME_SKIP_LEN, V31_FRAME_SKIP_OFF,
+ 0xFF},
+ {VFE_CMD_DUMMY_1},
+ {VFE_CMD_DUMMY_2},
+/*30*/ {VFE_CMD_DUMMY_3},
+ {VFE_CMD_UPDATE},
+ {VFE_CMD_BL_LVL_UPDATE, V31_BLACK_LEVEL_LEN,
+ V31_BLACK_LEVEL_OFF, 0xFF},
+ {VFE_CMD_DEMUX_UPDATE, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+ {VFE_CMD_FOV_UPDATE, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+/*35*/ {VFE_CMD_MAIN_SCALER_UPDATE, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF,
+ 0xFF},
+ {VFE_CMD_WB_UPDATE, V31_WB_LEN, V31_WB_OFF, 0xFF},
+ {VFE_CMD_COLOR_COR_UPDATE, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF,
+ 0xFF},
+ {VFE_CMD_RGB_G_UPDATE, V31_RGB_G_LEN, V31_CHROMA_EN_OFF, 0xFF},
+ {VFE_CMD_LA_UPDATE, V31_LA_LEN, V31_LA_OFF, 0xFF },
+/*40*/ {VFE_CMD_CHROMA_EN_UPDATE, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF,
+ 0xFF},
+ {VFE_CMD_CHROMA_SUP_UPDATE, V31_CHROMA_SUP_LEN,
+ V31_CHROMA_SUP_OFF, 0xFF},
+ {VFE_CMD_MCE_UPDATE, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+ {VFE_CMD_SK_ENHAN_UPDATE, V31_SCE_LEN, V31_SCE_OFF, 0xFF},
+ {VFE_CMD_S2CbCr_UPDATE, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+/*45*/ {VFE_CMD_S2Y_UPDATE, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+ {VFE_CMD_ASF_UPDATE, V31_ASF_UPDATE_LEN, V31_ASF_OFF, 0xFF},
+ {VFE_CMD_FRAME_SKIP_UPDATE},
+ {VFE_CMD_CAMIF_FRAME_UPDATE},
+ {VFE_CMD_STATS_AF_UPDATE, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*50*/ {VFE_CMD_STATS_AE_UPDATE, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+ {VFE_CMD_STATS_AWB_UPDATE, V31_STATS_AWB_LEN,
+ V31_STATS_AWB_OFF},
+ {VFE_CMD_STATS_RS_UPDATE, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+ {VFE_CMD_STATS_CS_UPDATE, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+ {VFE_CMD_STATS_SKIN_UPDATE},
+/*55*/ {VFE_CMD_STATS_IHIST_UPDATE, V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+ {VFE_CMD_DUMMY_4},
+ {VFE_CMD_EPOCH1_ACK},
+ {VFE_CMD_EPOCH2_ACK},
+ {VFE_CMD_START_RECORDING},
+/*60*/ {VFE_CMD_STOP_RECORDING},
+ {VFE_CMD_DUMMY_5},
+ {VFE_CMD_DUMMY_6},
+ {VFE_CMD_CAPTURE, V31_CAPTURE_LEN, 0xFF},
+ {VFE_CMD_DUMMY_7},
+/*65*/ {VFE_CMD_STOP},
+ {VFE_CMD_GET_HW_VERSION, V31_GET_HW_VERSION_LEN,
+ V31_GET_HW_VERSION_OFF},
+ {VFE_CMD_GET_FRAME_SKIP_COUNTS},
+ {VFE_CMD_OUTPUT1_BUFFER_ENQ},
+ {VFE_CMD_OUTPUT2_BUFFER_ENQ},
+/*70*/ {VFE_CMD_OUTPUT3_BUFFER_ENQ},
+ {VFE_CMD_JPEG_OUT_BUF_ENQ},
+ {VFE_CMD_RAW_OUT_BUF_ENQ},
+ {VFE_CMD_RAW_IN_BUF_ENQ},
+ {VFE_CMD_STATS_AF_ENQ},
+/*75*/ {VFE_CMD_STATS_AE_ENQ},
+ {VFE_CMD_STATS_AWB_ENQ},
+ {VFE_CMD_STATS_RS_ENQ},
+ {VFE_CMD_STATS_CS_ENQ},
+ {VFE_CMD_STATS_SKIN_ENQ},
+/*80*/ {VFE_CMD_STATS_IHIST_ENQ},
+ {VFE_CMD_DUMMY_8},
+ {VFE_CMD_JPEG_ENC_CFG},
+ {VFE_CMD_DUMMY_9},
+ {VFE_CMD_STATS_AF_START, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*85*/ {VFE_CMD_STATS_AF_STOP},
+ {VFE_CMD_STATS_AE_START, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+ {VFE_CMD_STATS_AE_STOP},
+ {VFE_CMD_STATS_AWB_START, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF},
+ {VFE_CMD_STATS_AWB_STOP},
+/*90*/ {VFE_CMD_STATS_RS_START, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+ {VFE_CMD_STATS_RS_STOP},
+ {VFE_CMD_STATS_CS_START, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+ {VFE_CMD_STATS_CS_STOP},
+ {VFE_CMD_STATS_SKIN_START},
+/*95*/ {VFE_CMD_STATS_SKIN_STOP},
+ {VFE_CMD_STATS_IHIST_START,
+ V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+ {VFE_CMD_STATS_IHIST_STOP},
+ {VFE_CMD_DUMMY_10},
+ {VFE_CMD_SYNC_TIMER_SETTING, V31_SYNC_TIMER_LEN,
+ V31_SYNC_TIMER_OFF},
+/*100*/ {VFE_CMD_ASYNC_TIMER_SETTING, V31_ASYNC_TIMER_LEN, V31_ASYNC_TIMER_OFF},
+ {VFE_CMD_LIVESHOT},
+ {VFE_CMD_LA_SETUP},
+ {VFE_CMD_LINEARIZATION_CFG},
+ {VFE_CMD_DEMOSAICV3},
+/*105*/ {VFE_CMD_DEMOSAICV3_ABCC_CFG},
+ {VFE_CMD_DEMOSAICV3_DBCC_CFG},
+ {VFE_CMD_DEMOSAICV3_DBPC_CFG, V31_DEMOSAICV3_DBPC_LEN,
+ V31_DEMOSAICV3_DBPC_CFG_OFF},
+ {VFE_CMD_DEMOSAICV3_ABF_CFG, V31_DEMOSAICV3_ABF_LEN,
+ V31_DEMOSAICV3_ABF_OFF},
+ {VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+/*110*/ {VFE_CMD_DEMOSAICV3_DBCC_UPDATE},
+ {VFE_CMD_DEMOSAICV3_DBPC_UPDATE, V31_DEMOSAICV3_DBPC_LEN,
+ V31_DEMOSAICV3_DBPC_CFG_OFF},
+ {VFE_CMD_XBAR_CFG},
+ {VFE_CMD_MODULE_CFG, V31_MODULE_CFG_LEN, V31_MODULE_CFG_OFF},
+ {VFE_CMD_ZSL},
+/*115*/ {VFE_CMD_LINEARIZATION_UPDATE},
+ {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V31_DEMOSAICV3_ABF_LEN,
+ V31_DEMOSAICV3_ABF_OFF},
+ {VFE_CMD_CLF_CFG},
+ {VFE_CMD_CLF_LUMA_UPDATE},
+ {VFE_CMD_CLF_CHROMA_UPDATE},
+/*120*/ {VFE_CMD_PCA_ROLL_OFF_CFG},
+ {VFE_CMD_PCA_ROLL_OFF_UPDATE},
+ {VFE_CMD_GET_REG_DUMP},
+ {VFE_CMD_GET_LINEARIZATON_TABLE},
+ {VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+/*125*/ {VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+ {VFE_CMD_GET_RGB_G_TABLE},
+ {VFE_CMD_GET_LA_TABLE},
+ {VFE_CMD_DEMOSAICV3_UPDATE},
+};
+
+uint32_t vfe31_AXI_WM_CFG[] = {
+ 0x0000004C,
+ 0x00000064,
+ 0x0000007C,
+ 0x00000094,
+ 0x000000AC,
+ 0x000000C4,
+ 0x000000DC,
+};
+
+static const char * const vfe31_general_cmd[] = {
+ "DUMMY_0", /* 0 */
+ "SET_CLK",
+ "RESET",
+ "START",
+ "TEST_GEN_START",
+ "OPERATION_CFG", /* 5 */
+ "AXI_OUT_CFG",
+ "CAMIF_CFG",
+ "AXI_INPUT_CFG",
+ "BLACK_LEVEL_CFG",
+ "ROLL_OFF_CFG", /* 10 */
+ "DEMUX_CFG",
+ "FOV_CFG",
+ "MAIN_SCALER_CFG",
+ "WB_CFG",
+ "COLOR_COR_CFG", /* 15 */
+ "RGB_G_CFG",
+ "LA_CFG",
+ "CHROMA_EN_CFG",
+ "CHROMA_SUP_CFG",
+ "MCE_CFG", /* 20 */
+ "SK_ENHAN_CFG",
+ "ASF_CFG",
+ "S2Y_CFG",
+ "S2CbCr_CFG",
+ "CHROMA_SUBS_CFG", /* 25 */
+ "OUT_CLAMP_CFG",
+ "FRAME_SKIP_CFG",
+ "DUMMY_1",
+ "DUMMY_2",
+ "DUMMY_3", /* 30 */
+ "UPDATE",
+ "BL_LVL_UPDATE",
+ "DEMUX_UPDATE",
+ "FOV_UPDATE",
+ "MAIN_SCALER_UPDATE", /* 35 */
+ "WB_UPDATE",
+ "COLOR_COR_UPDATE",
+ "RGB_G_UPDATE",
+ "LA_UPDATE",
+ "CHROMA_EN_UPDATE", /* 40 */
+ "CHROMA_SUP_UPDATE",
+ "MCE_UPDATE",
+ "SK_ENHAN_UPDATE",
+ "S2CbCr_UPDATE",
+ "S2Y_UPDATE", /* 45 */
+ "ASF_UPDATE",
+ "FRAME_SKIP_UPDATE",
+ "CAMIF_FRAME_UPDATE",
+ "STATS_AF_UPDATE",
+ "STATS_AE_UPDATE", /* 50 */
+ "STATS_AWB_UPDATE",
+ "STATS_RS_UPDATE",
+ "STATS_CS_UPDATE",
+ "STATS_SKIN_UPDATE",
+ "STATS_IHIST_UPDATE", /* 55 */
+ "DUMMY_4",
+ "EPOCH1_ACK",
+ "EPOCH2_ACK",
+ "START_RECORDING",
+ "STOP_RECORDING", /* 60 */
+ "DUMMY_5",
+ "DUMMY_6",
+ "CAPTURE",
+ "DUMMY_7",
+ "STOP", /* 65 */
+ "GET_HW_VERSION",
+ "GET_FRAME_SKIP_COUNTS",
+ "OUTPUT1_BUFFER_ENQ",
+ "OUTPUT2_BUFFER_ENQ",
+ "OUTPUT3_BUFFER_ENQ", /* 70 */
+ "JPEG_OUT_BUF_ENQ",
+ "RAW_OUT_BUF_ENQ",
+ "RAW_IN_BUF_ENQ",
+ "STATS_AF_ENQ",
+ "STATS_AE_ENQ", /* 75 */
+ "STATS_AWB_ENQ",
+ "STATS_RS_ENQ",
+ "STATS_CS_ENQ",
+ "STATS_SKIN_ENQ",
+ "STATS_IHIST_ENQ", /* 80 */
+ "DUMMY_8",
+ "JPEG_ENC_CFG",
+ "DUMMY_9",
+ "STATS_AF_START",
+ "STATS_AF_STOP", /* 85 */
+ "STATS_AE_START",
+ "STATS_AE_STOP",
+ "STATS_AWB_START",
+ "STATS_AWB_STOP",
+ "STATS_RS_START", /* 90 */
+ "STATS_RS_STOP",
+ "STATS_CS_START",
+ "STATS_CS_STOP",
+ "STATS_SKIN_START",
+ "STATS_SKIN_STOP", /* 95 */
+ "STATS_IHIST_START",
+ "STATS_IHIST_STOP",
+ "DUMMY_10",
+ "SYNC_TIMER_SETTING",
+ "ASYNC_TIMER_SETTING", /* 100 */
+ "LIVESHOT",
+ "LA_SETUP",
+ "LINEARIZATION_CFG",
+ "DEMOSAICV3",
+ "DEMOSAICV3_ABCC_CFG", /* 105 */
+ "DEMOSAICV3_DBCC_CFG",
+ "DEMOSAICV3_DBPC_CFG",
+ "DEMOSAICV3_ABF_CFG",
+ "DEMOSAICV3_ABCC_UPDATE",
+ "DEMOSAICV3_DBCC_UPDATE", /* 110 */
+ "DEMOSAICV3_DBPC_UPDATE",
+ "XBAR_CFG",
+ "EZTUNE_CFG",
+ "V31_ZSL",
+ "LINEARIZATION_UPDATE", /*115*/
+ "DEMOSAICV3_ABF_UPDATE",
+ "CLF_CFG",
+ "CLF_LUMA_UPDATE",
+ "CLF_CHROMA_UPDATE",
+ "PCA_ROLL_OFF_CFG", /*120*/
+ "PCA_ROLL_OFF_UPDATE",
+ "GET_REG_DUMP",
+ "GET_LINEARIZATON_TABLE",
+ "GET_MESH_ROLLOFF_TABLE",
+ "GET_PCA_ROLLOFF_TABLE", /*125*/
+ "GET_RGB_G_TABLE",
+ "GET_LA_TABLE",
+ "DEMOSAICV3_UPDATE",
+};
+
+static void vfe31_stop(void)
+{
+ unsigned long flags;
+
+ atomic_set(&vfe31_ctrl->vstate, 0);
+
+ /* for reset hw modules, and send msg when reset_irq comes.*/
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ vfe31_ctrl->stop_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+ /* disable all interrupts. */
+ /* in either continuous or snapshot mode, stop command can be issued
+ * at any time. stop camif immediately. */
+ msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
+ vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+ /* disable all interrupts. */
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_io_w(VFE_CLEAR_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_io_w(VFE_CLEAR_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1,
+ vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+ /* now enable only halt_irq & reset_irq */
+ msm_io_w(0xf0000000, /* this is for async timer. */
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* then apply axi halt command. */
+ msm_io_w_mb(AXI_HALT,
+ vfe31_ctrl->vfebase + VFE_AXI_CMD);
+
+ msm_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+ vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static void vfe31_subdev_notify(int id, int path)
+{
+ struct msm_vfe_resp *rp;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->sd_notify_lock, flags);
+ rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
+ if (!rp) {
+ CDBG("rp: cannot allocate buffer\n");
+ spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
+ return;
+ }
+ CDBG("vfe31_subdev_notify : msgId = %d\n", id);
+ rp->evt_msg.type = MSM_CAMERA_MSG;
+ rp->evt_msg.msg_id = path;
+ rp->type = id;
+ v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+ spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
+}
+
+static int vfe31_config_axi(int mode, uint32_t *ao)
+{
+ uint32_t *ch_info;
+ uint32_t *axi_cfg = ao+V31_AXI_RESERVED;
+ /* Update the corresponding write masters for each output*/
+ ch_info = axi_cfg + V31_AXI_CFG_LEN;
+ vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+
+ switch (mode) {
+ case OUTPUT_PRIM:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY;
+ break;
+ case OUTPUT_PRIM_ALL_CHNLS:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ break;
+ case OUTPUT_PRIM|OUTPUT_SEC:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_SECONDARY;
+ break;
+ case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ break;
+ case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_SECONDARY;
+ break;
+ default:
+ pr_err("%s Invalid AXI mode %d ", __func__, mode);
+ return -EINVAL;
+ }
+
+ msm_io_memcpy(vfe31_ctrl->vfebase +
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length - V31_AXI_CH_INF_LEN -
+ V31_AXI_RESERVED);
+ return 0;
+}
+
+static void vfe31_reset_internal_variables(void)
+{
+ unsigned long flags;
+ vfe31_ctrl->vfeImaskCompositePacked = 0;
+ /* state control variables */
+ vfe31_ctrl->start_ack_pending = FALSE;
+ atomic_set(&irq_cnt, 0);
+
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ vfe31_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+ vfe31_ctrl->reset_ack_pending = FALSE;
+
+ spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+ vfe31_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+
+ vfe31_ctrl->recording_state = VFE_STATE_IDLE;
+ vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ atomic_set(&vfe31_ctrl->vstate, 0);
+
+ /* 0 for continuous mode, 1 for snapshot mode */
+ vfe31_ctrl->operation_mode = 0;
+ vfe31_ctrl->outpath.output_mode = 0;
+ vfe31_ctrl->vfe_capture_count = 0;
+
+ /* this is unsigned 32 bit integer. */
+ vfe31_ctrl->vfeFrameId = 0;
+ /* Stats control variables. */
+ memset(&(vfe31_ctrl->afStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->awbStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->aecStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->ihistStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->rsStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->csStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ vfe31_ctrl->frame_skip_cnt = 31;
+ vfe31_ctrl->frame_skip_pattern = 0xffffffff;
+ vfe31_ctrl->snapshot_frame_cnt = 0;
+}
+
+static void vfe31_reset(void)
+{
+ vfe31_reset_internal_variables();
+ /* disable all interrupts. vfeImaskLocal is also reset to 0
+ * to begin with. */
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+ /* enable reset_ack interrupt. */
+ msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+ * is done, hardware interrupt will be generated. VFE ist processes
+ * the interrupt to complete the function call. Note that the reset
+ * function is synchronous. */
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(VFE_RESET_UPON_RESET_CMD,
+ vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe31_operation_config(uint32_t *cmd)
+{
+ uint32_t *p = cmd;
+
+ vfe31_ctrl->operation_mode = *p;
+ vfe31_ctrl->stats_comp = *(++p);
+ vfe31_ctrl->hfr_mode = *(++p);
+
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CFG);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_REALIGN_BUF);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CHROMA_UP);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_STATS_CFG);
+ return 0;
+}
+
+static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static void msm_io_dump2(void __iomem *addr, int size)
+{
+ char line_str[BUFF_SIZE_128], *p_str;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ CDBG("%s: %p %d\n", __func__, addr, size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ CDBG("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ CDBG("%s\n", line_str);
+}
+
+static void vfe31_start_common(void)
+{
+ uint32_t irq_mask = 0x00E00021;
+ vfe31_ctrl->start_ack_pending = TRUE;
+ CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
+ vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode);
+ if (vfe31_ctrl->stats_comp)
+ irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
+ else
+ irq_mask |= 0x000FE000;
+
+ msm_io_w(irq_mask, vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+ msm_io_dump2(vfe31_ctrl->vfebase, vfe31_ctrl->register_total*4);
+ atomic_set(&vfe31_ctrl->vstate, 1);
+}
+
+static int vfe31_start_recording(void)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+ vfe31_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ return 0;
+}
+
+static int vfe31_stop_recording(void)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ vfe31_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ return 0;
+}
+
+static void vfe31_start_liveshot(void){
+ struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+ if (p_sync)
+ p_sync->liveshot_enabled = true;
+
+ /* Hardcode 1 live snapshot for now. */
+ vfe31_ctrl->outpath.out0.capture_cnt = 1;
+ vfe31_ctrl->vfe_capture_count = vfe31_ctrl->outpath.out0.capture_cnt;
+
+ vfe31_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int vfe31_zsl(void)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ uint32_t irq_comp_mask = 0;
+ /* capture command is valid for both idle and active state. */
+ irq_comp_mask =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ CDBG("%s:op mode %d O/P Mode %d\n", __func__,
+ vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode);
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe31_ctrl->outpath.out0.ch1)));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe31_ctrl->outpath.out0.ch1)) |
+ (0x1 << (vfe31_ctrl->outpath.out0.ch2)));
+ }
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8)));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8)) |
+ (0x1 << (vfe31_ctrl->outpath.out1.ch2 + 8)));
+ }
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+ }
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
+ }
+
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ vfe31_start_common();
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_ZSL);
+
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x18C);
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x188);
+ return 0;
+}
+static int vfe31_capture_raw(uint32_t num_frames_capture)
+{
+ uint32_t irq_comp_mask = 0;
+ struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+
+ vfe31_ctrl->outpath.out0.capture_cnt = num_frames_capture;
+ vfe31_ctrl->vfe_capture_count = num_frames_capture;
+
+ irq_comp_mask =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out0.ch0));
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ }
+
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camio_bus_scale_cfg(
+ p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+ vfe31_start_common();
+ return 0;
+}
+
+static int vfe31_capture(uint32_t num_frames_capture)
+{
+ uint32_t irq_comp_mask = 0;
+ struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+ if (p_sync) {
+ p_sync->snap_count = num_frames_capture;
+ p_sync->thumb_count = num_frames_capture;
+ }
+ /* capture command is valid for both idle and active state. */
+ vfe31_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+ if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) {
+ vfe31_ctrl->outpath.out0.capture_cnt =
+ num_frames_capture;
+ }
+
+ vfe31_ctrl->vfe_capture_count = num_frames_capture;
+ irq_comp_mask = msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1);
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |=
+ (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8));
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ }
+ }
+
+ vfe31_ctrl->vfe_capture_count = num_frames_capture;
+
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camio_bus_scale_cfg(
+ p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+
+ vfe31_start_common();
+ /* for debug */
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x18C);
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x188);
+ return 0;
+}
+
+static int vfe31_start(void)
+{
+ uint32_t irq_comp_mask = 0;
+ struct msm_sync *sync = vfe_syncdata;
+
+ irq_comp_mask =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch2);
+ }
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch2 + 8));
+ }
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ switch (vfe31_ctrl->operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+ }
+ break;
+ default:
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
+ }
+ break;
+ }
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ vfe31_start_common();
+ return 0;
+}
+
+static void vfe31_update(void)
+{
+ unsigned long flags;
+
+ if (vfe31_ctrl->update_la) {
+ if (!msm_io_r(vfe31_ctrl->vfebase + V31_LA_OFF))
+ msm_io_w(1, vfe31_ctrl->vfebase + V31_LA_OFF);
+ else
+ msm_io_w(0, vfe31_ctrl->vfebase + V31_LA_OFF);
+ vfe31_ctrl->update_la = false;
+ }
+
+ if (vfe31_ctrl->update_gamma) {
+ if (!msm_io_r(vfe31_ctrl->vfebase + V31_RGB_G_OFF))
+ msm_io_w(7, vfe31_ctrl->vfebase+V31_RGB_G_OFF);
+ else
+ msm_io_w(0, vfe31_ctrl->vfebase+V31_RGB_G_OFF);
+ vfe31_ctrl->update_gamma = false;
+ }
+
+ spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+ vfe31_ctrl->update_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ return;
+}
+
+static void vfe31_sync_timer_stop(void)
+{
+ uint32_t value = 0;
+ vfe31_ctrl->sync_timer_state = 0;
+ if (vfe31_ctrl->sync_timer_number == 0)
+ value = 0x10000;
+ else if (vfe31_ctrl->sync_timer_number == 1)
+ value = 0x20000;
+ else if (vfe31_ctrl->sync_timer_number == 2)
+ value = 0x40000;
+
+ /* Timer Stop */
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF);
+}
+
+static void vfe31_sync_timer_start(const uint32_t *tbl)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = 1;
+ uint32_t val;
+
+ vfe31_ctrl->sync_timer_state = *tbl++;
+ vfe31_ctrl->sync_timer_repeat_count = *tbl++;
+ vfe31_ctrl->sync_timer_number = *tbl++;
+ CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n",
+ __func__, vfe31_ctrl->sync_timer_state,
+ vfe31_ctrl->sync_timer_repeat_count,
+ vfe31_ctrl->sync_timer_number);
+
+ if (vfe31_ctrl->sync_timer_state) { /* Start Timer */
+ value = value << vfe31_ctrl->sync_timer_number;
+ } else { /* Stop Timer */
+ CDBG("Failed to Start timer\n");
+ return;
+ }
+
+ /* Timer Start */
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF);
+ /* Sync Timer Line Start */
+ value = *tbl++;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+ 4 + ((vfe31_ctrl->sync_timer_number) * 12));
+ /* Sync Timer Pixel Start */
+ value = *tbl++;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+ 8 + ((vfe31_ctrl->sync_timer_number) * 12));
+ /* Sync Timer Pixel Duration */
+ value = *tbl++;
+ val = vfe_clk_rate / 10000;
+ val = 10000000 / val;
+ val = value * 10000 / val;
+ CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
+ msm_io_w(val, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+ 12 + ((vfe31_ctrl->sync_timer_number) * 12));
+ /* Timer0 Active High/LOW */
+ value = *tbl++;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_POLARITY_OFF);
+ /* Selects sync timer 0 output to drive onto timer1 port */
+ value = 0;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_TIMER_SELECT_OFF);
+}
+
+static void vfe31_program_dmi_cfg(enum VFE31_DMI_RAM_SEL bankSel)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = VFE_DMI_CFG_DEFAULT;
+ value += (uint32_t)bankSel;
+ CDBG("%s: banksel = %d\n", __func__, bankSel);
+
+ msm_io_w(value, vfe31_ctrl->vfebase + VFE_DMI_CFG);
+ /* by default, always starts with offset 0.*/
+ msm_io_w(0, vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+}
+static void vfe31_write_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl)
+{
+ int i;
+ uint32_t value, value1, value2;
+ vfe31_program_dmi_cfg(channel_sel);
+ for (i = 0 ; i < (VFE31_GAMMA_NUM_ENTRIES/2) ; i++) {
+ value = *tbl++;
+ value1 = value & 0x0000FFFF;
+ value2 = (value & 0xFFFF0000)>>16;
+ msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe31_read_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+ uint32_t *tbl)
+{
+ int i;
+ vfe31_program_dmi_cfg(channel_sel);
+ CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel);
+ for (i = 0 ; i < VFE31_GAMMA_NUM_ENTRIES ; i++) {
+ *tbl = msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *tbl);
+ tbl++;
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe31_write_la_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl)
+{
+ uint32_t i;
+ uint32_t value, value1, value2;
+
+ vfe31_program_dmi_cfg(channel_sel);
+ for (i = 0 ; i < (VFE31_LA_TABLE_LENGTH/2) ; i++) {
+ value = *tbl++;
+ value1 = value & 0x0000FFFF;
+ value2 = (value & 0xFFFF0000)>>16;
+ msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static struct vfe31_output_ch *vfe31_get_ch(int path)
+{
+ struct vfe31_output_ch *ch = NULL;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ ch = &vfe31_ctrl->outpath.out0;
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ ch = &vfe31_ctrl->outpath.out1;
+ else
+ pr_err("%s: Invalid path %d\n", __func__, path);
+
+ BUG_ON(ch == NULL);
+ return ch;
+}
+static struct msm_free_buf *vfe31_check_free_buffer(int id, int path)
+{
+ struct vfe31_output_ch *outch = NULL;
+ struct msm_free_buf *b = NULL;
+ vfe31_subdev_notify(id, path);
+ outch = vfe31_get_ch(path);
+ if (outch->free_buf.ch_paddr[0])
+ b = &outch->free_buf;
+ return b;
+}
+static int vfe31_configure_pingpong_buffers(int id, int path)
+{
+ struct vfe31_output_ch *outch = NULL;
+ int rc = 0;
+ vfe31_subdev_notify(id, path);
+ outch = vfe31_get_ch(path);
+ if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
+ /* Configure Preview Ping Pong */
+ CDBG("%s Configure ping/pong address for %d",
+ __func__, path);
+ vfe31_put_ch_ping_addr(outch->ch0,
+ outch->ping.ch_paddr[0]);
+ vfe31_put_ch_pong_addr(outch->ch0,
+ outch->pong.ch_paddr[0]);
+
+ if (vfe31_ctrl->operation_mode !=
+ VFE_OUTPUTS_RAW) {
+ vfe31_put_ch_ping_addr(outch->ch1,
+ outch->ping.ch_paddr[1]);
+ vfe31_put_ch_pong_addr(outch->ch1,
+ outch->pong.ch_paddr[1]);
+ }
+
+ if (outch->ping.num_planes > 2)
+ vfe31_put_ch_ping_addr(outch->ch2,
+ outch->ping.ch_paddr[2]);
+ if (outch->pong.num_planes > 2)
+ vfe31_put_ch_pong_addr(outch->ch2,
+ outch->pong.ch_paddr[2]);
+
+ /* avoid stale info */
+ memset(&outch->ping, 0, sizeof(struct msm_free_buf));
+ memset(&outch->pong, 0, sizeof(struct msm_free_buf));
+ } else {
+ pr_err("%s ping/pong addr is null!!", __func__);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static void vfe31_send_isp_msg(struct vfe31_ctrl_type *vctrl,
+ uint32_t isp_msg_id)
+{
+ struct isp_msg_event isp_msg_evt;
+
+ isp_msg_evt.msg_id = isp_msg_id;
+ isp_msg_evt.sof_count = vfe31_ctrl->vfeFrameId;
+ v4l2_subdev_notify(&vctrl->subdev,
+ NOTIFY_ISP_MSG_EVT, (void *)&isp_msg_evt);
+}
+
+static int vfe31_proc_general(struct msm_isp_cmd *cmd)
+{
+ int i , rc = 0;
+ uint32_t old_val = 0 , new_val = 0;
+ uint32_t *cmdp = NULL;
+ uint32_t *cmdp_local = NULL;
+ uint32_t snapshot_cnt = 0;
+ uint32_t temp1 = 0, temp2 = 0;
+
+ CDBG("vfe31_proc_general: cmdID = %s, length = %d\n",
+ vfe31_general_cmd[cmd->id], cmd->length);
+ switch (cmd->id) {
+ case VFE_CMD_RESET:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ vfe31_reset();
+ break;
+ case VFE_CMD_START:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ if ((vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+ (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW))
+ /* Configure primary channel */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START, VFE_MSG_OUTPUT_PRIMARY);
+ else
+ /* Configure secondary channel */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START, VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_start();
+ break;
+ case VFE_CMD_UPDATE:
+ vfe31_update();
+ break;
+ case VFE_CMD_CAPTURE_RAW:
+ pr_info("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+ if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for snapshot", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_capture_raw(snapshot_cnt);
+ break;
+ case VFE_CMD_CAPTURE:
+ if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) {
+ if (snapshot_cnt != 1) {
+ pr_err("only support 1 inline snapshot\n");
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ /* Configure primary channel for JPEG */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_JPEG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ } else {
+ /* Configure primary channel */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ }
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for primary output", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ /* Configure secondary channel */
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for secondary output", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_capture(snapshot_cnt);
+ break;
+ case VFE_CMD_START_RECORDING:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START_RECORDING,
+ VFE_MSG_OUTPUT_SECONDARY);
+ else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START_RECORDING,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for video", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_start_recording();
+ break;
+ case VFE_CMD_STOP_RECORDING:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ rc = vfe31_stop_recording();
+ break;
+ case VFE_CMD_OPERATION_CFG:
+ if (cmd->length != V31_OPERATION_CFG_LEN) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(V31_OPERATION_CFG_LEN, GFP_ATOMIC);
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ V31_OPERATION_CFG_LEN)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe31_operation_config(cmdp);
+ break;
+
+ case VFE_CMD_STATS_AE_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AE_BG_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+ case VFE_CMD_STATS_AF_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AF_BF_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+ case VFE_CMD_STATS_AWB_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AWB_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_STATS_IHIST_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= IHIST_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_STATS_RS_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_STATS_CS_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_MCE_UPDATE:
+ case VFE_CMD_MCE_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ the 2nd register has the mce_enable bit */
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 4);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+ old_val &= MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 4,
+ &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 8,
+ &new_val, 4);
+ cmdp_local += 1;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, (vfe31_cmd[cmd->id].length));
+ break;
+ case VFE_CMD_CHROMA_SUP_UPDATE:
+ case VFE_CMD_CHROMA_SUP_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF,
+ cmdp_local, 4);
+
+ cmdp_local += 1;
+ new_val = *cmdp_local;
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ * the 2nd register has the mce_enable bit
+ */
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 4);
+ old_val &= ~MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 4,
+ &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= ~MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 8,
+ &new_val, 4);
+ break;
+
+ case VFE_CMD_MESH_ROLL_OFF_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value) , cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, 16);
+ cmdp_local += 4;
+ vfe31_program_dmi_cfg(ROLLOFF_RAM);
+ /* for loop for extrcting init table. */
+ for (i = 0; i < (V31_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) {
+ msm_io_w(*cmdp_local ,
+ vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ cmdp_local++;
+ }
+ CDBG("done writing init table\n");
+ /* by default, always starts with offset 0. */
+ msm_io_w(V31_MESH_ROLL_OFF_DELTA_TABLE_OFFSET,
+ vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+ /* for loop for extracting delta table. */
+ for (i = 0; i < (V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) {
+ msm_io_w(*cmdp_local,
+ vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ cmdp_local++;
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+ break;
+
+ case VFE_CMD_GET_MESH_ROLLOFF_TABLE:
+ temp1 = sizeof(uint32_t) * ((V31_MESH_ROLL_OFF_INIT_TABLE_SIZE *
+ 2) + (V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2));
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ vfe31_program_dmi_cfg(ROLLOFF_RAM);
+ CDBG("%s: Mesh Rolloff init Table\n", __func__);
+ for (i = 0; i < (V31_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) {
+ *cmdp_local =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *cmdp_local);
+ cmdp_local++;
+ }
+ msm_io_w(V31_MESH_ROLL_OFF_DELTA_TABLE_OFFSET,
+ vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+ CDBG("%s: Mesh Rolloff Delta Table\n", __func__);
+ for (i = 0; i < (V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) {
+ *cmdp_local =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *cmdp_local);
+ cmdp_local++;
+ }
+ CDBG("done reading delta table\n");
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_LA_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, (vfe31_cmd[cmd->id].length));
+
+ cmdp_local += 1;
+ vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, cmdp_local);
+ break;
+
+ case VFE_CMD_LA_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ cmdp_local = cmdp + 1;
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_LA_OFF);
+ if (old_val != 0x0)
+ vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ cmdp_local);
+ else
+ vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+ cmdp_local);
+ vfe31_ctrl->update_la = true;
+ break;
+
+ case VFE_CMD_GET_LA_TABLE:
+ temp1 = sizeof(uint32_t) * VFE31_LA_TABLE_LENGTH / 2;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ if (msm_io_r(vfe31_ctrl->vfebase + V31_LA_OFF))
+ vfe31_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1);
+ else
+ vfe31_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0);
+ for (i = 0 ; i < (VFE31_LA_TABLE_LENGTH / 2) ; i++) {
+ *cmdp_local =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ *cmdp_local |= (msm_io_r(vfe31_ctrl->vfebase +
+ VFE_DMI_DATA_LO)) << 16;
+ cmdp_local++;
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_SK_ENHAN_CFG:
+ case VFE_CMD_SK_ENHAN_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_SCE_OFF,
+ cmdp, V31_SCE_LEN);
+ break;
+
+ case VFE_CMD_LIVESHOT:
+ /* Configure primary channel */
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for primary output", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ vfe31_start_liveshot();
+ break;
+
+ case VFE_CMD_DEMOSAICV3:
+ if (cmd->length != V31_DEMOSAICV3_LEN) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= DEMOSAIC_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, V31_DEMOSAICV3_LEN);
+ break;
+
+ case VFE_CMD_DEMOSAICV3_UPDATE:
+ if (cmd->length !=
+ V31_DEMOSAICV3_LEN * V31_DEMOSAICV3_UP_REG_CNT) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= DEMOSAIC_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, V31_DEMOSAICV3_LEN);
+
+ break;
+
+ case VFE_CMD_DEMOSAICV3_ABCC_CFG:
+ rc = -EFAULT;
+ break;
+
+ case VFE_CMD_DEMOSAICV3_ABF_UPDATE:/* 116 ABF update */
+ case VFE_CMD_DEMOSAICV3_ABF_CFG: /* 108 ABF config */
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= ABF_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, 4);
+
+ cmdp_local += 1;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_DEMOSAICV3_DBCC_CFG:
+ case VFE_CMD_DEMOSAICV3_DBCC_UPDATE:
+ return -EINVAL;
+
+ case VFE_CMD_DEMOSAICV3_DBPC_CFG:
+ case VFE_CMD_DEMOSAICV3_DBPC_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= BPC_MASK;
+
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, V31_DEMOSAICV3_LEN);
+ cmdp_local += 1;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_DBPC_CFG_OFF,
+ cmdp_local, V31_DEMOSAICV3_DBPC_LEN);
+ break;
+
+ case VFE_CMD_RGB_G_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_RGB_G_OFF,
+ cmdp, 4);
+ cmdp += 1;
+
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+ cmdp -= 1;
+ break;
+
+ case VFE_CMD_RGB_G_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_RGB_G_OFF);
+ cmdp += 1;
+ if (old_val != 0x0) {
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+ } else {
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, cmdp);
+ }
+ vfe31_ctrl->update_gamma = TRUE;
+ cmdp -= 1;
+ break;
+
+ case VFE_CMD_GET_RGB_G_TABLE:
+ temp1 = sizeof(uint32_t) * VFE31_GAMMA_NUM_ENTRIES * 3;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_RGB_G_OFF);
+ temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 :
+ RGBLUT_RAM_CH0_BANK0;
+ for (i = 0; i < 3; i++) {
+ vfe31_read_gamma_cfg(temp2,
+ cmdp_local + (VFE31_GAMMA_NUM_ENTRIES * i));
+ temp2 += 2;
+ }
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+
+ case VFE_CMD_STATS_AWB_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AWB_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+ case VFE_CMD_STATS_AE_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AE_BG_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+ case VFE_CMD_STATS_AF_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AF_BF_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STATS_IHIST_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~IHIST_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STATS_RS_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~RS_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STATS_CS_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~CS_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STOP:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ vfe31_stop();
+ break;
+
+ case VFE_CMD_SYNC_TIMER_SETTING:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ vfe31_sync_timer_start(cmdp);
+ break;
+
+ case VFE_CMD_MODULE_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ *cmdp &= ~STATS_ENABLE_MASK;
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= STATS_ENABLE_MASK;
+ *cmdp |= old_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_ZSL:
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_START,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0)
+ goto proc_general_done;
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_START,
+ VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0)
+ goto proc_general_done;
+
+ rc = vfe31_zsl();
+ break;
+
+ case VFE_CMD_ASF_CFG:
+ case VFE_CMD_ASF_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ cmdp_local = cmdp + V31_ASF_LEN/4;
+ break;
+
+ case VFE_CMD_GET_HW_VERSION:
+ if (cmd->length != V31_GET_HW_VERSION_LEN) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(V31_GET_HW_VERSION_LEN, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ *cmdp = msm_io_r(vfe31_ctrl->vfebase+V31_GET_HW_VERSION_OFF);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ V31_GET_HW_VERSION_LEN)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_GET_REG_DUMP:
+ temp1 = sizeof(uint32_t) * vfe31_ctrl->register_total;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(temp1, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ msm_io_dump(vfe31_ctrl->vfebase, vfe31_ctrl->register_total*4);
+ CDBG("%s: %p %p %d\n", __func__, (void *)cmdp,
+ vfe31_ctrl->vfebase, temp1);
+ memcpy_fromio((void *)cmdp, vfe31_ctrl->vfebase, temp1);
+ if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_FRAME_SKIP_CFG:
+ if (cmd->length != vfe31_cmd[cmd->id].length)
+ return -EINVAL;
+
+ cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ vfe31_ctrl->frame_skip_cnt = ((uint32_t)
+ *cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
+ vfe31_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
+ break;
+ default:
+ if (cmd->length != vfe31_cmd[cmd->id].length)
+ return -EINVAL;
+
+ cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ }
+
+proc_general_done:
+ kfree(cmdp);
+
+ return rc;
+}
+
+static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->af_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->afStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->awb_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->awbStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->aec_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->aecStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->ihist_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->rs_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->rsStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->cs_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->csStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
+{
+ uint32_t *temp;
+ memset(out, 0, sizeof(struct vfe31_irq_status));
+ temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_0);
+ out->vfeIrqStatus0 = msm_io_r(temp);
+
+ temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_1);
+ out->vfeIrqStatus1 = msm_io_r(temp);
+
+ temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS);
+ out->camifStatus = msm_io_r(temp);
+ CDBG("camifStatus = 0x%x\n", out->camifStatus);
+
+ /* clear the pending interrupt of the same kind.*/
+ msm_io_w(out->vfeIrqStatus0, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_io_w(out->vfeIrqStatus1, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+}
+
+static void vfe31_process_reg_update_irq(void)
+{
+ unsigned long flags;
+
+ if (vfe31_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ }
+ vfe31_ctrl->recording_state = VFE_STATE_STARTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ CDBG("start video triggered .\n");
+ } else if (vfe31_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ }
+ CDBG("stop video triggered .\n");
+ }
+
+ if (vfe31_ctrl->start_ack_pending == TRUE) {
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_START_ACK);
+ vfe31_ctrl->start_ack_pending = FALSE;
+ } else {
+ if (vfe31_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ vfe31_ctrl->recording_state = VFE_STATE_STOPPED;
+ /* request a reg update and send STOP_REC_ACK
+ * when we process the next reg update irq.
+ */
+ msm_io_w_mb(1,
+ vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe31_ctrl->recording_state ==
+ VFE_STATE_STOPPED) {
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_STOP_REC_ACK);
+ vfe31_ctrl->recording_state = VFE_STATE_IDLE;
+ }
+ spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+ if (vfe31_ctrl->update_ack_pending == TRUE) {
+ vfe31_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe31_ctrl->update_ack_lock, flags);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_UPDATE_ACK);
+ } else {
+ spin_unlock_irqrestore(
+ &vfe31_ctrl->update_ack_lock, flags);
+ }
+ }
+
+ if (vfe31_ctrl->liveshot_state == VFE_STATE_START_REQUESTED) {
+ pr_info("%s enabling liveshot output\n", __func__);
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ vfe31_ctrl->liveshot_state = VFE_STATE_STARTED;
+ }
+ }
+
+ if (vfe31_ctrl->liveshot_state == VFE_STATE_STARTED) {
+ vfe31_ctrl->vfe_capture_count--;
+ if (!vfe31_ctrl->vfe_capture_count)
+ vfe31_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe31_ctrl->liveshot_state == VFE_STATE_STOP_REQUESTED) {
+ CDBG("%s: disabling liveshot output\n", __func__);
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ vfe31_ctrl->liveshot_state = VFE_STATE_STOPPED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ }
+ } else if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED) {
+ vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
+ }
+
+ if ((vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) ||
+ (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB) ||
+ (vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) ||
+ (vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB)) {
+ /* in snapshot mode */
+ /* later we need to add check for live snapshot mode. */
+ if (vfe31_ctrl->frame_skip_pattern & (0x1 <<
+ (vfe31_ctrl->snapshot_frame_cnt %
+ vfe31_ctrl->frame_skip_cnt))) {
+ vfe31_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (vfe31_ctrl->vfe_capture_count == 0) {
+ /* stop the bus output:write master enable = 0*/
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out0.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out0.ch1]);
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out1.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out1.ch1]);
+ }
+ msm_io_w_mb
+ (CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ vfe31_ctrl->snapshot_frame_cnt = -1;
+ vfe31_ctrl->frame_skip_cnt = 31;
+ vfe31_ctrl->frame_skip_pattern = 0xffffffff;
+ } /*if snapshot count is 0*/
+ } /*if frame is not being dropped*/
+ vfe31_ctrl->snapshot_frame_cnt++;
+ /* then do reg_update. */
+ msm_io_w(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } /* if snapshot mode. */
+}
+
+static void vfe31_set_default_reg_values(void)
+{
+ msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+ msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+ /* What value should we program CGC_OVERRIDE to? */
+ msm_io_w(0xFFFFF, vfe31_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+ /* default frame drop period and pattern */
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+ msm_io_w(0xFFFFFFFF, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+ msm_io_w(0xFFFFFFFF,
+ vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+ msm_io_w(0xFFFFFFFF,
+ vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+ msm_io_w(0xFFFFFFFF,
+ vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+ msm_io_w(0, vfe31_ctrl->vfebase + VFE_CLAMP_MIN);
+ msm_io_w(0xFFFFFF, vfe31_ctrl->vfebase + VFE_CLAMP_MAX);
+
+ /* stats UB config */
+ msm_io_w(0x3980007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+ msm_io_w(0x3A00007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+ msm_io_w(0x3A8000F, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+ msm_io_w(0x3B80007, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+ msm_io_w(0x3C0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+ msm_io_w(0x3E0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+}
+
+static void vfe31_process_reset_irq(void)
+{
+ unsigned long flags;
+
+ atomic_set(&vfe31_ctrl->vstate, 0);
+
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ if (vfe31_ctrl->stop_ack_pending) {
+ vfe31_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_STOP_ACK);
+ } else {
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+ /* this is from reset command. */
+ vfe31_set_default_reg_values();
+
+ /* reload all write masters. (frame & line)*/
+ msm_io_w(0x7FFF, vfe31_ctrl->vfebase + VFE_BUS_CMD);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_RESET_ACK);
+ }
+}
+
+static void vfe31_process_camif_sof_irq(void)
+{
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW) {
+ if (vfe31_ctrl->start_ack_pending) {
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_START_ACK);
+ vfe31_ctrl->start_ack_pending = FALSE;
+ }
+ vfe31_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (vfe31_ctrl->vfe_capture_count == 0) {
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ }
+ } /* if raw snapshot mode. */
+ if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) &&
+ (vfe31_ctrl->operation_mode == VFE_MODE_OF_OPERATION_VIDEO) &&
+ (vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) {
+ vfe31_ctrl->vfeFrameId++;
+ CDBG("Skip the SOF notification when HFR enabled\n");
+ return;
+ }
+ vfe31_ctrl->vfeFrameId++;
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_SOF_ACK);
+ CDBG("camif_sof_irq, frameId = %d\n", vfe31_ctrl->vfeFrameId);
+
+ if (vfe31_ctrl->sync_timer_state) {
+ if (vfe31_ctrl->sync_timer_repeat_count == 0)
+ vfe31_sync_timer_stop();
+ else
+ vfe31_ctrl->sync_timer_repeat_count--;
+ }
+}
+
+static void vfe31_process_error_irq(uint32_t errStatus)
+{
+ uint32_t reg_value, read_val;
+
+ if (errStatus & VFE31_IMASK_CAMIF_ERROR) {
+ pr_err("vfe31_irq: camif errors\n");
+ reg_value = msm_io_r(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS);
+ pr_err("camifStatus = 0x%x\n", reg_value);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_CAMIF_ERROR);
+ }
+
+ if (errStatus & VFE31_IMASK_STATS_CS_OVWR)
+ pr_err("vfe31_irq: stats cs overwrite\n");
+
+ if (errStatus & VFE31_IMASK_STATS_IHIST_OVWR)
+ pr_err("vfe31_irq: stats ihist overwrite\n");
+
+ if (errStatus & VFE31_IMASK_REALIGN_BUF_Y_OVFL)
+ pr_err("vfe31_irq: realign bug Y overflow\n");
+
+ if (errStatus & VFE31_IMASK_REALIGN_BUF_CB_OVFL)
+ pr_err("vfe31_irq: realign bug CB overflow\n");
+
+ if (errStatus & VFE31_IMASK_REALIGN_BUF_CR_OVFL)
+ pr_err("vfe31_irq: realign bug CR overflow\n");
+
+ if (errStatus & VFE31_IMASK_VIOLATION)
+ pr_err("vfe31_irq: violation interrupt\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_0_BUS_OVFL)
+ pr_err("vfe31_irq: image master 0 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_1_BUS_OVFL)
+ pr_err("vfe31_irq: image master 1 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_2_BUS_OVFL)
+ pr_err("vfe31_irq: image master 2 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_3_BUS_OVFL)
+ pr_err("vfe31_irq: image master 3 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_4_BUS_OVFL)
+ pr_err("vfe31_irq: image master 4 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_5_BUS_OVFL)
+ pr_err("vfe31_irq: image master 5 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_6_BUS_OVFL)
+ pr_err("vfe31_irq: image master 6 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_AE_BG_BUS_OVFL)
+ pr_err("vfe31_irq: ae/bg stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_AF_BF_BUS_OVFL)
+ pr_err("vfe31_irq: af/bf stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_AWB_BUS_OVFL)
+ pr_err("vfe31_irq: awb stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_RS_BUS_OVFL)
+ pr_err("vfe31_irq: rs stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_CS_BUS_OVFL)
+ pr_err("vfe31_irq: cs stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_IHIST_BUS_OVFL)
+ pr_err("vfe31_irq: ihist stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+ pr_err("vfe31_irq: skin/bhist stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_AXI_ERROR) {
+ pr_err("vfe31_irq: axi error\n");
+ /* read status too when overflow happens.*/
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+ pr_debug("VFE_BUS_PING_PONG_STATUS = 0x%x\n", read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_OPERATION_STATUS);
+ pr_debug("VFE_BUS_OPERATION_STATUS = 0x%x\n", read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0);
+ pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 = 0x%x\n",
+ read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1);
+ pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 = 0x%x\n",
+ read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_AXI_STATUS);
+ pr_debug("VFE_AXI_STATUS = 0x%x\n", read_val);
+ }
+}
+static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
+ uint32_t ch0_paddr, uint32_t ch1_paddr, uint32_t ch2_paddr)
+{
+ struct isp_msg_output msg;
+
+ msg.output_id = msgid;
+ msg.buf.ch_paddr[0] = ch0_paddr;
+ msg.buf.ch_paddr[1] = ch1_paddr;
+ msg.buf.ch_paddr[2] = ch2_paddr;
+ msg.frameCounter = vfe31_ctrl->vfeFrameId;
+
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_OUT, &msg);
+ return;
+}
+
+static void vfe31_process_output_path_irq_0(void)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+ uint8_t out_bool = 0;
+ struct msm_free_buf *free_buf = NULL;
+
+ free_buf = vfe31_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_PRIMARY);
+
+ /* we render frames in the following conditions:
+ * 1. Continuous mode and the free buffer is avaialable.
+ * 2. In snapshot shot mode, free buffer is not always available.
+ * when pending snapshot count is <=1, then no need to use
+ * free buffer.
+ */
+ out_bool = ((vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STARTED ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STOP_REQUESTED ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED) &&
+ (vfe31_ctrl->vfe_capture_count <= 1)) || free_buf;
+
+ if (out_bool) {
+ ping_pong = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Channel 0*/
+ ch0_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch0);
+ /* Channel 1*/
+ ch1_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch1);
+ /* Channel 2*/
+ ch2_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch2);
+
+ CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ ch0_paddr, ch1_paddr, ch2_paddr);
+ if (free_buf) {
+ /* Y channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch0,
+ free_buf->ch_paddr[0]);
+ /* Chroma channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch1,
+ free_buf->ch_paddr[1]);
+ if (free_buf->num_planes > 2)
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch2,
+ free_buf->ch_paddr[2]);
+ }
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
+ vfe31_ctrl->outpath.out0.capture_cnt--;
+
+ vfe_send_outmsg(&vfe31_ctrl->subdev,
+ MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
+ ch1_paddr, ch2_paddr);
+
+ if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
+ vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ } else {
+ vfe31_ctrl->outpath.out0.frame_drop_cnt++;
+ CDBG("path_irq_0 - no free buffer!\n");
+ }
+}
+
+static void vfe31_process_output_path_irq_1(void)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+ /* this must be snapshot main image output. */
+ uint8_t out_bool = 0;
+ struct msm_free_buf *free_buf = NULL;
+
+ free_buf = vfe31_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_SECONDARY);
+ out_bool = ((vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB) &&
+ (vfe31_ctrl->vfe_capture_count <= 1)) || free_buf;
+
+ if (out_bool) {
+ ping_pong = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Y channel */
+ ch0_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch0);
+ /* Chroma channel */
+ ch1_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch1);
+ ch2_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch2);
+
+ pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ __func__, ch0_paddr, ch1_paddr, ch2_paddr);
+ if (free_buf) {
+ /* Y channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch0,
+ free_buf->ch_paddr[0]);
+ /* Chroma channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch1,
+ free_buf->ch_paddr[1]);
+ if (free_buf->num_planes > 2)
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch2,
+ free_buf->ch_paddr[2]);
+ }
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB)
+ vfe31_ctrl->outpath.out1.capture_cnt--;
+
+ vfe_send_outmsg(&vfe31_ctrl->subdev,
+ MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
+ ch1_paddr, ch2_paddr);
+ } else {
+ vfe31_ctrl->outpath.out1.frame_drop_cnt++;
+ CDBG("path_irq_1 - no free buffer!\n");
+ }
+}
+
+static uint32_t vfe31_process_stats_irq_common(uint32_t statsNum,
+ uint32_t newAddr)
+{
+
+ uint32_t pingpongStatus;
+ uint32_t returnAddr;
+ uint32_t pingpongAddr;
+
+ /* must be 0=ping, 1=pong */
+ pingpongStatus =
+ ((msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS))
+ & ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+ /* stats bits starts at 7 */
+ CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+ pingpongAddr =
+ ((uint32_t)(vfe31_ctrl->vfebase +
+ VFE_BUS_STATS_PING_PONG_BASE)) +
+ (3*statsNum)*4 + (1-pingpongStatus)*4;
+ returnAddr = msm_io_r((uint32_t *)pingpongAddr);
+ msm_io_w(newAddr, (uint32_t *)pingpongAddr);
+ return returnAddr;
+}
+
+static void
+vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
+{
+ unsigned long flags;
+ /* fill message with right content. */
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ struct isp_msg_stats msgStats;
+ msgStats.frameCounter = vfe31_ctrl->vfeFrameId;
+ msgStats.buffer = bufAddress;
+
+ switch (statsNum) {
+ case STATS_AE_NUM:{
+ msgStats.id = MSG_ID_STATS_AEC;
+ spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
+ vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ }
+ break;
+ case STATS_AF_NUM:{
+ msgStats.id = MSG_ID_STATS_AF;
+ spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
+ vfe31_ctrl->afStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ }
+ break;
+ case STATS_AWB_NUM: {
+ msgStats.id = MSG_ID_STATS_AWB;
+ spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
+ vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ }
+ break;
+
+ case STATS_IHIST_NUM: {
+ msgStats.id = MSG_ID_STATS_IHIST;
+ spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
+ vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+ }
+ break;
+ case STATS_RS_NUM: {
+ msgStats.id = MSG_ID_STATS_RS;
+ spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
+ vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+ }
+ break;
+ case STATS_CS_NUM: {
+ msgStats.id = MSG_ID_STATS_CS;
+ spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
+ vfe31_ctrl->csStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+ }
+ break;
+
+ default:
+ goto stats_done;
+ }
+
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS,
+ &msgStats);
+stats_done:
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+ return;
+}
+
+static void vfe_send_comp_stats_msg(uint32_t status_bits)
+{
+ struct msm_stats_buf msgStats;
+ uint32_t temp;
+
+ msgStats.frame_id = vfe31_ctrl->vfeFrameId;
+ msgStats.status_bits = status_bits;
+
+ msgStats.aec.buff = vfe31_ctrl->aecStatsControl.bufToRender;
+ msgStats.awb.buff = vfe31_ctrl->awbStatsControl.bufToRender;
+ msgStats.af.buff = vfe31_ctrl->afStatsControl.bufToRender;
+
+ msgStats.ihist.buff = vfe31_ctrl->ihistStatsControl.bufToRender;
+ msgStats.rs.buff = vfe31_ctrl->rsStatsControl.bufToRender;
+ msgStats.cs.buff = vfe31_ctrl->csStatsControl.bufToRender;
+
+ temp = msm_io_r(vfe31_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG);
+ msgStats.awb_ymin = (0xFF00 & temp) >> 8;
+
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_COMP_STATS, &msgStats);
+}
+
+static void vfe31_process_stats_ae_irq(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
+ if (!(vfe31_ctrl->aecStatsControl.ackPending)) {
+ spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ vfe31_ctrl->aecStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AE_NUM,
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
+ STATS_AE_NUM);
+ } else{
+ spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->aecStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_awb_irq(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
+ if (!(vfe31_ctrl->awbStatsControl.ackPending)) {
+ spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ vfe31_ctrl->awbStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AWB_NUM,
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
+ STATS_AWB_NUM);
+ } else{
+ spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->awbStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_af_irq(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
+ if (!(vfe31_ctrl->afStatsControl.ackPending)) {
+ spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ vfe31_ctrl->afStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AF_NUM,
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
+ STATS_AF_NUM);
+ } else{
+ spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->afStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_ihist_irq(void)
+{
+ if (!(vfe31_ctrl->ihistStatsControl.ackPending)) {
+ vfe31_ctrl->ihistStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
+ STATS_IHIST_NUM);
+ } else {
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_rs_irq(void)
+{
+ if (!(vfe31_ctrl->rsStatsControl.ackPending)) {
+ vfe31_ctrl->rsStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_RS_NUM,
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
+ STATS_RS_NUM);
+ } else {
+ vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->rsStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_cs_irq(void)
+{
+ if (!(vfe31_ctrl->csStatsControl.ackPending)) {
+ vfe31_ctrl->csStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_CS_NUM,
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+ STATS_CS_NUM);
+ } else {
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats(uint32_t status_bits)
+{
+ unsigned long flags;
+ int32_t process_stats = false;
+ CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+
+ spin_lock_irqsave(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
+ if (!vfe31_ctrl->aecStatsControl.ackPending) {
+ vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+ vfe31_ctrl->aecStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AE_NUM,
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else{
+ vfe31_ctrl->aecStatsControl.bufToRender = 0;
+ vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe31_ctrl->aecStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
+ if (!vfe31_ctrl->awbStatsControl.ackPending) {
+ vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+ vfe31_ctrl->awbStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AWB_NUM,
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else{
+ vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->awbStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->awbStatsControl.bufToRender = 0;
+ }
+
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
+ if (!vfe31_ctrl->afStatsControl.ackPending) {
+ vfe31_ctrl->afStatsControl.ackPending = TRUE;
+ vfe31_ctrl->afStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AF_NUM,
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->afStatsControl.bufToRender = 0;
+ vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe31_ctrl->afStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
+ if (!vfe31_ctrl->ihistStatsControl.ackPending) {
+ vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+ vfe31_ctrl->ihistStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->ihistStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->ihistStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
+ if (!vfe31_ctrl->rsStatsControl.ackPending) {
+ vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+ vfe31_ctrl->rsStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_RS_NUM,
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->rsStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->rsStatsControl.bufToRender = 0;
+ }
+
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
+ if (!vfe31_ctrl->csStatsControl.ackPending) {
+ vfe31_ctrl->csStatsControl.ackPending = TRUE;
+ vfe31_ctrl->csStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_CS_NUM,
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->csStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->csStatsControl.bufToRender = 0;
+ }
+
+ spin_unlock_irqrestore(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ if (process_stats)
+ vfe_send_comp_stats_msg(status_bits);
+
+ return;
+}
+
+static void vfe31_process_stats_irq(uint32_t *irqstatus)
+{
+ uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
+
+ if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) &&
+ (vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) {
+ CDBG("Skip the stats when HFR enabled\n");
+ return;
+ }
+
+ vfe31_process_stats(status_bits);
+ return;
+}
+
+static void vfe31_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+
+ struct vfe31_isr_queue_cmd *qcmd = NULL;
+
+ CDBG("=== vfe31_do_tasklet start ===\n");
+
+ while (atomic_read(&irq_cnt)) {
+ spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+ qcmd = list_first_entry(&vfe31_ctrl->tasklet_q,
+ struct vfe31_isr_queue_cmd, list);
+ atomic_sub(1, &irq_cnt);
+
+ if (!qcmd) {
+ spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock,
+ flags);
+ return;
+ }
+
+ list_del(&qcmd->list);
+ spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock,
+ flags);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+ CDBG("irq camifSofIrq\n");
+ vfe31_process_camif_sof_irq();
+ }
+ /* interrupt to be processed, *qcmd has the payload. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+ CDBG("irq regUpdateIrq\n");
+ vfe31_process_reg_update_irq();
+ }
+
+ if (qcmd->vfeInterruptStatus1 &
+ VFE_IMASK_WHILE_STOPPING_1) {
+ CDBG("irq resetAckIrq\n");
+ vfe31_process_reset_irq();
+ }
+
+ if (atomic_read(&vfe31_ctrl->vstate)) {
+ if (qcmd->vfeInterruptStatus1 &
+ VFE31_IMASK_ERROR_ONLY_1) {
+ pr_err("irq errorIrq\n");
+ vfe31_process_error_irq(
+ qcmd->vfeInterruptStatus1 &
+ VFE31_IMASK_ERROR_ONLY_1);
+ }
+ /* next, check output path related interrupts. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+ CDBG("Image composite done 0 irq occured.\n");
+ vfe31_process_output_path_irq_0();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+ CDBG("Image composite done 1 irq occured.\n");
+ vfe31_process_output_path_irq_1();
+ }
+ /* in snapshot mode if done then send
+ snapshot done message */
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW) {
+ if ((vfe31_ctrl->outpath.out0.capture_cnt == 0)
+ && (vfe31_ctrl->outpath.out1.
+ capture_cnt == 0)) {
+ msm_io_w_mb(
+ CAMIF_COMMAND_STOP_IMMEDIATELY,
+ vfe31_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SNAPSHOT_DONE);
+ }
+ }
+ /* then process stats irq. */
+ if (vfe31_ctrl->stats_comp) {
+ /* process stats comb interrupt. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
+ CDBG("Stats composite irq occured.\n");
+ vfe31_process_stats_irq(
+ &qcmd->vfeInterruptStatus0);
+ }
+ } else {
+ /* process individual stats interrupt. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AEC) {
+ CDBG("Stats AEC irq occured.\n");
+ vfe31_process_stats_ae_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AWB) {
+ CDBG("Stats AWB irq occured.\n");
+ vfe31_process_stats_awb_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AF) {
+ CDBG("Stats AF irq occured.\n");
+ vfe31_process_stats_af_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_IHIST) {
+ CDBG("Stats IHIST irq occured.\n");
+ vfe31_process_stats_ihist_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_RS) {
+ CDBG("Stats RS irq occured.\n");
+ vfe31_process_stats_rs_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_CS) {
+ CDBG("Stats CS irq occured.\n");
+ vfe31_process_stats_cs_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_SYNC_TIMER0) {
+ CDBG("SYNC_TIMER 0 irq occured.\n");
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SYNC_TIMER0_DONE);
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_SYNC_TIMER1) {
+ CDBG("SYNC_TIMER 1 irq occured.\n");
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SYNC_TIMER1_DONE);
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_SYNC_TIMER2) {
+ CDBG("SYNC_TIMER 2 irq occured.\n");
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SYNC_TIMER2_DONE);
+ }
+ }
+ }
+ kfree(qcmd);
+ }
+ CDBG("=== vfe31_do_tasklet end ===\n");
+}
+
+DECLARE_TASKLET(vfe31_tasklet, vfe31_do_tasklet, 0);
+
+static irqreturn_t vfe31_parse_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ struct vfe31_irq_status irq;
+ struct vfe31_isr_queue_cmd *qcmd;
+
+ CDBG("vfe_parse_irq\n");
+
+ vfe31_read_irq_status(&irq);
+
+ if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+ CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+ return IRQ_HANDLED;
+ }
+
+ qcmd = kzalloc(sizeof(struct vfe31_isr_queue_cmd),
+ GFP_ATOMIC);
+ if (!qcmd) {
+ pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ if (vfe31_ctrl->stop_ack_pending) {
+ irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+ irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
+ }
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+ CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+ irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+ qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+ qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+
+ spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+ list_add_tail(&qcmd->list, &vfe31_ctrl->tasklet_q);
+
+ atomic_add(1, &irq_cnt);
+ spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags);
+ tasklet_schedule(&vfe31_tasklet);
+ return IRQ_HANDLED;
+}
+
+static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int subdev_cmd, void *arg)
+{
+ struct msm_isp_cmd vfecmd;
+ struct msm_camvfe_params *vfe_params =
+ (struct msm_camvfe_params *)arg;
+ struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+ void *data = vfe_params->data;
+
+ long rc = 0;
+ uint32_t i = 0;
+ struct vfe_cmd_stats_buf *scfg = NULL;
+ struct msm_pmem_region *regptr = NULL;
+ struct vfe_cmd_stats_ack *sack = NULL;
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n", __func__,
+ __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+ /* then must be stats release. */
+ if (!data)
+ return -EFAULT;
+ sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+ GFP_ATOMIC);
+ if (!sack)
+ return -ENOMEM;
+
+ sack->nextStatsBuf = *(uint32_t *)data;
+ }
+ }
+
+ CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+ if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+ struct axidata *axid;
+ axid = data;
+ if (!axid) {
+ rc = -EFAULT;
+ goto vfe31_config_done;
+ }
+
+ scfg =
+ kmalloc(sizeof(struct vfe_cmd_stats_buf),
+ GFP_ATOMIC);
+ if (!scfg) {
+ rc = -ENOMEM;
+ goto vfe31_config_done;
+ }
+ regptr = axid->region;
+ if (axid->bufnum1 > 0) {
+ for (i = 0; i < axid->bufnum1; i++) {
+ scfg->statsBuf[i] =
+ (uint32_t)(regptr->paddr);
+ regptr++;
+ }
+ }
+ /* individual */
+ switch (cmd->cmd_type) {
+ case CMD_STATS_AEC_ENABLE:
+ rc = vfe_stats_aec_buf_init(scfg);
+ break;
+ case CMD_STATS_AF_ENABLE:
+ rc = vfe_stats_af_buf_init(scfg);
+ break;
+ case CMD_STATS_AWB_ENABLE:
+ rc = vfe_stats_awb_buf_init(scfg);
+ break;
+ case CMD_STATS_IHIST_ENABLE:
+ rc = vfe_stats_ihist_buf_init(scfg);
+ break;
+ case CMD_STATS_RS_ENABLE:
+ rc = vfe_stats_rs_buf_init(scfg);
+ break;
+ case CMD_STATS_CS_ENABLE:
+ rc = vfe_stats_cs_buf_init(scfg);
+ break;
+ default:
+ pr_err("%s Unsupported cmd type %d",
+ __func__, cmd->cmd_type);
+ break;
+ }
+ goto vfe31_config_done;
+ }
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL: {
+ rc = vfe31_proc_general(&vfecmd);
+ }
+ break;
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_SNAP_BUF_RELEASE:
+ break;
+
+ case CMD_STATS_AEC_BUF_RELEASE: {
+ vfe31_stats_aec_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_AF_BUF_RELEASE: {
+ vfe31_stats_af_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_AWB_BUF_RELEASE: {
+ vfe31_stats_awb_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_IHIST_BUF_RELEASE: {
+ vfe31_stats_ihist_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_RS_BUF_RELEASE: {
+ vfe31_stats_rs_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_CS_BUF_RELEASE: {
+ vfe31_stats_cs_ack(sack);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ pr_err("%s Invalid/Unsupported AXI configuration %x",
+ __func__, cmd->cmd_type);
+ }
+ break;
+
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cmd->cmd_type);
+ break;
+ }
+vfe31_config_done:
+ kfree(scfg);
+ kfree(sack);
+ CDBG("%s done: rc = %d\n", __func__, (int) rc);
+ return rc;
+}
+
+static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+ u32 freq, u32 flags)
+{
+ int rc = 0;
+ int round_rate;
+
+ round_rate = clk_round_rate(vfe31_ctrl->vfe_clk[0], freq);
+ if (rc < 0) {
+ pr_err("%s: clk_round_rate failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vfe_clk_rate = round_rate;
+ rc = clk_set_rate(vfe31_ctrl->vfe_clk[0], round_rate);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
+ .s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
+};
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+ .ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+ .core = &msm_vfe_subdev_core_ops,
+ .video = &msm_vfe_subdev_video_ops,
+};
+
+static struct msm_cam_clk_info vfe_clk_info[] = {
+ {"vfe_clk", VFE_CLK_RATE},
+ {"vfe_pclk", -1},
+};
+
+static struct msm_cam_clk_info vfe_camif_clk_info[] = {
+ {"camif_pad_pclk", -1},
+ {"vfe_camif_clk", -1},
+};
+
+static void msm_vfe_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+ struct clk *clk = NULL;
+
+ clk = vfe31_ctrl->vfe_camif_clk[1];
+
+ if (clk != NULL) {
+ switch (srctype) {
+ case MSM_CAMIO_CLK_SRC_INTERNAL:
+ clk_set_flags(clk, 0x00000100 << 1);
+ break;
+
+ case MSM_CAMIO_CLK_SRC_EXTERNAL:
+ clk_set_flags(clk, 0x00000100);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static void msm_vfe_camif_pad_reg_reset(void)
+{
+ uint32_t reg;
+
+ msm_vfe_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+ usleep_range(10000, 15000);
+
+ reg = (msm_io_r(vfe31_ctrl->camifbase)) & CAMIF_CFG_RMSK;
+ reg |= 0x3;
+ msm_io_w(reg, vfe31_ctrl->camifbase);
+ usleep_range(10000, 15000);
+
+ reg = (msm_io_r(vfe31_ctrl->camifbase)) & CAMIF_CFG_RMSK;
+ reg |= 0x10;
+ msm_io_w(reg, vfe31_ctrl->camifbase);
+ usleep_range(10000, 15000);
+
+ reg = (msm_io_r(vfe31_ctrl->camifbase)) & CAMIF_CFG_RMSK;
+ /* Need to be uninverted*/
+ reg &= 0x03;
+ msm_io_w(reg, vfe31_ctrl->camifbase);
+ usleep_range(10000, 15000);
+}
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
+ struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_sync *sync = data;
+ v4l2_set_subdev_hostdata(sd, data);
+ vfe_syncdata = data;
+
+ spin_lock_init(&vfe31_ctrl->stop_flag_lock);
+ spin_lock_init(&vfe31_ctrl->state_lock);
+ spin_lock_init(&vfe31_ctrl->io_lock);
+ spin_lock_init(&vfe31_ctrl->update_ack_lock);
+ spin_lock_init(&vfe31_ctrl->tasklet_lock);
+
+ spin_lock_init(&vfe31_ctrl->aec_ack_lock);
+ spin_lock_init(&vfe31_ctrl->awb_ack_lock);
+ spin_lock_init(&vfe31_ctrl->af_ack_lock);
+ spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
+ spin_lock_init(&vfe31_ctrl->rs_ack_lock);
+ spin_lock_init(&vfe31_ctrl->cs_ack_lock);
+ spin_lock_init(&vfe31_ctrl->comp_stats_ack_lock);
+ spin_lock_init(&vfe31_ctrl->sd_notify_lock);
+ INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
+
+ vfe31_ctrl->update_linear = false;
+ vfe31_ctrl->update_rolloff = false;
+ vfe31_ctrl->update_la = false;
+ vfe31_ctrl->update_gamma = false;
+ vfe31_ctrl->hfr_mode = HFR_MODE_OFF;
+
+ vfe31_ctrl->vfebase = ioremap(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ if (!vfe31_ctrl->vfebase) {
+ rc = -ENOMEM;
+ pr_err("%s: vfe ioremap failed\n", __func__);
+ goto vfe_remap_failed;
+ }
+ if (!sync->sdata->csi_if) {
+ vfe31_ctrl->camifbase = ioremap(vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem));
+ if (!vfe31_ctrl->camifbase) {
+ rc = -ENOMEM;
+ pr_err("%s: camif ioremap failed\n", __func__);
+ goto camif_remap_failed;
+ }
+ }
+
+ if (vfe31_ctrl->fs_vfe == NULL) {
+ vfe31_ctrl->fs_vfe =
+ regulator_get(&vfe31_ctrl->pdev->dev, "fs_vfe");
+ if (IS_ERR(vfe31_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator FS_VFE get failed %ld\n",
+ __func__, PTR_ERR(vfe31_ctrl->fs_vfe));
+ vfe31_ctrl->fs_vfe = NULL;
+ goto vfe_fs_failed;
+ } else if (regulator_enable(vfe31_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator FS_VFE enable failed\n",
+ __func__);
+ regulator_put(vfe31_ctrl->fs_vfe);
+ vfe31_ctrl->fs_vfe = NULL;
+ goto vfe_fs_failed;
+ }
+ }
+
+ rc = msm_cam_clk_enable(&vfe31_ctrl->pdev->dev, vfe_clk_info,
+ vfe31_ctrl->vfe_clk, ARRAY_SIZE(vfe_clk_info), 1);
+ if (rc < 0)
+ goto vfe_clk_enable_failed;
+
+ if (!sync->sdata->csi_if) {
+ rc = msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
+ vfe_camif_clk_info,
+ vfe31_ctrl->vfe_camif_clk,
+ ARRAY_SIZE(vfe_camif_clk_info), 1);
+ if (rc < 0)
+ goto vfe_clk_enable_failed;
+ msm_vfe_camif_pad_reg_reset();
+ }
+
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_INIT);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ vfe31_ctrl->register_total = VFE31_REGISTER_TOTAL;
+
+ enable_irq(vfe31_ctrl->vfeirq->start);
+
+ return rc;
+
+vfe_clk_enable_failed:
+ regulator_disable(vfe31_ctrl->fs_vfe);
+ regulator_put(vfe31_ctrl->fs_vfe);
+ vfe31_ctrl->fs_vfe = NULL;
+vfe_fs_failed:
+ if (!sync->sdata->csi_if)
+ iounmap(vfe31_ctrl->camifbase);
+camif_remap_failed:
+ iounmap(vfe31_ctrl->vfebase);
+vfe_remap_failed:
+ disable_irq(vfe31_ctrl->vfeirq->start);
+ return rc;
+}
+
+void msm_vfe_subdev_release(struct platform_device *pdev)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ disable_irq(vfe31_ctrl->vfeirq->start);
+ tasklet_kill(&vfe31_tasklet);
+
+ if (!sync->sdata->csi_if)
+ msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
+ vfe_camif_clk_info,
+ vfe31_ctrl->vfe_camif_clk,
+ ARRAY_SIZE(vfe_camif_clk_info), 0);
+
+ msm_cam_clk_enable(&vfe31_ctrl->pdev->dev, vfe_clk_info,
+ vfe31_ctrl->vfe_clk, ARRAY_SIZE(vfe_clk_info), 0);
+ if (vfe31_ctrl->fs_vfe) {
+ regulator_disable(vfe31_ctrl->fs_vfe);
+ regulator_put(vfe31_ctrl->fs_vfe);
+ vfe31_ctrl->fs_vfe = NULL;
+ }
+ CDBG("%s, 31ee_irq\n", __func__);
+ if (!sync->sdata->csi_if)
+ iounmap(vfe31_ctrl->camifbase);
+ iounmap(vfe31_ctrl->vfebase);
+
+ if (atomic_read(&irq_cnt))
+ pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_EXIT);
+ vfe_syncdata = NULL;
+}
+
+
+static int __devinit vfe31_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+ vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
+ if (!vfe31_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ v4l2_subdev_init(&vfe31_ctrl->subdev, &msm_vfe_subdev_ops);
+ snprintf(vfe31_ctrl->subdev.name,
+ sizeof(vfe31_ctrl->subdev.name), "vfe3.1");
+ v4l2_set_subdevdata(&vfe31_ctrl->subdev, vfe31_ctrl);
+ platform_set_drvdata(pdev, &vfe31_ctrl->subdev);
+
+ vfe31_ctrl->vfemem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "msm_vfe");
+ if (!vfe31_ctrl->vfemem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe31_no_resource;
+ }
+ vfe31_ctrl->vfeirq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "msm_vfe");
+ if (!vfe31_ctrl->vfeirq) {
+ pr_err("%s: no irq resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe31_no_resource;
+ }
+ vfe31_ctrl->camifmem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "msm_camif");
+ if (!vfe31_ctrl->camifmem)
+ pr_err("%s: camif not supported\n", __func__);
+
+ vfe31_ctrl->vfeio = request_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem), pdev->name);
+ if (!vfe31_ctrl->vfeio) {
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto vfe31_no_resource;
+ }
+
+ if (vfe31_ctrl->camifmem) {
+ vfe31_ctrl->camifio = request_mem_region(
+ vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem), pdev->name);
+ if (!vfe31_ctrl->camifio) {
+ release_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto vfe31_no_resource;
+ }
+ }
+
+ rc = request_irq(vfe31_ctrl->vfeirq->start, vfe31_parse_irq,
+ IRQF_TRIGGER_RISING, "vfe", 0);
+ if (rc < 0) {
+ if (vfe31_ctrl->camifmem) {
+ release_mem_region(vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem));
+ }
+ release_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ pr_err("%s: irq request fail\n", __func__);
+ rc = -EBUSY;
+ goto vfe31_no_resource;
+ }
+
+ disable_irq(vfe31_ctrl->vfeirq->start);
+
+ vfe31_ctrl->pdev = pdev;
+ return 0;
+
+vfe31_no_resource:
+ kfree(vfe31_ctrl);
+ return 0;
+}
+
+static struct platform_driver vfe31_driver = {
+ .probe = vfe31_probe,
+ .driver = {
+ .name = MSM_VFE_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_vfe31_init_module(void)
+{
+ return platform_driver_register(&vfe31_driver);
+}
+
+static void __exit msm_vfe31_exit_module(void)
+{
+ platform_driver_unregister(&vfe31_driver);
+}
+
+module_init(msm_vfe31_init_module);
+module_exit(msm_vfe31_exit_module);
+MODULE_DESCRIPTION("VFE 3.1 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
new file mode 100644
index 0000000..e94f286
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -0,0 +1,955 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_VFE31_V4L2_H__
+#define __MSM_VFE31_V4L2_H__
+
+#include <linux/bitops.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* This defines total number registers in VFE.
+ * Each register is 4 bytes so to get the range,
+ * multiply this number with 4. */
+#define VFE31_REGISTER_TOTAL 0x0000017F
+
+/* at start of camif, bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START 0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR 0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT 0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR 0x00000000
+
+/* clear axi_halt_irq */
+#define MASK_AXI_HALT_IRQ 0xFF7FFFFF
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD 0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD 0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 = halted, 0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go; bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO 0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go; bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO 0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples. JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */
+#define VFE_CLEAR_ALL_IRQS 0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK 0x00000001
+#define VFE_IRQ_STATUS0_CAMIF_EOF_MASK 0x00000004
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK 0x00000020
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000
+#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK 0x00800000
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK 0x01000000
+
+#define VFE_IRQ_STATUS0_STATS_AEC 0x2000 /* bit 13 */
+#define VFE_IRQ_STATUS0_STATS_AF 0x4000 /* bit 14 */
+#define VFE_IRQ_STATUS0_STATS_AWB 0x8000 /* bit 15 */
+#define VFE_IRQ_STATUS0_STATS_RS 0x10000 /* bit 16 */
+#define VFE_IRQ_STATUS0_STATS_CS 0x20000 /* bit 17 */
+#define VFE_IRQ_STATUS0_STATS_IHIST 0x40000 /* bit 18 */
+
+#define VFE_IRQ_STATUS0_SYNC_TIMER0 0x2000000 /* bit 25 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER1 0x4000000 /* bit 26 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER2 0x8000000 /* bit 27 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER0 0x10000000 /* bit 28 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER1 0x20000000 /* bit 29 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER2 0x40000000 /* bit 30 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER3 0x80000000 /* bit 31 */
+
+/* imask for while waiting for stop ack, driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-31 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+ irq */
+#define VFE_IMASK_WHILE_STOPPING_0 0xF0000000
+#define VFE_IMASK_WHILE_STOPPING_1 0x00C00000
+#define VFE_IMASK_RESET 0x00400000
+#define VFE_IMASK_AXI_HALT 0x00800000
+
+
+/* no error irq in mask 0 */
+#define VFE_IMASK_ERROR_ONLY_0 0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE_IMASK_ERROR_ONLY_1 0x003fffff
+
+/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */
+#define BPC_MASK 0xF80C0FFE
+
+/* For BPC bit 1 and 2 are set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF9
+
+/* For DBPC bit 0 is set to zero and other's 1 */
+#define DBPC_MASK 0xFFFFFFFE
+
+/* For DBCC bit 1 is set to zero and other's 1 */
+#define DBCC_MASK 0xFFFFFFFD
+
+/* For DBPC/ABF/DBCC/ABCC bits are set to 1 all others 0 */
+#define DEMOSAIC_MASK 0x8FFFFFFF
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 31 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define AE_BG_ENABLE_MASK 0x00000020 /* bit 5 */
+#define AF_BF_ENABLE_MASK 0x00000040 /* bit 6 */
+#define AWB_ENABLE_MASK 0x00000080 /* bit 7 */
+
+#define RS_ENABLE_MASK 0x00000100 /* bit 8 */
+#define CS_ENABLE_MASK 0x00000200 /* bit 9 */
+#define RS_CS_ENABLE_MASK 0x00000300 /* bit 8,9 */
+#define IHIST_ENABLE_MASK 0x00008000 /* bit 15 */
+#define STATS_ENABLE_MASK 0x000483E0 /* bit 18,15,9,8,7,6,5*/
+
+#define VFE_REG_UPDATE_TRIGGER 1
+#define VFE_PM_BUF_MAX_CNT_MASK 0xFF
+#define VFE_DMI_CFG_DEFAULT 0x00000100
+#define VFE_AE_PINGPONG_STATUS_BIT 0x80
+#define VFE_AF_PINGPONG_STATUS_BIT 0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT 0x200
+
+#define HFR_MODE_OFF 1
+#define VFE_FRAME_SKIP_PERIOD_MASK 0x0000001F /*bits 0 -4*/
+
+enum VFE31_DMI_RAM_SEL {
+ NO_MEM_SELECTED = 0,
+ ROLLOFF_RAM = 0x1,
+ RGBLUT_RAM_CH0_BANK0 = 0x2,
+ RGBLUT_RAM_CH0_BANK1 = 0x3,
+ RGBLUT_RAM_CH1_BANK0 = 0x4,
+ RGBLUT_RAM_CH1_BANK1 = 0x5,
+ RGBLUT_RAM_CH2_BANK0 = 0x6,
+ RGBLUT_RAM_CH2_BANK1 = 0x7,
+ STATS_HIST_RAM = 0x8,
+ RGBLUT_CHX_BANK0 = 0x9,
+ RGBLUT_CHX_BANK1 = 0xa,
+ LUMA_ADAPT_LUT_RAM_BANK0 = 0xb,
+ LUMA_ADAPT_LUT_RAM_BANK1 = 0xc
+};
+
+enum vfe_output_state {
+ VFE_STATE_IDLE,
+ VFE_STATE_START_REQUESTED,
+ VFE_STATE_STARTED,
+ VFE_STATE_STOP_REQUESTED,
+ VFE_STATE_STOPPED,
+};
+
+#define V31_CAMIF_OFF 0x000001E4
+#define V31_CAMIF_LEN 32
+
+#define V31_DEMUX_OFF 0x00000284
+#define V31_DEMUX_LEN 20
+
+#define V31_DEMOSAICV3_UP_REG_CNT 5
+
+#define V31_OUT_CLAMP_OFF 0x00000524
+#define V31_OUT_CLAMP_LEN 8
+
+#define V31_OPERATION_CFG_LEN 32
+
+#define V31_AXI_OUT_OFF 0x00000038
+#define V31_AXI_OUT_LEN 212
+#define V31_AXI_CH_INF_LEN 24
+#define V31_AXI_CFG_LEN 47
+#define V31_AXI_RESERVED 1
+
+#define V31_FRAME_SKIP_OFF 0x00000504
+#define V31_FRAME_SKIP_LEN 32
+
+#define V31_CHROMA_SUBS_OFF 0x000004F8
+#define V31_CHROMA_SUBS_LEN 12
+
+#define V31_FOV_OFF 0x00000360
+#define V31_FOV_LEN 8
+
+#define V31_MAIN_SCALER_OFF 0x00000368
+#define V31_MAIN_SCALER_LEN 28
+
+#define V31_S2Y_OFF 0x000004D0
+#define V31_S2Y_LEN 20
+
+#define V31_S2CbCr_OFF 0x000004E4
+#define V31_S2CbCr_LEN 20
+
+#define V31_CHROMA_EN_OFF 0x000003C4
+#define V31_CHROMA_EN_LEN 36
+
+#define V31_SYNC_TIMER_OFF 0x0000020C
+#define V31_SYNC_TIMER_POLARITY_OFF 0x00000234
+#define V31_TIMER_SELECT_OFF 0x0000025C
+#define V31_SYNC_TIMER_LEN 28
+
+#define V31_ASYNC_TIMER_OFF 0x00000238
+#define V31_ASYNC_TIMER_LEN 28
+
+#define V31_BLACK_LEVEL_OFF 0x00000264
+#define V31_BLACK_LEVEL_LEN 16
+
+#define V31_MESH_ROLL_OFF_CFG_OFF 0x00000274
+#define V31_MESH_ROLL_OFF_CFG_LEN 16
+#define V31_MESH_ROLL_OFF_INIT_TABLE_SIZE 13
+#define V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE 208
+#define V31_MESH_ROLL_OFF_DELTA_TABLE_OFFSET 32
+
+#define V31_COLOR_COR_OFF 0x00000388
+#define V31_COLOR_COR_LEN 52
+
+#define V31_WB_OFF 0x00000384
+#define V31_WB_LEN 4
+
+#define V31_RGB_G_OFF 0x000003BC
+#define V31_RGB_G_LEN 4
+
+#define V31_LA_OFF 0x000003C0
+#define V31_LA_LEN 4
+
+#define V31_SCE_OFF 0x00000418
+#define V31_SCE_LEN 136
+
+#define V31_CHROMA_SUP_OFF 0x000003E8
+#define V31_CHROMA_SUP_LEN 12
+
+#define V31_MCE_OFF 0x000003F4
+#define V31_MCE_LEN 36
+#define V31_STATS_AF_OFF 0x0000053c
+#define V31_STATS_AF_LEN 16
+
+#define V31_STATS_AE_OFF 0x00000534
+#define V31_STATS_AE_LEN 8
+
+#define V31_STATS_AWB_OFF 0x0000054c
+#define V31_STATS_AWB_LEN 32
+
+#define V31_STATS_IHIST_OFF 0x0000057c
+#define V31_STATS_IHIST_LEN 8
+
+#define V31_STATS_RS_OFF 0x0000056c
+#define V31_STATS_RS_LEN 8
+
+#define V31_STATS_CS_OFF 0x00000574
+#define V31_STATS_CS_LEN 8
+
+#define V31_ASF_OFF 0x000004A0
+#define V31_ASF_LEN 48
+#define V31_ASF_UPDATE_LEN 36
+#define V31_CAPTURE_LEN 4
+#define V31_GET_HW_VERSION_OFF 0
+#define V31_GET_HW_VERSION_LEN 4
+#define V31_DEMOSAICV3_OFF 0x00000298
+#define V31_DEMOSAICV3_LEN 4
+/* BPC */
+#define V31_DEMOSAICV3_DBPC_CFG_OFF 0x0000029C
+#define V31_DEMOSAICV3_DBPC_LEN 8
+#define V31_XBAR_CFG_OFF 0x00000040
+/* ABF */
+#define V31_DEMOSAICV3_ABF_OFF 0x000002A4
+#define V31_DEMOSAICV3_ABF_LEN 180
+#define V31_XBAR_CFG_LEN 8
+
+#define V31_MODULE_CFG_OFF 0x00000010
+#define V31_MODULE_CFG_LEN 4
+#define V31_EZTUNE_CFG_OFF 0x00000010
+#define V31_EZTUNE_CFG_LEN 4
+
+struct vfe_cmd_hw_version {
+ uint32_t minorVersion;
+ uint32_t majorVersion;
+ uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+ VFE_AXI_OUTPUT_MODE_Output1,
+ VFE_AXI_OUTPUT_MODE_Output2,
+ VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+ VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+ VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+ VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+ VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+ VFE_RAW_OUTPUT_DISABLED,
+ VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+ VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+ VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH 4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3
+
+struct vfe_cmds_per_write_master {
+ uint16_t imageWidth;
+ uint16_t imageHeight;
+ uint16_t outRowCount;
+ uint16_t outRowIncrement;
+ uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+ [VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+ uint8_t fragmentCount;
+ struct vfe_cmds_per_write_master firstWM;
+ struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+ VFE_AXI_BURST_LENGTH_IS_2 = 2,
+ VFE_AXI_BURST_LENGTH_IS_4 = 4,
+ VFE_AXI_BURST_LENGTH_IS_8 = 8,
+ VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+struct vfe_cmd_fov_crop_config {
+ uint8_t enable;
+ uint16_t firstPixel;
+ uint16_t lastPixel;
+ uint16_t firstLine;
+ uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+ uint16_t MNCounterInit;
+ uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+ uint8_t enable;
+ uint16_t inputSize;
+ uint16_t outputSize;
+ uint32_t phaseMultiplicationFactor;
+ uint8_t interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+ uint8_t enable;
+ struct vfe_cmds_scaler_one_dimension hconfig;
+ struct vfe_cmds_scaler_one_dimension vconfig;
+ struct vfe_cmds_main_scaler_stripe_init MNInitH;
+ struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+ uint8_t enable;
+ struct vfe_cmds_scaler_one_dimension hconfig;
+ struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+ uint32_t output1Pattern;
+ uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+ uint8_t minCh0;
+ uint8_t minCh1;
+ uint8_t minCh2;
+ uint8_t maxCh0;
+ uint8_t maxCh1;
+ uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+ uint8_t enable;
+ uint8_t cropEnable;
+ uint8_t vsubSampleEnable;
+ uint8_t hsubSampleEnable;
+ uint8_t vCosited;
+ uint8_t hCosited;
+ uint8_t vCositedPhase;
+ uint8_t hCositedPhase;
+ uint16_t cropWidthFirstPixel;
+ uint16_t cropWidthLastPixel;
+ uint16_t cropHeightFirstLine;
+ uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_PIXEL_PATTERN {
+ VFE_BAYER_RGRGRG,
+ VFE_BAYER_GRGRGR,
+ VFE_BAYER_BGBGBG,
+ VFE_BAYER_GBGBGB,
+ VFE_YUV_YCbYCr,
+ VFE_YUV_YCrYCb,
+ VFE_YUV_CbYCrY,
+ VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+ VFE_BAYER_RAW,
+ VFE_YUV_INTERLEAVED,
+ VFE_YUV_PSEUDO_PLANAR_Y,
+ VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+ VFE_YUV_COSITED,
+ VFE_YUV_INTERPOLATED
+};
+
+#define VFE31_GAMMA_NUM_ENTRIES 64
+
+#define VFE31_LA_TABLE_LENGTH 64
+
+#define VFE31_HIST_TABLE_LENGTH 256
+
+struct vfe_cmds_demosaic_abf {
+ uint8_t enable;
+ uint8_t forceOn;
+ uint8_t shift;
+ uint16_t lpThreshold;
+ uint16_t max;
+ uint16_t min;
+ uint8_t ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+ uint8_t enable;
+ uint16_t fmaxThreshold;
+ uint16_t fminThreshold;
+ uint16_t redDiffThreshold;
+ uint16_t blueDiffThreshold;
+ uint16_t greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+ uint8_t enable;
+ uint8_t slopeShift;
+ struct vfe_cmds_demosaic_abf abfConfig;
+ struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+ struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+ struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+ uint8_t enable;
+ uint16_t ch2Gain;
+ uint16_t ch1Gain;
+ uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+ COEF_IS_Q7_SIGNED,
+ COEF_IS_Q8_SIGNED,
+ COEF_IS_Q9_SIGNED,
+ COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+ uint8_t enable;
+ enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+ int16_t C0;
+ int16_t C1;
+ int16_t C2;
+ int16_t C3;
+ int16_t C4;
+ int16_t C5;
+ int16_t C6;
+ int16_t C7;
+ int16_t C8;
+ int16_t K0;
+ int16_t K1;
+ int16_t K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 64
+
+struct vfe_cmd_la_config {
+ uint8_t enable;
+ int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+ RGB_GAMMA_CH0_SELECTED,
+ RGB_GAMMA_CH1_SELECTED,
+ RGB_GAMMA_CH2_SELECTED,
+ RGB_GAMMA_CH0_CH1_SELECTED,
+ RGB_GAMMA_CH0_CH2_SELECTED,
+ RGB_GAMMA_CH1_CH2_SELECTED,
+ RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+ uint8_t enable;
+ enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+ int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+ uint8_t enable;
+ int16_t am;
+ int16_t ap;
+ int16_t bm;
+ int16_t bp;
+ int16_t cm;
+ int16_t cp;
+ int16_t dm;
+ int16_t dp;
+ int16_t kcr;
+ int16_t kcb;
+ int16_t RGBtoYConversionV0;
+ int16_t RGBtoYConversionV1;
+ int16_t RGBtoYConversionV2;
+ uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+ uint8_t enable;
+ uint8_t m1;
+ uint8_t m3;
+ uint8_t n1;
+ uint8_t n3;
+ uint8_t nn1;
+ uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+ uint8_t enable;
+ uint8_t smoothFilterEnabled;
+ uint8_t sharpMode;
+ uint8_t smoothCoefCenter;
+ uint8_t smoothCoefSurr;
+ uint8_t normalizeFactor;
+ uint8_t sharpK1;
+ uint8_t sharpK2;
+ uint8_t sharpThreshE1;
+ int8_t sharpThreshE2;
+ int8_t sharpThreshE3;
+ int8_t sharpThreshE4;
+ int8_t sharpThreshE5;
+ int8_t filter1Coefficients[9];
+ int8_t filter2Coefficients[9];
+ uint8_t cropEnable;
+ uint16_t cropFirstPixel;
+ uint16_t cropLastPixel;
+ uint16_t cropFirstLine;
+ uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+ uint8_t enable;
+ uint8_t smoothFilterEnabled;
+ uint8_t sharpMode;
+ uint8_t smoothCoefCenter;
+ uint8_t smoothCoefSurr;
+ uint8_t normalizeFactor;
+ uint8_t sharpK1;
+ uint8_t sharpK2;
+ uint8_t sharpThreshE1;
+ int8_t sharpThreshE2;
+ int8_t sharpThreshE3;
+ int8_t sharpThreshE4;
+ int8_t sharpThreshE5;
+ int8_t filter1Coefficients[9];
+ int8_t filter2Coefficients[9];
+ uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+ VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+ VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+ uint8_t output2YWrPmEnable;
+ uint8_t output2CbcrWrPmEnable;
+ uint8_t output1YWrPmEnable;
+ uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_frame_skip_counts {
+ uint32_t totalFrameCount;
+ uint32_t output1Count;
+ uint32_t output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+ VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_frame_bpc_info {
+ uint32_t greenDefectPixelCount;
+ uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+ uint32_t asfMaxEdge;
+ uint32_t asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+ uint8_t camifState;
+ uint32_t pixelCount;
+ uint32_t lineCount;
+};
+
+struct vfe31_irq_status {
+ uint32_t vfeIrqStatus0;
+ uint32_t vfeIrqStatus1;
+ uint32_t camifStatus;
+ uint32_t demosaicStatus;
+ uint32_t asfMaxEdge;
+};
+
+#define V31_PREVIEW_AXI_FLAG 0x00000001
+#define V31_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe31_cmd_type {
+ uint16_t id;
+ uint32_t length;
+ uint32_t offset;
+ uint32_t flag;
+};
+
+struct vfe31_free_buf {
+ struct list_head node;
+ uint32_t paddr;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+};
+
+struct vfe31_output_ch {
+ struct list_head free_buf_queue;
+ spinlock_t free_buf_lock;
+ uint16_t output_fmt;
+ int8_t ch0;
+ int8_t ch1;
+ int8_t ch2;
+ uint32_t capture_cnt;
+ uint32_t frame_drop_cnt;
+ struct msm_free_buf ping;
+ struct msm_free_buf pong;
+ struct msm_free_buf free_buf;
+};
+
+/* no error irq in mask 0 */
+#define VFE31_IMASK_ERROR_ONLY_0 0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE31_IMASK_ERROR_ONLY_1 0x003FFFFF
+#define VFE31_IMASK_CAMIF_ERROR (0x00000001<<0)
+#define VFE31_IMASK_STATS_CS_OVWR (0x00000001<<1)
+#define VFE31_IMASK_STATS_IHIST_OVWR (0x00000001<<2)
+#define VFE31_IMASK_REALIGN_BUF_Y_OVFL (0x00000001<<3)
+#define VFE31_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<4)
+#define VFE31_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<5)
+#define VFE31_IMASK_VIOLATION (0x00000001<<6)
+#define VFE31_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<7)
+#define VFE31_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<8)
+#define VFE31_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<9)
+#define VFE31_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<10)
+#define VFE31_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<11)
+#define VFE31_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<12)
+#define VFE31_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<13)
+#define VFE31_IMASK_STATS_AE_BG_BUS_OVFL (0x00000001<<14)
+#define VFE31_IMASK_STATS_AF_BF_BUS_OVFL (0x00000001<<15)
+#define VFE31_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<16)
+#define VFE31_IMASK_STATS_RS_BUS_OVFL (0x00000001<<17)
+#define VFE31_IMASK_STATS_CS_BUS_OVFL (0x00000001<<18)
+#define VFE31_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<19)
+#define VFE31_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<20)
+#define VFE31_IMASK_AXI_ERROR (0x00000001<<21)
+
+#define VFE_COM_STATUS 0x000FE000
+
+struct vfe31_output_path {
+ uint16_t output_mode; /* bitmask */
+
+ struct vfe31_output_ch out0; /* preview and thumbnail */
+ struct vfe31_output_ch out1; /* snapshot */
+ struct vfe31_output_ch out2; /* video */
+};
+
+struct vfe31_frame_extra {
+ uint32_t greenDefectPixelCount;
+ uint32_t redBlueDefectPixelCount;
+
+ uint32_t asfMaxEdge;
+ uint32_t asfHbiCount;
+
+ uint32_t yWrPmStats0;
+ uint32_t yWrPmStats1;
+ uint32_t cbcrWrPmStats0;
+ uint32_t cbcrWrPmStats1;
+
+ uint32_t frameCounter;
+};
+
+#define VFE_DISABLE_ALL_IRQS 0
+#define VFE_CLEAR_ALL_IRQS 0xffffffff
+
+#define VFE_HW_VERSION 0x00000000
+#define VFE_GLOBAL_RESET 0x00000004
+#define VFE_MODULE_RESET 0x00000008
+#define VFE_CGC_OVERRIDE 0x0000000C
+#define VFE_MODULE_CFG 0x00000010
+#define VFE_CFG 0x00000014
+#define VFE_IRQ_CMD 0x00000018
+#define VFE_IRQ_MASK_0 0x0000001C
+#define VFE_IRQ_MASK_1 0x00000020
+#define VFE_IRQ_CLEAR_0 0x00000024
+#define VFE_IRQ_CLEAR_1 0x00000028
+#define VFE_IRQ_STATUS_0 0x0000002C
+#define VFE_IRQ_STATUS_1 0x00000030
+#define VFE_IRQ_COMP_MASK 0x00000034
+#define VFE_BUS_CMD 0x00000038
+#define VFE_BUS_PING_PONG_STATUS 0x00000180
+#define VFE_BUS_OPERATION_STATUS 0x00000184
+
+#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 0x00000190
+#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 0x00000194
+
+#define VFE_AXI_CMD 0x000001D8
+#define VFE_AXI_STATUS 0x000001DC
+#define VFE_BUS_STATS_PING_PONG_BASE 0x000000F4
+
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR 0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR 0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG 0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR 0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR 0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG 0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG 0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG 0x00000120
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG 0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG 0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG 0x00000144
+#define VFE_BUS_PM_CMD 0x00000188
+#define VFE_BUS_PM_CFG 0x0000018C
+#define VFE_CAMIF_COMMAND 0x000001E0
+#define VFE_CAMIF_STATUS 0x00000204
+#define VFE_REG_UPDATE_CMD 0x00000260
+#define VFE_DEMUX_GAIN_0 0x00000288
+#define VFE_DEMUX_GAIN_1 0x0000028C
+#define VFE_CHROMA_UP 0x0000035C
+#define VFE_FRAMEDROP_ENC_Y_CFG 0x00000504
+#define VFE_FRAMEDROP_ENC_CBCR_CFG 0x00000508
+#define VFE_FRAMEDROP_ENC_Y_PATTERN 0x0000050C
+#define VFE_FRAMEDROP_ENC_CBCR_PATTERN 0x00000510
+#define VFE_FRAMEDROP_VIEW_Y 0x00000514
+#define VFE_FRAMEDROP_VIEW_CBCR 0x00000518
+#define VFE_FRAMEDROP_VIEW_Y_PATTERN 0x0000051C
+#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN 0x00000520
+#define VFE_CLAMP_MAX 0x00000524
+#define VFE_CLAMP_MIN 0x00000528
+#define VFE_REALIGN_BUF 0x0000052C
+#define VFE_STATS_CFG 0x00000530
+#define VFE_STATS_AWB_SGW_CFG 0x00000554
+#define VFE_DMI_CFG 0x00000598
+#define VFE_DMI_ADDR 0x0000059C
+#define VFE_DMI_DATA_LO 0x000005A4
+#define VFE_AXI_CFG 0x00000600
+
+#define VFE31_OUTPUT_MODE_PT BIT(0)
+#define VFE31_OUTPUT_MODE_S BIT(1)
+#define VFE31_OUTPUT_MODE_V BIT(2)
+#define VFE31_OUTPUT_MODE_P BIT(3)
+#define VFE31_OUTPUT_MODE_T BIT(4)
+#define VFE31_OUTPUT_MODE_P_ALL_CHNLS BIT(5)
+#define VFE31_OUTPUT_MODE_PRIMARY BIT(6)
+#define VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS BIT(7)
+#define VFE31_OUTPUT_MODE_SECONDARY BIT(8)
+#define VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS BIT(9)
+struct vfe_stats_control {
+ uint8_t ackPending;
+ uint32_t nextFrameAddrBuf;
+ uint32_t droppedStatsFrameCount;
+ uint32_t bufToRender;
+};
+
+struct vfe31_ctrl_type {
+ uint16_t operation_mode; /* streaming or snapshot */
+ struct vfe31_output_path outpath;
+
+ uint32_t vfeImaskCompositePacked;
+
+ spinlock_t stop_flag_lock;
+ spinlock_t update_ack_lock;
+ spinlock_t state_lock;
+ spinlock_t io_lock;
+
+ spinlock_t aec_ack_lock;
+ spinlock_t awb_ack_lock;
+ spinlock_t af_ack_lock;
+ spinlock_t ihist_ack_lock;
+ spinlock_t rs_ack_lock;
+ spinlock_t cs_ack_lock;
+ spinlock_t comp_stats_ack_lock;
+
+ uint32_t extlen;
+ void *extdata;
+
+ int8_t start_ack_pending;
+ int8_t stop_ack_pending;
+ int8_t reset_ack_pending;
+ int8_t update_ack_pending;
+ enum vfe_output_state recording_state;
+ int8_t update_linear;
+ int8_t update_rolloff;
+ int8_t update_la;
+ int8_t update_gamma;
+ enum vfe_output_state liveshot_state;
+
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+ void __iomem *vfebase;
+ void __iomem *camifbase;
+ void *syncdata;
+ uint32_t register_total;
+
+ struct resource *vfemem;
+ struct resource *camifmem;
+ struct resource *vfeio;
+ struct resource *camifio;
+ struct resource *vfeirq;
+ struct regulator *fs_vfe;
+
+ uint32_t stats_comp;
+ atomic_t vstate;
+ uint32_t vfe_capture_count;
+ uint32_t sync_timer_repeat_count;
+ uint32_t sync_timer_state;
+ uint32_t sync_timer_number;
+
+ uint32_t vfeFrameId;
+ uint32_t output1Pattern;
+ uint32_t output1Period;
+ uint32_t output2Pattern;
+ uint32_t output2Period;
+ uint32_t vfeFrameSkipCount;
+ uint32_t vfeFrameSkipPeriod;
+ struct vfe_stats_control afStatsControl;
+ struct vfe_stats_control awbStatsControl;
+ struct vfe_stats_control aecStatsControl;
+ struct vfe_stats_control ihistStatsControl;
+ struct vfe_stats_control rsStatsControl;
+ struct vfe_stats_control csStatsControl;
+
+ /* v4l2 subdev */
+ struct v4l2_subdev subdev;
+ struct platform_device *pdev;
+ struct clk *vfe_clk[5];
+ struct clk *vfe_camif_clk[2];
+ spinlock_t sd_notify_lock;
+ uint32_t hfr_mode;
+ uint32_t frame_skip_cnt;
+ uint32_t frame_skip_pattern;
+ uint32_t snapshot_frame_cnt;
+};
+
+enum VFE31_STATS_NUM {
+ STATS_AE_NUM,
+ STATS_AF_NUM,
+ STATS_AWB_NUM,
+ STATS_RS_NUM,
+ STATS_CS_NUM,
+ STATS_IHIST_NUM,
+ STATS_SKIN_NUM,
+ STATS_MAX_NUM,
+};
+
+struct vfe_cmd_stats_ack {
+ uint32_t nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT 3
+
+struct vfe_cmd_stats_buf {
+ uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+#endif /* __MSM_VFE31_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index a332fba..e2236191 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -292,7 +292,8 @@
"VFE_DEMOSAICv3_BPC_UPDATE"},
{VFE_CMD_XBAR_CFG, VFE_MAX, VFE_MAX},
{VFE_CMD_MODULE_CFG, VFE_MAX, VFE_MAX},
- {VFE_CMD_ZSL, VFE_MAX, VFE_MAX},
+ {VFE_CMD_ZSL, VFE_START, QDSP_CMDQUEUE,
+ "VFE_CMD_ZSL", "VFE_START"},
{VFE_CMD_LINEARIZATION_UPDATE, VFE_MAX, VFE_MAX},
{VFE_CMD_DEMOSAICV3_ABF_UPDATE, VFE_DEMOSAICv3_ABF_CFG,
QDSP_TABLEQUEUE, "VFE_CMD_DEMOSAICV3_ABF_UPDATE",
@@ -452,6 +453,75 @@
y_phy, cbcr_phy);
break;
case MSG_OUTPUT1:
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ kfree(data);
+ return;
+ } else {
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_SECONDARY
+ );
+ CDBG("free_buf = %x\n",
+ (unsigned int) free_buf);
+ if (free_buf) {
+ fack.header = VFE_OUTPUT1_ACK;
+
+ fack.output2newybufferaddress =
+ (void *)(free_buf->ch_paddr[0]);
+
+ fack.output2newcbcrbufferaddress =
+ (void *)(free_buf->ch_paddr[1]);
+
+ cmd_data = &fack;
+ len = sizeof(fack);
+ msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+ cmd_data, len);
+ } else {
+ fack.header = VFE_OUTPUT1_ACK;
+ fack.output2newybufferaddress =
+ (void *)
+ ((struct vfe_endframe *)data)->y_address;
+ fack.output2newcbcrbufferaddress =
+ (void *)
+ ((struct vfe_endframe *)data)->cbcr_address;
+ cmd_data = &fack;
+ len = sizeof(fack);
+ msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+ cmd_data, len);
+ }
+ }
+ y_phy = ((struct vfe_endframe *)data)->y_address;
+ cbcr_phy = ((struct vfe_endframe *)data)->cbcr_address;
+
+
+ CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+ y_phy, cbcr_phy);
+ if (free_buf) {
+ for (i = 0; i < 3; i++) {
+ if (vfe2x_ctrl->free_buf.buf[i].
+ ch_paddr[0] == y_phy) {
+ vfe2x_ctrl->free_buf.
+ buf[i].ch_paddr[0] =
+ free_buf->ch_paddr[0];
+ vfe2x_ctrl->free_buf.
+ buf[i].ch_paddr[1] =
+ free_buf->ch_paddr[1];
+ break;
+ }
+ }
+ if (i == 3)
+ CDBG("Address doesnt match\n");
+ }
+ memcpy(((struct vfe_frame_extra *)extdata),
+ &((struct vfe_endframe *)data)->extra,
+ sizeof(struct vfe_frame_extra));
+
+ vfe2x_ctrl->vfeFrameId =
+ ((struct vfe_frame_extra *)extdata)->frame_id;
+ vfe_send_outmsg(&vfe2x_ctrl->subdev,
+ MSG_ID_OUTPUT_SECONDARY,
+ y_phy, cbcr_phy);
+ break;
case MSG_OUTPUT2:
if (op_mode & SNAPSHOT_MASK_MODE) {
kfree(data);
@@ -601,6 +671,7 @@
}
if (MSG_TABLE_CMD_ACK == id) {
spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+ vfe2x_ctrl->tableack_pending = 0;
if (list_empty(&vfe2x_ctrl->table_q)) {
if (vfe2x_ctrl->start_pending) {
CDBG("Send START\n");
@@ -633,14 +704,12 @@
cmd_data, len);
vfe2x_ctrl->update_pending = 0;
}
- vfe2x_ctrl->tableack_pending = 0;
spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
return;
}
table_pending = list_first_entry(&vfe2x_ctrl->table_q,
struct table_cmd, list);
if (!table_pending) {
- vfe2x_ctrl->tableack_pending = 0;
spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
return;
}
@@ -673,16 +742,32 @@
if (mode == OUTPUT_SEC) {
/* Thumbnail */
- ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
- ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
- ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
- ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
- bptr = &ao->output1buffer3_y_phy;
- for (cnt = 0; cnt < 6; cnt++) {
- *bptr = ad->pong.ch_paddr[0];
- bptr++;
- *bptr = ad->pong.ch_paddr[1];
- bptr++;
+ if (vfe2x_ctrl->zsl_mode) {
+ ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+ ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+ ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+ ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+ ao->output1buffer3_y_phy = ad->free_buf.ch_paddr[0];
+ ao->output1buffer3_cbcr_phy = ad->free_buf.ch_paddr[1];
+ bptr = &ao->output1buffer4_y_phy;
+ for (cnt = 0; cnt < 5; cnt++) {
+ *bptr = ad->pong.ch_paddr[0];
+ bptr++;
+ *bptr = ad->pong.ch_paddr[1];
+ bptr++;
+ }
+ } else {
+ ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+ ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+ ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+ ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+ bptr = &ao->output1buffer3_y_phy;
+ for (cnt = 0; cnt < 6; cnt++) {
+ *bptr = ad->pong.ch_paddr[0];
+ bptr++;
+ *bptr = ad->pong.ch_paddr[1];
+ bptr++;
+ }
}
} else if (mode == OUTPUT_PRIM && o_mode != SNAPSHOT_MASK_MODE) {
/* Preview */
@@ -775,8 +860,13 @@
else if (path == VFE_MSG_OUTPUT_SECONDARY)
outch = &vfe2x_ctrl->thumb;
} else {
- if (path == VFE_MSG_OUTPUT_PRIMARY)
- outch = &vfe2x_ctrl->prev;
+ if (path == VFE_MSG_OUTPUT_PRIMARY) {
+ if (vfe2x_ctrl->zsl_mode)
+ outch = &vfe2x_ctrl->zsl_prim;
+ else
+ outch = &vfe2x_ctrl->prev;
+ } else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ outch = &vfe2x_ctrl->zsl_sec;
}
if (outch->free_buf.ch_paddr[0])
return &outch->free_buf;
@@ -797,8 +887,13 @@
else if (path == VFE_MSG_OUTPUT_SECONDARY)
outch = &vfe2x_ctrl->thumb;
} else {
- if (path == VFE_MSG_OUTPUT_PRIMARY)
- outch = &vfe2x_ctrl->prev;
+ if (path == VFE_MSG_OUTPUT_PRIMARY) {
+ if (vfe2x_ctrl->zsl_mode)
+ outch = &vfe2x_ctrl->zsl_prim;
+ else
+ outch = &vfe2x_ctrl->prev;
+ } else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ outch = &vfe2x_ctrl->zsl_sec;
}
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
/* Configure Preview Ping Pong */
@@ -823,8 +918,13 @@
else if (path == VFE_MSG_OUTPUT_PRIMARY)
ch = &vfe2x_ctrl->snap;
} else {
- if (path == VFE_MSG_OUTPUT_PRIMARY)
- ch = &vfe2x_ctrl->prev;
+ if (path == VFE_MSG_OUTPUT_PRIMARY) {
+ if (vfe2x_ctrl->zsl_mode)
+ ch = &vfe2x_ctrl->zsl_prim;
+ else
+ ch = &vfe2x_ctrl->prev;
+ } else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ ch = &vfe2x_ctrl->zsl_sec;
}
BUG_ON(ch == NULL);
@@ -1121,6 +1221,7 @@
case VFE_CMD_START:
case VFE_CMD_CAPTURE:
case VFE_CMD_CAPTURE_RAW:
+ case VFE_CMD_ZSL:
spin_lock_irqsave(&vfe2x_ctrl->table_lock,
flags);
if ((!list_empty(&vfe2x_ctrl->table_q)) ||
@@ -1185,6 +1286,7 @@
case CMD_AXI_CFG_SEC: {
CDBG("CMD_AXI_CFG_SEC\n");
raw_mode = 0;
+ vfe2x_ctrl->zsl_mode = 0;
axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
if (!axio) {
pr_err("NULL axio\n");
@@ -1237,6 +1339,7 @@
case CMD_AXI_CFG_PRIM: {
CDBG("CMD_AXI_CFG_PRIM : %d\n", op_mode);
raw_mode = 0;
+ vfe2x_ctrl->zsl_mode = 0;
axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
if (!axio) {
pr_err("NULL axio\n");
@@ -1299,9 +1402,74 @@
cmd_data = axio;
}
break;
+ case CMD_AXI_CFG_ZSL: {
+ CDBG("CMD_AXI_CFG_ZSL: %d\n", op_mode);
+ raw_mode = 0;
+ vfe2x_ctrl->zsl_mode = 1;
+ axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+ if (!axio) {
+ pr_err("NULL axio\n");
+ rc = -ENOMEM;
+ goto config_failure;
+ }
+
+ if (copy_from_user((char *)axio + 4,
+ (void __user *)(vfecmd.value),
+ sizeof(struct axiout))) {
+ pr_err("copy_from_user failed\n");
+ rc = -EFAULT;
+ goto config_done;
+ }
+ if (!vfe2x_ctrl->reconfig_vfe) {
+ rc = vfe2x_configure_pingpong_buffers(
+ VFE_MSG_V2X_PREVIEW,
+ VFE_MSG_OUTPUT_PRIMARY);
+ rc = vfe2x_configure_pingpong_buffers(
+ VFE_MSG_V2X_PREVIEW,
+ VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto config_done;
+ }
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_PRIMARY);
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_SECONDARY);
+ } else {
+ vfe2x_ctrl->prev.ping.ch_paddr[0] =
+ vfe2x_ctrl->free_buf.buf[0].ch_paddr[0];
+ vfe2x_ctrl->prev.ping.ch_paddr[1] =
+ vfe2x_ctrl->free_buf.buf[0].ch_paddr[1];
+ vfe2x_ctrl->prev.pong.ch_paddr[0] =
+ vfe2x_ctrl->free_buf.buf[1].ch_paddr[0];
+ vfe2x_ctrl->prev.pong.ch_paddr[1] =
+ vfe2x_ctrl->free_buf.buf[1].ch_paddr[1];
+ vfe2x_ctrl->prev.free_buf.ch_paddr[0] =
+ vfe2x_ctrl->free_buf.buf[2].ch_paddr[0];
+ vfe2x_ctrl->prev.free_buf.ch_paddr[1] =
+ vfe2x_ctrl->free_buf.buf[2].ch_paddr[1];
+ vfe2x_ctrl->reconfig_vfe = 0;
+ }
+ header = cmds_map[vfecmd.id].vfe_id;
+ queue = cmds_map[vfecmd.id].queue;
+ if (header == -1 && queue == -1) {
+ rc = -EFAULT;
+ goto config_done;
+ }
+ *(uint32_t *)axio = header;
+ vfe_7x_config_axi(OUTPUT_PRIM, &vfe2x_ctrl->zsl_prim, axio);
+ vfe_7x_config_axi(OUTPUT_SEC, &vfe2x_ctrl->zsl_sec, axio);
+ cmd_data = axio;
+ }
+ break;
case CMD_AXI_CFG_SEC|CMD_AXI_CFG_PRIM: {
CDBG("CMD_AXI_CFG_SEC|PRIM\n");
raw_mode = 0;
+ vfe2x_ctrl->zsl_mode = 0;
axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
if (!axio) {
pr_err("NULL axio\n");
@@ -1440,20 +1608,22 @@
spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
} else {
if (queue == QDSP_TABLEQUEUE) {
- CDBG("sending table cmd\n");
spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+ CDBG("sending table cmd\n");
+ vfe2x_ctrl->tableack_pending = 1;
rc = msm_adsp_write(vfe_mod, queue,
cmd_data, vfecmd.length + 4);
- vfe2x_ctrl->tableack_pending = 1;
spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
} else {
- CDBG("send n-table cmd\n");
if (*(uint32_t *)cmd_data == VFE_OUTPUT2_ACK) {
uint32_t *ptr = cmd_data;
CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
}
+ spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+ CDBG("send n-table cmd\n");
rc = msm_adsp_write(vfe_mod, queue,
cmd_data, vfecmd.length + 4);
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
CDBG("%x\n", vfecmd.length + 4);
}
}
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 2b77159..2f2d3c6 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -85,6 +85,10 @@
struct buf_info raw;
struct buf_info thumb;
struct prev_free_buf_info free_buf;
+ struct buf_info zsl_prim;
+ struct buf_info zsl_sec;
+ struct prev_free_buf_info zsl_free_buf[2];
+
spinlock_t table_lock;
struct list_head table_q;
@@ -106,6 +110,7 @@
struct clk *vfe_clk[3];
spinlock_t sd_notify_lock;
uint32_t reconfig_vfe;
+ uint32_t zsl_mode;
} __packed;
struct vfe_frame_extra {
diff --git a/drivers/media/video/msm/ov7692.c b/drivers/media/video/msm/ov7692.c
index 7372156..7696b44 100644
--- a/drivers/media/video/msm/ov7692.c
+++ b/drivers/media/video/msm/ov7692.c
@@ -522,6 +522,8 @@
case CFG_PWR_DOWN:
rc = ov7692_power_down();
break;
+ case CFG_SET_EFFECT:
+ break;
default:
rc = -EFAULT;
break;
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index ac133d2..3052832 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -3,6 +3,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/io
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
+obj-$(CONFIG_OV5647) += ov5647_v4l2.o
obj-$(CONFIG_IMX074) += imx074_v4l2.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_IMX091) += imx091.o
@@ -12,4 +13,3 @@
obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd_v4l2.o
-obj-$(CONFIG_OV5647) += ov5647_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index af9d1f4..5330d7b 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -168,6 +168,19 @@
},
};
+static struct msm_camera_csi_params imx074_csic_params = {
+ .data_format = CSI_10BIT,
+ .lane_cnt = 4,
+ .lane_assign = 0xe4,
+ .dpcm_scheme = 0,
+ .settle_cnt = 0x14,
+};
+
+static struct msm_camera_csi_params *imx074_csic_params_array[] = {
+ &imx074_csic_params,
+ &imx074_csic_params,
+};
+
static struct msm_camera_csid_vc_cfg imx074_cid_cfg[] = {
{0, CSI_RAW10, CSI_DECODE_10BIT},
{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
@@ -288,6 +301,7 @@
.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
.sensor_setting = msm_sensor_setting,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
@@ -323,6 +337,7 @@
.sensor_id_info = &imx074_id_info,
.sensor_exp_gain_info = &imx074_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
+ .csic_params = &imx074_csic_params_array[0],
.csi_params = &imx074_csi_params_array[0],
.msm_sensor_mutex = &imx074_mut,
.sensor_i2c_driver = &imx074_i2c_driver,
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 1112be7..3da7c5d 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -214,59 +214,6 @@
return rc;
}
-int32_t msm_sensor_setting2(struct msm_sensor_ctrl_t *s_ctrl,
- int update_type, int res)
-{
- int32_t rc = 0;
- static int csi_config;
-
- s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
- if (csi_config == 0 || res == 0)
- msleep(66);
- else
- msleep(266);
- if (update_type == MSM_SENSOR_REG_INIT) {
- CDBG("Register INIT\n");
- s_ctrl->curr_csi_params = NULL;
- msm_camera_i2c_write(
- s_ctrl->sensor_i2c_client,
- 0x103, 0x1,
- MSM_CAMERA_I2C_BYTE_DATA);
- msm_sensor_enable_debugfs(s_ctrl);
- msm_sensor_write_init_settings(s_ctrl);
- csi_config = 0;
- } else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
- CDBG("PERIODIC : %d\n", res);
- msm_sensor_write_conf_array(
- s_ctrl->sensor_i2c_client,
- s_ctrl->msm_sensor_reg->mode_settings, res);
- msleep(30);
- if (!csi_config) {
- s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
- CDBG("CSI config in progress\n");
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CSIC_CFG,
- s_ctrl->curr_csic_params);
- CDBG("CSI config is done\n");
- mb();
- msleep(30);
- csi_config = 1;
- msm_camera_i2c_write(
- s_ctrl->sensor_i2c_client,
- 0x100, 0x1,
- MSM_CAMERA_I2C_BYTE_DATA);
- }
- msm_camera_i2c_write(
- s_ctrl->sensor_i2c_client,
- 0x4800, 0x4,
- MSM_CAMERA_I2C_BYTE_DATA);
- msleep(266);
- s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
- msleep(50);
- }
- return rc;
-}
-
int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res)
{
@@ -298,6 +245,10 @@
msleep(30);
csi_config = 1;
}
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_PCLK_CHANGE,
+ &s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
+
s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
msleep(50);
}
@@ -365,8 +316,13 @@
s_ctrl->msm_sensor_reg->
output_settings[res].line_length_pclk;
- if (s_ctrl->func_tbl->sensor_setting
- (s_ctrl, MSM_SENSOR_UPDATE_PERIODIC, res) < 0)
+ if (s_ctrl->sensordata->pdata->is_csic)
+ rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
+ MSM_SENSOR_UPDATE_PERIODIC, res);
+ else
+ rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
+ MSM_SENSOR_UPDATE_PERIODIC, res);
+ if (rc < 0)
return rc;
s_ctrl->curr_res = res;
}
@@ -386,8 +342,12 @@
s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
s_ctrl->cam_mode = mode;
- rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
- MSM_SENSOR_REG_INIT, 0);
+ if (s_ctrl->sensordata->pdata->is_csic)
+ rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
+ MSM_SENSOR_REG_INIT, 0);
+ else
+ rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
+ MSM_SENSOR_REG_INIT, 0);
}
return rc;
}
@@ -661,6 +621,8 @@
msm_sensor_disable_i2c_mux(
data->sensor_platform_info->i2c_conf);
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ msleep(20);
if (data->sensor_platform_info->ext_power_ctrl != NULL)
data->sensor_platform_info->ext_power_ctrl(0);
msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
@@ -679,7 +641,6 @@
return 0;
}
-
int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
@@ -739,7 +700,10 @@
if (rc < 0)
goto probe_fail;
- rc = msm_sensor_match_id(s_ctrl);
+ if (s_ctrl->func_tbl->sensor_match_id)
+ rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+ else
+ rc = msm_sensor_match_id(s_ctrl);
if (rc < 0)
goto probe_fail;
@@ -770,7 +734,7 @@
msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
goto power_down;
probe_fail:
- CDBG("%s_i2c_probe failed\n", client->name);
+ pr_err("%s_i2c_probe failed\n", client->name);
power_down:
if (rc > 0)
rc = 0;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index d1a6cee..421e1d1 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -120,6 +120,8 @@
uint16_t, uint32_t);
int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
int update_type, int rt);
+ int32_t (*sensor_csi_setting) (struct msm_sensor_ctrl_t *,
+ int update_type, int rt);
int32_t (*sensor_set_sensor_mode)
(struct msm_sensor_ctrl_t *, int, int);
int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
@@ -130,6 +132,7 @@
int (*sensor_power_down)
(struct msm_sensor_ctrl_t *);
int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
+ int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
};
struct msm_sensor_ctrl_t {
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index a6bc653..e6e2d52 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -465,7 +465,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = mt9e013_write_exp_gain,
.sensor_write_snapshot_exp_gain = mt9e013_write_exp_snapshot_gain,
- .sensor_setting = msm_sensor_setting1,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index fed514c..7c23fe6 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -12,6 +12,7 @@
*/
#include "msm_sensor.h"
+#include "msm.h"
#define SENSOR_NAME "ov5647"
#define PLATFORM_DRIVER_NAME "msm_camera_ov5647"
#define ov5647_obj ov5647_##obj
@@ -272,16 +273,16 @@
.y_output = 0x7A0, /*1952*/
.line_length_pclk = 0xA8C,
.frame_length_lines = 0x7B0,
- .vt_pixel_clk = 159408000,
+ .vt_pixel_clk = 79704000,
.op_pixel_clk = 159408000,
.binning_factor = 0x0,
},
{ /* For PREVIEW */
- .x_output = 0x500, /*2608*/ /*for 5Mp*/
- .y_output = 0x3C0, /*1952*/
- .line_length_pclk = 0x768 * 2,
+ .x_output = 0x500, /*1280*/
+ .y_output = 0x3C0, /*960*/
+ .line_length_pclk = 0x768,
.frame_length_lines = 0x3D8,
- .vt_pixel_clk = 159408000,
+ .vt_pixel_clk = 55969920,
.op_pixel_clk = 159408000,
.binning_factor = 0x0,
},
@@ -333,27 +334,31 @@
, gain, line, line);
if (line > 1964) {
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)((line+4) >> 8),
MSM_CAMERA_I2C_BYTE_DATA);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
(uint8_t)((line+4) & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
max_line = line + 4;
} else if (line > 1968) {
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)((line+4) >> 8),
MSM_CAMERA_I2C_BYTE_DATA);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
(uint8_t)((line+4) & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
max_line = 1968;
}
@@ -447,24 +452,24 @@
if (line > 980) {
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)((line+4) >> 8),
MSM_CAMERA_I2C_BYTE_DATA);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset + 1,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
(uint8_t)((line+4) & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
max_line = line + 4;
} else if (line > 984) {
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)(984 >> 8),
MSM_CAMERA_I2C_BYTE_DATA);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_exp_gain_info->vert_offset + 1 ,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines + 1 ,
(uint8_t)(984 & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
max_line = 984;
@@ -568,33 +573,118 @@
.video = &ov5647_subdev_video_ops,
};
+int32_t ov5647_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ struct msm_camera_sensor_info *info = NULL;
+ unsigned short rdata;
+ int rc;
+
+ info = s_ctrl->sensordata;
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x4202, 0xf,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msleep(20);
+ rc = msm_camera_i2c_read(s_ctrl->sensor_i2c_client, 0x3018,
+ &rdata, MSM_CAMERA_I2C_WORD_DATA);
+ CDBG("ov5647_sensor_power_down: %d\n", rc);
+ rdata |= 0x18;
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ 0x3018, rdata,
+ MSM_CAMERA_I2C_WORD_DATA);
+ msleep(20);
+ gpio_direction_output(info->sensor_pwd, 1);
+ usleep_range(5000, 5100);
+ msm_sensor_power_down(s_ctrl);
+ return 0;
+}
+
int32_t ov5647_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
struct msm_camera_sensor_info *info = NULL;
+ info = s_ctrl->sensordata;
+ gpio_direction_output(info->sensor_pwd, 1);
+ gpio_direction_output(info->sensor_reset, 0);
+ usleep_range(10000, 11000);
+ if (info->pmic_gpio_enable) {
+ info->pmic_gpio_enable = 0;
+ lcd_camera_power_onoff(1);
+ }
+ usleep_range(10000, 11000);
rc = msm_sensor_power_up(s_ctrl);
if (rc < 0) {
CDBG("%s: msm_sensor_power_up failed\n", __func__);
return rc;
}
- info = s_ctrl->sensordata;
- gpio_direction_output(info->sensor_pwd, 1);
- gpio_direction_output(info->sensor_reset, 0);
- usleep_range(1000, 1100);
/* turn on ldo and vreg */
- if (info->pmic_gpio_enable)
- lcd_camera_power_onoff(1);
gpio_direction_output(info->sensor_pwd, 0);
- usleep_range(4000, 4100);
+ msleep(20);
gpio_direction_output(info->sensor_reset, 1);
- usleep_range(2000, 2100);
+ msleep(25);
return rc;
}
+
+int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+ int update_type, int res)
+{
+ int32_t rc = 0;
+ static int csi_config;
+
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ if (csi_config == 0 || res == 0)
+ msleep(66);
+ else
+ msleep(266);
+ msm_camera_i2c_write(
+ s_ctrl->sensor_i2c_client,
+ 0x4800, 0x25,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (update_type == MSM_SENSOR_REG_INIT) {
+ CDBG("Register INIT\n");
+ s_ctrl->curr_csi_params = NULL;
+ msm_camera_i2c_write(
+ s_ctrl->sensor_i2c_client,
+ 0x103, 0x1,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_sensor_enable_debugfs(s_ctrl);
+ msm_sensor_write_init_settings(s_ctrl);
+ csi_config = 0;
+ } else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+ CDBG("PERIODIC : %d\n", res);
+ msm_sensor_write_conf_array(
+ s_ctrl->sensor_i2c_client,
+ s_ctrl->msm_sensor_reg->mode_settings, res);
+ msleep(30);
+ if (!csi_config) {
+ s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+ CDBG("CSI config in progress\n");
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_CSIC_CFG,
+ s_ctrl->curr_csic_params);
+ CDBG("CSI config is done\n");
+ mb();
+ msleep(30);
+ csi_config = 1;
+ msm_camera_i2c_write(
+ s_ctrl->sensor_i2c_client,
+ 0x100, 0x1,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ msm_camera_i2c_write(
+ s_ctrl->sensor_i2c_client,
+ 0x4800, 0x4,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msleep(266);
+ s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+ msleep(50);
+ }
+ return rc;
+}
static struct msm_sensor_fn_t ov5647_func_tbl = {
.sensor_start_stream = msm_sensor_start_stream,
.sensor_stop_stream = msm_sensor_stop_stream,
@@ -603,13 +693,13 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = ov5647_write_prev_exp_gain,
.sensor_write_snapshot_exp_gain = ov5647_write_pict_exp_gain,
- .sensor_setting = msm_sensor_setting2,
+ .sensor_csi_setting = ov5647_sensor_setting,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
.sensor_config = msm_sensor_config,
.sensor_power_up = ov5647_sensor_power_up,
- .sensor_power_down = msm_sensor_power_down,
+ .sensor_power_down = ov5647_sensor_power_down,
};
static struct msm_sensor_reg_t ov5647_regs = {
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
index 99e96f0..9fe2e8a 100644
--- a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -688,7 +688,7 @@
.sensor_group_hold_on = msm_sensor_group_hold_on,
.sensor_group_hold_off = msm_sensor_group_hold_off,
.sensor_set_fps = ov7692_sensor_set_fps,
- .sensor_setting = msm_sensor_setting3,
+ .sensor_csi_setting = msm_sensor_setting3,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index 17291ff..61c693e 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -229,7 +229,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
- .sensor_setting = msm_sensor_setting1,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index 699f0dd..6671073 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -450,7 +450,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = s5k4e1_write_prev_exp_gain,
.sensor_write_snapshot_exp_gain = s5k4e1_write_pict_exp_gain,
- .sensor_setting = msm_sensor_setting1,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/wfd/Makefile b/drivers/media/video/msm/wfd/Makefile
index 2b39e66..5decaca 100644
--- a/drivers/media/video/msm/wfd/Makefile
+++ b/drivers/media/video/msm/wfd/Makefile
@@ -2,3 +2,4 @@
obj-y += enc-subdev.o
obj-y += vsg-subdev.o
obj-y += wfd-ioctl.o
+obj-y += wfd-util.o
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index d531c22..57dff2e 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -1311,6 +1311,204 @@
return rc;
}
+static long venc_set_multislicing_mode(struct video_client_ctx *client_ctx,
+ __u32 control, __s32 value)
+{
+ int rc = 0;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size vcd_frame_size;
+ struct vcd_buffer_requirement vcd_buf_req;
+ struct vcd_property_multi_slice vcd_multi_slice;
+
+ if (!client_ctx) {
+ WFD_MSG_ERR("Invalid parameters\n");
+ rc = -EINVAL;
+ goto set_multislicing_mode_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz =
+ sizeof(vcd_frame_size);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_frame_size);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get frame size\n");
+ goto set_multislicing_mode_fail;
+ }
+
+ rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get buf reqs\n");
+ goto set_multislicing_mode_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_MULTI_SLICE;
+ vcd_property_hdr.sz = sizeof(vcd_multi_slice);
+ rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &vcd_multi_slice);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get multi slice\n");
+ goto set_multislicing_mode_fail;
+ }
+
+ switch (control) {
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ if (vcd_multi_slice.m_slice_sel !=
+ VCD_MSLICE_BY_BYTE_COUNT) {
+ WFD_MSG_ERR("Not in proper mode\n");
+ goto set_multislicing_mode_fail;
+ }
+ vcd_multi_slice.m_slice_size = value;
+ break;
+
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ if (vcd_multi_slice.m_slice_sel !=
+ VCD_MSLICE_BY_MB_COUNT) {
+ WFD_MSG_ERR("Not in proper mode\n");
+ goto set_multislicing_mode_fail;
+ }
+ vcd_multi_slice.m_slice_size = value;
+ break;
+
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ switch (value) {
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+ vcd_multi_slice.m_slice_sel = VCD_MSLICE_OFF;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+ vcd_multi_slice.m_slice_sel = VCD_MSLICE_BY_MB_COUNT;
+ /* Just a temporary size until client calls
+ * V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB */
+ vcd_multi_slice.m_slice_size =
+ (vcd_frame_size.stride / 16) *
+ (vcd_frame_size.scan_lines / 16);
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+ vcd_multi_slice.m_slice_sel = VCD_MSLICE_BY_BYTE_COUNT;
+ /* Just a temporary size until client calls
+ * V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES */
+ vcd_multi_slice.m_slice_size = vcd_buf_req.sz;
+ break;
+ default:
+ WFD_MSG_ERR("Unrecognized mode %d\n", value);
+ rc = -ENOTSUPP;
+ goto set_multislicing_mode_fail;
+ }
+
+ break;
+ default:
+ rc = -EINVAL;
+ goto set_multislicing_mode_fail;
+ }
+
+ rc = vcd_set_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &vcd_multi_slice);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set multi slice\n");
+ goto set_multislicing_mode_fail;
+ }
+
+set_multislicing_mode_fail:
+ return rc;
+}
+
+static long venc_get_multislicing_mode(struct video_client_ctx *client_ctx,
+ __u32 control, __s32 *value)
+{
+ int rc = 0;
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_frame_size vcd_frame_size;
+ struct vcd_buffer_requirement vcd_buf_req;
+ struct vcd_property_multi_slice vcd_multi_slice;
+
+ if (!client_ctx) {
+ WFD_MSG_ERR("Invalid parameters\n");
+ rc = -EINVAL;
+ goto get_multislicing_mode_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+ vcd_property_hdr.sz =
+ sizeof(vcd_frame_size);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_frame_size);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get frame size\n");
+ goto get_multislicing_mode_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_MULTI_SLICE;
+ vcd_property_hdr.sz = sizeof(vcd_multi_slice);
+ rc = vcd_get_property(client_ctx->vcd_handle, &vcd_property_hdr,
+ &vcd_multi_slice);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get multi slice\n");
+ goto get_multislicing_mode_fail;
+ }
+
+ rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &vcd_buf_req);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get buf reqs\n");
+ goto get_multislicing_mode_fail;
+ }
+
+ switch (control) {
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ if (vcd_multi_slice.m_slice_sel == VCD_MSLICE_BY_BYTE_COUNT)
+ *value = vcd_multi_slice.m_slice_size;
+ else {
+ WFD_MSG_ERR("Invalid query when in slice mode %d\n",
+ vcd_multi_slice.m_slice_sel);
+ rc = -EINVAL;
+ goto get_multislicing_mode_fail;
+ }
+ break;
+
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ if (vcd_multi_slice.m_slice_sel == VCD_MSLICE_BY_MB_COUNT)
+ *value = vcd_multi_slice.m_slice_size;
+ else {
+ WFD_MSG_ERR("Invalid query when in slice mode %d\n",
+ vcd_multi_slice.m_slice_sel);
+ rc = -EINVAL;
+ goto get_multislicing_mode_fail;
+ }
+ break;
+
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ switch (vcd_multi_slice.m_slice_sel) {
+ case VCD_MSLICE_OFF:
+ *value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE;
+ break;
+ case VCD_MSLICE_BY_MB_COUNT:
+ *value = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB;
+ break;
+ case VCD_MSLICE_BY_BYTE_COUNT:
+ *value = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES;
+ break;
+ default:
+ WFD_MSG_ERR("Encoder in an unknown mode %d\n",
+ vcd_multi_slice.m_slice_sel);
+ rc = -ENOENT;
+ goto get_multislicing_mode_fail;
+
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ goto get_multislicing_mode_fail;
+ }
+
+get_multislicing_mode_fail:
+ return rc;
+}
+
static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
{
struct mem_region *mregion = arg;
@@ -1675,6 +1873,12 @@
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
rc = venc_set_header_mode(client_ctx, ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ rc = venc_set_multislicing_mode(client_ctx, ctrl->id,
+ ctrl->value);
+ break;
default:
WFD_MSG_ERR("Set property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
@@ -1728,6 +1932,12 @@
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
rc = venc_get_header_mode(client_ctx, &ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ rc = venc_get_multislicing_mode(client_ctx, ctrl->id,
+ &ctrl->value);
+ break;
default:
WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.c b/drivers/media/video/msm/wfd/vsg-subdev.c
index 7f5a4ad..ac8e4e7 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.c
+++ b/drivers/media/video/msm/wfd/vsg-subdev.c
@@ -21,6 +21,7 @@
#define DEFAULT_FRAME_INTERVAL (66*NSEC_PER_MSEC)
#define DEFAULT_MAX_FRAME_INTERVAL (1*NSEC_PER_SEC)
#define DEFAULT_MODE ((enum vsg_modes)VSG_MODE_CFR)
+#define MAX_BUFS_BUSY_WITH_ENC 5
static int vsg_release_input_buffer(struct vsg_context *context,
struct vsg_buf_info *buf)
@@ -55,25 +56,10 @@
if (buf->flags & VSG_NEVER_SET_LAST_BUFFER)
WFD_MSG_WARN("Shouldn't be setting this to last buffer\n");
- /* Update the last buffer and memcpy the data into the back up buffer*/
context->last_buffer = buf;
WFD_MSG_DBG("Setting last buffer to paddr %p\n",
(void *)buf->mdp_buf_info.paddr);
-
- if (context->regen_buffer) {
- int buf_size;
- void *cookie;
-
- /*FIXME: Somewhat hacky, looking into cookie */
- cookie = buf->mdp_buf_info.cookie;
- buf_size = ((struct mem_region *)cookie)->size;
-
- memcpy((void *)context->regen_buffer->mdp_buf_info.kvaddr,
- (void *)buf->mdp_buf_info.kvaddr,
- buf_size);
- context->send_regen_buffer = false;
- }
}
static void vsg_encode_helper_func(struct work_struct *task)
@@ -101,7 +87,7 @@
struct vsg_encode_work *encode_work;
struct vsg_context *context = work->context;
struct vsg_buf_info *buf_info = NULL, *temp = NULL;
- int rc = 0;
+ int rc = 0, count = 0;
mutex_lock(&context->mutex);
if (list_empty(&context->free_queue.node)) {
@@ -113,6 +99,14 @@
goto err_skip_encode;
}
+ list_for_each_entry(temp, &context->busy_queue.node, node) {
+ if (++count > MAX_BUFS_BUSY_WITH_ENC) {
+ WFD_MSG_WARN("Skipping encode, too many "
+ "buffers with encoder");
+ goto err_skip_encode;
+ }
+ }
+
buf_info = list_first_entry(&context->free_queue.node,
struct vsg_buf_info, node);
list_del(&buf_info->node);
@@ -122,18 +116,20 @@
hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(
context->max_frame_interval));
+ temp = NULL;
list_for_each_entry(temp, &context->busy_queue.node, node) {
if (mdp_buf_info_equals(&temp->mdp_buf_info,
&buf_info->mdp_buf_info)) {
- WFD_MSG_DBG("Buffer %p already in queue "
- "to be encoded, delaying encoding\n",
- (void *)temp->mdp_buf_info.paddr);
- list_add(&buf_info->node, &context->free_queue.node);
- /* just skip the push to encoder*/
- goto err_skip_encode;
+ temp->flags |= VSG_NEVER_RELEASE;
}
}
+ if (context->last_buffer &&
+ mdp_buf_info_equals(&context->last_buffer->mdp_buf_info,
+ &buf_info->mdp_buf_info)) {
+ context->last_buffer->flags |= VSG_NEVER_RELEASE;
+ }
+
encode_work = kmalloc(sizeof(*encode_work), GFP_KERNEL);
encode_work->buf = buf_info;
encode_work->context = context;
@@ -143,37 +139,34 @@
WFD_MSG_ERR("Queueing buffer for encode failed\n");
kfree(encode_work);
encode_work = NULL;
- goto err_queue_encode_fail;
+ goto err_skip_encode;
}
buf_info->flags |= VSG_BUF_BEING_ENCODED;
if (!(buf_info->flags & VSG_NEVER_SET_LAST_BUFFER)) {
- bool is_same_buffer = context->last_buffer &&
- mdp_buf_info_equals(
- &context->last_buffer->mdp_buf_info,
- &buf_info->mdp_buf_info);
-
- if (!context->last_buffer || !is_same_buffer) {
+ if (context->last_buffer) {
struct vsg_buf_info *old_last_buffer =
context->last_buffer;
bool last_buf_with_us = old_last_buffer &&
!(old_last_buffer->flags &
VSG_BUF_BEING_ENCODED);
+ bool can_release = old_last_buffer &&
+ !(old_last_buffer->flags &
+ VSG_NEVER_RELEASE);
- if (old_last_buffer && last_buf_with_us) {
+ if (old_last_buffer && last_buf_with_us
+ && can_release) {
vsg_release_input_buffer(context,
old_last_buffer);
kfree(old_last_buffer);
}
-
- vsg_set_last_buffer(context, buf_info);
}
+ vsg_set_last_buffer(context, buf_info);
}
list_add_tail(&buf_info->node, &context->busy_queue.node);
err_skip_encode:
mutex_unlock(&context->mutex);
-err_queue_encode_fail:
kfree(work);
}
@@ -208,24 +201,12 @@
goto err_locked;
}
- if (context->regen_buffer) {
- if (context->send_regen_buffer) {
- buf_to_encode =
- context->regen_buffer;
- } else {
- buf_to_encode = context->last_buffer;
- }
-
- context->send_regen_buffer =
- !context->send_regen_buffer;
- } else {
- WFD_MSG_WARN("Have no regen buffer\n");
- buf_to_encode = context->last_buffer;
- }
+ buf_to_encode = context->last_buffer;
info->mdp_buf_info = buf_to_encode->mdp_buf_info;
- info->flags = buf_to_encode->flags;
+ info->flags = 0;
INIT_LIST_HEAD(&info->node);
+
list_add_tail(&info->node, &context->free_queue.node);
WFD_MSG_DBG("Regenerated frame with paddr %p\n",
(void *)info->mdp_buf_info.paddr);
@@ -263,7 +244,7 @@
goto threshold_err_bad_param;
} else if (!context) {
WFD_MSG_ERR("Context not proper in %s", __func__);
- goto threshold_err_bad_param;
+ goto threshold_err_no_context;
}
INIT_WORK(&task->work, vsg_timer_helper_func);
@@ -274,6 +255,8 @@
hrtimer_forward_now(&context->threshold_timer, ns_to_ktime(
context->max_frame_interval));
return HRTIMER_RESTART;
+threshold_err_no_context:
+ return HRTIMER_NORESTART;
}
int vsg_init(struct v4l2_subdev *sd, u32 val)
@@ -302,8 +285,7 @@
HRTIMER_MODE_REL);
context->threshold_timer.function = vsg_threshold_timeout_func;
- context->last_buffer = context->regen_buffer = NULL;
- context->send_regen_buffer = false;
+ context->last_buffer = NULL;
context->mode = DEFAULT_MODE;
context->state = VSG_STATE_NONE;
mutex_init(&context->mutex);
@@ -321,7 +303,6 @@
context = (struct vsg_context *)sd->dev_priv;
destroy_workqueue(context->work_queue);
- kfree(context->regen_buffer);
kfree(context);
return 0;
}
@@ -415,25 +396,18 @@
list_for_each_safe(pos, next, &context->free_queue.node) {
struct vsg_buf_info *temp =
list_entry(pos, struct vsg_buf_info, node);
- bool is_last_buffer, is_regen_buffer;
-
- is_last_buffer = context->last_buffer &&
+ bool is_last_buffer = context->last_buffer &&
mdp_buf_info_equals(
&context->last_buffer->mdp_buf_info,
&temp->mdp_buf_info);
- is_regen_buffer = context->regen_buffer &&
- mdp_buf_info_equals(
- &context->regen_buffer->mdp_buf_info,
- &temp->mdp_buf_info);
+ list_del(&temp->node);
- if (!is_last_buffer && !is_regen_buffer &&
+ if (!is_last_buffer &&
!(temp->flags & VSG_NEVER_RELEASE)) {
vsg_release_input_buffer(context, temp);
kfree(temp);
}
-
- list_del(&temp->node);
}
}
@@ -474,7 +448,7 @@
{
struct vsg_context *context = NULL;
struct vsg_buf_info *buf_info, *last_buffer,
- *regen_buffer, *expected_buffer;
+ *expected_buffer;
int rc = 0;
if (!arg || !sd) {
@@ -487,7 +461,6 @@
mutex_lock(&context->mutex);
buf_info = (struct vsg_buf_info *)arg;
last_buffer = context->last_buffer;
- regen_buffer = context->regen_buffer;
expected_buffer = list_first_entry(&context->busy_queue.node,
struct vsg_buf_info, node);
@@ -530,38 +503,6 @@
return rc;
}
-static long vsg_set_scratch_buffer(struct v4l2_subdev *sd, void *arg)
-{
- struct vsg_context *context = NULL;
- struct vsg_buf_info *buf_info;
- struct vsg_buf_info *regen_buffer =
- kzalloc(sizeof(*regen_buffer), GFP_KERNEL);
- int rc = 0;
-
- if (!arg || !sd) {
- WFD_MSG_ERR("ERROR, invalid arguments into %s\n", __func__);
- rc = -EINVAL;
- goto set_scratch_buf_err_bad_param;
- } else if (!regen_buffer) {
- WFD_MSG_ERR("ERROR, out of memory in %s\n", __func__);
- rc = -ENOMEM;
- goto set_scratch_buf_err_bad_param;
- }
-
- context = (struct vsg_context *)sd->dev_priv;
- buf_info = (struct vsg_buf_info *)arg;
-
- mutex_lock(&context->mutex);
- *regen_buffer = *buf_info;
- regen_buffer->flags = VSG_NEVER_RELEASE | VSG_NEVER_SET_LAST_BUFFER;
- context->regen_buffer = regen_buffer;
- WFD_MSG_DBG("setting buffer with paddr %p as scratch buffer\n",
- (void *)regen_buffer->mdp_buf_info.paddr);
- mutex_unlock(&context->mutex);
-set_scratch_buf_err_bad_param:
- return rc;
-}
-
static long vsg_set_frame_interval(struct v4l2_subdev *sd, void *arg)
{
struct vsg_context *context = NULL;
@@ -724,9 +665,6 @@
case VSG_RETURN_IP_BUFFER:
rc = vsg_return_ip_buffer(sd, arg);
break;
- case VSG_SET_SCRATCH_BUFFER:
- rc = vsg_set_scratch_buffer(sd, arg);
- break;
case VSG_GET_FRAME_INTERVAL:
rc = vsg_get_frame_interval(sd, arg);
break;
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.h b/drivers/media/video/msm/wfd/vsg-subdev.h
index f0e16633..dfc2e2e 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.h
+++ b/drivers/media/video/msm/wfd/vsg-subdev.h
@@ -63,8 +63,7 @@
struct workqueue_struct *work_queue;
struct hrtimer threshold_timer;
struct mutex mutex;
- struct vsg_buf_info *last_buffer, *regen_buffer;
- bool send_regen_buffer;
+ struct vsg_buf_info *last_buffer;
int mode;
int state;
};
@@ -88,13 +87,12 @@
#define VSG_DQ_BUFFER _IOR(VSG_MAGIC_IOCTL, 6, struct vsg_out_buf *)
#define VSG_RETURN_IP_BUFFER _IOW(VSG_MAGIC_IOCTL, 7, struct vsg_buf_info *)
#define VSG_ENCODE_DONE _IO(VSG_MAGIC_IOCTL, 8)
-#define VSG_SET_SCRATCH_BUFFER _IOW(VSG_MAGIC_IOCTL, 9, struct vsg_buf_info *)
/* Time related arguments for frame interval ioctls are always in nanosecs*/
-#define VSG_SET_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 10, int64_t *)
-#define VSG_GET_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 11, int64_t *)
-#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 12, int64_t *)
-#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 13, int64_t *)
-#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 14, enum vsg_modes *)
+#define VSG_SET_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 9, int64_t *)
+#define VSG_GET_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 10, int64_t *)
+#define VSG_SET_MAX_FRAME_INTERVAL _IOW(VSG_MAGIC_IOCTL, 11, int64_t *)
+#define VSG_GET_MAX_FRAME_INTERVAL _IOR(VSG_MAGIC_IOCTL, 12, int64_t *)
+#define VSG_SET_MODE _IOW(VSG_MAGIC_IOCTL, 13, enum vsg_modes *)
extern int vsg_init(struct v4l2_subdev *sd, u32 val);
extern long vsg_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 05fe2bb..2c2c551 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -35,12 +35,12 @@
#include "vsg-subdev.h"
#define WFD_VERSION KERNEL_VERSION(0, 0, 1)
-#define WFD_DEVICE_NUMBER 38
+#define WFD_NUM_DEVICES 2
+#define WFD_DEVICE_NUMBER_BASE 38
+#define WFD_DEVICE_SECURE (WFD_DEVICE_NUMBER_BASE + 1)
#define DEFAULT_WFD_WIDTH 640
#define DEFAULT_WFD_HEIGHT 480
-#define VSG_SCRATCH_BUFFERS 1
-#define MDP_WRITEBACK_BUFFERS 3
-#define VENC_INPUT_BUFFERS (VSG_SCRATCH_BUFFERS + MDP_WRITEBACK_BUFFERS)
+#define VENC_INPUT_BUFFERS 4
struct wfd_device {
struct platform_device *pdev;
@@ -50,6 +50,7 @@
struct v4l2_subdev enc_sdev;
struct v4l2_subdev vsg_sdev;
struct ion_client *ion_client;
+ bool secure_device;
};
struct mem_info {
@@ -85,6 +86,7 @@
u32 input_buf_size;
u32 out_buf_size;
struct list_head input_mem_list;
+ struct wfd_stats stats;
};
struct wfd_vid_buffer {
@@ -141,17 +143,19 @@
}
static int wfd_allocate_ion_buffer(struct ion_client *client,
- struct mem_region *mregion)
+ bool secure, struct mem_region *mregion)
{
struct ion_handle *handle;
void *kvaddr, *phys_addr;
unsigned long size;
+ unsigned int alloc_regions = 0;
int rc;
+ alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
+ alloc_regions |= secure ? 0 :
+ ION_HEAP(ION_IOMMU_HEAP_ID);
handle = ion_alloc(client,
- mregion->size, SZ_4K,
- ION_HEAP(ION_IOMMU_HEAP_ID) |
- ION_HEAP(ION_CP_MM_HEAP_ID));
+ mregion->size, SZ_4K, alloc_regions);
if (IS_ERR_OR_NULL(handle)) {
WFD_MSG_ERR("Failed to allocate input buffer\n");
@@ -241,7 +245,6 @@
int rc;
unsigned long flags;
struct mdp_buf_info mdp_buf = {0};
- struct vsg_buf_info vsg_buf = {};
spin_lock_irqsave(&inst->inst_lock, flags);
if (inst->input_bufs_allocated) {
spin_unlock_irqrestore(&inst->inst_lock, flags);
@@ -256,7 +259,8 @@
mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
enc_mregion->size = ALIGN(inst->input_buf_size, SZ_4K);
- rc = wfd_allocate_ion_buffer(wfd_dev->ion_client, enc_mregion);
+ rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
+ wfd_dev->secure_device, enc_mregion);
if (rc) {
WFD_MSG_ERR("Failed to allocate input memory."
" This error causes memory leak!!!\n");
@@ -294,7 +298,6 @@
mdp_buf.cookie = enc_mregion;
mdp_buf.kvaddr = (u32) mdp_mregion->kvaddr;
mdp_buf.paddr = (u32) mdp_mregion->paddr;
- vsg_buf.mdp_buf_info = mdp_buf;
WFD_MSG_DBG("NOTE: mdp paddr = %p, kvaddr = %p\n",
mdp_mregion->paddr,
@@ -305,23 +308,15 @@
mpair->mdp = mdp_mregion;
list_add_tail(&mpair->list, &inst->input_mem_list);
- if (i < MDP_WRITEBACK_BUFFERS) {
- rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
- MDP_Q_BUFFER, (void *)&mdp_buf);
- if (rc) {
- WFD_MSG_ERR("Unable to queue the"
- " buffer to mdp\n");
- break;
- }
- } else /*if (i < VSG_SCRATCH_BUFFERS*/ {
- rc = v4l2_subdev_call(&wfd_dev->vsg_sdev, core, ioctl,
- VSG_SET_SCRATCH_BUFFER,
- (void *)&vsg_buf);
- if (rc) {
- WFD_MSG_ERR("Unable to set scratch"
- " buffer to vsg\n");
- break;
- }
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_Q_BUFFER, (void *)&mdp_buf);
+ if (rc) {
+ WFD_MSG_ERR("Unable to queue the"
+ " buffer to mdp\n");
+ break;
+ } else {
+ wfd_stats_update(&inst->stats,
+ WFD_STAT_EVENT_MDP_QUEUE);
}
}
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
@@ -523,6 +518,9 @@
WFD_MSG_ERR("Either streamoff called or"
" MDP REPORTED ERROR\n");
break;
+ } else {
+ wfd_stats_update(&inst->stats,
+ WFD_STAT_EVENT_MDP_DEQUEUE);
}
mregion = obuf_mdp.cookie;
@@ -543,8 +541,11 @@
core, ioctl, VSG_Q_BUFFER, (void *)&ibuf_vsg);
if (rc) {
- WFD_MSG_ERR("Failed to encode frame\n");
+ WFD_MSG_ERR("Failed to queue frame to vsg\n");
break;
+ } else {
+ wfd_stats_update(&inst->stats,
+ WFD_STAT_EVENT_VSG_QUEUE);
}
}
WFD_MSG_DBG("Exiting the thread\n");
@@ -842,9 +843,13 @@
WFD_MSG_ERR("Failed to register buffer\n");
return rc;
}
+
rc = vb2_qbuf(&inst->vid_bufq, b);
if (rc)
WFD_MSG_ERR("Failed to queue buffer\n");
+ else
+ wfd_stats_update(&inst->stats, WFD_STAT_EVENT_CLIENT_QUEUE);
+
return rc;
}
@@ -903,8 +908,17 @@
struct v4l2_buffer *b)
{
struct wfd_inst *inst = filp->private_data;
+ int rc;
+
WFD_MSG_INFO("Waiting to dequeue buffer\n");
- return vb2_dqbuf(&inst->vid_bufq, b, 0);
+ rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
+
+ if (rc)
+ WFD_MSG_ERR("Failed to dequeue buffer\n");
+ else
+ wfd_stats_update(&inst->stats, WFD_STAT_EVENT_CLIENT_DEQUEUE);
+
+ return rc;
}
static int wfdioc_g_ctrl(struct file *filp, void *fh,
struct v4l2_control *a)
@@ -1138,11 +1152,15 @@
ioctl, VSG_RETURN_IP_BUFFER, (void *)&buf);
if (rc)
WFD_MSG_ERR("Failed to return buffer to vsg\n");
+ else
+ wfd_stats_update(&inst->stats, WFD_STAT_EVENT_ENC_DEQUEUE);
+
}
static int vsg_release_input_frame(void *cookie, struct vsg_buf_info *buf)
{
struct file *filp = cookie;
+ struct wfd_inst *inst = filp->private_data;
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
int rc = 0;
@@ -1151,6 +1169,10 @@
ioctl, MDP_Q_BUFFER, buf);
if (rc)
WFD_MSG_ERR("Failed to Q buffer to mdp\n");
+ else {
+ wfd_stats_update(&inst->stats, WFD_STAT_EVENT_MDP_QUEUE);
+ wfd_stats_update(&inst->stats, WFD_STAT_EVENT_VSG_DEQUEUE);
+ }
return rc;
}
@@ -1158,9 +1180,11 @@
static int vsg_encode_frame(void *cookie, struct vsg_buf_info *buf)
{
struct file *filp = cookie;
+ struct wfd_inst *inst = filp->private_data;
struct wfd_device *wfd_dev =
(struct wfd_device *)video_drvdata(filp);
struct venc_buf_info venc_buf;
+ int rc = 0;
if (!buf)
return -EINVAL;
@@ -1171,8 +1195,16 @@
};
wfd_flush_ion_buffer(wfd_dev->ion_client, venc_buf.mregion);
- return v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENCODE_FRAME, &venc_buf);
+
+ if (rc)
+ WFD_MSG_ERR("Encode failed\n");
+ else
+ wfd_stats_update(&inst->stats, WFD_STAT_EVENT_ENC_QUEUE);
+
+ return rc;
}
void *wfd_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
@@ -1229,6 +1261,9 @@
spin_lock_init(&inst->inst_lock);
INIT_LIST_HEAD(&inst->input_mem_list);
INIT_LIST_HEAD(&inst->minfo_list);
+
+ wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
+
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
(void *)&inst->mdp_inst);
if (rc) {
@@ -1307,6 +1342,8 @@
kfree(inst);
}
+
+ wfd_stats_deinit(&inst->stats);
WFD_MSG_DBG("wfd_close: X\n");
return 0;
}
@@ -1320,19 +1357,11 @@
{
}
-static int __devinit __wfd_probe(struct platform_device *pdev)
+
+static int wfd_dev_setup(struct wfd_device *wfd_dev, int dev_num,
+ struct platform_device *pdev)
{
int rc = 0;
- struct wfd_device *wfd_dev;
- WFD_MSG_DBG("__wfd_probe: E\n");
- wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL);
- if (!wfd_dev) {
- WFD_MSG_ERR("Could not allocate memory for "
- "wfd device\n");
- rc = -ENOMEM;
- goto err_v4l2_registration;
- }
- pdev->dev.platform_data = (void *) wfd_dev;
rc = v4l2_device_register(&pdev->dev, &wfd_dev->v4l2_dev);
if (rc) {
WFD_MSG_ERR("Failed to register the video device\n");
@@ -1349,7 +1378,7 @@
wfd_dev->pvdev->ioctl_ops = &g_wfd_ioctl_ops;
rc = video_register_device(wfd_dev->pvdev, VFL_TYPE_GRABBER,
- WFD_DEVICE_NUMBER);
+ dev_num);
if (rc) {
WFD_MSG_ERR("Failed to register the device\n");
goto err_video_register_device;
@@ -1359,7 +1388,7 @@
v4l2_subdev_init(&wfd_dev->mdp_sdev, &mdp_subdev_ops);
strncpy(wfd_dev->mdp_sdev.name, "wfd-mdp", V4L2_SUBDEV_NAME_SIZE);
rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
- &wfd_dev->mdp_sdev);
+ &wfd_dev->mdp_sdev);
if (rc) {
WFD_MSG_ERR("Failed to register mdp subdevice: %d\n", rc);
goto err_mdp_register_subdev;
@@ -1368,7 +1397,7 @@
v4l2_subdev_init(&wfd_dev->enc_sdev, &enc_subdev_ops);
strncpy(wfd_dev->enc_sdev.name, "wfd-venc", V4L2_SUBDEV_NAME_SIZE);
rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
- &wfd_dev->enc_sdev);
+ &wfd_dev->enc_sdev);
if (rc) {
WFD_MSG_ERR("Failed to register encoder subdevice: %d\n", rc);
goto err_venc_register_subdev;
@@ -1382,23 +1411,15 @@
v4l2_subdev_init(&wfd_dev->vsg_sdev, &vsg_subdev_ops);
strncpy(wfd_dev->vsg_sdev.name, "wfd-vsg", V4L2_SUBDEV_NAME_SIZE);
rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
- &wfd_dev->vsg_sdev);
+ &wfd_dev->vsg_sdev);
if (rc) {
WFD_MSG_ERR("Failed to register vsg subdevice: %d\n", rc);
goto err_venc_init;
}
- wfd_dev->ion_client = msm_ion_client_create(-1, "wfd");
- if (!wfd_dev->ion_client) {
- WFD_MSG_ERR("Failed to create ion client\n");
- rc = -ENODEV;
- goto err_vsg_register_subdev;
- }
WFD_MSG_DBG("__wfd_probe: X\n");
return rc;
-err_vsg_register_subdev:
- v4l2_device_unregister_subdev(&wfd_dev->vsg_sdev);
err_venc_init:
v4l2_device_unregister_subdev(&wfd_dev->enc_sdev);
err_venc_register_subdev:
@@ -1410,6 +1431,74 @@
err_video_device_alloc:
v4l2_device_unregister(&wfd_dev->v4l2_dev);
err_v4l2_registration:
+ return rc;
+}
+static int __devinit __wfd_probe(struct platform_device *pdev)
+{
+ int rc = 0, c = 0;
+ struct wfd_device *wfd_dev; /* Should be taken as an array*/
+ struct ion_client *ion_client = NULL;
+
+ WFD_MSG_DBG("__wfd_probe: E\n");
+ wfd_dev = kzalloc(sizeof(*wfd_dev)*WFD_NUM_DEVICES, GFP_KERNEL);
+ if (!wfd_dev) {
+ WFD_MSG_ERR("Could not allocate memory for "
+ "wfd device\n");
+ rc = -ENOMEM;
+ goto err_v4l2_probe;
+ }
+ pdev->dev.platform_data = (void *) wfd_dev;
+
+ ion_client = msm_ion_client_create(-1, "wfd");
+
+ rc = wfd_stats_setup();
+ if (rc) {
+ WFD_MSG_ERR("No debugfs support: %d\n", rc);
+ /* Don't treat this as a fatal err */
+ rc = 0;
+ }
+
+ if (!ion_client) {
+ WFD_MSG_ERR("Failed to create ion client\n");
+ rc = -ENODEV;
+ goto err_v4l2_probe;
+ }
+
+ for (c = 0; c < WFD_NUM_DEVICES; ++c) {
+ rc = wfd_dev_setup(&wfd_dev[c],
+ WFD_DEVICE_NUMBER_BASE + c, pdev);
+
+ if (rc) {
+ /* Clear out old devices */
+ for (--c; c >= 0; --c) {
+ v4l2_device_unregister_subdev(
+ &wfd_dev[c].vsg_sdev);
+ v4l2_device_unregister_subdev(
+ &wfd_dev[c].enc_sdev);
+ v4l2_device_unregister_subdev(
+ &wfd_dev[c].mdp_sdev);
+ video_unregister_device(wfd_dev[c].pvdev);
+ video_device_release(wfd_dev[c].pvdev);
+ v4l2_device_unregister(&wfd_dev[c].v4l2_dev);
+ }
+
+ goto err_v4l2_probe;
+ }
+
+ /* Other device specific stuff */
+ wfd_dev[c].ion_client = ion_client;
+ switch (WFD_DEVICE_NUMBER_BASE + c) {
+ case WFD_DEVICE_SECURE:
+ wfd_dev[c].secure_device = true;
+ break;
+ default:
+ break;
+ }
+
+ }
+ WFD_MSG_DBG("__wfd_probe: X\n");
+ return rc;
+err_v4l2_probe:
kfree(wfd_dev);
return rc;
}
@@ -1417,6 +1506,8 @@
static int __devexit __wfd_remove(struct platform_device *pdev)
{
struct wfd_device *wfd_dev;
+ int c = 0;
+
wfd_dev = (struct wfd_device *)pdev->dev.platform_data;
WFD_MSG_DBG("Inside wfd_remove\n");
@@ -1425,10 +1516,16 @@
return -ENODEV;
}
- v4l2_device_unregister_subdev(&wfd_dev->mdp_sdev);
- video_unregister_device(wfd_dev->pvdev);
- video_device_release(wfd_dev->pvdev);
- v4l2_device_unregister(&wfd_dev->v4l2_dev);
+ wfd_stats_teardown();
+ for (c = 0; c < WFD_NUM_DEVICES; ++c) {
+ v4l2_device_unregister_subdev(&wfd_dev[c].vsg_sdev);
+ v4l2_device_unregister_subdev(&wfd_dev[c].enc_sdev);
+ v4l2_device_unregister_subdev(&wfd_dev[c].mdp_sdev);
+ video_unregister_device(wfd_dev[c].pvdev);
+ video_device_release(wfd_dev[c].pvdev);
+ v4l2_device_unregister(&wfd_dev[c].v4l2_dev);
+ }
+
kfree(wfd_dev);
return 0;
}
diff --git a/drivers/media/video/msm/wfd/wfd-util.c b/drivers/media/video/msm/wfd/wfd-util.c
new file mode 100644
index 0000000..233668b0
--- /dev/null
+++ b/drivers/media/video/msm/wfd/wfd-util.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/debugfs.h>
+#include <linux/hrtimer.h>
+#include <linux/limits.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include "wfd-util.h"
+
+static struct dentry *wfd_debugfs_root;
+
+int wfd_stats_setup()
+{
+ wfd_debugfs_root = debugfs_create_dir("wfd", NULL);
+
+ if (wfd_debugfs_root == ERR_PTR(-ENODEV))
+ return -ENODEV;
+ else if (!wfd_debugfs_root)
+ return -ENOMEM;
+ else
+ return 0;
+}
+
+void wfd_stats_teardown()
+{
+ if (wfd_debugfs_root)
+ debugfs_remove_recursive(wfd_debugfs_root);
+}
+
+int wfd_stats_init(struct wfd_stats *stats, int device)
+{
+ char device_str[NAME_MAX] = "";
+ int rc = 0;
+
+ if (!stats) {
+ rc = -EINVAL;
+ goto wfd_stats_init_fail;
+ } else if (!wfd_debugfs_root) {
+ WFD_MSG_ERR("wfd debugfs root does not exist\n");
+ rc = -ENOENT;
+ goto wfd_stats_init_fail;
+ }
+
+ memset(stats, 0, sizeof(*stats));
+ INIT_LIST_HEAD(&stats->enc_queue);
+
+ snprintf(device_str, sizeof(device_str), "%d", device);
+ stats->d_parent = debugfs_create_dir(device_str, wfd_debugfs_root);
+ if (IS_ERR(stats->d_parent)) {
+ rc = PTR_ERR(stats->d_parent);
+ stats->d_parent = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_v4l2_buf_count = debugfs_create_u32("v4l2_buf_count", S_IRUGO,
+ stats->d_parent, &stats->v4l2_buf_count);
+ if (IS_ERR(stats->d_v4l2_buf_count)) {
+ rc = PTR_ERR(stats->d_v4l2_buf_count);
+ stats->d_v4l2_buf_count = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_mdp_buf_count = debugfs_create_u32("mdp_buf_count", S_IRUGO,
+ stats->d_parent, &stats->mdp_buf_count);
+ if (IS_ERR(stats->d_mdp_buf_count)) {
+ rc = PTR_ERR(stats->d_mdp_buf_count);
+ stats->d_mdp_buf_count = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_vsg_buf_count = debugfs_create_u32("vsg_buf_count", S_IRUGO,
+ stats->d_parent, &stats->vsg_buf_count);
+ if (IS_ERR(stats->d_vsg_buf_count)) {
+ rc = PTR_ERR(stats->d_vsg_buf_count);
+ stats->d_vsg_buf_count = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_enc_buf_count = debugfs_create_u32("enc_buf_count", S_IRUGO,
+ stats->d_parent, &stats->enc_buf_count);
+ if (IS_ERR(stats->d_enc_buf_count)) {
+ rc = PTR_ERR(stats->d_enc_buf_count);
+ stats->d_enc_buf_count = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_frames_encoded = debugfs_create_u32("frames_encoded", S_IRUGO,
+ stats->d_parent, &stats->frames_encoded);
+ if (IS_ERR(stats->d_frames_encoded)) {
+ rc = PTR_ERR(stats->d_frames_encoded);
+ stats->d_frames_encoded = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_mdp_updates = debugfs_create_u32("mdp_updates", S_IRUGO,
+ stats->d_parent, &stats->mdp_updates);
+ if (IS_ERR(stats->d_mdp_updates)) {
+ rc = PTR_ERR(stats->d_mdp_updates);
+ stats->d_mdp_updates = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ stats->d_enc_avg_latency = debugfs_create_u32("enc_avg_latency",
+ S_IRUGO, stats->d_parent, &stats->enc_avg_latency);
+ if (IS_ERR(stats->d_enc_avg_latency)) {
+ rc = PTR_ERR(stats->d_enc_avg_latency);
+ stats->d_enc_avg_latency = NULL;
+ goto wfd_stats_init_fail;
+ }
+
+ return rc;
+wfd_stats_init_fail:
+ return rc;
+}
+
+int wfd_stats_update(struct wfd_stats *stats, enum wfd_stats_event event)
+{
+ int rc = 0;
+ switch (event) {
+ case WFD_STAT_EVENT_CLIENT_QUEUE:
+ stats->v4l2_buf_count++;
+ break;
+ case WFD_STAT_EVENT_CLIENT_DEQUEUE: {
+ struct wfd_stats_encode_sample *sample = NULL;
+
+ stats->v4l2_buf_count--;
+
+ if (!list_empty(&stats->enc_queue))
+ sample = list_first_entry(&stats->enc_queue,
+ struct wfd_stats_encode_sample,
+ list);
+ if (sample) {
+ ktime_t kdiff = ktime_sub(ktime_get(),
+ sample->encode_start_ts);
+ uint32_t diff = ktime_to_ms(kdiff);
+
+ stats->enc_cumulative_latency += diff;
+ stats->enc_latency_samples++;
+ stats->enc_avg_latency = stats->enc_cumulative_latency /
+ stats->enc_latency_samples;
+
+ list_del(&sample->list);
+ kfree(sample);
+ sample = NULL;
+ }
+ break;
+ }
+ case WFD_STAT_EVENT_MDP_QUEUE:
+ stats->mdp_buf_count++;
+ stats->mdp_updates++;
+ break;
+ case WFD_STAT_EVENT_MDP_DEQUEUE:
+ stats->mdp_buf_count--;
+ break;
+ case WFD_STAT_EVENT_ENC_QUEUE: {
+ struct wfd_stats_encode_sample *sample = NULL;
+
+ stats->enc_buf_count++;
+ stats->frames_encoded++;
+
+ sample = kzalloc(sizeof(*sample), GFP_KERNEL);
+ if (sample) {
+ INIT_LIST_HEAD(&sample->list);
+ sample->encode_start_ts = ktime_get();
+ list_add_tail(&sample->list, &stats->enc_queue);
+ } else {
+ WFD_MSG_WARN("Unable to measure latency\n");
+ }
+ break;
+ }
+ case WFD_STAT_EVENT_ENC_DEQUEUE:
+ stats->enc_buf_count--;
+ break;
+ case WFD_STAT_EVENT_VSG_QUEUE:
+ stats->vsg_buf_count++;
+ break;
+ case WFD_STAT_EVENT_VSG_DEQUEUE:
+ stats->vsg_buf_count--;
+ break;
+ default:
+ rc = -ENOTSUPP;
+ }
+
+ return rc;
+}
+
+int wfd_stats_deinit(struct wfd_stats *stats)
+{
+ WFD_MSG_ERR("Latencies: avg enc. latency %d",
+ stats->enc_avg_latency);
+ /* Delete all debugfs files in one shot :) */
+ if (stats->d_parent)
+ debugfs_remove_recursive(stats->d_parent);
+
+ stats->d_parent =
+ stats->d_v4l2_buf_count =
+ stats->d_mdp_buf_count =
+ stats->d_vsg_buf_count =
+ stats->d_enc_buf_count =
+ stats->d_frames_encoded =
+ stats->d_mdp_updates =
+ stats->d_enc_avg_latency = NULL;
+
+ return 0;
+}
diff --git a/drivers/media/video/msm/wfd/wfd-util.h b/drivers/media/video/msm/wfd/wfd-util.h
index 06dbffa..b6bb245 100644
--- a/drivers/media/video/msm/wfd/wfd-util.h
+++ b/drivers/media/video/msm/wfd/wfd-util.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -11,6 +11,10 @@
*
*/
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/ktime.h>
+
#ifndef _WFD_UTIL_H_
#define _WFD_UTIL_H_
@@ -27,4 +31,59 @@
#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
+
+
+struct wfd_stats_encode_sample {
+ ktime_t encode_start_ts;
+ struct list_head list;
+};
+
+struct wfd_stats {
+ /* Output Buffers */
+ uint32_t v4l2_buf_count;
+
+ /* Input Buffers */
+ uint32_t mdp_buf_count;
+ uint32_t vsg_buf_count;
+ uint32_t enc_buf_count;
+
+ /* Other */
+ uint32_t frames_encoded;
+ uint32_t mdp_updates;
+
+ uint32_t enc_avg_latency;
+ uint32_t enc_cumulative_latency;
+ uint32_t enc_latency_samples;
+ struct list_head enc_queue;
+
+ /* Debugfs entries */
+ struct dentry *d_parent;
+ struct dentry *d_v4l2_buf_count;
+ struct dentry *d_mdp_buf_count;
+ struct dentry *d_vsg_buf_count;
+ struct dentry *d_enc_buf_count;
+ struct dentry *d_frames_encoded;
+ struct dentry *d_mdp_updates;
+ struct dentry *d_enc_avg_latency;
+};
+
+enum wfd_stats_event {
+ WFD_STAT_EVENT_CLIENT_QUEUE,
+ WFD_STAT_EVENT_CLIENT_DEQUEUE,
+
+ WFD_STAT_EVENT_MDP_QUEUE,
+ WFD_STAT_EVENT_MDP_DEQUEUE,
+
+ WFD_STAT_EVENT_VSG_QUEUE,
+ WFD_STAT_EVENT_VSG_DEQUEUE,
+
+ WFD_STAT_EVENT_ENC_QUEUE,
+ WFD_STAT_EVENT_ENC_DEQUEUE,
+};
+
+int wfd_stats_setup(void);
+int wfd_stats_init(struct wfd_stats *, int device);
+int wfd_stats_update(struct wfd_stats *, enum wfd_stats_event);
+int wfd_stats_deinit(struct wfd_stats *);
+void wfd_stats_teardown(void);
#endif
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 7c26947..deb35cc 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -159,11 +159,16 @@
} fmt;
};
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+struct v4l2_create_buffers32 {
+ __u32 index; /* output: buffers index...index + count - 1 have been created */
+ __u32 count;
+ enum v4l2_memory memory;
+ struct v4l2_format32 format; /* filled in by the user, plane sizes calculated by the driver */
+ __u32 reserved[8];
+};
+
+static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
- if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
- get_user(kp->type, &up->type))
- return -EFAULT;
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -192,11 +197,24 @@
}
}
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
- put_user(kp->type, &up->type))
- return -EFAULT;
+ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
+ get_user(kp->type, &up->type))
+ return -EFAULT;
+ return __get_v4l2_format32(kp, up);
+}
+
+static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+{
+ if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
+ copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt)))
+ return -EFAULT;
+ return __get_v4l2_format32(&kp->format, &up->format);
+}
+
+static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -225,6 +243,22 @@
}
}
+static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
+ put_user(kp->type, &up->type))
+ return -EFAULT;
+ return __put_v4l2_format32(kp, up);
+}
+
+static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+{
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
+ copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
+ return -EFAULT;
+ return __put_v4l2_format32(&kp->format, &up->format);
+}
+
struct v4l2_standard32 {
__u32 index;
__u32 id[2]; /* __u64 would get the alignment wrong */
@@ -675,6 +709,8 @@
#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
+#define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32)
+#define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32)
#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
#define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
@@ -693,6 +729,7 @@
struct v4l2_input v2i;
struct v4l2_standard v2s;
struct v4l2_ext_controls v2ecs;
+ struct v4l2_create_buffers v2crt;
unsigned long vx;
int vi;
} karg;
@@ -722,6 +759,8 @@
case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
+ case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
+ case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
}
switch (cmd) {
@@ -746,6 +785,12 @@
compatible_arg = 0;
break;
+ case VIDIOC_CREATE_BUFS:
+ err = get_v4l2_create32(&karg.v2crt, up);
+ compatible_arg = 0;
+ break;
+
+ case VIDIOC_PREPARE_BUF:
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
@@ -824,6 +869,10 @@
err = put_v4l2_format32(&karg.v2f, up);
break;
+ case VIDIOC_CREATE_BUFS:
+ err = put_v4l2_create32(&karg.v2crt, up);
+ break;
+
case VIDIOC_QUERYBUF:
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
@@ -922,6 +971,8 @@
case VIDIOC_DQEVENT:
case VIDIOC_SUBSCRIBE_EVENT:
case VIDIOC_UNSUBSCRIBE_EVENT:
+ case VIDIOC_CREATE_BUFS32:
+ case VIDIOC_PREPARE_BUF32:
ret = do_video_ioctl(file, cmd, arg);
break;
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index bda252f..5e44c90 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -259,6 +259,8 @@
[_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT",
[_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT",
[_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
+ [_IOC_NR(VIDIOC_CREATE_BUFS)] = "VIDIOC_CREATE_BUFS",
+ [_IOC_NR(VIDIOC_PREPARE_BUF)] = "VIDIOC_PREPARE_BUF",
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -2196,6 +2198,40 @@
dbgarg(cmd, "type=0x%8.8x", sub->type);
break;
}
+ case VIDIOC_CREATE_BUFS:
+ {
+ struct v4l2_create_buffers *create = arg;
+
+ if (!ops->vidioc_create_bufs)
+ break;
+ /*if (ret_prio) {
+ ret = ret_prio;
+ break;
+ }*/
+ ret = check_fmt(ops, create->format.type);
+ if (ret)
+ break;
+
+ ret = ops->vidioc_create_bufs(file, fh, create);
+
+ dbgarg(cmd, "count=%d @ %d\n", create->count, create->index);
+ break;
+ }
+ case VIDIOC_PREPARE_BUF:
+ {
+ struct v4l2_buffer *b = arg;
+
+ if (!ops->vidioc_prepare_buf)
+ break;
+ ret = check_fmt(ops, b->type);
+ if (ret)
+ break;
+
+ ret = ops->vidioc_prepare_buf(file, fh, b);
+
+ dbgarg(cmd, "index=%d", b->index);
+ break;
+ }
default:
{
bool valid_prio = true;
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index c12bed3..7782955 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -45,9 +45,9 @@
#define D(fmt, args...) do {} while (0)
#endif
-static int32_t msm_mem_allocate(struct videobuf2_contig_pmem *mem)
+static unsigned long msm_mem_allocate(struct videobuf2_contig_pmem *mem)
{
- int32_t phyaddr;
+ unsigned long phyaddr;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
int rc, len;
mem->client = msm_ion_client_create(-1, "camera");
@@ -61,8 +61,10 @@
pr_err("%s Could not allocate\n", __func__);
goto alloc_failed;
}
- rc = ion_phys(mem->client, mem->ion_handle, (ion_phys_addr_t *)&phyaddr,
- (size_t *)&len);
+ rc = ion_map_iommu(mem->client, mem->ion_handle,
+ CAMERA_DOMAIN, GEN_POOL, SZ_4K, 0,
+ (unsigned long *)&phyaddr,
+ (unsigned long *)&len, UNCACHED, 0);
if (rc < 0) {
pr_err("%s Could not get physical address\n", __func__);
goto phys_failed;
@@ -85,6 +87,7 @@
{
int32_t rc = 0;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(mem->client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL);
ion_free(mem->client, mem->ion_handle);
ion_client_destroy(mem->client);
#else
@@ -116,8 +119,6 @@
static void *msm_vb2_mem_ops_alloc(void *alloc_ctx, unsigned long size)
{
struct videobuf2_contig_pmem *mem;
- unsigned int flags = 0;
- long rc;
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem)
return ERR_PTR(-ENOMEM);
@@ -132,18 +133,7 @@
kfree(mem);
return ERR_PTR(-ENOMEM);
}
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mem->subsys_id = MSM_SUBSYSTEM_CAMERA;
- mem->msm_buffer = msm_subsystem_map_buffer(mem->phyaddr, mem->size,
- flags, &(mem->subsys_id), 1);
- if (IS_ERR((void *)mem->msm_buffer)) {
- pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
- rc = PTR_ERR((void *)mem->msm_buffer);
- msm_mem_free(mem);
- kfree(mem);
- return ERR_PTR(-ENOMEM);
- }
- mem->mapped_phyaddr = mem->msm_buffer->iova[0];
+ mem->mapped_phyaddr = mem->phyaddr;
return mem;
}
static void msm_vb2_mem_ops_put(void *buf_priv)
@@ -151,8 +141,6 @@
struct videobuf2_contig_pmem *mem = buf_priv;
if (!mem->is_userptr) {
D("%s Freeing memory ", __func__);
- if (msm_subsystem_unmap_buffer(mem->msm_buffer) < 0)
- D("%s unmapped memory\n", __func__);
msm_mem_free(mem);
}
kfree(mem);
@@ -193,7 +181,6 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
unsigned long kvstart;
#endif
- unsigned int flags = 0;
unsigned long paddr = 0;
if (mem->phyaddr != 0)
return 0;
@@ -203,8 +190,10 @@
pr_err("%s ION import failed\n", __func__);
return PTR_ERR(mem->ion_handle);
}
- rc = ion_phys(client, mem->ion_handle, (ion_phys_addr_t *)&mem->phyaddr,
- (size_t *)&len);
+ rc = ion_map_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL,
+ SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
+ if (rc < 0)
+ ion_free(client, mem->ion_handle);
#elif CONFIG_ANDROID_PMEM
rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
&kvstart, &len, &mem->file);
@@ -224,20 +213,6 @@
mem->path = path;
mem->buffer_type = buffer_type;
paddr = mem->phyaddr;
- flags = MSM_SUBSYSTEM_MAP_IOVA;
- mem->subsys_id = MSM_SUBSYSTEM_CAMERA;
- mem->msm_buffer = msm_subsystem_map_buffer(mem->phyaddr, len,
- flags, &(mem->subsys_id), 1);
- if (IS_ERR((void *)mem->msm_buffer)) {
- pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
-#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_free(client, mem->ion_handle);
-#elif CONFIG_ANDROID_PMEM
- put_pmem_file(mem->file);
-#endif
- return PTR_ERR((void *)mem->msm_buffer);
- }
- paddr = mem->msm_buffer->iova[0];
mem->mapped_phyaddr = paddr + addr_offset;
mem->addr_offset = addr_offset;
return rc;
@@ -247,10 +222,10 @@
void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
struct ion_client *client)
{
- if (msm_subsystem_unmap_buffer(mem->msm_buffer) < 0)
- D("%s unmapped memory\n", __func__);
if (mem->is_userptr) {
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(client, mem->ion_handle,
+ CAMERA_DOMAIN, GEN_POOL);
ion_free(client, mem->ion_handle);
#elif CONFIG_ANDROID_PMEM
put_pmem_file(mem->file);
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index f986b5d..041815776 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -284,7 +284,7 @@
#define MAX_NAME_COMPARISON_LEN 32
static int __devinit match_regulator(
- struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+ struct pm8xxx_regulator_core_platform_data *core_data, const char *name)
{
int found = 0;
int i;
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index ac57418..b03b7ac 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -326,7 +326,7 @@
#define MAX_NAME_COMPARISON_LEN 32
static int __devinit match_regulator(
- struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+ struct pm8xxx_regulator_core_platform_data *core_data, const char *name)
{
int found = 0;
int i;
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 68395e3..0f41ba7 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -448,7 +448,7 @@
#define MAX_NAME_COMPARISON_LEN 32
static int __devinit match_regulator(enum pm8xxx_version version,
- struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+ struct pm8xxx_regulator_core_platform_data *core_data, const char *name)
{
int found = 0;
int i;
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index b655848..64c0bd1 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -999,6 +999,10 @@
{
int rc;
+ /* dVdd preloading is not needed for PMIC PM8901 rev 2.3 and beyond. */
+ if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8901_2p3)
+ return 0;
+
rc = pm8xxx_writeb(chip->dev->parent, 0x0BD, 0x0F);
if (rc)
pr_err("pm8xxx_writeb failed for 0x0BD, rc=%d\n", rc);
diff --git a/drivers/mfd/pmic8901.c b/drivers/mfd/pmic8901.c
index aec382a..63ea55a 100644
--- a/drivers/mfd/pmic8901.c
+++ b/drivers/mfd/pmic8901.c
@@ -270,11 +270,23 @@
return rc;
}
+static const char * const pm8901_rev_names[] = {
+ [PM8XXX_REVISION_8901_TEST] = "test",
+ [PM8XXX_REVISION_8901_1p0] = "1.0",
+ [PM8XXX_REVISION_8901_1p1] = "1.1",
+ [PM8XXX_REVISION_8901_2p0] = "2.0",
+ [PM8XXX_REVISION_8901_2p1] = "2.1",
+ [PM8XXX_REVISION_8901_2p2] = "2.2",
+ [PM8XXX_REVISION_8901_2p3] = "2.3",
+};
+
static int __devinit pm8901_probe(struct platform_device *pdev)
{
int rc;
struct pm8901_platform_data *pdata = pdev->dev.platform_data;
+ const char *revision_name = "unknown";
struct pm8901_chip *pmic;
+ int revision;
if (pdata == NULL) {
pr_err("%s: No platform_data or IRQ.\n", __func__);
@@ -298,7 +310,11 @@
pr_err("%s: Failed reading version register rc=%d.\n",
__func__, rc);
- pr_info("%s: PMIC REVISION = %X\n", __func__, pmic->revision);
+ pr_info("%s: PMIC revision reg: %02X\n", __func__, pmic->revision);
+ revision = pm8xxx_get_revision(pmic->dev);
+ if (revision >= 0 && revision < ARRAY_SIZE(pm8901_rev_names))
+ revision_name = pm8901_rev_names[revision];
+ pr_info("%s: PMIC version: PM8901 rev %s\n", __func__, revision_name);
(void) memcpy((void *)&pmic->pdata, (const void *)pdata,
sizeof(pmic->pdata));
diff --git a/drivers/misc/pmic8058-xoadc.c b/drivers/misc/pmic8058-xoadc.c
index 14b790f..3452672 100644
--- a/drivers/misc/pmic8058-xoadc.c
+++ b/drivers/misc/pmic8058-xoadc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -650,23 +650,6 @@
#define PM8058_XOADC_DEV_PM_OPS NULL
#endif
-static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
-{
- struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
-
- if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
- adc_pmic->pdata->xoadc_vreg_shutdown();
-
- wake_lock_destroy(&adc_pmic->adc_wakelock);
- msm_xo_put(adc_pmic->adc_voter);
- platform_set_drvdata(pdev, NULL);
- device_init_wakeup(&pdev->dev, 0);
- kfree(adc_pmic);
- xoadc_initialized = false;
-
- return 0;
-}
-
static int __devinit pm8058_xoadc_probe(struct platform_device *pdev)
{
struct xoadc_platform_data *pdata = pdev->dev.platform_data;
@@ -678,7 +661,7 @@
return -EINVAL;
}
- adc_pmic = kzalloc(sizeof(struct pmic8058_adc), GFP_KERNEL);
+ adc_pmic = devm_kzalloc(&pdev->dev, sizeof(*adc_pmic), GFP_KERNEL);
if (!adc_pmic) {
dev_err(&pdev->dev, "Unable to allocate memory\n");
return -ENOMEM;
@@ -693,17 +676,16 @@
if (adc_pmic->xoadc_num > XOADC_PMIC_0) {
dev_err(&pdev->dev, "ADC device not supported\n");
- rc = -EINVAL;
- goto err_cleanup;
+ return -EINVAL;
}
adc_pmic->pdata = pdata;
- adc_pmic->adc_graph = kzalloc(sizeof(struct linear_graph)
- * MAX_CHANNEL_PROPERTIES_QUEUE, GFP_KERNEL);
+ adc_pmic->adc_graph = devm_kzalloc(&pdev->dev,
+ sizeof(struct linear_graph) * MAX_CHANNEL_PROPERTIES_QUEUE,
+ GFP_KERNEL);
if (!adc_pmic->adc_graph) {
dev_err(&pdev->dev, "Unable to allocate memory\n");
- rc = -ENOMEM;
- goto err_cleanup;
+ return -ENOMEM;
}
/* Will be replaced by individual channel calibration */
@@ -739,32 +721,29 @@
INIT_LIST_HEAD(&adc_pmic->conv_queue_list->slots);
adc_pmic->adc_irq = platform_get_irq(pdev, 0);
- if (adc_pmic->adc_irq < 0) {
- rc = -ENXIO;
- goto err_cleanup;
- }
+ if (adc_pmic->adc_irq < 0)
+ return -ENXIO;
rc = request_threaded_irq(adc_pmic->adc_irq,
NULL, pm8058_xoadc,
IRQF_TRIGGER_RISING, "pm8058_adc_interrupt", adc_pmic);
if (rc) {
dev_err(&pdev->dev, "failed to request adc irq\n");
- goto err_cleanup;
+ return rc;
}
disable_irq(adc_pmic->adc_irq);
- device_init_wakeup(&pdev->dev, pdata->xoadc_wakeup);
-
if (adc_pmic->adc_voter == NULL) {
adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D1,
"pmic8058_xoadc");
if (IS_ERR(adc_pmic->adc_voter)) {
dev_err(&pdev->dev, "Failed to get XO vote\n");
- goto err_cleanup;
+ return PTR_ERR(adc_pmic->adc_voter);
}
}
+ device_init_wakeup(&pdev->dev, pdata->xoadc_wakeup);
wake_lock_init(&adc_pmic->adc_wakelock, WAKE_LOCK_SUSPEND,
"pmic8058_xoadc_wakelock");
@@ -777,11 +756,21 @@
xoadc_calib_first_adc = false;
return 0;
+}
-err_cleanup:
- pm8058_xoadc_teardown(pdev);
+static int __devexit pm8058_xoadc_teardown(struct platform_device *pdev)
+{
+ struct pmic8058_adc *adc_pmic = platform_get_drvdata(pdev);
- return rc;
+ if (adc_pmic->pdata->xoadc_vreg_shutdown != NULL)
+ adc_pmic->pdata->xoadc_vreg_shutdown();
+
+ wake_lock_destroy(&adc_pmic->adc_wakelock);
+ msm_xo_put(adc_pmic->adc_voter);
+ device_init_wakeup(&pdev->dev, 0);
+ xoadc_initialized = false;
+
+ return 0;
}
static struct platform_driver pm8058_xoadc_driver = {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index ba00d5e..60e1e55 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,3 +1,4 @@
+
/* Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
@@ -552,7 +553,8 @@
}
if (data->abort) {
- pr_err("Aborting driver\n");
+ pr_err("Aborting listener service %d\n",
+ data->listener.id);
return -ENODEV;
}
qseecom.send_resp_flag = 0;
@@ -605,7 +607,8 @@
app_id = resp.data;
if (app_id) {
- pr_warn("App id already exists\n");
+ pr_warn("App id %d (%s) already exists\n", app_id,
+ (char *)(req.app_name));
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(entry,
&qseecom.registered_app_list_head, list){
@@ -619,7 +622,8 @@
} else {
struct qseecom_load_app_ireq load_req;
- pr_warn("App id does not exist\n");
+ pr_warn("App (%s) does not exist, loading apps for first time\n",
+ (char *)(load_req.app_name));
/* Get the handle of the shared fd */
ihandle = ion_import_fd(qseecom.ion_clnt,
load_img_req.ifd_data_fd);
@@ -642,6 +646,13 @@
sizeof(struct qseecom_load_app_ireq),
&resp, sizeof(resp));
+ if (resp.result == QSEOS_RESULT_FAILURE) {
+ pr_err("scm_call failed resp.result QSEOS_RESULT_FAILURE -1\n");
+ if (!IS_ERR_OR_NULL(ihandle))
+ ion_free(qseecom.ion_clnt, ihandle);
+ return -EFAULT;
+ }
+
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
@@ -653,7 +664,8 @@
}
}
if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("scm_call failed resp.result != QSEOS_RESULT_SUCCESS\n");
+ pr_err("scm_call failed resp.result unknown, %d\n",
+ resp.result);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
return -EFAULT;
@@ -677,6 +689,9 @@
list_add_tail(&entry->list, &qseecom.registered_app_list_head);
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
+
+ pr_warn("App with id %d (%s) now loaded\n", app_id,
+ (char *)(load_req.app_name));
}
data->client.app_id = app_id;
load_img_req.app_id = app_id;
@@ -720,10 +735,14 @@
unload = __qseecom_cleanup_app(data);
list_del(&ptr_app->list);
kzfree(ptr_app);
+ pr_warn("App id %d now unloaded\n",
+ ptr_app->app_id);
break;
} else {
ptr_app->ref_cnt--;
data->released = true;
+ pr_warn("Can't unload app with id %d (it is inuse)\n",
+ ptr_app->app_id);
break;
}
}
@@ -748,7 +767,7 @@
sizeof(struct qseecom_unload_app_ireq),
&resp, sizeof(resp));
if (ret) {
- pr_err("Fail to unload APP\n");
+ pr_err("Fail to unload app id %d\n", req.app_id);
return -EFAULT;
}
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -964,7 +983,7 @@
int i = 0;
for (i = 0; i < MAX_ION_FD; i++) {
- if (req->ifd_data[i].fd != 0) {
+ if (req->ifd_data[i].fd > 0) {
field = (char *)req->cmd_req_buf +
req->ifd_data[i].cmd_buf_offset;
update = (uint32_t *) field;
@@ -986,7 +1005,7 @@
uint32_t length;
for (i = 0; i < MAX_ION_FD; i++) {
- if (req->ifd_data[i].fd != 0) {
+ if (req->ifd_data[i].fd > 0) {
/* Get the handle of the shared fd */
ihandle = ion_import_fd(qseecom.ion_clnt,
req->ifd_data[i].fd);
@@ -1113,11 +1132,13 @@
int ret = 0;
if (!qsee_perf_client)
- return -EINVAL;
+ return ret;
/* Check if the clk is valid */
- if (IS_ERR_OR_NULL(qseecom_bus_clk))
+ if (IS_ERR_OR_NULL(qseecom_bus_clk)) {
+ pr_warn("qseecom bus clock is null or error");
return -EINVAL;
+ }
mutex_lock(&qsee_bw_mutex);
if (!qsee_bw_count) {
@@ -1147,8 +1168,10 @@
return;
/* Check if the clk is valid */
- if (IS_ERR_OR_NULL(qseecom_bus_clk))
+ if (IS_ERR_OR_NULL(qseecom_bus_clk)) {
+ pr_warn("qseecom bus clock is null or error");
return;
+ }
mutex_lock(&qsee_bw_mutex);
if (qsee_bw_count > 0) {
@@ -1401,6 +1424,10 @@
char qsee_not_legacy = 0;
uint32_t system_call_id = QSEOS_CHECK_VERSION_CMD;
+ qsee_bw_count = 0;
+ qseecom_bus_clk = NULL;
+ qsee_perf_client = 0;
+
rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
if (rc < 0) {
pr_err("alloc_chrdev_region failed %d\n", rc);
@@ -1464,8 +1491,8 @@
&qsee_bus_pdata);
if (!qsee_perf_client) {
pr_err("Unable to register bus client\n");
-
- qseecom_bus_clk = clk_get(class_dev, "qseecom");
+ } else {
+ qseecom_bus_clk = clk_get(class_dev, "bus_clk");
if (IS_ERR(qseecom_bus_clk)) {
qseecom_bus_clk = NULL;
} else if (qseecom_bus_clk != NULL) {
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index a2b005e..9063e98 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -2889,7 +2889,8 @@
}
#ifdef CONFIG_HIGHMEM
- __free_pages(test->highmem, BUFFER_ORDER);
+ if (test->highmem)
+ __free_pages(test->highmem, BUFFER_ORDER);
#endif
kfree(test->buffer);
kfree(test);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index ce2176e..9385087 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -626,6 +626,11 @@
else if (host->ios.clock <= 200000000)
index = EXT_CSD_PWR_CL_200_195;
break;
+ case MMC_VDD_27_28:
+ case MMC_VDD_28_29:
+ case MMC_VDD_29_30:
+ case MMC_VDD_30_31:
+ case MMC_VDD_31_32:
case MMC_VDD_32_33:
case MMC_VDD_33_34:
case MMC_VDD_34_35:
@@ -1036,11 +1041,10 @@
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
- if (err) {
- pr_err("%s: power class selection to bus width %d failed\n",
- mmc_hostname(card->host), 1 << bus_width);
- goto err;
- }
+ if (err)
+ pr_warning("%s: power class selection to bus width %d"
+ " failed\n", mmc_hostname(card->host),
+ 1 << bus_width);
}
/*
@@ -1072,10 +1076,10 @@
err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
ext_csd);
if (err)
- pr_err("%s: power class selection to "
- "bus width %d failed\n",
- mmc_hostname(card->host),
- 1 << bus_width);
+ pr_warning("%s: power class selection to "
+ "bus width %d failed\n",
+ mmc_hostname(card->host),
+ 1 << bus_width);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
@@ -1103,10 +1107,10 @@
err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
ext_csd);
if (err)
- pr_err("%s: power class selection to "
- "bus width %d ddr %d failed\n",
- mmc_hostname(card->host),
- 1 << bus_width, ddr);
+ pr_warning("%s: power class selection to "
+ "bus width %d ddr %d failed\n",
+ mmc_hostname(card->host),
+ 1 << bus_width, ddr);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 8b250c12..28505636 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -31,17 +31,6 @@
{
int i, ret, count;
unsigned char pending;
- struct sdio_func *func;
-
- /*
- * Optimization, if there is only 1 function interrupt registered
- * call irq handler directly
- */
- func = card->sdio_single_irq;
- if (func) {
- func->irq_handler(func);
- return 1;
- }
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
if (ret) {
@@ -53,7 +42,7 @@
count = 0;
for (i = 1; i <= 7; i++) {
if (pending & (1 << i)) {
- func = card->sdio_func[i - 1];
+ struct sdio_func *func = card->sdio_func[i - 1];
if (!func) {
printk(KERN_WARNING "%s: pending IRQ for "
"non-existent function\n",
@@ -203,24 +192,6 @@
return 0;
}
-/* If there is only 1 function registered set sdio_single_irq */
-static void sdio_single_irq_set(struct mmc_card *card)
-{
- struct sdio_func *func;
- int i;
-
- card->sdio_single_irq = NULL;
- if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
- card->host->sdio_irqs == 1)
- for (i = 0; i < card->sdio_funcs; i++) {
- func = card->sdio_func[i];
- if (func && func->irq_handler) {
- card->sdio_single_irq = func;
- break;
- }
- }
-}
-
/**
* sdio_claim_irq - claim the IRQ for a SDIO function
* @func: SDIO function
@@ -262,7 +233,6 @@
ret = sdio_card_irq_get(func->card);
if (ret)
func->irq_handler = NULL;
- sdio_single_irq_set(func->card);
return ret;
}
@@ -287,7 +257,6 @@
if (func->irq_handler) {
func->irq_handler = NULL;
sdio_card_irq_put(func->card);
- sdio_single_irq_set(func->card);
}
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index ddb3881..14d8b75 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -449,12 +449,6 @@
This provides support for the SD/MMC cell found in the
MSM and QSD SOCs from Qualcomm.
-config MMC_MSM_SDIO_SUPPORT
- boolean "Qualcomm MSM SDIO support"
- depends on MMC_MSM
- help
- This enables SDIO support in the msm_sdcc driver.
-
config MMC_MSM_CARD_HW_DETECTION
boolean "Qualcomm MMC Hardware detection support"
depends on MMC_MSM
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 69ec647..b4d2edc 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1666,13 +1666,11 @@
msmsdcc_print_status(host, "irq0-p", status);
#endif
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
if (status & MCI_SDIOINTROPE) {
if (host->sdcc_suspending)
wake_lock(&host->sdio_suspend_wlock);
mmc_signal_sdio_irq(host->mmc);
}
-#endif
data = host->curr.data;
if (host->dummy_52_sent) {
@@ -2741,7 +2739,6 @@
return status;
}
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct msmsdcc_host *host = mmc_priv(mmc);
@@ -2771,7 +2768,6 @@
}
}
}
-#endif /* CONFIG_MMC_MSM_SDIO_SUPPORT */
#ifdef CONFIG_PM_RUNTIME
static int msmsdcc_enable(struct mmc_host *mmc)
@@ -3201,14 +3197,15 @@
static int find_most_appropriate_phase(struct msmsdcc_host *host,
u8 *phase_table, u8 total_phases)
{
+ #define MAX_PHASES 16
int ret;
- u8 ranges[16][16] = { {0}, {0} };
- u8 phases_per_row[16] = {0};
+ u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
+ u8 phases_per_row[MAX_PHASES] = {0};
int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
bool phase_0_found = false, phase_15_found = false;
- if (total_phases > 16) {
+ if (!total_phases || (total_phases > MAX_PHASES)) {
pr_err("%s: %s: invalid argument: total_phases=%d\n",
mmc_hostname(host->mmc), __func__, total_phases);
return -EINVAL;
@@ -3228,6 +3225,9 @@
}
}
+ if (row_index >= MAX_PHASES)
+ return -EINVAL;
+
/* Check if phase-0 is present in first valid window? */
if (!ranges[0][0]) {
phase_0_found = true;
@@ -3235,7 +3235,7 @@
/* Check if cycle exist between 2 valid windows */
for (cnt = 1; cnt <= row_index; cnt++) {
if (phases_per_row[cnt]) {
- for (i = 0; i <= phases_per_row[cnt]; i++) {
+ for (i = 0; i < phases_per_row[cnt]; i++) {
if (ranges[cnt][i] == 15) {
phase_15_found = true;
phase_15_raw_index = cnt;
@@ -3253,12 +3253,23 @@
/* number of phases in raw where phase 15 is present */
u8 phases_15 = phases_per_row[phase_15_raw_index];
- cnt = 0;
- for (i = phases_15; i < (phases_15 + phases_0); i++) {
+ if (phases_0 + phases_15 >= MAX_PHASES)
+ /*
+ * If there are more than 1 phase windows then total
+ * number of phases in both the windows should not be
+ * more than or equal to MAX_PHASES.
+ */
+ return -EINVAL;
+
+ /* Merge 2 cyclic windows */
+ i = phases_15;
+ for (cnt = 0; cnt < phases_0; cnt++) {
ranges[phase_15_raw_index][i] =
ranges[phase_0_raw_index][cnt];
- cnt++;
+ if (++i >= MAX_PHASES)
+ break;
}
+
phases_per_row[phase_0_raw_index] = 0;
phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
}
@@ -3270,9 +3281,18 @@
}
}
- i = ((curr_max * 3) / 4) - 1;
+ i = ((curr_max * 3) / 4);
+ if (i)
+ i--;
+
ret = (int)ranges[selected_row_index][i];
+ if (ret >= MAX_PHASES) {
+ ret = -EINVAL;
+ pr_err("%s: %s: invalid phase selected=%d\n",
+ mmc_hostname(host->mmc), __func__, ret);
+ }
+
return ret;
}
@@ -3397,9 +3417,7 @@
.request = msmsdcc_request,
.set_ios = msmsdcc_set_ios,
.get_ro = msmsdcc_get_ro,
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
.enable_sdio_irq = msmsdcc_enable_sdio_irq,
-#endif
.start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
.execute_tuning = msmsdcc_execute_tuning
};
@@ -4526,9 +4544,7 @@
if (plat->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
mmc->caps |= MMC_CAP_SDIO_IRQ;
-#endif
if (plat->is_sdio_al_client)
mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY;
diff --git a/drivers/net/msm_rmnet_bam.c b/drivers/net/msm_rmnet_bam.c
index 401b63c..bbcf3c4 100644
--- a/drivers/net/msm_rmnet_bam.c
+++ b/drivers/net/msm_rmnet_bam.c
@@ -79,6 +79,7 @@
#endif
struct sk_buff *waiting_for_ul_skb;
spinlock_t lock;
+ spinlock_t tx_queue_lock;
struct tasklet_struct tsklt;
u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */
uint8_t device_up;
@@ -321,6 +322,7 @@
{
struct rmnet_private *p = netdev_priv(dev);
u32 opmode = p->operation_mode;
+ unsigned long flags;
DBG1("%s: write complete\n", __func__);
if (RMNET_IS_MODE_IP(opmode) ||
@@ -335,12 +337,15 @@
((struct net_device *)(dev))->name, p->stats.tx_packets,
skb->len, skb->mark);
dev_kfree_skb_any(skb);
+
+ spin_lock_irqsave(&p->tx_queue_lock, flags);
if (netif_queue_stopped(dev) &&
msm_bam_dmux_is_ch_low(p->ch_id)) {
DBG0("%s: Low WM hit, waking queue=%p\n",
__func__, skb);
netif_wake_queue(dev);
}
+ spin_unlock_irqrestore(&p->tx_queue_lock, flags);
}
static void bam_notify(void *dev, int event, unsigned long data)
@@ -509,10 +514,12 @@
goto exit;
}
+ spin_lock_irqsave(&p->tx_queue_lock, flags);
if (msm_bam_dmux_is_ch_full(p->ch_id)) {
netif_stop_queue(dev);
DBG0("%s: High WM hit, stopping queue=%p\n", __func__, skb);
}
+ spin_unlock_irqrestore(&p->tx_queue_lock, flags);
exit:
msm_bam_dmux_ul_power_unvote();
@@ -770,6 +777,7 @@
p->waiting_for_ul_skb = NULL;
p->in_reset = 0;
spin_lock_init(&p->lock);
+ spin_lock_init(&p->tx_queue_lock);
#ifdef CONFIG_MSM_RMNET_DEBUG
p->timeout_us = timeout_us;
p->wakeups_xmit = p->wakeups_rcv = 0;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 2620108..d07487b 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -372,6 +372,7 @@
tasklet_schedule (&dev->bh);
break;
case 0:
+ usb_mark_last_busy(dev->udev);
__skb_queue_tail (&dev->rxq, skb);
}
} else {
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index 9b90184..8cfc0fa 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -29,6 +29,7 @@
static suspend_handler_t *libra_suspend_hldr;
static resume_handler_t *libra_resume_hldr;
static notify_card_removal_t *libra_notify_card_removal_hdlr;
+static shutdown_handler_t *libra_sdio_shutdown_hdlr;
int libra_enable_sdio_irq_in_chip(struct sdio_func *func, u8 enable)
{
@@ -452,6 +453,23 @@
#define libra_sdio_resume 0
#endif
+static void libra_sdio_shutdown(struct device *dev)
+{
+ if (libra_sdio_shutdown_hdlr) {
+ libra_sdio_shutdown_hdlr();
+ printk(KERN_INFO "%s : Notified shutdown event to Libra driver.\n",
+ __func__);
+ }
+}
+
+int libra_sdio_register_shutdown_hdlr(
+ shutdown_handler_t *libra_shutdown_hdlr)
+{
+ libra_sdio_shutdown_hdlr = libra_shutdown_hdlr;
+ return 0;
+}
+EXPORT_SYMBOL(libra_sdio_register_shutdown_hdlr);
+
int libra_sdio_notify_card_removal(
notify_card_removal_t *libra_sdio_notify_card_removal_hdlr)
{
@@ -472,11 +490,12 @@
};
static struct sdio_driver libra_sdiofn_driver = {
- .name = "libra_sdiofn",
- .id_table = libra_sdioid,
- .probe = libra_sdio_probe,
- .remove = libra_sdio_remove,
- .drv.pm = &libra_sdio_pm_ops,
+ .name = "libra_sdiofn",
+ .id_table = libra_sdioid,
+ .probe = libra_sdio_probe,
+ .remove = libra_sdio_remove,
+ .drv.pm = &libra_sdio_pm_ops,
+ .drv.shutdown = libra_sdio_shutdown,
};
static int __init libra_sdioif_init(void)
@@ -487,6 +506,7 @@
libra_suspend_hldr = NULL;
libra_resume_hldr = NULL;
libra_notify_card_removal_hdlr = NULL;
+ libra_sdio_shutdown_hdlr = NULL;
sdio_register_driver(&libra_sdiofn_driver);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index a306357..b8cdc6b 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -81,4 +81,10 @@
help
OpenFirmware SPMI bus accessors
+config OF_SLIMBUS
+ def_tristate SLIMBUS
+ depends on SLIMBUS
+ help
+ OpenFirmware SLIMBUS accessors
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 2087c5e..bc2b481 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_SPMI) += of_spmi.o
+obj-$(CONFIG_OF_SLIMBUS) += of_slimbus.o
diff --git a/drivers/of/of_slimbus.c b/drivers/of/of_slimbus.c
new file mode 100644
index 0000000..512ca73
--- /dev/null
+++ b/drivers/of/of_slimbus.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+/* OF helpers for SLIMbus */
+#include <linux/slimbus/slimbus.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_slimbus.h>
+
+int of_register_slim_devices(struct slim_controller *ctrl)
+{
+ struct device_node *node;
+ struct slim_boardinfo *binfo = NULL;
+ int n = 0;
+ int ret = 0;
+
+ if (!ctrl->dev.of_node)
+ return -EINVAL;
+
+ for_each_child_of_node(ctrl->dev.of_node, node) {
+ struct property *prop;
+ struct slim_device *slim;
+ char *name;
+ prop = of_find_property(node, "elemental-addr", NULL);
+ if (!prop || prop->length != 6) {
+ dev_err(&ctrl->dev, "of_slim: invalid E-addr");
+ continue;
+ }
+ name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
+ if (!name) {
+ dev_err(&ctrl->dev, "of_slim: out of memory");
+ ret = -ENOMEM;
+ goto of_slim_err;
+ }
+ if (of_modalias_node(node, name, SLIMBUS_NAME_SIZE) < 0) {
+ dev_err(&ctrl->dev, "of_slim: modalias failure on %s\n",
+ node->full_name);
+ kfree(name);
+ continue;
+ }
+ slim = kzalloc(sizeof(struct slim_device), GFP_KERNEL);
+ if (!slim) {
+ dev_err(&ctrl->dev, "of_slim: out of memory");
+ ret = -ENOMEM;
+ kfree(name);
+ goto of_slim_err;
+ }
+ memcpy(slim->e_addr, prop->value, 6);
+
+ binfo = krealloc(binfo, (n + 1) * sizeof(struct slim_boardinfo),
+ GFP_KERNEL);
+ if (!binfo) {
+ dev_err(&ctrl->dev, "out of memory");
+ kfree(name);
+ kfree(slim);
+ return -ENOMEM;
+ }
+ slim->name = (const char *)name;
+ binfo[n].bus_num = ctrl->nr;
+ binfo[n].slim_slave = slim;
+ n++;
+ }
+ return slim_register_board_info(binfo, n);
+of_slim_err:
+ n--;
+ while (n >= 0) {
+ kfree(binfo[n].slim_slave->name);
+ kfree(binfo[n].slim_slave);
+ }
+ kfree(binfo);
+ return ret;
+}
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index 112497c..61085c9 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -203,9 +203,18 @@
struct device_node *node;
int rc, i, num_dev_node = 0;
- /* first count the total number of device_nodes */
- for_each_child_of_node(container, node)
+ if (!of_device_is_available(container))
+ return;
+
+ /*
+ * Count the total number of device_nodes so we know how much
+ * device_store to allocate.
+ */
+ for_each_child_of_node(container, node) {
+ if (!of_device_is_available(node))
+ continue;
num_dev_node++;
+ }
rc = of_spmi_alloc_device_store(d_info, num_dev_node);
if (rc) {
@@ -214,9 +223,10 @@
return;
}
- /* allocate resources per device_node */
i = 0;
for_each_child_of_node(container, node) {
+ if (!of_device_is_available(node))
+ continue;
of_spmi_init_resource(&r_info, node);
of_spmi_sum_node_resources(&r_info, 1);
rc = of_spmi_allocate_node_resources(d_info, &r_info, i);
@@ -226,17 +236,6 @@
of_spmi_free_device_resources(d_info);
return;
}
- i++;
- }
-
- /**
- * Now we need to cycle through again and actually populate
- * the resources for each node.
- */
- i = 0;
- for_each_child_of_node(container, node) {
- of_spmi_init_resource(&r_info, node);
- of_spmi_sum_node_resources(&r_info, 1);
of_spmi_populate_node_resources(d_info, &r_info, i);
i++;
}
@@ -265,6 +264,9 @@
for_each_child_of_node(container, node) {
struct of_spmi_res_info r_info;
+ if (!of_device_is_available(node))
+ continue;
+
/**
* Check to see if this node contains children which
* should be all created as the same spmi_device.
@@ -365,6 +367,9 @@
continue;
}
+ if (!of_device_is_available(node))
+ continue;
+
rc = of_spmi_alloc_device_store(&d_info, 1);
if (rc) {
dev_err(&ctrl->dev, "%s: unable to allocate"
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index edef402..f2981bf 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -27,7 +27,7 @@
*
*/
#define BAM_MIN_VERSION 2
-#define BAM_MAX_VERSION 0x1f
+#define BAM_MAX_VERSION 0x2f
#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
@@ -95,6 +95,8 @@
*
*/
/* CTRL */
+#define CACHE_MISS_ERR_RESP_EN 0x80000
+#define LOCAL_CLK_GATING 0x60000
#define IBC_DISABLE 0x10000
#define BAM_CACHED_DESC_STORE 0x8000
#define BAM_DESC_CACHE_SEL 0x6000
@@ -172,17 +174,23 @@
#define AHB_MASTER_ERR_CTRLS_BAM_ERR_HTRANS 0x3
/* TRUST_REG */
+#define LOCK_EE_CTRL 0x2000
#define BAM_VMID 0x1f00
#define BAM_RST_BLOCK 0x80
#define BAM_EE 0x7
/* TEST_BUS_SEL */
+#define BAM_SW_EVENTS_ZERO 0x200000
+#define BAM_SW_EVENTS_SEL 0x180000
#define BAM_DATA_ERASE 0x40000
#define BAM_DATA_FLUSH 0x20000
#define BAM_CLK_ALWAYS_ON 0x10000
#define BAM_TESTBUS_SEL 0x7f
/* CNFG_BITS */
+#define CNFG_BITS_MULTIPLE_EVENTS_DESC_AVAIL_EN 0x40000000
+#define CNFG_BITS_MULTIPLE_EVENTS_SIZE_EN 0x20000000
+#define CNFG_BITS_BAM_ZLT_W_CD_SUPPORT 0x10000000
#define CNFG_BITS_BAM_CD_ENABLE 0x8000000
#define CNFG_BITS_BAM_AU_ACCUMED 0x4000000
#define CNFG_BITS_BAM_PSM_P_HD_DATA 0x2000000
@@ -222,6 +230,7 @@
/* P_TRUST_REGn */
#define BAM_P_VMID 0x1f00
+#define BAM_P_SUP_GROUP 0xf8
#define BAM_P_EE 0x7
/* P_IRQ_STTSn */
@@ -663,6 +672,12 @@
bam_write_reg_field(base, CTRL, BAM_EN, 1);
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ bam_write_reg_field(base, CTRL, CACHE_MISS_ERR_RESP_EN, 1);
+
+ bam_write_reg_field(base, CTRL, LOCAL_CLK_GATING, 1);
+#endif
+
bam_write_reg(base, DESC_CNT_TRSHLD, summing_threshold);
bam_write_reg(base, CNFG_BITS, cfg_bits);
@@ -862,6 +877,14 @@
bam_write_reg_field(base, P_CTRL(pipe), P_SYS_STRM,
param->stream_mode);
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ bam_write_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP,
+ param->lock_group);
+
+ SPS_DBG("sps:bam=0x%x(va).pipe=%d.lock_group=%d.\n",
+ (u32) base, pipe, param->lock_group);
+#endif
+
if (param->mode == BAM_PIPE_MODE_BAM2BAM) {
u32 peer_dest_addr = param->peer_phys_addr +
P_EVNT_REG(param->peer_pipe);
@@ -878,6 +901,14 @@
(u32) base, pipe,
(u32) param->peer_phys_addr,
param->peer_pipe);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ bam_write_reg_field(base, P_CTRL(pipe), P_WRITE_NWD,
+ param->write_nwd);
+
+ SPS_DBG("sps:%s WRITE_NWD bit for this bam2bam pipe.",
+ param->write_nwd ? "Set" : "Do not set");
+#endif
}
/* Pipe Enable - at last */
diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h
index d672a88..789769f 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/sps/bam.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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,6 +39,13 @@
BAM_STREAM_MODE_ENABLE = 1,
};
+/* NWD written Type */
+enum bam_write_nwd {
+ BAM_WRITE_NWD_DISABLE = 0,
+ BAM_WRITE_NWD_ENABLE = 1,
+};
+
+
/* Enable Type */
enum bam_enable {
BAM_DISABLE = 0,
@@ -63,8 +70,10 @@
u32 pipe_irq_mask;
enum bam_pipe_dir dir;
enum bam_pipe_mode mode;
+ enum bam_write_nwd write_nwd;
u32 desc_base; /* Physical address of descriptor FIFO */
u32 desc_size; /* Size (bytes) of descriptor FIFO */
+ u32 lock_group; /* The lock group this pipe belongs to */
enum bam_stream_mode stream_mode;
u32 ee; /* BAM execution environment index */
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index b876d2d..0fe8f2a 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -824,6 +824,12 @@
return -EAGAIN;
}
+ if ((connect->lock_group != SPSRM_CLEAR)
+ && (connect->lock_group > BAM_MAX_P_LOCK_GROUP_NUM)) {
+ SPS_ERR("sps:The value of pipe lock group is invalid.\n");
+ return SPS_ERROR;
+ }
+
mutex_lock(&sps->lock);
/*
* Must lock the BAM device at the top level function, so must
@@ -1060,6 +1066,34 @@
SPS_DBG("sps:%s.", __func__);
+ if ((flags & SPS_IOVEC_FLAG_NWD) &&
+ !(flags & (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_CMD))) {
+ SPS_ERR("sps:NWD is only valid with EOT or CMD.\n");
+ return SPS_ERROR;
+ } else if ((flags & SPS_IOVEC_FLAG_EOT) &&
+ (flags & SPS_IOVEC_FLAG_CMD)) {
+ SPS_ERR("sps:EOT and CMD are not allowed to coexist.\n");
+ return SPS_ERROR;
+ } else if (!(flags & SPS_IOVEC_FLAG_CMD) &&
+ (flags & (SPS_IOVEC_FLAG_LOCK | SPS_IOVEC_FLAG_UNLOCK))) {
+ SPS_ERR("sps:pipe lock and unlock flags are only valid with "
+ "Command Descriptor.\n");
+ return SPS_ERROR;
+ } else if ((flags & SPS_IOVEC_FLAG_LOCK) &&
+ (flags & SPS_IOVEC_FLAG_UNLOCK)) {
+ SPS_ERR("sps:Can't lock and unlock a pipe by the same"
+ "Command Descriptor.\n");
+ return SPS_ERROR;
+ } else if ((flags & SPS_IOVEC_FLAG_IMME) &&
+ (flags & SPS_IOVEC_FLAG_CMD)) {
+ SPS_ERR("sps:Immediate and CMD are not allowed to coexist.\n");
+ return SPS_ERROR;
+ } else if ((flags & SPS_IOVEC_FLAG_IMME) &&
+ (flags & SPS_IOVEC_FLAG_NWD)) {
+ SPS_ERR("sps:Immediate and NWD are not allowed to coexist.\n");
+ return SPS_ERROR;
+ }
+
bam = sps_bam_lock(pipe);
if (bam == NULL)
return SPS_ERROR;
@@ -1318,6 +1352,32 @@
EXPORT_SYMBOL(sps_free_mem);
/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ */
+int sps_get_unused_desc_num(struct sps_pipe *h, u32 *desc_num)
+{
+ struct sps_pipe *pipe = h;
+ struct sps_bam *bam;
+ int result;
+
+ SPS_DBG("sps:%s.", __func__);
+
+ bam = sps_bam_lock(pipe);
+ if (bam == NULL)
+ return SPS_ERROR;
+
+ result = sps_bam_pipe_get_unused_desc_num(bam, pipe->pipe_index,
+ desc_num);
+
+ sps_bam_unlock(bam);
+
+ return result;
+}
+EXPORT_SYMBOL(sps_get_unused_desc_num);
+
+/**
* Register a BAM device
*
*/
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index b5192d1..6c8b1f9 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -35,7 +35,9 @@
/* Mask for valid hardware descriptor flags */
#define BAM_IOVEC_FLAG_MASK \
- (SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_EOB)
+ (SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_EOB | \
+ SPS_IOVEC_FLAG_NWD | SPS_IOVEC_FLAG_CMD | SPS_IOVEC_FLAG_LOCK | \
+ SPS_IOVEC_FLAG_UNLOCK | SPS_IOVEC_FLAG_IMME)
/* Mask for invalid BAM-to-BAM pipe options */
#define BAM2BAM_O_INVALID \
@@ -712,6 +714,7 @@
}
hw_params.event_threshold = (u16) map_pipe->event_threshold;
hw_params.ee = dev->props.ee;
+ hw_params.lock_group = map_pipe->lock_group;
/* Verify that control of this pipe is allowed */
if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_CTRL) ||
@@ -751,6 +754,14 @@
/* Clear the data FIFO for debug */
if (map->data.base != NULL && bam_pipe->mode == SPS_MODE_SRC)
memset(map->data.base, 0, hw_params.data_size);
+
+ /* set NWD bit for BAM2BAM producer pipe */
+ if (bam_pipe->mode == SPS_MODE_SRC) {
+ if ((params->options & SPS_O_WRITE_NWD) == 0)
+ hw_params.write_nwd = BAM_WRITE_NWD_DISABLE;
+ else
+ hw_params.write_nwd = BAM_WRITE_NWD_ENABLE;
+ }
} else {
/* System mode */
hw_params.mode = BAM_PIPE_MODE_SYSTEM;
@@ -1949,3 +1960,29 @@
return result;
}
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ */
+int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index,
+ u32 *desc_num)
+{
+ u32 sw_offset, peer_offset, fifo_size;
+ u32 desc_size = sizeof(struct sps_iovec);
+ struct sps_pipe *pipe = dev->pipes[pipe_index];
+
+ if (pipe == NULL)
+ return SPS_ERROR;
+
+ fifo_size = pipe->desc_size;
+
+ sw_offset = bam_pipe_get_desc_read_offset(dev->base, pipe_index);
+ peer_offset = bam_pipe_get_desc_write_offset(dev->base, pipe_index);
+
+ if (sw_offset <= peer_offset)
+ *desc_num = (peer_offset - sw_offset) / desc_size;
+ else
+ *desc_num = (peer_offset + fifo_size - sw_offset) / desc_size;
+
+ return 0;
+}
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 70e7898..6004b75 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -545,4 +545,20 @@
int sps_bam_pipe_timer_ctrl(struct sps_bam *dev, u32 pipe_index,
struct sps_timer_ctrl *timer_ctrl,
struct sps_timer_result *timer_result);
+
+
+/**
+ * Get the number of unused descriptors in the descriptor FIFO
+ * of a pipe
+ *
+ * @dev - pointer to BAM device descriptor
+ *
+ * @pipe_index - pipe index
+ *
+ * @desc_num - number of unused descriptors
+ *
+ */
+int sps_bam_pipe_get_unused_desc_num(struct sps_bam *dev, u32 pipe_index,
+ u32 *desc_num);
+
#endif /* _SPSBAM_H_ */
diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c
index 75194e0..c980eb0 100644
--- a/drivers/platform/msm/sps/sps_rm.c
+++ b/drivers/platform/msm/sps/sps_rm.c
@@ -22,9 +22,6 @@
#include "spsi.h"
#include "sps_core.h"
-/* "Clear" value for the connection parameter struct */
-#define SPSRM_CLEAR 0xcccccccc
-
/* Max BAM FIFO sizes */
#define SPSRM_MAX_DESC_FIFO_SIZE 0xffff
#define SPSRM_MAX_DATA_FIFO_SIZE 0xffff
@@ -198,6 +195,8 @@
pipe->pipe_index = map->src.pipe_index;
if (pipe->connect.event_thresh != SPSRM_CLEAR)
map->src.event_threshold = pipe->connect.event_thresh;
+ if (pipe->connect.lock_group != SPSRM_CLEAR)
+ map->src.lock_group = pipe->connect.lock_group;
} else {
map->client_dest = pipe;
pipe->bam = map->dest.bam;
@@ -205,6 +204,8 @@
if (pipe->connect.event_thresh != SPSRM_CLEAR)
map->dest.event_threshold =
pipe->connect.event_thresh;
+ if (pipe->connect.lock_group != SPSRM_CLEAR)
+ map->dest.lock_group = pipe->connect.lock_group;
}
pipe->map = map;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 4126999..8e4907b 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -28,6 +28,7 @@
#include "sps_map.h"
#define BAM_MAX_PIPES 31
+#define BAM_MAX_P_LOCK_GROUP_NUM 31
/* Adjust for offset of struct sps_q_event */
#define SPS_EVENT_INDEX(e) ((e) - 1)
@@ -36,6 +37,9 @@
/* BAM identifier used in log messages */
#define BAM_ID(dev) ((dev)->props.phys_addr)
+/* "Clear" value for the connection parameter struct */
+#define SPSRM_CLEAR 0xcccccccc
+
#ifdef CONFIG_DEBUG_FS
extern u8 debugfs_record_enabled;
extern u8 logging_option;
@@ -127,6 +131,7 @@
u32 bam_phys; /* Physical address of BAM. */
u32 pipe_index; /* Pipe index */
u32 event_threshold; /* Pipe event threshold */
+ u32 lock_group; /* The lock group this pipe belongs to */
void *bam;
};
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index cdc6c50..1454ca9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1904,13 +1904,14 @@
turn_on_usb_ovp_fet(chip);
} else {
- pm_chg_masked_write(chip, USB_OVP_CONTROL,
- USB_OVP_DEBOUNCE_TIME, 0x1);
- pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
- count, chg_gone, usb_chg_plugged_in);
- return;
+ break;
}
}
+ pm_chg_masked_write(chip, USB_OVP_CONTROL,
+ USB_OVP_DEBOUNCE_TIME, 0x2);
+ pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
+ count, chg_gone, usb_chg_plugged_in);
+ return;
}
static int find_usb_ma_value(int value)
@@ -2249,7 +2250,7 @@
pr_debug("fsm_state=%d reg_loop=0x%x\n",
pm_chg_get_fsm_state(data),
pm_chg_get_regulation_loop(data));
- unplug_check_worker(&(chip->unplug_check_work.work));
+ schedule_work(&chip->unplug_check_work.work);
return IRQ_HANDLED;
}
@@ -2326,15 +2327,23 @@
static irqreturn_t chg_gone_irq_handler(int irq, void *data)
{
struct pm8921_chg_chip *chip = data;
- int chg_gone, usb_chg_plugged_in;
+ u8 reg;
+ int rc, chg_gone, usb_chg_plugged_in;
usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
+ pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
+
+ rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL_3, ®);
+ if (rc)
+ pr_err("Failed to read CHG_CNTRL_3 rc=%d\n", rc);
+
+ if (reg & CHG_USB_SUSPEND_BIT)
+ return IRQ_HANDLED;
schedule_work(&chip->unplug_ovp_fet_open_work);
- pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
power_supply_changed(&chip->batt_psy);
power_supply_changed(&chip->usb_psy);
return IRQ_HANDLED;
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 65bc654..ce72a5b 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -214,8 +214,8 @@
break;
}
if (i == ADC_WAIT_COUNT) {
- pr_err("waited too long for offset eoc\n");
- return rc;
+ pr_err("waited too long for offset eoc returning -EBUSY\n");
+ return -EBUSY;
}
rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index d63fddb..443f2df 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -426,7 +426,7 @@
/* replace driver_data with info */
info->regulator = regulator_register(&info->desc, &pdev->dev,
- pdata, info);
+ pdata, info, NULL);
if (IS_ERR(info->regulator)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
info->desc.name);
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 74b1f71..7e529c7 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_REGULATOR) += core.o dummy.o
+obj-$(CONFIG_OF) += of_regulator.o
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 585e494..042271a 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -634,7 +634,7 @@
rdev = regulator_register(&ab3100_regulator_desc[i],
&pdev->dev,
&plfdata->reg_constraints[i],
- reg);
+ reg, NULL);
if (IS_ERR(rdev)) {
err = PTR_ERR(rdev);
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 02f3c23..8b13b0e 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -821,7 +821,7 @@
/* register regulator with framework */
info->regulator = regulator_register(&info->desc, &pdev->dev,
- &pdata->regulator[i], info);
+ &pdata->regulator[i], info, NULL);
if (IS_ERR(info->regulator)) {
err = PTR_ERR(info->regulator);
dev_err(&pdev->dev, "failed to register regulator %s\n",
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index a4be416..483c809 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -233,7 +233,7 @@
chip->current_mask = (chip->current_level - 1) << chip->current_offset;
chip->rdev = regulator_register(&ad5398_reg, &client->dev,
- init_data, chip);
+ init_data, chip, NULL);
if (IS_ERR(chip->rdev)) {
ret = PTR_ERR(chip->rdev);
dev_err(&client->dev, "failed to register %s %s\n",
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
index 068d488..dc4a8e6 100644
--- a/drivers/regulator/bq24022.c
+++ b/drivers/regulator/bq24022.c
@@ -106,7 +106,7 @@
ret = gpio_direction_output(pdata->gpio_nce, 1);
bq24022 = regulator_register(&bq24022_desc, &pdev->dev,
- pdata->init_data, pdata);
+ pdata->init_data, pdata, NULL);
if (IS_ERR(bq24022)) {
dev_dbg(&pdev->dev, "couldn't register regulator\n");
ret = PTR_ERR(bq24022);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2b58215..3f9beaa4 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -27,6 +27,8 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -128,6 +130,33 @@
return NULL;
}
+/**
+ * of_get_regulator - get a regulator device node based on supply name
+ * @dev: Device pointer for the consumer (of regulator) device
+ * @supply: regulator supply name
+ *
+ * Extract the regulator device node corresponding to the supply name.
+ * retruns the device node corresponding to the regulator if found, else
+ * returns NULL.
+ */
+static struct device_node *of_get_regulator(struct device *dev, const char *supply)
+{
+ struct device_node *regnode = NULL;
+ char prop_name[32]; /* 32 is max size of property name */
+
+ dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
+
+ snprintf(prop_name, 32, "%s-supply", supply);
+ regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+ if (!regnode) {
+ dev_warn(dev, "%s property in node %s references invalid phandle",
+ prop_name, dev->of_node->full_name);
+ return NULL;
+ }
+ return regnode;
+}
+
/* Platform voltage constraint check */
static int regulator_check_voltage(struct regulator_dev *rdev,
int *min_uV, int *max_uV)
@@ -1208,6 +1237,30 @@
return rdev->desc->ops->enable_time(rdev);
}
+static struct regulator_dev *regulator_dev_lookup(struct device *dev,
+ const char *supply)
+{
+ struct regulator_dev *r;
+ struct device_node *node;
+
+ /* first do a dt based lookup */
+ if (dev && dev->of_node) {
+ node = of_get_regulator(dev, supply);
+ if (node)
+ list_for_each_entry(r, ®ulator_list, list)
+ if (r->dev.parent &&
+ node == r->dev.of_node)
+ return r;
+ }
+
+ /* if not found, try doing it non-dt way */
+ list_for_each_entry(r, ®ulator_list, list)
+ if (strcmp(rdev_get_name(r), supply) == 0)
+ return r;
+
+ return NULL;
+}
+
/* Internal regulator request function */
static struct regulator *_regulator_get(struct device *dev, const char *id,
int exclusive)
@@ -1228,6 +1281,10 @@
mutex_lock(®ulator_list_mutex);
+ rdev = regulator_dev_lookup(dev, id);
+ if (rdev)
+ goto found;
+
list_for_each_entry(map, ®ulator_map_list, list) {
/* If the mapping has a device set up it must match */
if (map->dev_name &&
@@ -3080,11 +3137,12 @@
*/
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, const struct regulator_init_data *init_data,
- void *driver_data)
+ void *driver_data, struct device_node *of_node)
{
static atomic_t regulator_no = ATOMIC_INIT(0);
struct regulator_dev *rdev;
int ret, i;
+ const char *supply = NULL;
if (regulator_desc == NULL)
return ERR_PTR(-EINVAL);
@@ -3140,6 +3198,7 @@
/* register with sysfs */
rdev->dev.class = ®ulator_class;
+ rdev->dev.of_node = of_node;
rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(®ulator_no) - 1);
@@ -3161,21 +3220,18 @@
if (ret < 0)
goto scrub;
- if (init_data->supply_regulator) {
+ if (init_data->supply_regulator)
+ supply = init_data->supply_regulator;
+ else if (regulator_desc->supply_name)
+ supply = regulator_desc->supply_name;
+
+ if (supply) {
struct regulator_dev *r;
- int found = 0;
- list_for_each_entry(r, ®ulator_list, list) {
- if (strcmp(rdev_get_name(r),
- init_data->supply_regulator) == 0) {
- found = 1;
- break;
- }
- }
+ r = regulator_dev_lookup(dev, supply);
- if (!found) {
- dev_err(dev, "Failed to find supply %s\n",
- init_data->supply_regulator);
+ if (!r) {
+ dev_err(dev, "Failed to find supply %s\n", supply);
ret = -ENODEV;
goto scrub;
}
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 362e082..f3064fe 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -536,7 +536,7 @@
ri->desc.ops = &da9030_regulator_ldo1_15_ops;
rdev = regulator_register(&ri->desc, &pdev->dev,
- pdev->dev.platform_data, ri);
+ pdev->dev.platform_data, ri, NULL);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
index 2bb8f45..f88b13d 100644
--- a/drivers/regulator/db8500-prcmu.c
+++ b/drivers/regulator/db8500-prcmu.c
@@ -485,7 +485,7 @@
/* register with the regulator framework */
info->rdev = regulator_register(&info->desc, &pdev->dev,
- init_data, info);
+ init_data, info, NULL);
if (IS_ERR(info->rdev)) {
err = PTR_ERR(info->rdev);
dev_err(&pdev->dev, "failed to register %s: err %i\n",
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index c7410bd..910583f 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -36,6 +36,29 @@
.ops = &dummy_ops,
};
+static int __devinit dummy_regulator_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
+ &dummy_initdata, NULL, NULL);
+ if (IS_ERR(dummy_regulator_rdev)) {
+ ret = PTR_ERR(dummy_regulator_rdev);
+ pr_err("Failed to register regulator: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver dummy_regulator_driver = {
+ .probe = dummy_regulator_probe,
+ .driver = {
+ .name = "reg-dummy",
+ .owner = THIS_MODULE,
+ },
+};
+
static struct platform_device *dummy_pdev;
void __init regulator_dummy_init(void)
@@ -55,12 +78,9 @@
return;
}
- dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
- &dummy_initdata, NULL);
- if (IS_ERR(dummy_regulator_rdev)) {
- ret = PTR_ERR(dummy_regulator_rdev);
- pr_err("Failed to register regulator: %d\n", ret);
+ ret = platform_driver_register(&dummy_regulator_driver);
+ if (ret != 0) {
+ pr_err("Failed to register dummy regulator driver: %d\n", ret);
platform_device_unregister(dummy_pdev);
- return;
}
}
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 2fe9d99c..906b265 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -26,6 +26,10 @@
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
struct fixed_voltage_data {
struct regulator_desc desc;
@@ -37,6 +41,53 @@
bool is_enabled;
};
+
+/**
+ * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
+ * @dev: device requesting for fixed_voltage_config
+ *
+ * Populates fixed_voltage_config structure by extracting data from device
+ * tree node, returns a pointer to the populated structure of NULL if memory
+ * alloc fails.
+ */
+struct fixed_voltage_config *of_get_fixed_voltage_config(struct device *dev)
+{
+ struct fixed_voltage_config *config;
+ struct device_node *np = dev->of_node;
+ const __be32 *delay;
+ struct regulator_init_data *init_data;
+
+ config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
+ GFP_KERNEL);
+ if (!config)
+ return NULL;
+
+ config->init_data = of_get_regulator_init_data(dev);
+ init_data = config->init_data;
+
+ config->supply_name = init_data->constraints.name;
+ if (init_data->constraints.min_uV == init_data->constraints.max_uV) {
+ config->microvolts = init_data->constraints.min_uV;
+ } else {
+ dev_err(dev,
+ "Fixed regulator specified with variable voltages\n");
+ return NULL;
+ }
+
+ if (init_data->constraints.boot_on)
+ config->enabled_at_boot = true;
+
+ config->gpio = of_get_named_gpio(np, "gpio", 0);
+ delay = of_get_property(np, "startup-delay-us", NULL);
+ if (delay)
+ config->startup_delay = be32_to_cpu(*delay);
+
+ if (of_find_property(np, "enable-active-high", NULL))
+ config->enable_high = true;
+
+ return config;
+}
+
static int fixed_voltage_is_enabled(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
@@ -108,6 +159,9 @@
struct fixed_voltage_data *drvdata;
int ret;
+ if (pdev->dev.of_node)
+ config = of_get_fixed_voltage_config(&pdev->dev);
+
drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
if (drvdata == NULL) {
dev_err(&pdev->dev, "Failed to allocate device data\n");
@@ -179,7 +233,7 @@
}
drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
- config->init_data, drvdata);
+ config->init_data, drvdata, NULL);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
@@ -216,12 +270,23 @@
return 0;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id fixed_of_match[] __devinitconst = {
+ { .compatible = "regulator-fixed", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, fixed_of_match);
+#else
+#define fixed_of_match NULL
+#endif
+
static struct platform_driver regulator_fixed_voltage_driver = {
.probe = reg_fixed_voltage_probe,
.remove = __devexit_p(reg_fixed_voltage_remove),
.driver = {
.name = "reg-fixed-voltage",
.owner = THIS_MODULE,
+ .of_match_table = fixed_of_match,
},
};
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index b91e32f..1fd390c 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -152,7 +152,7 @@
vreg->desc.owner = THIS_MODULE;
vreg->rdev = regulator_register(&vreg->desc, &pdev->dev,
- &pdata->init_data, vreg);
+ &pdata->init_data, vreg, NULL);
if (IS_ERR(vreg->rdev)) {
rc = PTR_ERR(vreg->rdev);
pr_err("%s: regulator_register failed, rc=%d.\n", vreg->name,
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index e4b3592..c1a456c 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -170,7 +170,7 @@
for (i = 0; i < 3; i++) {
pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev,
- init_data, pmic);
+ init_data, pmic, NULL);
if (IS_ERR(pmic->rdev[i])) {
dev_err(&i2c->dev, "failed to register %s\n", id->name);
err = PTR_ERR(pmic->rdev[i]);
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 0f22ef1..42b1a30 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -450,7 +450,7 @@
for (i = 0; i < pdata->num_regulators; i++) {
struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
lp3971->rdev[i] = regulator_register(®ulators[reg->id],
- lp3971->dev, reg->initdata, lp3971);
+ lp3971->dev, reg->initdata, lp3971, NULL);
if (IS_ERR(lp3971->rdev[i])) {
err = PTR_ERR(lp3971->rdev[i]);
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 6aa1b50..939e7f4 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -554,7 +554,7 @@
for (i = 0; i < pdata->num_regulators; i++) {
struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
lp3972->rdev[i] = regulator_register(®ulators[reg->id],
- lp3972->dev, reg->initdata, lp3972);
+ lp3972->dev, reg->initdata, lp3972, NULL);
if (IS_ERR(lp3972->rdev[i])) {
err = PTR_ERR(lp3972->rdev[i]);
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 3f49512..40e7a4d 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -214,7 +214,7 @@
}
rdev[i] = regulator_register(&max1586_reg[id], &client->dev,
pdata->subdevs[i].platform_data,
- max1586);
+ max1586, NULL);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(&client->dev, "failed to register %s\n",
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 30eb9e5..14d6d28 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -347,7 +347,7 @@
}
info->regulator = regulator_register(&dcdc_desc, &client->dev,
- pdata->regulator, info);
+ pdata->regulator, info, NULL);
if (IS_ERR(info->regulator)) {
dev_err(info->dev, "failed to register regulator %s\n",
dcdc_desc.name);
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 33f5d9a..a838e66 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -449,7 +449,7 @@
rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
pdata->subdevs[i].platform_data,
- max8660);
+ max8660, NULL);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(&client->dev, "failed to register %s\n",
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index e4dbd66..dd5fae9 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -265,7 +265,7 @@
ri->chip = chip;
rdev = regulator_register(&ri->desc, &pdev->dev,
- pdata->regulator[pdev->id], ri);
+ pdata->regulator[pdev->id], ri, NULL);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 486ed81..c4bfd4d 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -211,7 +211,7 @@
mutex_init(&max8952->mutex);
max8952->rdev = regulator_register(®ulator, max8952->dev,
- &pdata->reg_data, max8952);
+ &pdata->reg_data, max8952, NULL);
if (IS_ERR(max8952->rdev)) {
ret = PTR_ERR(max8952->rdev);
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index ad6628c..f701ca5 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -1145,7 +1145,7 @@
regulators[id].n_voltages = 16;
rdev[i] = regulator_register(®ulators[id], max8997->dev,
- pdata->regulators[i].initdata, max8997);
+ pdata->regulators[i].initdata, max8997, NULL);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(max8997->dev, "regulator init failed for %d\n",
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 41a1495..2d38c24 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -847,7 +847,7 @@
regulators[index].n_voltages = count;
}
rdev[i] = regulator_register(®ulators[index], max8998->dev,
- pdata->regulators[i].initdata, max8998);
+ pdata->regulators[i].initdata, max8998, NULL);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(max8998->dev, "regulator init failed\n");
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 730f43a..8d5822b 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -356,7 +356,7 @@
init_data = &pdata->regulators[i];
priv->regulators[i] = regulator_register(
&mc13783_regulators[init_data->id].desc,
- &pdev->dev, init_data->init_data, priv);
+ &pdev->dev, init_data->init_data, priv, NULL);
if (IS_ERR(priv->regulators[i])) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 3285d41..9d82b5c 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -572,7 +572,7 @@
init_data = &pdata->regulators[i];
priv->regulators[i] = regulator_register(
&mc13892_regulators[init_data->id].desc,
- &pdev->dev, init_data->init_data, priv);
+ &pdev->dev, init_data->init_data, priv, NULL);
if (IS_ERR(priv->regulators[i])) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
new file mode 100644
index 0000000..76673c7
--- /dev/null
+++ b/drivers/regulator/of_regulator.c
@@ -0,0 +1,81 @@
+/*
+ * OF helpers for regulator framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.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.
+ */
+
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/regulator/machine.h>
+
+static void of_get_regulation_constraints(struct device_node *np,
+ struct regulator_init_data **init_data)
+{
+ const __be32 *min_uV, *max_uV, *uV_offset;
+ const __be32 *min_uA, *max_uA;
+ struct regulation_constraints *constraints = &(*init_data)->constraints;
+
+ constraints->name = of_get_property(np, "regulator-name", NULL);
+
+ min_uV = of_get_property(np, "regulator-min-microvolt", NULL);
+ if (min_uV)
+ constraints->min_uV = be32_to_cpu(*min_uV);
+ max_uV = of_get_property(np, "regulator-max-microvolt", NULL);
+ if (max_uV)
+ constraints->max_uV = be32_to_cpu(*max_uV);
+
+ /* Voltage change possible? */
+ if (constraints->min_uV != constraints->max_uV)
+ constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
+
+ uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL);
+ if (uV_offset)
+ constraints->uV_offset = be32_to_cpu(*uV_offset);
+ min_uA = of_get_property(np, "regulator-min-microamp", NULL);
+ if (min_uA)
+ constraints->min_uA = be32_to_cpu(*min_uA);
+ max_uA = of_get_property(np, "regulator-max-microamp", NULL);
+ if (max_uA)
+ constraints->max_uA = be32_to_cpu(*max_uA);
+
+ /* Current change possible? */
+ if (constraints->min_uA != constraints->max_uA)
+ constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
+
+ if (of_find_property(np, "regulator-boot-on", NULL))
+ constraints->boot_on = true;
+
+ if (of_find_property(np, "regulator-always-on", NULL))
+ constraints->always_on = true;
+ else /* status change should be possible if not always on. */
+ constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+}
+
+/**
+ * of_get_regulator_init_data - extract regulator_init_data structure info
+ * @dev: device requesting for regulator_init_data
+ *
+ * Populates regulator_init_data structure by extracting data from device
+ * tree node, returns a pointer to the populated struture or NULL if memory
+ * alloc fails.
+ */
+struct regulator_init_data *of_get_regulator_init_data(struct device *dev)
+{
+ struct regulator_init_data *init_data;
+
+ if (!dev->of_node)
+ return NULL;
+
+ init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+ if (!init_data)
+ return NULL; /* Out of memory? */
+
+ of_get_regulation_constraints(dev->of_node, &init_data);
+ return init_data;
+}
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 31f6e11..a5aab1b 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -277,7 +277,7 @@
void *pcap = dev_get_drvdata(pdev->dev.parent);
rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, pcap);
+ pdev->dev.platform_data, pcap, NULL);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 69a11d9..1d1c310 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -320,7 +320,7 @@
pcf = dev_to_pcf50633(pdev->dev.parent);
rdev = regulator_register(®ulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, pcf);
+ pdev->dev.platform_data, pcf, NULL);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/pm8058-xo.c b/drivers/regulator/pm8058-xo.c
index b778660..90093dd 100644
--- a/drivers/regulator/pm8058-xo.c
+++ b/drivers/regulator/pm8058-xo.c
@@ -162,7 +162,7 @@
goto bail;
xo->rdev = regulator_register(rdesc, &pdev->dev,
- &xo->pdata->init_data, xo);
+ &xo->pdata->init_data, xo, NULL);
if (IS_ERR(xo->rdev)) {
rc = PTR_ERR(xo->rdev);
pr_err("FAIL: regulator_register(%s): rc=%d\n",
diff --git a/drivers/regulator/pm8xxx-regulator.c b/drivers/regulator/pm8xxx-regulator.c
index fd691f0..833c513 100644
--- a/drivers/regulator/pm8xxx-regulator.c
+++ b/drivers/regulator/pm8xxx-regulator.c
@@ -3206,7 +3206,7 @@
if (!core_data->is_pin_controlled) {
vreg->rdev = regulator_register(rdesc, &pdev->dev,
- &(pdata->init_data), vreg);
+ &(pdata->init_data), vreg, NULL);
if (IS_ERR(vreg->rdev)) {
rc = PTR_ERR(vreg->rdev);
vreg->rdev = NULL;
@@ -3215,7 +3215,7 @@
}
} else {
vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
- &(pdata->init_data), vreg);
+ &(pdata->init_data), vreg, NULL);
if (IS_ERR(vreg->rdev_pc)) {
rc = PTR_ERR(vreg->rdev_pc);
vreg->rdev_pc = NULL;
diff --git a/drivers/regulator/pmic8058-regulator.c b/drivers/regulator/pmic8058-regulator.c
index e137b0f..01f4abf 100644
--- a/drivers/regulator/pmic8058-regulator.c
+++ b/drivers/regulator/pmic8058-regulator.c
@@ -1692,7 +1692,7 @@
&= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
vreg->rdev = regulator_register(rdesc, &pdev->dev,
- &vreg->pdata->init_data, vreg);
+ &vreg->pdata->init_data, vreg, NULL);
if (IS_ERR(vreg->rdev)) {
rc = PTR_ERR(vreg->rdev);
pr_err("%s: regulator_register failed for %s, rc=%d\n",
diff --git a/drivers/regulator/pmic8901-regulator.c b/drivers/regulator/pmic8901-regulator.c
index 6fd0a05..72894ba 100644
--- a/drivers/regulator/pmic8901-regulator.c
+++ b/drivers/regulator/pmic8901-regulator.c
@@ -954,7 +954,7 @@
&= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
vreg->rdev = regulator_register(rdesc, &pdev->dev,
- &vreg->pdata->init_data, vreg);
+ &vreg->pdata->init_data, vreg, NULL);
if (IS_ERR(vreg->rdev)) {
rc = PTR_ERR(vreg->rdev);
pr_err("%s: regulator_register failed for %s, rc=%d\n",
diff --git a/drivers/regulator/stub-regulator.c b/drivers/regulator/stub-regulator.c
index 5b44c04..1c4b935 100644
--- a/drivers/regulator/stub-regulator.c
+++ b/drivers/regulator/stub-regulator.c
@@ -182,7 +182,7 @@
vreg_priv->voltage = vreg_pdata->init_data.constraints.min_uV;
vreg_priv->rdev = regulator_register(rdesc, &pdev->dev,
- &(vreg_pdata->init_data), vreg_priv);
+ &(vreg_pdata->init_data), vreg_priv, NULL);
if (IS_ERR(vreg_priv->rdev)) {
rc = PTR_ERR(vreg_priv->rdev);
vreg_priv->rdev = NULL;
@@ -215,11 +215,18 @@
},
};
-static int __init regulator_stub_init(void)
+int __init regulator_stub_init(void)
{
+ static int registered;
+
+ if (registered)
+ return 0;
+ else
+ registered = 1;
return platform_driver_register(®ulator_stub_driver);
}
postcore_initcall(regulator_stub_init);
+EXPORT_SYMBOL(regulator_stub_init);
static void __exit regulator_stub_exit(void)
{
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
index 1011873..d9278da 100644
--- a/drivers/regulator/tps6105x-regulator.c
+++ b/drivers/regulator/tps6105x-regulator.c
@@ -151,7 +151,8 @@
/* Register regulator with framework */
tps6105x->regulator = regulator_register(&tps6105x_regulator_desc,
&tps6105x->client->dev,
- pdata->regulator_data, tps6105x);
+ pdata->regulator_data, tps6105x,
+ NULL);
if (IS_ERR(tps6105x->regulator)) {
ret = PTR_ERR(tps6105x->regulator);
dev_err(&tps6105x->client->dev,
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index fbddc15..8efb772 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -507,7 +507,7 @@
/* Register the regulators */
rdev = regulator_register(&tps->desc[i], &client->dev,
- init_data, tps);
+ init_data, tps, NULL);
if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n",
id->name);
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index bfffabc..0f86e56 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -605,7 +605,7 @@
tps->desc[i].owner = THIS_MODULE;
rdev = regulator_register(&tps->desc[i],
- tps6507x_dev->dev, init_data, tps);
+ tps6507x_dev->dev, init_data, tps, NULL);
if (IS_ERR(rdev)) {
dev_err(tps6507x_dev->dev,
"failed to register %s regulator\n",
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 9166aa0..70b7b1f 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -651,7 +651,7 @@
hw->desc[i].n_voltages = 1;
hw->rdev[i] = regulator_register(&hw->desc[i], dev,
- init_data, hw);
+ init_data, hw, NULL);
if (IS_ERR(hw->rdev[i])) {
ret = PTR_ERR(hw->rdev[i]);
hw->rdev[i] = NULL;
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index bb04a75..6a35c3a 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -365,7 +365,7 @@
return err;
rdev = regulator_register(&ri->desc, &pdev->dev,
- pdev->dev.platform_data, ri);
+ pdev->dev.platform_data, ri, NULL);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 425aab3..e436dcd 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -939,7 +939,7 @@
pmic->desc[i].owner = THIS_MODULE;
rdev = regulator_register(&pmic->desc[i],
- tps65910->dev, reg_data, pmic);
+ tps65910->dev, reg_data, pmic, NULL);
if (IS_ERR(rdev)) {
dev_err(tps65910->dev,
"failed to register %s regulator\n",
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 87fe0f7..1c12070 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -1074,7 +1074,7 @@
break;
}
- rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
+ rdev = regulator_register(&info->desc, &pdev->dev, initdata, info, NULL);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "can't register %s, %ld\n",
info->desc.name, PTR_ERR(rdev));
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index a0982e8..38bb80d 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -556,7 +556,7 @@
wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->dcdc[id], dcdc);
+ pdata->dcdc[id], dcdc, NULL);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -744,7 +744,7 @@
dcdc->desc.owner = THIS_MODULE;
dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->dcdc[id], dcdc);
+ pdata->dcdc[id], dcdc, NULL);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -871,7 +871,7 @@
dcdc->desc.owner = THIS_MODULE;
dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->dcdc[id], dcdc);
+ pdata->dcdc[id], dcdc, NULL);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
@@ -970,7 +970,7 @@
dcdc->desc.owner = THIS_MODULE;
dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
- pdata->epe[id], dcdc);
+ pdata->epe[id], dcdc, NULL);
if (IS_ERR(dcdc->regulator)) {
ret = PTR_ERR(dcdc->regulator);
dev_err(wm831x->dev, "Failed to register EPE%d: %d\n",
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 01f27c7..d3ad3f5 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -189,7 +189,7 @@
isink->desc.owner = THIS_MODULE;
isink->regulator = regulator_register(&isink->desc, &pdev->dev,
- pdata->isink[id], isink);
+ pdata->isink[id], isink, NULL);
if (IS_ERR(isink->regulator)) {
ret = PTR_ERR(isink->regulator);
dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n",
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 2220cf8..d0fe563 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -345,7 +345,7 @@
ldo->desc.owner = THIS_MODULE;
ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
- pdata->ldo[id], ldo);
+ pdata->ldo[id], ldo, NULL);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
@@ -609,7 +609,7 @@
ldo->desc.owner = THIS_MODULE;
ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
- pdata->ldo[id], ldo);
+ pdata->ldo[id], ldo, NULL);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
@@ -799,7 +799,7 @@
ldo->desc.owner = THIS_MODULE;
ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
- pdata->ldo[id], ldo);
+ pdata->ldo[id], ldo, NULL);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 1bcb22c..6894009 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1428,7 +1428,7 @@
/* register regulator */
rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
pdev->dev.platform_data,
- dev_get_drvdata(&pdev->dev));
+ dev_get_drvdata(&pdev->dev), NULL);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n",
wm8350_reg[pdev->id].name);
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 0f12c70..f468f8a 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -325,7 +325,7 @@
struct regulator_dev *rdev;
rdev = regulator_register(®ulators[pdev->id], &pdev->dev,
- pdev->dev.platform_data, wm8400);
+ pdev->dev.platform_data, wm8400, NULL);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 35b2958..6f3132c 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -256,7 +256,7 @@
ldo->is_enabled = true;
ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
- pdata->ldo[id].init_data, ldo);
+ pdata->ldo[id].init_data, ldo, NULL);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 2aab31e..fa9d1df 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -22,6 +22,8 @@
#include <linux/kthread.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_slimbus.h>
#include <mach/sps.h>
/* Per spec.max 40 bytes per received message */
@@ -86,10 +88,80 @@
#define QC_DEVID_PGD 0x5
#define QC_MSM_DEVS 5
+#define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
+#define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
+#define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r))
+
+#define PGD_THIS_EE_V2(r) (dev->base + (r ## _V2) + (dev->ee * 0x1000))
+#define PGD_PORT_V2(r, p) (dev->base + (r ## _V2) + ((p) * 0x1000))
+#define CFG_PORT_V2(r) ((r ## _V2))
/* Component registers */
-enum comp_reg {
- COMP_CFG = 0,
- COMP_TRUST_CFG = 0x14,
+enum comp_reg_v2 {
+ COMP_CFG_V2 = 4,
+ COMP_TRUST_CFG_V2 = 0x3000,
+};
+
+/* Manager PGD registers */
+enum pgd_reg_v2 {
+ PGD_CFG_V2 = 0x800,
+ PGD_STAT_V2 = 0x804,
+ PGD_INT_EN_V2 = 0x810,
+ PGD_INT_STAT_V2 = 0x814,
+ PGD_INT_CLR_V2 = 0x818,
+ PGD_OWN_EEn_V2 = 0x300C,
+ PGD_PORT_INT_EN_EEn_V2 = 0x5000,
+ PGD_PORT_INT_ST_EEn_V2 = 0x5004,
+ PGD_PORT_INT_CL_EEn_V2 = 0x5008,
+ PGD_PORT_CFGn_V2 = 0x14000,
+ PGD_PORT_STATn_V2 = 0x14004,
+ PGD_PORT_PARAMn_V2 = 0x14008,
+ PGD_PORT_BLKn_V2 = 0x1400C,
+ PGD_PORT_TRANn_V2 = 0x14010,
+ PGD_PORT_MCHANn_V2 = 0x14014,
+ PGD_PORT_PSHPLLn_V2 = 0x14018,
+ PGD_PORT_PC_CFGn_V2 = 0x8000,
+ PGD_PORT_PC_VALn_V2 = 0x8004,
+ PGD_PORT_PC_VFR_TSn_V2 = 0x8008,
+ PGD_PORT_PC_VFR_STn_V2 = 0x800C,
+ PGD_PORT_PC_VFR_CLn_V2 = 0x8010,
+ PGD_IE_STAT_V2 = 0x820,
+ PGD_VE_STAT_V2 = 0x830,
+};
+
+#define PGD_THIS_EE_V1(r) (dev->base + (r ## _V1) + (dev->ee * 16))
+#define PGD_PORT_V1(r, p) (dev->base + (r ## _V1) + ((p) * 32))
+#define CFG_PORT_V1(r) ((r ## _V1))
+/* Component registers */
+enum comp_reg_v1 {
+ COMP_CFG_V1 = 0,
+ COMP_TRUST_CFG_V1 = 0x14,
+};
+
+/* Manager PGD registers */
+enum pgd_reg_v1 {
+ PGD_CFG_V1 = 0x1000,
+ PGD_STAT_V1 = 0x1004,
+ PGD_INT_EN_V1 = 0x1010,
+ PGD_INT_STAT_V1 = 0x1014,
+ PGD_INT_CLR_V1 = 0x1018,
+ PGD_OWN_EEn_V1 = 0x1020,
+ PGD_PORT_INT_EN_EEn_V1 = 0x1030,
+ PGD_PORT_INT_ST_EEn_V1 = 0x1034,
+ PGD_PORT_INT_CL_EEn_V1 = 0x1038,
+ PGD_PORT_CFGn_V1 = 0x1080,
+ PGD_PORT_STATn_V1 = 0x1084,
+ PGD_PORT_PARAMn_V1 = 0x1088,
+ PGD_PORT_BLKn_V1 = 0x108C,
+ PGD_PORT_TRANn_V1 = 0x1090,
+ PGD_PORT_MCHANn_V1 = 0x1094,
+ PGD_PORT_PSHPLLn_V1 = 0x1098,
+ PGD_PORT_PC_CFGn_V1 = 0x1600,
+ PGD_PORT_PC_VALn_V1 = 0x1604,
+ PGD_PORT_PC_VFR_TSn_V1 = 0x1608,
+ PGD_PORT_PC_VFR_STn_V1 = 0x160C,
+ PGD_PORT_PC_VFR_CLn_V1 = 0x1610,
+ PGD_IE_STAT_V1 = 0x1700,
+ PGD_VE_STAT_V1 = 0x1710,
};
/* Manager registers */
@@ -141,33 +213,6 @@
INTF_VE_STAT = 0x640,
};
-/* Manager PGD registers */
-enum pgd_reg {
- PGD_CFG = 0x1000,
- PGD_STAT = 0x1004,
- PGD_INT_EN = 0x1010,
- PGD_INT_STAT = 0x1014,
- PGD_INT_CLR = 0x1018,
- PGD_OWN_EEn = 0x1020,
- PGD_PORT_INT_EN_EEn = 0x1030,
- PGD_PORT_INT_ST_EEn = 0x1034,
- PGD_PORT_INT_CL_EEn = 0x1038,
- PGD_PORT_CFGn = 0x1080,
- PGD_PORT_STATn = 0x1084,
- PGD_PORT_PARAMn = 0x1088,
- PGD_PORT_BLKn = 0x108C,
- PGD_PORT_TRANn = 0x1090,
- PGD_PORT_MCHANn = 0x1094,
- PGD_PORT_PSHPLLn = 0x1098,
- PGD_PORT_PC_CFGn = 0x1600,
- PGD_PORT_PC_VALn = 0x1604,
- PGD_PORT_PC_VFR_TSn = 0x1608,
- PGD_PORT_PC_VFR_STn = 0x160C,
- PGD_PORT_PC_VFR_CLn = 0x1610,
- PGD_IE_STAT = 0x1700,
- PGD_VE_STAT = 0x1710,
-};
-
enum rsc_grp {
EE_MGR_RSC_GRP = 1 << 10,
EE_NGD_2 = 2 << 6,
@@ -243,6 +288,7 @@
bool chan_active;
enum msm_ctrl_state state;
int nsats;
+ u32 ver;
};
struct msm_sat_chan {
@@ -507,13 +553,13 @@
mb();
complete(&dev->reconf);
}
- pstat = readl_relaxed(dev->base + PGD_PORT_INT_ST_EEn + (16 * dev->ee));
+ pstat = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_ST_EEn, dev->ver));
if (pstat != 0) {
int i = 0;
for (i = dev->pipe_b; i < MSM_SLIM_NPORTS; i++) {
if (pstat & 1 << i) {
- u32 val = readl_relaxed(dev->base +
- PGD_PORT_STATn + (i * 32));
+ u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn,
+ i, dev->ver));
if (val & (1 << 19)) {
dev->ctrl.ports[i].err =
SLIM_P_DISCONNECT;
@@ -530,8 +576,8 @@
dev->ctrl.ports[i].err =
SLIM_P_UNDERFLOW;
}
- writel_relaxed(1, dev->base + PGD_PORT_INT_CL_EEn +
- (dev->ee * 16));
+ writel_relaxed(1, PGD_THIS_EE(PGD_PORT_INT_CL_EEn,
+ dev->ver));
}
/*
* Guarantee that port interrupt bit(s) clearing writes go
@@ -610,13 +656,13 @@
static void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn)
{
u32 set_cfg = DEF_WATERMARK | DEF_ALIGN | DEF_PACK | ENABLE_PORT;
- u32 int_port = readl_relaxed(dev->base + PGD_PORT_INT_EN_EEn +
- (dev->ee * 16));
- writel_relaxed(set_cfg, dev->base + PGD_PORT_CFGn + (pn * 32));
- writel_relaxed(DEF_BLKSZ, dev->base + PGD_PORT_BLKn + (pn * 32));
- writel_relaxed(DEF_TRANSZ, dev->base + PGD_PORT_TRANn + (pn * 32));
- writel_relaxed((int_port | 1 << pn) , dev->base + PGD_PORT_INT_EN_EEn +
- (dev->ee * 16));
+ u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+ dev->ver));
+ writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, pn, dev->ver));
+ writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, pn, dev->ver));
+ writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, pn, dev->ver));
+ writel_relaxed((int_port | 1 << pn) , PGD_THIS_EE(PGD_PORT_INT_EN_EEn,
+ dev->ver));
/* Make sure that port registers are updated before returning */
mb();
}
@@ -643,8 +689,8 @@
}
}
- stat = readl_relaxed(dev->base + PGD_PORT_STATn +
- (32 * (pn + dev->pipe_b)));
+ stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, (pn + dev->pipe_b),
+ dev->ver));
if (dev->ctrl.ports[pn].flow == SLIM_SRC) {
cfg->destination = dev->bam.hdl;
cfg->source = SPS_DEV_HANDLE_MEM;
@@ -1868,7 +1914,24 @@
ret = -ENOMEM;
goto err_ioremap_bam_failed;
}
- dev->ctrl.nr = pdev->id;
+ if (pdev->dev.of_node) {
+
+ ret = of_property_read_u32(pdev->dev.of_node, "cell-index",
+ &dev->ctrl.nr);
+ if (ret) {
+ dev_err(&pdev->dev, "Cell index not specified:%d", ret);
+ goto err_of_init_failed;
+ }
+ /* Optional properties */
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,min-clk-gear", &dev->ctrl.min_cg);
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-clk-gear", &dev->ctrl.max_cg);
+ pr_err("min_cg:%d, max_cg:%d, ret:%d", dev->ctrl.min_cg,
+ dev->ctrl.max_cg, ret);
+ } else {
+ dev->ctrl.nr = pdev->id;
+ }
dev->ctrl.nchans = MSM_SLIM_NCHANS;
dev->ctrl.nports = MSM_SLIM_NPORTS;
dev->ctrl.set_laddr = msm_set_laddr;
@@ -1901,6 +1964,7 @@
dev->ctrl.a_framer = &dev->framer;
dev->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
dev->ctrl.dev.parent = &pdev->dev;
+ dev->ctrl.dev.of_node = pdev->dev.of_node;
ret = request_irq(dev->irq, msm_slim_interrupt, IRQF_TRIGGER_HIGH,
"msm_slim_irq", dev);
@@ -1927,10 +1991,13 @@
clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
clk_prepare_enable(dev->rclk);
+ dev->ver = readl_relaxed(dev->base);
+ /* Version info in 16 MSbits */
+ dev->ver >>= 16;
/* Component register initialization */
- writel_relaxed(1, dev->base + COMP_CFG);
+ writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
writel_relaxed((EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1),
- dev->base + COMP_TRUST_CFG);
+ dev->base + CFG_PORT(COMP_TRUST_CFG, dev->ver));
/*
* Manager register initialization
@@ -1981,20 +2048,24 @@
* ported generic device inside MSM manager
*/
mb();
- writel_relaxed(1, dev->base + PGD_CFG);
- writel_relaxed(0x3F<<17, dev->base + (PGD_OWN_EEn + (4 * dev->ee)));
+ writel_relaxed(1, dev->base + CFG_PORT(PGD_CFG, dev->ver));
+ writel_relaxed(0x3F<<17, dev->base + CFG_PORT(PGD_OWN_EEn, dev->ver) +
+ (4 * dev->ee));
/*
* Make sure that ported generic device is enabled and port-EE settings
* are written through before finally enabling the component
*/
mb();
- writel_relaxed(1, dev->base + COMP_CFG);
+ writel_relaxed(1, dev->base + CFG_PORT(COMP_CFG, dev->ver));
/*
* Make sure that all writes have gone through before exiting this
* function
*/
mb();
+ if (pdev->dev.of_node)
+ of_register_slim_devices(&dev->ctrl);
+
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, MSM_SLIM_AUTOSUSPEND);
pm_runtime_set_active(&pdev->dev);
@@ -2003,12 +2074,13 @@
return 0;
err_ctrl_failed:
- writel_relaxed(0, dev->base + COMP_CFG);
+ writel_relaxed(0, dev->base + CFG_PORT(COMP_CFG, dev->ver));
err_clk_get_failed:
kfree(dev->satd);
err_request_irq_failed:
msm_slim_sps_exit(dev);
err_sps_init_failed:
+err_of_init_failed:
iounmap(dev->bam.base);
err_ioremap_bam_failed:
iounmap(dev->base);
@@ -2162,6 +2234,13 @@
)
};
+static struct of_device_id msm_slim_dt_match[] = {
+ {
+ .compatible = "qcom,slim-msm",
+ },
+ {}
+};
+
static struct platform_driver msm_slim_driver = {
.probe = msm_slim_probe,
.remove = msm_slim_remove,
@@ -2169,6 +2248,7 @@
.name = MSM_SLIM_NAME,
.owner = THIS_MODULE,
.pm = &msm_slim_dev_pm_ops,
+ .of_match_table = msm_slim_dt_match,
},
};
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index acca6f1..4250ff5 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -223,6 +223,9 @@
{
int ret = 0;
+ if (fmem_state == FMEM_UNINITIALIZED)
+ return NOTIFY_OK;
+
switch (action) {
case MEM_ONLINE:
fmem_mem_online_callback(arg);
diff --git a/drivers/staging/qcache/qcache-main.c b/drivers/staging/qcache/qcache-main.c
index e3a95e0..ea6635c 100644
--- a/drivers/staging/qcache/qcache-main.c
+++ b/drivers/staging/qcache/qcache-main.c
@@ -160,15 +160,18 @@
spin_lock_irqsave(&qc->lock, flags);
offset = bitmap_find_free_region(qc->bitmap, qc->pages, 0);
- spin_unlock_irqrestore(&qc->lock, flags);
- if (offset < 0)
+ if (offset < 0) {
+ spin_unlock_irqrestore(&qc->lock, flags);
return NULL;
+ }
- addr = qc->addr + offset * PAGE_SIZE;
zcache_qc_allocated++;
zcache_qc_used++;
zcache_qc_max_used = max(zcache_qc_max_used, zcache_qc_used);
+ spin_unlock_irqrestore(&qc->lock, flags);
+
+ addr = qc->addr + offset * PAGE_SIZE;
return addr;
}
@@ -183,10 +186,10 @@
spin_lock_irqsave(&qc->lock, flags);
bitmap_release_region(qc->bitmap, offset, 0);
- spin_unlock_irqrestore(&qc->lock, flags);
zcache_qc_freed++;
zcache_qc_used--;
+ spin_unlock_irqrestore(&qc->lock, flags);
}
/*
@@ -737,26 +740,21 @@
{
struct tmem_pool *pool;
int pool_id;
+ struct zcache_preload *kp;
+
+ kp = &__get_cpu_var(zcache_preloads);
for (pool_id = 0; pool_id < MAX_POOLS_PER_CLIENT; pool_id++) {
pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id);
tmem_flush_pool(pool);
}
-}
-
-static void reset_qcache(void)
-{
- struct qcache_info *qc = &qcache_info;
- int bitmap_size;
- struct zcache_preload *kp;
-
- bitmap_size = BITS_TO_LONGS(qc->pages) * sizeof(long);
- memset(qc->bitmap, 0, bitmap_size);
- zcache_qc_used = 0;
- zcache_qc_freed = zcache_qc_allocated;
-
- kp = &__get_cpu_var(zcache_preloads);
- kp->page = NULL;
+ if (kp->page) {
+ qcache_free(kp->page);
+ kp->page = NULL;
+ }
+ if (zcache_qc_used)
+ pr_warn("pages used not 0 after qcache flush all, is %ld\n",
+ zcache_qc_used);
}
/*
@@ -771,9 +769,6 @@
static void zcache_control(bool freeze)
{
zcache_freeze = freeze;
-
- if (freeze)
- reset_qcache();
}
static struct tmem_hostops zcache_hostops = {
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 3aa4553..0e121d1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -161,6 +161,8 @@
struct msm_hs_wakeup wakeup;
struct wake_lock dma_wake_lock; /* held while any DMA active */
+
+ struct dentry *loopback_dir;
};
#define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */
@@ -367,13 +369,15 @@
{
char node_name[15];
snprintf(node_name, sizeof(node_name), "loopback.%d", id);
- if (IS_ERR_OR_NULL(debugfs_create_file(node_name,
- S_IRUGO | S_IWUSR,
- debug_base,
- msm_uport,
- &loopback_enable_fops))) {
- debugfs_remove_recursive(debug_base);
- }
+ msm_uport->loopback_dir = debugfs_create_file(node_name,
+ S_IRUGO | S_IWUSR,
+ debug_base,
+ msm_uport,
+ &loopback_enable_fops);
+
+ if (IS_ERR_OR_NULL(msm_uport->loopback_dir))
+ pr_err("%s(): Cannot create loopback.%d debug entry",
+ __func__, id);
}
static int __devexit msm_hs_remove(struct platform_device *pdev)
@@ -397,7 +401,7 @@
dev_err(dev, "GPIO config error\n");
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
- debugfs_remove_recursive(debug_base);
+ debugfs_remove(msm_uport->loopback_dir);
dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box),
DMA_TO_DEVICE);
@@ -436,7 +440,6 @@
int ret;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- wake_lock(&msm_uport->dma_wake_lock);
/* Set up the MREG/NREG/DREG/MNDREG */
ret = clk_set_rate(msm_uport->clk, uport->uartclk);
if (ret) {
@@ -452,6 +455,7 @@
if (msm_uport->pclk) {
ret = clk_enable(msm_uport->pclk);
if (ret) {
+ clk_disable(msm_uport->clk);
dev_err(uport->dev,
"Error could not turn on UART pclk\n");
return ret;
@@ -1574,10 +1578,14 @@
tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE,
DMA_TO_DEVICE);
+ wake_lock(&msm_uport->dma_wake_lock);
/* turn on uart clk */
ret = msm_hs_init_clk(uport);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ pr_err("Turning ON uartclk error\n");
+ wake_unlock(&msm_uport->dma_wake_lock);
return ret;
+ }
/* Set auto RFR Level */
data = msm_hs_read(uport, UARTDM_MR1_ADDR);
@@ -1642,20 +1650,26 @@
if (use_low_power_wakeup(msm_uport)) {
ret = irq_set_irq_wake(msm_uport->wakeup.irq, 1);
- if (unlikely(ret))
- return ret;
+ if (unlikely(ret)) {
+ pr_err("%s():Err setting wakeup irq\n", __func__);
+ goto deinit_uart_clk;
+ }
}
ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH,
"msm_hs_uart", msm_uport);
- if (unlikely(ret))
- return ret;
+ if (unlikely(ret)) {
+ pr_err("%s():Error getting uart irq\n", __func__);
+ goto free_wake_irq;
+ }
if (use_low_power_wakeup(msm_uport)) {
ret = request_irq(msm_uport->wakeup.irq, msm_hs_wakeup_isr,
IRQF_TRIGGER_FALLING,
"msm_hs_wakeup", msm_uport);
- if (unlikely(ret))
- return ret;
+ if (unlikely(ret)) {
+ pr_err("%s():Err getting uart wakeup_irq\n", __func__);
+ goto free_uart_irq;
+ }
disable_irq(msm_uport->wakeup.irq);
}
@@ -1669,8 +1683,19 @@
dev_err(uport->dev, "set active error:%d\n", ret);
pm_runtime_enable(uport->dev);
-
return 0;
+
+free_uart_irq:
+ free_irq(uport->irq, msm_uport);
+free_wake_irq:
+ irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+deinit_uart_clk:
+ clk_disable(msm_uport->clk);
+ if (msm_uport->pclk)
+ clk_disable(msm_uport->pclk);
+ wake_unlock(&msm_uport->dma_wake_lock);
+
+ return ret;
}
/* Initialize tx and rx data structures */
@@ -1796,7 +1821,7 @@
return ret;
}
-static int __init msm_hs_probe(struct platform_device *pdev)
+static int __devinit msm_hs_probe(struct platform_device *pdev)
{
int ret;
struct uart_port *uport;
@@ -1930,8 +1955,7 @@
if (IS_ERR_OR_NULL(debug_base))
pr_info("msm_serial_hs: Cannot create debugfs dir\n");
- ret = platform_driver_probe(&msm_serial_hs_platform_driver,
- msm_hs_probe);
+ ret = platform_driver_register(&msm_serial_hs_platform_driver);
if (ret) {
printk(KERN_ERR "%s failed to load\n", __FUNCTION__);
debugfs_remove_recursive(debug_base);
@@ -2001,6 +2025,7 @@
static void __exit msm_serial_hs_exit(void)
{
printk(KERN_INFO "msm_serial_hs module removed\n");
+ debugfs_remove_recursive(debug_base);
platform_driver_unregister(&msm_serial_hs_platform_driver);
uart_unregister_driver(&msm_hs_driver);
}
@@ -2039,7 +2064,8 @@
};
static struct platform_driver msm_serial_hs_platform_driver = {
- .remove = msm_hs_remove,
+ .probe = msm_hs_probe,
+ .remove = __devexit_p(msm_hs_remove),
.driver = {
.name = "msm_serial_hs",
.pm = &msm_hs_dev_pm_ops,
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 9a8d552..285d1de 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -141,6 +141,16 @@
return UART_TO_MSM(port)->is_uartdm;
}
+static int get_line(struct platform_device *pdev)
+{
+ const struct msm_serial_hslite_platform_data *pdata =
+ pdev->dev.platform_data;
+ if (pdata)
+ return pdata->line;
+
+ return pdev->id;
+}
+
static int clk_en(struct uart_port *port, int enable)
{
struct msm_hsl_port *msm_hsl_port = UART_TO_MSM(port);
@@ -1243,7 +1253,7 @@
struct uart_port *port;
struct platform_device *pdev = to_platform_device(dev);
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
enable = get_console_state(port);
@@ -1264,7 +1274,7 @@
struct uart_port *port;
struct platform_device *pdev = to_platform_device(dev);
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
cur_state = get_console_state(port);
enable = buf[0] - '0';
@@ -1332,12 +1342,12 @@
if (pdev->id == -1)
pdev->id = atomic_inc_return(&msm_serial_hsl_next_id) - 1;
- if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+ if (unlikely(get_line(pdev) < 0 || get_line(pdev) >= UART_NR))
return -ENXIO;
printk(KERN_INFO "msm_serial_hsl: detected port #%d\n", pdev->id);
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
port->dev = &pdev->dev;
msm_hsl_port = UART_TO_MSM(port);
@@ -1395,7 +1405,7 @@
if (unlikely(ret))
pr_err("%s():Can't create console attribute\n", __func__);
#endif
- msm_hsl_debugfs_init(msm_hsl_port, pdev->id);
+ msm_hsl_debugfs_init(msm_hsl_port, get_line(pdev));
/* Temporarily increase the refcount on the GSBI clock to avoid a race
* condition with the earlyprintk handover mechanism.
@@ -1413,7 +1423,7 @@
struct msm_hsl_port *msm_hsl_port = platform_get_drvdata(pdev);
struct uart_port *port;
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
device_remove_file(&pdev->dev, &dev_attr_console);
#endif
@@ -1436,7 +1446,7 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct uart_port *port;
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
if (port) {
@@ -1455,7 +1465,7 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct uart_port *port;
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
if (port) {
@@ -1478,7 +1488,7 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct uart_port *port;
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
dev_dbg(dev, "pm_runtime: suspending\n");
msm_hsl_deinit_clock(port);
@@ -1489,7 +1499,7 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct uart_port *port;
- port = get_port_from_line(pdev->id);
+ port = get_port_from_line(get_line(pdev));
dev_dbg(dev, "pm_runtime: resuming\n");
msm_hsl_init_clock(port);
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 593d1db..5607ac4 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -4,10 +4,7 @@
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
-
-ifneq ($(CONFIG_USB_GADGET_DWC3),)
- dwc3-y += gadget.o ep0.o
-endif
+dwc3-y += gadget.o ep0.o
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o
@@ -28,7 +25,7 @@
# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
##
-obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 71145a4..9206096 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -110,7 +110,7 @@
list_move_tail(&req->list, &dep->req_queued);
}
-#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
+#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_DWC3_MODULE)
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
#else
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 0865f91..f8327c8 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -300,17 +300,6 @@
PXA9xx Processor series include a high speed USB2.0 device
controller, which support high speed and full speed USB peripheral.
-config USB_GADGET_DWC3
- tristate "DesignWare USB3.0 (DRD) Controller"
- depends on USB_DWC3
- select USB_GADGET_DUALSPEED
- select USB_GADGET_SUPERSPEED
- help
- DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
- which can be configured for peripheral-only, host-only, hub-only
- and Dual-Role operation. This Controller was first integrated into
- the OMAP5 series of processors. More information about the OMAP5
- version of this controller, refer to http://www.ti.com/omap5.
#
# Controllers available in both integrated and discrete versions
#
@@ -476,6 +465,32 @@
dynamically linked module called "ci13xxx_msm_hsic" and force all
gadget drivers to also be dynamically linked.
+config USB_DWC3_MSM
+ tristate "DesignWare USB3.0 (DRD) Controller for MSM"
+ depends on ARCH_MSM
+ select USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SELECTED
+ help
+ The DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ integrated into the Qualcomm MSM chipset series, supporting host,
+ device and otg modes of operation. For more information please
+ refer to http://www.qualcomm.com/chipsets.
+
+config USB_DWC3_OMAP
+ tristate "DesignWare USB3.0 (DRD) Controller for OMAP"
+ depends on ARCH_OMAP
+ select USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SUPERSPEED
+ select USB_GADGET_SELECTED
+ help
+ DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ which can be configured for peripheral-only, host-only, hub-only
+ and Dual-Role operation. This Controller was first integrated into
+ the OMAP5 series of processors. More information about the OMAP5
+ version of this controller, refer to http://www.ti.com/omap5.
+
#
# LAST -- dummy/emulated controller
#
@@ -527,9 +542,15 @@
# Selected by UDC drivers that support super-speed opperation
config USB_GADGET_SUPERSPEED
- bool
+ bool "Operate as superspeed"
depends on USB_GADGET
depends on USB_GADGET_DUALSPEED
+ default n
+ help
+ When a superspeed peripheral controller is selected
+ (for example DesignWare USB3.0 controller), use this flag to
+ indicate if the device should operate in superspeed(=y)
+ or not.
#
# USB Gadget Drivers
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index ee44846..3fb9c83 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -70,6 +70,8 @@
#include "f_rndis.c"
#include "rndis.c"
#include "u_ether.c"
+#include "u_bam_data.c"
+#include "f_mbim.c"
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -183,6 +185,12 @@
.bConfigurationValue = 1,
};
+enum android_device_state {
+ USB_DISCONNECTED,
+ USB_CONNECTED,
+ USB_CONFIGURED,
+};
+
static void android_work(struct work_struct *data)
{
struct android_dev *dev = container_of(data, struct android_dev, work);
@@ -191,18 +199,45 @@
char *connected[2] = { "USB_STATE=CONNECTED", NULL };
char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
char **uevent_envp = NULL;
+ static enum android_device_state last_uevent, next_state;
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- if (cdev->config)
+ if (cdev->config) {
uevent_envp = configured;
- else if (dev->connected != dev->sw_connected)
+ next_state = USB_CONFIGURED;
+ } else if (dev->connected != dev->sw_connected) {
uevent_envp = dev->connected ? connected : disconnected;
+ next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
+ }
dev->sw_connected = dev->connected;
spin_unlock_irqrestore(&cdev->lock, flags);
if (uevent_envp) {
+ /*
+ * Some userspace modules, e.g. MTP, work correctly only if
+ * CONFIGURED uevent is preceded by DISCONNECT uevent.
+ * Check if we missed sending out a DISCONNECT uevent. This can
+ * happen if host PC resets and configures device really quick.
+ */
+ if (((uevent_envp == connected) &&
+ (last_uevent != USB_DISCONNECTED)) ||
+ ((uevent_envp == configured) &&
+ (last_uevent == USB_CONFIGURED))) {
+ pr_info("%s: sent missed DISCONNECT event\n", __func__);
+ kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE,
+ disconnected);
+ msleep(20);
+ }
+ /*
+ * Before sending out CONFIGURED uevent give function drivers
+ * a chance to wakeup userspace threads and notify disconnect
+ */
+ if (uevent_envp == configured)
+ msleep(50);
+
kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
+ last_uevent = next_state;
pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
} else {
pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
@@ -353,6 +388,35 @@
.attributes = rmnet_function_attributes,
};
+
+/* MBIM - used with BAM */
+#define MAX_MBIM_INSTANCES 1
+
+static int mbim_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ return mbim_init(MAX_MBIM_INSTANCES);
+}
+
+static void mbim_function_cleanup(struct android_usb_function *f)
+{
+ fmbim_cleanup();
+}
+
+static int mbim_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ return mbim_bind_config(c, 0);
+}
+
+static struct android_usb_function mbim_function = {
+ .name = "usb_mbim",
+ .cleanup = mbim_function_cleanup,
+ .bind_config = mbim_function_bind_config,
+ .init = mbim_function_init,
+};
+
+
/* DIAG */
static char diag_clients[32]; /*enabled DIAG clients- "diag[,diag_mdm]" */
static ssize_t clients_store(
@@ -971,6 +1035,7 @@
static struct android_usb_function *supported_functions[] = {
+ &mbim_function,
&rmnet_smd_function,
&rmnet_sdio_function,
&rmnet_smd_sdio_function,
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 9f7affc..863143b 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -54,6 +54,7 @@
CI13XXX_REQUIRE_TRANSCEIVER |
CI13XXX_PULLUP_ON_VBUS |
CI13XXX_ZERO_ITC |
+ CI13XXX_DISABLE_STREAMING |
CI13XXX_IS_OTG,
.notify_event = ci13xxx_msm_notify_event,
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 95a70d5..c74b69a 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -643,7 +643,7 @@
}
dev_info(&pdev->dev, "HSIC Peripheral regs = %p\n", mhsic->regs);
- mhsic->xo_handle = msm_xo_get(MSM_XO_CXO, "hsic_peripheral");
+ mhsic->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "hsic_peripheral");
if (IS_ERR(mhsic->xo_handle)) {
dev_err(&pdev->dev, "%s not able to get the handle "
"to vote for TCXO\n", __func__);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 9cbfad8..8e0bef0 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2710,6 +2710,12 @@
return 0;
}
+static int is_sps_req(struct ci13xxx_req *mReq)
+{
+ return (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID &&
+ mReq->req.udc_priv & MSM_SPS_MODE);
+}
+
/**
* ep_set_halt: sets the endpoint halt feature
*
@@ -2731,7 +2737,9 @@
#ifndef STALL_IN
/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
- !list_empty(&mEp->qh.queue)) {
+ !list_empty(&mEp->qh.queue) &&
+ !is_sps_req(list_entry(mEp->qh.queue.next, struct ci13xxx_req,
+ queue))){
spin_unlock_irqrestore(mEp->lock, flags);
return -EAGAIN;
}
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index c4c7941..72bff49 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -664,21 +664,20 @@
struct usb_diag_ch *ch;
list_for_each_entry(ch, &usb_diag_ch_list, list) {
- struct diag_context *ctxt;
+ struct diag_context *ctxt = ch->priv_usb;
- ctxt = ch->priv_usb;
-
- temp += scnprintf(buf + temp, PAGE_SIZE - temp,
- "---Name: %s---\n"
- "endpoints: %s, %s\n"
- "dpkts_tolaptop: %lu\n"
- "dpkts_tomodem: %lu\n"
- "pkts_tolaptop_pending: %u\n",
- ch->name,
- ctxt->in->name, ctxt->out->name,
- ctxt->dpkts_tolaptop,
- ctxt->dpkts_tomodem,
- ctxt->dpkts_tolaptop_pending);
+ if (ctxt)
+ temp += scnprintf(buf + temp, PAGE_SIZE - temp,
+ "---Name: %s---\n"
+ "endpoints: %s, %s\n"
+ "dpkts_tolaptop: %lu\n"
+ "dpkts_tomodem: %lu\n"
+ "pkts_tolaptop_pending: %u\n",
+ ch->name,
+ ctxt->in->name, ctxt->out->name,
+ ctxt->dpkts_tolaptop,
+ ctxt->dpkts_tomodem,
+ ctxt->dpkts_tolaptop_pending);
}
return simple_read_from_buffer(ubuf, count, ppos, buf, temp);
@@ -690,13 +689,13 @@
struct usb_diag_ch *ch;
list_for_each_entry(ch, &usb_diag_ch_list, list) {
- struct diag_context *ctxt;
+ struct diag_context *ctxt = ch->priv_usb;
- ctxt = ch->priv_usb;
-
- ctxt->dpkts_tolaptop = 0;
- ctxt->dpkts_tomodem = 0;
- ctxt->dpkts_tolaptop_pending = 0;
+ if (ctxt) {
+ ctxt->dpkts_tolaptop = 0;
+ ctxt->dpkts_tomodem = 0;
+ ctxt->dpkts_tolaptop_pending = 0;
+ }
}
return count;
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
new file mode 100644
index 0000000..21b393e
--- /dev/null
+++ b/drivers/usb/gadget/f_mbim.c
@@ -0,0 +1,1772 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include <linux/usb/cdc.h>
+
+#include <linux/usb/composite.h>
+#include <linux/usb/android_composite.h>
+#include <linux/platform_device.h>
+
+#include <linux/spinlock.h>
+
+/*
+ * This function is a "Mobile Broadband Interface Model" (MBIM) link.
+ * MBIM is intended to be used with high-speed network attachments.
+ *
+ * Note that MBIM requires the use of "alternate settings" for its data
+ * interface. This means that the set_alt() method has real work to do,
+ * and also means that a get_alt() method is required.
+ */
+
+#define MBIM_BULK_BUFFER_SIZE 4096
+
+#define MBIM_IOCTL_MAGIC 'o'
+#define MBIM_GET_NTB_SIZE _IOR(MBIM_IOCTL_MAGIC, 2, u32)
+#define MBIM_GET_DATAGRAM_COUNT _IOR(MBIM_IOCTL_MAGIC, 3, u16)
+
+#define NR_MBIM_PORTS 1
+
+struct ctrl_pkt {
+ void *buf;
+ int len;
+ struct list_head list;
+};
+
+struct mbim_ep_descs {
+ struct usb_endpoint_descriptor *in;
+ struct usb_endpoint_descriptor *out;
+ struct usb_endpoint_descriptor *notify;
+};
+
+struct mbim_notify_port {
+ struct usb_ep *notify;
+ struct usb_request *notify_req;
+ u8 notify_state;
+ atomic_t notify_count;
+};
+
+enum mbim_notify_state {
+ NCM_NOTIFY_NONE,
+ NCM_NOTIFY_CONNECT,
+ NCM_NOTIFY_SPEED,
+};
+
+struct f_mbim {
+ struct usb_function function;
+ struct usb_composite_dev *cdev;
+
+ atomic_t online;
+ bool is_open;
+
+ atomic_t open_excl;
+ atomic_t ioctl_excl;
+ atomic_t read_excl;
+ atomic_t write_excl;
+
+ wait_queue_head_t read_wq;
+ wait_queue_head_t write_wq;
+
+ u8 port_num;
+ struct data_port bam_port;
+ struct mbim_notify_port not_port;
+
+ struct mbim_ep_descs fs;
+ struct mbim_ep_descs hs;
+
+ u8 ctrl_id, data_id;
+
+ struct ndp_parser_opts *parser_opts;
+
+ spinlock_t lock;
+
+ struct list_head cpkt_req_q;
+ struct list_head cpkt_resp_q;
+
+ u32 ntb_input_size;
+ u16 ntb_max_datagrams;
+
+ pid_t user_pid;
+
+ atomic_t error;
+};
+
+struct mbim_ntb_input_size {
+ u32 ntb_input_size;
+ u16 ntb_max_datagrams;
+ u16 reserved;
+};
+
+/* temporary variable used between mbim_open() and mbim_gadget_bind() */
+static struct f_mbim *_mbim_dev;
+
+static unsigned int nr_mbim_ports;
+
+static struct mbim_ports {
+ struct f_mbim *port;
+ unsigned port_num;
+} mbim_ports[NR_MBIM_PORTS];
+
+static inline struct f_mbim *func_to_mbim(struct usb_function *f)
+{
+ return container_of(f, struct f_mbim, function);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static inline unsigned mbim_bitrate(struct usb_gadget *g)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return 13 * 512 * 8 * 1000 * 8;
+ else
+ return 19 * 64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define NTB_DEFAULT_IN_SIZE (0x4000)
+#define NTB_OUT_SIZE (0x1000)
+#define NDP_IN_DIVISOR (0x4)
+
+#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
+
+static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
+ .wLength = sizeof ntb_parameters,
+ .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
+ .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
+ .wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
+ .wNdpInPayloadRemainder = cpu_to_le16(0),
+ .wNdpInAlignment = cpu_to_le16(4),
+
+ .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+ .wNdpOutDivisor = cpu_to_le16(4),
+ .wNdpOutPayloadRemainder = cpu_to_le16(0),
+ .wNdpOutAlignment = cpu_to_le16(4),
+ .wNtbOutMaxDatagrams = cpu_to_le16(4),
+};
+
+/*
+ * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
+ * packet, to simplify cancellation; and a big transfer interval, to
+ * waste less bandwidth.
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
+#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
+
+static struct usb_interface_assoc_descriptor mbim_iad_desc = {
+ .bLength = sizeof mbim_iad_desc,
+ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+
+ /* .bFirstInterface = DYNAMIC, */
+ .bInterfaceCount = 2, /* control + data */
+ .bFunctionClass = 2,
+ .bFunctionSubClass = 0x0e,
+ .bFunctionProtocol = 0,
+ /* .iFunction = DYNAMIC */
+};
+
+/* interface descriptor: */
+static struct usb_interface_descriptor mbim_control_intf = {
+ .bLength = sizeof mbim_control_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ /* .bInterfaceNumber = DYNAMIC */
+ .bNumEndpoints = 1,
+ .bInterfaceClass = 0x02,
+ .bInterfaceSubClass = 0x0e,
+ .bInterfaceProtocol = 0,
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc mbim_header_desc = {
+ .bLength = sizeof mbim_header_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
+
+ .bcdCDC = cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_union_desc mbim_union_desc = {
+ .bLength = sizeof(mbim_union_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
+ /* .bMasterInterface0 = DYNAMIC */
+ /* .bSlaveInterface0 = DYNAMIC */
+};
+
+static struct usb_cdc_mbb_desc mbb_desc = {
+ .bLength = sizeof mbb_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_MBB_TYPE,
+
+ .bcdMbbVersion = cpu_to_le16(0x0100),
+
+ .wMaxControlMessage = cpu_to_le16(0x1000),
+ .bNumberFilters = 0x10,
+ .bMaxFilterSize = 0x80,
+ .wMaxSegmentSize = cpu_to_le16(0x1000),
+ .bmNetworkCapabilities = 0x20,
+};
+
+/* the default data interface has no endpoints ... */
+static struct usb_interface_descriptor mbim_data_nop_intf = {
+ .bLength = sizeof mbim_data_nop_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ /* .bInterfaceNumber = DYNAMIC */
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = 0x0a,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0x02,
+ /* .iInterface = DYNAMIC */
+};
+
+/* ... but the "real" data interface has two bulk endpoints */
+static struct usb_interface_descriptor mbim_data_intf = {
+ .bLength = sizeof mbim_data_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ /* .bInterfaceNumber = DYNAMIC */
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0x0a,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0x02,
+ /* .iInterface = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor fs_mbim_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
+ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor fs_mbim_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor fs_mbim_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *mbim_fs_function[] = {
+ (struct usb_descriptor_header *) &mbim_iad_desc,
+ /* MBIM control descriptors */
+ (struct usb_descriptor_header *) &mbim_control_intf,
+ (struct usb_descriptor_header *) &mbim_header_desc,
+ (struct usb_descriptor_header *) &mbb_desc,
+ (struct usb_descriptor_header *) &fs_mbim_notify_desc,
+ /* data interface, altsettings 0 and 1 */
+ (struct usb_descriptor_header *) &mbim_data_nop_intf,
+ (struct usb_descriptor_header *) &mbim_data_intf,
+ (struct usb_descriptor_header *) &fs_mbim_in_desc,
+ (struct usb_descriptor_header *) &fs_mbim_out_desc,
+ NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor hs_mbim_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 4*cpu_to_le16(NCM_STATUS_BYTECOUNT),
+ .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+static struct usb_endpoint_descriptor hs_mbim_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor hs_mbim_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *mbim_hs_function[] = {
+ (struct usb_descriptor_header *) &mbim_iad_desc,
+ /* MBIM control descriptors */
+ (struct usb_descriptor_header *) &mbim_control_intf,
+ (struct usb_descriptor_header *) &mbim_header_desc,
+ (struct usb_descriptor_header *) &mbb_desc,
+ (struct usb_descriptor_header *) &hs_mbim_notify_desc,
+ /* data interface, altsettings 0 and 1 */
+ (struct usb_descriptor_header *) &mbim_data_nop_intf,
+ (struct usb_descriptor_header *) &mbim_data_intf,
+ (struct usb_descriptor_header *) &hs_mbim_in_desc,
+ (struct usb_descriptor_header *) &hs_mbim_out_desc,
+ NULL,
+};
+
+/* string descriptors: */
+
+#define STRING_CTRL_IDX 0
+#define STRING_DATA_IDX 1
+
+static struct usb_string mbim_string_defs[] = {
+ [STRING_CTRL_IDX].s = "MBIM Control",
+ [STRING_DATA_IDX].s = "MBIM Data",
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings mbim_string_table = {
+ .language = 0x0409, /* en-us */
+ .strings = mbim_string_defs,
+};
+
+static struct usb_gadget_strings *mbim_strings[] = {
+ &mbim_string_table,
+ NULL,
+};
+
+/*
+ * Here are options for the Datagram Pointer table (NDP) parser.
+ * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3),
+ * in NDP16 offsets and sizes fields are 1 16bit word wide,
+ * in NDP32 -- 2 16bit words wide. Also signatures are different.
+ * To make the parser code the same, put the differences in the structure,
+ * and switch pointers to the structures when the format is changed.
+ */
+
+struct ndp_parser_opts {
+ u32 nth_sign;
+ u32 ndp_sign;
+ unsigned nth_size;
+ unsigned ndp_size;
+ unsigned ndplen_align;
+ /* sizes in u16 units */
+ unsigned dgram_item_len; /* index or length */
+ unsigned block_length;
+ unsigned fp_index;
+ unsigned reserved1;
+ unsigned reserved2;
+ unsigned next_fp_index;
+};
+
+#define INIT_NDP16_OPTS { \
+ .nth_sign = USB_CDC_NCM_NTH16_SIGN, \
+ .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \
+ .nth_size = sizeof(struct usb_cdc_ncm_nth16), \
+ .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \
+ .ndplen_align = 4, \
+ .dgram_item_len = 1, \
+ .block_length = 1, \
+ .fp_index = 1, \
+ .reserved1 = 0, \
+ .reserved2 = 0, \
+ .next_fp_index = 1, \
+}
+
+#define INIT_NDP32_OPTS { \
+ .nth_sign = USB_CDC_NCM_NTH32_SIGN, \
+ .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \
+ .nth_size = sizeof(struct usb_cdc_ncm_nth32), \
+ .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \
+ .ndplen_align = 8, \
+ .dgram_item_len = 2, \
+ .block_length = 2, \
+ .fp_index = 2, \
+ .reserved1 = 1, \
+ .reserved2 = 2, \
+ .next_fp_index = 2, \
+}
+
+static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
+static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+
+static inline int mbim_lock(atomic_t *excl)
+{
+ if (atomic_inc_return(excl) == 1) {
+ return 0;
+ } else {
+ atomic_dec(excl);
+ return -EBUSY;
+ }
+}
+
+static inline void mbim_unlock(atomic_t *excl)
+{
+ atomic_dec(excl);
+}
+
+static struct ctrl_pkt *mbim_alloc_ctrl_pkt(unsigned len, gfp_t flags)
+{
+ struct ctrl_pkt *pkt;
+
+ pkt = kzalloc(sizeof(struct ctrl_pkt), flags);
+ if (!pkt)
+ return ERR_PTR(-ENOMEM);
+
+ pkt->buf = kmalloc(len, flags);
+ if (!pkt->buf) {
+ kfree(pkt);
+ return ERR_PTR(-ENOMEM);
+ }
+ pkt->len = len;
+
+ return pkt;
+}
+
+static void mbim_free_ctrl_pkt(struct ctrl_pkt *pkt)
+{
+ if (pkt) {
+ kfree(pkt->buf);
+ kfree(pkt);
+ }
+}
+
+static struct usb_request *mbim_alloc_req(struct usb_ep *ep, int buffer_size)
+{
+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (!req)
+ return NULL;
+
+ req->buf = kmalloc(buffer_size, GFP_KERNEL);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+ req->length = buffer_size;
+ return req;
+}
+
+void fmbim_free_req(struct usb_ep *ep, struct usb_request *req)
+{
+ if (req) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+static void fmbim_ctrl_response_available(struct f_mbim *dev)
+{
+ struct usb_request *req = dev->not_port.notify_req;
+ struct usb_cdc_notification *event = NULL;
+ unsigned long flags;
+ int ret;
+
+ int notif_c = 0;
+
+ pr_info("dev:%p portno#%d\n", dev, dev->port_num);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ if (!atomic_read(&dev->online)) {
+ pr_info("dev:%p is not online\n", dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return;
+ }
+
+ if (!req) {
+ pr_info("dev:%p req is NULL\n", dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return;
+ }
+
+ if (!req->buf) {
+ pr_info("dev:%p req->buf is NULL\n", dev);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return;
+ }
+
+ notif_c = atomic_inc_return(&dev->not_port.notify_count);
+ pr_info("atomic_inc_return[notif_c] = %d", notif_c);
+
+ event = req->buf;
+ event->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+ | USB_RECIP_INTERFACE;
+ event->bNotificationType = USB_CDC_NOTIFY_RESPONSE_AVAILABLE;
+ event->wValue = cpu_to_le16(0);
+ event->wIndex = cpu_to_le16(dev->ctrl_id);
+ event->wLength = cpu_to_le16(0);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ pr_info("Call usb_ep_queue");
+
+ ret = usb_ep_queue(dev->not_port.notify,
+ dev->not_port.notify_req, GFP_ATOMIC);
+ if (ret) {
+ atomic_dec(&dev->not_port.notify_count);
+ pr_err("ep enqueue error %d\n", ret);
+ }
+
+ pr_info("Succcessfull Exit");
+}
+
+static int
+fmbim_send_cpkt_response(struct f_mbim *gr, struct ctrl_pkt *cpkt)
+{
+ struct f_mbim *dev = gr;
+ unsigned long flags;
+
+ if (!gr || !cpkt) {
+ pr_err("Invalid cpkt, dev:%p cpkt:%p\n",
+ gr, cpkt);
+ return -ENODEV;
+ }
+
+ pr_info("dev:%p port_num#%d\n", dev, dev->port_num);
+
+ if (!atomic_read(&dev->online)) {
+ pr_info("dev:%p is not connected\n", dev);
+ mbim_free_ctrl_pkt(cpkt);
+ return 0;
+ }
+
+ spin_lock_irqsave(&dev->lock, flags);
+ list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ fmbim_ctrl_response_available(dev);
+
+ return 0;
+}
+
+/* ---------------------------- BAM INTERFACE ----------------------------- */
+
+static int mbim_bam_setup(int no_ports)
+{
+ int ret;
+
+ pr_info("no_ports:%d\n", no_ports);
+
+ ret = bam_data_setup(no_ports);
+ if (ret) {
+ pr_err("bam_data_setup failed err: %d\n", ret);
+ return ret;
+ }
+
+ pr_info("Initialized %d ports\n", no_ports);
+ return 0;
+}
+
+static int mbim_bam_connect(struct f_mbim *dev)
+{
+ int ret;
+
+ pr_info("dev:%p portno:%d\n", dev, dev->port_num);
+
+ ret = bam_data_connect(&dev->bam_port, dev->port_num, dev->port_num);
+ if (ret) {
+ pr_err("bam_data_setup failed: err:%d\n",
+ ret);
+ return ret;
+ } else {
+ pr_info("mbim bam connected\n");
+ }
+
+ return 0;
+}
+
+static int mbim_bam_disconnect(struct f_mbim *dev)
+{
+ pr_info("dev:%p port:%d. Do nothing.\n",
+ dev, dev->port_num);
+
+ /* bam_data_disconnect(&dev->bam_port, dev->port_num); */
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------*/
+
+static inline void mbim_reset_values(struct f_mbim *mbim)
+{
+ mbim->parser_opts = &ndp16_opts;
+
+ mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
+
+ atomic_set(&mbim->not_port.notify_count, 0);
+ atomic_set(&mbim->online, 0);
+}
+
+/*
+ * Context: mbim->lock held
+ */
+static void mbim_do_notify(struct f_mbim *mbim)
+{
+ struct usb_request *req = mbim->not_port.notify_req;
+ struct usb_cdc_notification *event;
+ struct usb_composite_dev *cdev = mbim->cdev;
+ __le32 *data;
+ int status;
+
+ pr_info("notify_state: %d", mbim->not_port.notify_state);
+
+ if (!req)
+ return;
+
+ event = req->buf;
+
+ switch (mbim->not_port.notify_state) {
+
+ case NCM_NOTIFY_NONE:
+ return;
+
+ case NCM_NOTIFY_CONNECT:
+ event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
+ if (mbim->is_open)
+ event->wValue = cpu_to_le16(1);
+ else
+ event->wValue = cpu_to_le16(0);
+ event->wLength = 0;
+ req->length = sizeof *event;
+
+ pr_info("notify connect %s\n",
+ mbim->is_open ? "true" : "false");
+ mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ break;
+
+ case NCM_NOTIFY_SPEED:
+ event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
+ event->wValue = cpu_to_le16(0);
+ event->wLength = cpu_to_le16(8);
+ req->length = NCM_STATUS_BYTECOUNT;
+
+ /* SPEED_CHANGE data is up/down speeds in bits/sec */
+ data = req->buf + sizeof *event;
+ data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
+ data[1] = data[0];
+
+ pr_info("notify speed %d\n",
+ mbim_bitrate(cdev->gadget));
+ mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
+ break;
+ }
+ event->bmRequestType = 0xA1;
+ event->wIndex = cpu_to_le16(mbim->ctrl_id);
+
+ mbim->not_port.notify_req = NULL;
+ /*
+ * In double buffering if there is a space in FIFO,
+ * completion callback can be called right after the call,
+ * so unlocking
+ */
+ spin_unlock(&mbim->lock);
+ status = usb_ep_queue(mbim->not_port.notify, req, GFP_ATOMIC);
+ spin_lock(&mbim->lock);
+ if (status < 0) {
+ mbim->not_port.notify_req = req;
+ atomic_dec(&mbim->not_port.notify_count);
+ pr_err("usb_ep_queue failed, err: %d", status);
+ }
+}
+
+/*
+ * Context: mbim->lock held
+ */
+static void mbim_notify(struct f_mbim *mbim)
+{
+ /*
+ * If mbim_notify() is called before the second (CONNECT)
+ * notification is sent, then it will reset to send the SPEED
+ * notificaion again (and again, and again), but it's not a problem
+ */
+ pr_info("dev:%p\n", mbim);
+
+ mbim->not_port.notify_state = NCM_NOTIFY_SPEED;
+ mbim_do_notify(mbim);
+}
+
+static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_mbim *mbim = req->context;
+ struct usb_cdc_notification *event = req->buf;
+
+ int notif_c = 0;
+
+ pr_info("dev:%p\n", mbim);
+
+ spin_lock(&mbim->lock);
+ switch (req->status) {
+ case 0:
+ pr_info("Notification %02x sent\n",
+ event->bNotificationType);
+
+ notif_c = atomic_dec_return(&mbim->not_port.notify_count);
+
+ if (notif_c != 0) {
+ pr_info("Continue to mbim_do_notify()");
+ break;
+ } else {
+ pr_info("notify_count decreased to 0. Do not notify");
+ spin_unlock(&mbim->lock);
+ return;
+ }
+
+ break;
+
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ /* connection gone */
+ mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ atomic_set(&mbim->not_port.notify_count, 0);
+ pr_info("ESHUTDOWN/ECONNRESET, connection gone");
+ break;
+ default:
+ pr_err("Unknown event %02x --> %d\n",
+ event->bNotificationType, req->status);
+ break;
+ }
+
+ mbim->not_port.notify_req = req;
+ mbim_do_notify(mbim);
+
+ spin_unlock(&mbim->lock);
+
+ pr_info("dev:%p Exit\n", mbim);
+}
+
+static void mbim_ep0out_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ /* now for SET_NTB_INPUT_SIZE only */
+ unsigned in_size = 0;
+ struct usb_function *f = req->context;
+ struct f_mbim *mbim = func_to_mbim(f);
+ struct mbim_ntb_input_size *ntb = NULL;
+
+ pr_info("dev:%p\n", mbim);
+
+ req->context = NULL;
+ if (req->status || req->actual != req->length) {
+ pr_err("Bad control-OUT transfer\n");
+ goto invalid;
+ }
+
+ if (req->length == 4) {
+ in_size = get_unaligned_le32(req->buf);
+ if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
+ in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
+ goto invalid;
+ }
+ } else if (req->length == 8) {
+ ntb = (struct mbim_ntb_input_size *)req->buf;
+ in_size = get_unaligned_le32(&(ntb->ntb_input_size));
+ if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
+ in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
+ goto invalid;
+ }
+ mbim->ntb_max_datagrams =
+ get_unaligned_le16(&(ntb->ntb_max_datagrams));
+ } else {
+ pr_err("Illegal NTB length %d\n", in_size);
+ goto invalid;
+ }
+
+ pr_info("Set NTB INPUT SIZE %d\n", in_size);
+
+ mbim->ntb_input_size = in_size;
+ return;
+
+invalid:
+ usb_ep_set_halt(ep);
+
+ pr_err("dev:%p Failed\n", mbim);
+
+ return;
+}
+
+static void
+fmbim_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct f_mbim *dev = req->context;
+ struct ctrl_pkt *cpkt = NULL;
+ int len = req->actual;
+
+ if (!dev) {
+ pr_err("mbim dev is null\n");
+ return;
+ }
+
+ if (req->status < 0) {
+ pr_err("mbim command error %d\n", req->status);
+ return;
+ }
+
+ pr_info("dev:%p port#%d\n", dev, dev->port_num);
+
+ spin_lock(&dev->lock);
+ if (!dev->is_open) {
+ pr_err("mbim file handler %p is not open", dev);
+ spin_unlock(&dev->lock);
+ return;
+ }
+
+ cpkt = mbim_alloc_ctrl_pkt(len, GFP_ATOMIC);
+ if (!cpkt) {
+ pr_err("Unable to allocate ctrl pkt\n");
+ spin_unlock(&dev->lock);
+ return;
+ }
+
+ pr_info("Add to cpkt_req_q packet with len = %d\n", len);
+ memcpy(cpkt->buf, req->buf, len);
+ list_add_tail(&cpkt->list, &dev->cpkt_req_q);
+ spin_unlock(&dev->lock);
+
+ /* wakeup read thread */
+ pr_info("Wake up read queue");
+ wake_up(&dev->read_wq);
+
+ return;
+}
+
+static int
+mbim_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct f_mbim *mbim = func_to_mbim(f);
+ struct usb_composite_dev *cdev = mbim->cdev;
+ struct usb_request *req = cdev->req;
+ struct ctrl_pkt *cpkt = NULL;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /*
+ * composite driver infrastructure handles everything except
+ * CDC class messages; interface activation uses set_alt().
+ */
+
+ if (!atomic_read(&mbim->online)) {
+ pr_info("usb cable is not connected\n");
+ return -ENOTCONN;
+ }
+
+ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_RESET_FUNCTION:
+
+ pr_info("USB_CDC_RESET_FUNCTION");
+ value = 0;
+ if (!_mbim_dev->user_pid) {
+ pr_err("QBI pid is not set");
+ break;
+ }
+
+ if (!_mbim_dev->is_open) {
+ pr_err("QBI is not up yet");
+ break;
+ }
+
+ send_sig_info(SIGUSR1, SEND_SIG_NOINFO,
+ find_task_by_vpid(_mbim_dev->user_pid));
+
+ pr_info("Sent signal to QBI pid %d",
+ _mbim_dev->user_pid);
+ break;
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SEND_ENCAPSULATED_COMMAND:
+
+ pr_info("USB_CDC_SEND_ENCAPSULATED_COMMAND");
+
+ if (w_length > req->length) {
+ pr_err("w_length > req->length: %d > %d",
+ w_length, req->length);
+ }
+ value = w_length;
+ req->complete = fmbim_cmd_complete;
+ req->context = mbim;
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_ENCAPSULATED_RESPONSE:
+
+ pr_info("USB_CDC_GET_ENCAPSULATED_RESPONSE");
+
+ if (w_value) {
+ pr_err("w_length > 0: %d", w_length);
+ break;
+ }
+
+ pr_info("req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+
+ spin_lock(&mbim->lock);
+ if (list_empty(&mbim->cpkt_resp_q)) {
+ pr_err("ctrl resp queue empty\n");
+ spin_unlock(&mbim->lock);
+ break;
+ }
+
+ cpkt = list_first_entry(&mbim->cpkt_resp_q,
+ struct ctrl_pkt, list);
+ list_del(&cpkt->list);
+ spin_unlock(&mbim->lock);
+
+ value = min_t(unsigned, w_length, cpkt->len);
+ memcpy(req->buf, cpkt->buf, value);
+ mbim_free_ctrl_pkt(cpkt);
+
+ pr_info("copied encapsulated_response %d bytes",
+ value);
+
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_NTB_PARAMETERS:
+
+ pr_info("USB_CDC_GET_NTB_PARAMETERS");
+
+ if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
+ break;
+
+ value = w_length > sizeof ntb_parameters ?
+ sizeof ntb_parameters : w_length;
+ memcpy(req->buf, &ntb_parameters, value);
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_NTB_INPUT_SIZE:
+
+ pr_info("USB_CDC_GET_NTB_INPUT_SIZE");
+
+ if (w_length < 4 || w_value != 0 || w_index != mbim->ctrl_id)
+ break;
+
+ put_unaligned_le32(mbim->ntb_input_size, req->buf);
+ value = 4;
+ pr_info("Reply to host INPUT SIZE %d\n",
+ mbim->ntb_input_size);
+ break;
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SET_NTB_INPUT_SIZE:
+
+ pr_info("USB_CDC_SET_NTB_INPUT_SIZE");
+
+ if (w_length != 4 && w_length != 8) {
+ pr_err("wrong NTB length %d", w_length);
+ break;
+ }
+
+ if (w_value != 0 || w_index != mbim->ctrl_id)
+ break;
+
+ req->complete = mbim_ep0out_complete;
+ req->length = w_length;
+ req->context = f;
+
+ value = req->length;
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_NTB_FORMAT:
+ {
+ uint16_t format;
+
+ pr_info("USB_CDC_GET_NTB_FORMAT");
+
+ if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
+ break;
+
+ format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+ put_unaligned_le16(format, req->buf);
+ value = 2;
+ pr_info("NTB FORMAT: sending %d\n", format);
+ break;
+ }
+
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SET_NTB_FORMAT:
+ {
+ pr_info("USB_CDC_SET_NTB_FORMAT");
+
+ if (w_length != 0 || w_index != mbim->ctrl_id)
+ break;
+ switch (w_value) {
+ case 0x0000:
+ mbim->parser_opts = &ndp16_opts;
+ pr_info("NCM16 selected\n");
+ break;
+ case 0x0001:
+ mbim->parser_opts = &ndp32_opts;
+ pr_info("NCM32 selected\n");
+ break;
+ default:
+ break;
+ }
+ value = 0;
+ break;
+ }
+
+ /* optional in mbim descriptor: */
+ /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */
+ /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */
+
+ default:
+ pr_err("invalid control req: %02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ pr_info("control request: %02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->zero = 0;
+ req->length = value;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ pr_err("queueing req failed: %02x.%02x, err %d\n",
+ ctrl->bRequestType,
+ ctrl->bRequest, value);
+ }
+ } else {
+ pr_err("ctrl req err %d: %02x.%02x v%04x i%04x l%d\n",
+ value, ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static int mbim_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct f_mbim *mbim = func_to_mbim(f);
+ struct usb_composite_dev *cdev = mbim->cdev;
+ int ret = 0;
+
+ /* Control interface has only altsetting 0 */
+ if (intf == mbim->ctrl_id) {
+
+ pr_info("CONTROL_INTERFACE");
+
+ if (alt != 0)
+ goto fail;
+
+ if (mbim->not_port.notify->driver_data) {
+ pr_info("reset mbim control %d\n", intf);
+ usb_ep_disable(mbim->not_port.notify);
+ }
+
+ ret = config_ep_by_speed(cdev->gadget, f,
+ mbim->not_port.notify);
+ if (ret) {
+ mbim->not_port.notify->desc = NULL;
+ pr_err("Failed configuring notify ep %s: err %d\n",
+ mbim->not_port.notify->name, ret);
+ return ret;
+ }
+
+ ret = usb_ep_enable(mbim->not_port.notify);
+ if (ret) {
+ pr_err("usb ep#%s enable failed, err#%d\n",
+ mbim->not_port.notify->name, ret);
+ return ret;
+ }
+ mbim->not_port.notify->driver_data = mbim;
+
+ /* Data interface has two altsettings, 0 and 1 */
+ } else if (intf == mbim->data_id) {
+
+ pr_info("DATA_INTERFACE");
+
+ if (alt > 1)
+ goto fail;
+
+ if (mbim->bam_port.in->driver_data) {
+ pr_info("reset mbim\n");
+ mbim_reset_values(mbim);
+ mbim_bam_disconnect(mbim);
+ }
+
+ /*
+ * CDC Network only sends data in non-default altsettings.
+ * Changing altsettings resets filters, statistics, etc.
+ */
+ if (alt == 1) {
+ pr_info("Alt set 1, initialize ports");
+
+ if (!mbim->bam_port.in->desc) {
+
+ pr_info("Choose endpoints");
+
+ ret = config_ep_by_speed(cdev->gadget, f,
+ mbim->bam_port.in);
+ if (ret) {
+ mbim->bam_port.in->desc = NULL;
+ pr_err("IN ep %s failed: %d\n",
+ mbim->bam_port.in->name, ret);
+ return ret;
+ }
+
+ pr_info("Set mbim port in_desc = 0x%p",
+ mbim->bam_port.in->desc);
+
+ ret = config_ep_by_speed(cdev->gadget, f,
+ mbim->bam_port.out);
+ if (ret) {
+ mbim->bam_port.out->desc = NULL;
+ pr_err("OUT ep %s failed: %d\n",
+ mbim->bam_port.out->name, ret);
+ return ret;
+ }
+
+ pr_info("Set mbim port out_desc = 0x%p",
+ mbim->bam_port.out->desc);
+ } else {
+ pr_info("PORTS already SET");
+ }
+
+ pr_info("Activate mbim\n");
+ mbim_bam_connect(mbim);
+ }
+
+ spin_lock(&mbim->lock);
+ mbim_notify(mbim);
+ spin_unlock(&mbim->lock);
+ } else {
+ goto fail;
+ }
+
+ atomic_set(&mbim->online, 1);
+
+ pr_info("SET DEVICE ONLINE");
+
+ /* wakeup file threads */
+ wake_up(&mbim->read_wq);
+ wake_up(&mbim->write_wq);
+
+ return 0;
+
+fail:
+ pr_err("ERROR: Illegal Interface");
+ return -EINVAL;
+}
+
+/*
+ * Because the data interface supports multiple altsettings,
+ * this MBIM function *MUST* implement a get_alt() method.
+ */
+static int mbim_get_alt(struct usb_function *f, unsigned intf)
+{
+ struct f_mbim *mbim = func_to_mbim(f);
+
+ if (intf == mbim->ctrl_id)
+ return 0;
+ return mbim->bam_port.in->driver_data ? 1 : 0;
+}
+
+static void mbim_disable(struct usb_function *f)
+{
+ struct f_mbim *mbim = func_to_mbim(f);
+
+ pr_info("SET DEVICE OFFLINE");
+ atomic_set(&mbim->online, 0);
+
+ if (_mbim_dev && _mbim_dev->user_pid && _mbim_dev->is_open) {
+ send_sig_info(SIGUSR1, SEND_SIG_NOINFO,
+ find_task_by_vpid(_mbim_dev->user_pid));
+ pr_info("Sending reset signal to QBI pid %d",
+ _mbim_dev->user_pid);
+ }
+
+ mbim_bam_disconnect(mbim);
+
+ if (mbim->not_port.notify->driver_data) {
+ usb_ep_disable(mbim->not_port.notify);
+ mbim->not_port.notify->driver_data = NULL;
+ }
+
+ pr_info("mbim deactivated\n");
+}
+
+/*---------------------- function driver setup/binding ---------------------*/
+
+static int
+mbim_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_mbim *mbim = func_to_mbim(f);
+ int status;
+ struct usb_ep *ep;
+
+ pr_info("Enter");
+
+ mbim->cdev = cdev;
+
+ /* allocate instance-specific interface IDs */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ mbim->ctrl_id = status;
+ mbim_iad_desc.bFirstInterface = status;
+
+ mbim_control_intf.bInterfaceNumber = status;
+ mbim_union_desc.bMasterInterface0 = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ mbim->data_id = status;
+
+ mbim_data_nop_intf.bInterfaceNumber = status;
+ mbim_data_intf.bInterfaceNumber = status;
+ mbim_union_desc.bSlaveInterface0 = status;
+
+ status = -ENODEV;
+
+ /* allocate instance-specific endpoints */
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_in_desc);
+ if (!ep) {
+ pr_err("usb epin autoconfig failed\n");
+ goto fail;
+ }
+ pr_info("usb epin autoconfig succeeded\n");
+ ep->driver_data = cdev; /* claim */
+ mbim->bam_port.in = ep;
+
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_out_desc);
+ if (!ep) {
+ pr_err("usb epout autoconfig failed\n");
+ goto fail;
+ }
+ pr_info("usb epout autoconfig succeeded\n");
+ ep->driver_data = cdev; /* claim */
+ mbim->bam_port.out = ep;
+
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_mbim_notify_desc);
+ if (!ep) {
+ pr_err("usb notify ep autoconfig failed\n");
+ goto fail;
+ }
+ pr_info("usb notify ep autoconfig succeeded\n");
+ mbim->not_port.notify = ep;
+ ep->driver_data = cdev; /* claim */
+
+ status = -ENOMEM;
+
+ /* allocate notification request and buffer */
+ mbim->not_port.notify_req = mbim_alloc_req(ep, NCM_STATUS_BYTECOUNT);
+ if (!mbim->not_port.notify_req) {
+ pr_info("failed to allocate notify request\n");
+ goto fail;
+ }
+ pr_info("allocated notify ep request & request buffer\n");
+
+ mbim->not_port.notify_req->context = mbim;
+ mbim->not_port.notify_req->complete = mbim_notify_complete;
+
+ /* copy descriptors, and track endpoint copies */
+ f->descriptors = usb_copy_descriptors(mbim_fs_function);
+ if (!f->descriptors)
+ goto fail;
+
+ /*
+ * support all relevant hardware speeds... we expect that when
+ * hardware is dual speed, all bulk-capable endpoints work at
+ * both speeds
+ */
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+ hs_mbim_in_desc.bEndpointAddress =
+ fs_mbim_in_desc.bEndpointAddress;
+ hs_mbim_out_desc.bEndpointAddress =
+ fs_mbim_out_desc.bEndpointAddress;
+ hs_mbim_notify_desc.bEndpointAddress =
+ fs_mbim_notify_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->hs_descriptors = usb_copy_descriptors(mbim_hs_function);
+ if (!f->hs_descriptors)
+ goto fail;
+ }
+
+ pr_info("mbim(%d): %s speed IN/%s OUT/%s NOTIFY/%s\n",
+ mbim->port_num,
+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+ mbim->bam_port.in->name, mbim->bam_port.out->name,
+ mbim->not_port.notify->name);
+
+ return 0;
+
+fail:
+ pr_err("%s failed to bind, err %d\n", f->name, status);
+
+ if (f->descriptors)
+ usb_free_descriptors(f->descriptors);
+
+ if (mbim->not_port.notify_req) {
+ kfree(mbim->not_port.notify_req->buf);
+ usb_ep_free_request(mbim->not_port.notify,
+ mbim->not_port.notify_req);
+ }
+
+ /* we might as well release our claims on endpoints */
+ if (mbim->not_port.notify)
+ mbim->not_port.notify->driver_data = NULL;
+ if (mbim->bam_port.out)
+ mbim->bam_port.out->driver_data = NULL;
+ if (mbim->bam_port.in)
+ mbim->bam_port.in->driver_data = NULL;
+
+ return status;
+}
+
+static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_mbim *mbim = func_to_mbim(f);
+
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->descriptors);
+
+ kfree(mbim->not_port.notify_req->buf);
+ usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);
+}
+
+/**
+ * mbim_bind_config - add MBIM link to a configuration
+ * @c: the configuration to support the network link
+ * Context: single threaded during gadget setup
+ * Returns zero on success, else negative errno.
+ */
+int mbim_bind_config(struct usb_configuration *c, unsigned portno)
+{
+ struct f_mbim *mbim = NULL;
+ int status = 0;
+
+ pr_info("port number %u", portno);
+
+ if (portno >= nr_mbim_ports) {
+ pr_err("Can not add port %u. Max ports = %d",
+ portno, nr_mbim_ports);
+ return -ENODEV;
+ }
+
+ status = mbim_bam_setup(nr_mbim_ports);
+ if (status) {
+ pr_err("bam setup failed");
+ return status;
+ }
+
+ /* maybe allocate device-global string IDs */
+ if (mbim_string_defs[0].id == 0) {
+
+ /* control interface label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ mbim_string_defs[STRING_CTRL_IDX].id = status;
+ mbim_control_intf.iInterface = status;
+
+ /* data interface label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ mbim_string_defs[STRING_DATA_IDX].id = status;
+ mbim_data_nop_intf.iInterface = status;
+ mbim_data_intf.iInterface = status;
+ }
+
+ /* allocate and initialize one new instance */
+ mbim = mbim_ports[0].port;
+ if (!mbim) {
+ pr_info("mbim struct not allocated");
+ return -ENOMEM;
+ }
+
+ mbim->cdev = c->cdev;
+
+ spin_lock_init(&mbim->lock);
+
+ mbim_reset_values(mbim);
+
+ mbim->function.name = "usb_mbim";
+ mbim->function.strings = mbim_strings;
+ mbim->function.bind = mbim_bind;
+ mbim->function.unbind = mbim_unbind;
+ mbim->function.set_alt = mbim_set_alt;
+ mbim->function.get_alt = mbim_get_alt;
+ mbim->function.setup = mbim_setup;
+ mbim->function.disable = mbim_disable;
+
+ INIT_LIST_HEAD(&mbim->cpkt_req_q);
+ INIT_LIST_HEAD(&mbim->cpkt_resp_q);
+
+ status = usb_add_function(c, &mbim->function);
+
+ pr_info("Exit status %d", status);
+
+ return status;
+}
+
+/* ------------ MBIM DRIVER File Operations API for USER SPACE ------------ */
+
+static ssize_t
+mbim_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
+{
+ struct f_mbim *dev = fp->private_data;
+ struct ctrl_pkt *cpkt = NULL;
+ int ret = 0;
+
+ pr_debug("Enter(%d)\n", count);
+
+ if (!dev) {
+ pr_err("Received NULL mbim pointer\n");
+ return -ENODEV;
+ }
+
+ if (count > MBIM_BULK_BUFFER_SIZE) {
+ pr_err("Buffer size is too big %d, should be at most %d\n",
+ count, MBIM_BULK_BUFFER_SIZE);
+ return -EINVAL;
+ }
+
+ if (mbim_lock(&dev->read_excl)) {
+ pr_err("Previous reading is not finished yet\n");
+ return -EBUSY;
+ }
+
+ /* block until mbim online */
+ while (!(atomic_read(&dev->online) || atomic_read(&dev->error))) {
+ pr_err("USB cable not connected. Wait.\n");
+ ret = wait_event_interruptible(dev->read_wq,
+ (atomic_read(&dev->online) ||
+ atomic_read(&dev->error)));
+ if (ret < 0) {
+ mbim_unlock(&dev->read_excl);
+ return 0;
+ }
+ }
+
+ if (atomic_read(&dev->error)) {
+ mbim_unlock(&dev->read_excl);
+ return -EIO;
+ }
+
+ while (list_empty(&dev->cpkt_req_q)) {
+ pr_err("Requests list is empty. Wait.\n");
+ ret = wait_event_interruptible(dev->read_wq,
+ !list_empty(&dev->cpkt_req_q));
+ if (ret < 0) {
+ pr_err("Waiting failed\n");
+ mbim_unlock(&dev->read_excl);
+ return 0;
+ }
+ pr_debug("Received request packet\n");
+ }
+
+ cpkt = list_first_entry(&dev->cpkt_req_q, struct ctrl_pkt,
+ list);
+ if (cpkt->len > count) {
+ mbim_unlock(&dev->read_excl);
+ pr_err("cpkt size too big:%d > buf size:%d\n",
+ cpkt->len, count);
+ return -ENOMEM;
+ }
+
+ pr_debug("cpkt size:%d\n", cpkt->len);
+
+ list_del(&cpkt->list);
+ mbim_unlock(&dev->read_excl);
+
+ ret = copy_to_user(buf, cpkt->buf, cpkt->len);
+ if (ret) {
+ pr_err("copy_to_user failed: err %d\n", ret);
+ ret = 0;
+ } else {
+ pr_debug("copied %d bytes to user\n", cpkt->len);
+ ret = cpkt->len;
+ }
+
+ mbim_free_ctrl_pkt(cpkt);
+
+ return ret;
+}
+
+static ssize_t
+mbim_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos)
+{
+ struct f_mbim *dev = fp->private_data;
+ struct ctrl_pkt *cpkt = NULL;
+ int ret = 0;
+
+ pr_debug("Enter(%d)", count);
+
+ if (!dev) {
+ pr_err("Received NULL mbim pointer\n");
+ return -ENODEV;
+ }
+
+ if (!count) {
+ pr_err("zero length ctrl pkt\n");
+ return -ENODEV;
+ }
+
+ if (count > MAX_CTRL_PKT_SIZE) {
+ pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
+ count, MAX_CTRL_PKT_SIZE);
+ return -ENOMEM;
+ }
+
+ if (mbim_lock(&dev->write_excl)) {
+ pr_err("Previous writing not finished yet\n");
+ return -EBUSY;
+ }
+
+ if (!atomic_read(&dev->online)) {
+ pr_err("USB cable not connected\n");
+ mbim_unlock(&dev->write_excl);
+ return -EPIPE;
+ }
+
+ cpkt = mbim_alloc_ctrl_pkt(count, GFP_KERNEL);
+ if (!cpkt) {
+ pr_err("failed to allocate ctrl pkt\n");
+ mbim_unlock(&dev->write_excl);
+ return -ENOMEM;
+ }
+
+ ret = copy_from_user(cpkt->buf, buf, count);
+ if (ret) {
+ pr_err("copy_from_user failed err:%d\n", ret);
+ mbim_free_ctrl_pkt(cpkt);
+ mbim_unlock(&dev->write_excl);
+ return 0;
+ }
+
+ fmbim_send_cpkt_response(dev, cpkt);
+
+ mbim_unlock(&dev->write_excl);
+
+ pr_debug("Exit(%d)", count);
+
+ return count;
+}
+
+static int mbim_open(struct inode *ip, struct file *fp)
+{
+ pr_info("Open mbim driver\n");
+
+ while (!_mbim_dev) {
+ pr_err("mbim_dev not created yet\n");
+ return -ENODEV;
+ }
+
+ if (mbim_lock(&_mbim_dev->open_excl)) {
+ pr_err("Already opened\n");
+ return -EBUSY;
+ }
+
+ pr_info("Lock mbim_dev->open_excl for open\n");
+
+ if (!atomic_read(&_mbim_dev->online))
+ pr_err("USB cable not connected\n");
+
+ pr_info("Set QBI pid %d\n", pid_nr(task_pid(current)));
+ _mbim_dev->user_pid = pid_nr(task_pid(current));
+
+ fp->private_data = _mbim_dev;
+
+ atomic_set(&_mbim_dev->error, 0);
+
+ spin_lock(&_mbim_dev->lock);
+ _mbim_dev->is_open = true;
+ mbim_notify(_mbim_dev);
+ spin_unlock(&_mbim_dev->lock);
+
+ pr_info("Exit, mbim file opened\n");
+
+ return 0;
+}
+
+static int mbim_release(struct inode *ip, struct file *fp)
+{
+ struct f_mbim *mbim = fp->private_data;
+
+ pr_info("Close mbim file");
+
+ spin_lock(&mbim->lock);
+ mbim->is_open = false;
+ mbim_notify(mbim);
+ spin_unlock(&mbim->lock);
+
+ mbim->user_pid = 0;
+
+ mbim_unlock(&_mbim_dev->open_excl);
+
+ return 0;
+}
+
+static long mbim_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+ struct f_mbim *mbim = fp->private_data;
+ int ret = 0;
+
+ pr_info("Received command %d", cmd);
+
+ if (mbim_lock(&mbim->ioctl_excl))
+ return -EBUSY;
+
+ switch (cmd) {
+ case MBIM_GET_NTB_SIZE:
+ ret = copy_to_user((void __user *)arg,
+ &mbim->ntb_input_size, sizeof(mbim->ntb_input_size));
+ if (ret) {
+ pr_err("copying to user space failed");
+ ret = -EFAULT;
+ }
+ pr_info("Sent NTB size %d", mbim->ntb_input_size);
+ break;
+ case MBIM_GET_DATAGRAM_COUNT:
+ ret = copy_to_user((void __user *)arg,
+ &mbim->ntb_max_datagrams,
+ sizeof(mbim->ntb_max_datagrams));
+ if (ret) {
+ pr_err("copying to user space failed");
+ ret = -EFAULT;
+ }
+ pr_info("Sent NTB datagrams count %d",
+ mbim->ntb_max_datagrams);
+ break;
+ default:
+ pr_err("wrong parameter");
+ ret = -EINVAL;
+ }
+
+ mbim_unlock(&mbim->ioctl_excl);
+
+ return ret;
+}
+
+/* file operations for MBIM device /dev/android_mbim */
+static const struct file_operations mbim_fops = {
+ .owner = THIS_MODULE,
+ .open = mbim_open,
+ .release = mbim_release,
+ .read = mbim_read,
+ .write = mbim_write,
+ .unlocked_ioctl = mbim_ioctl,
+};
+
+static struct miscdevice mbim_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "android_mbim",
+ .fops = &mbim_fops,
+};
+
+static int mbim_init(int instances)
+{
+ int i;
+ struct f_mbim *dev = NULL;
+ int ret;
+
+ pr_info("initialize %d instances\n", instances);
+
+ if (instances > NR_MBIM_PORTS) {
+ pr_err("Max-%d instances supported\n", NR_MBIM_PORTS);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < instances; i++) {
+ dev = kzalloc(sizeof(struct f_mbim), GFP_KERNEL);
+ if (!dev) {
+ pr_err("Failed to allocate mbim dev\n");
+ ret = -ENOMEM;
+ goto fail_probe;
+ }
+
+ dev->port_num = i;
+ spin_lock_init(&dev->lock);
+ INIT_LIST_HEAD(&dev->cpkt_req_q);
+ INIT_LIST_HEAD(&dev->cpkt_resp_q);
+
+ mbim_ports[i].port = dev;
+ mbim_ports[i].port_num = i;
+
+ init_waitqueue_head(&dev->read_wq);
+ init_waitqueue_head(&dev->write_wq);
+
+ atomic_set(&dev->open_excl, 0);
+ atomic_set(&dev->ioctl_excl, 0);
+ atomic_set(&dev->read_excl, 0);
+ atomic_set(&dev->write_excl, 0);
+
+ nr_mbim_ports++;
+
+ }
+
+ _mbim_dev = dev;
+ ret = misc_register(&mbim_device);
+ if (ret) {
+ pr_err("mbim driver failed to register");
+ goto fail_probe;
+ }
+
+ pr_info("Initialized %d ports\n", nr_mbim_ports);
+
+ return ret;
+
+fail_probe:
+ pr_err("Failed");
+ for (i = 0; i < nr_mbim_ports; i++) {
+ kfree(mbim_ports[i].port);
+ mbim_ports[i].port = NULL;
+ }
+
+ return ret;
+}
+
+static void fmbim_cleanup(void)
+{
+ int i = 0;
+
+ pr_info("Enter");
+
+ for (i = 0; i < nr_mbim_ports; i++) {
+ kfree(mbim_ports[i].port);
+ mbim_ports[i].port = NULL;
+ }
+ nr_mbim_ports = 0;
+
+ misc_deregister(&mbim_device);
+
+ _mbim_dev = NULL;
+}
+
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index cc26c85..b086428 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -488,20 +488,16 @@
}
dev->notify->driver_data = dev;
- if (dev->port.in->driver_data) {
- pr_debug("%s: reset port:%d\n", __func__, dev->port_num);
- gport_rmnet_disconnect(dev);
+ if (!dev->port.in->driver_data) {
+ if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
+ config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
+ dev->port.in->desc = NULL;
+ dev->port.out->desc = NULL;
+ return -EINVAL;
+ }
+ ret = gport_rmnet_connect(dev);
}
- if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
- config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
- dev->port.in->desc = NULL;
- dev->port.out->desc = NULL;
- return -EINVAL;
- }
-
- ret = gport_rmnet_connect(dev);
-
atomic_set(&dev->online, 1);
return ret;
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 28e217b..e0fc12c 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -2,7 +2,7 @@
* Driver for HighSpeed USB Client Controller in MSM7K
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
* Author: Mike Lockwood <lockwood@android.com>
* Brian Swetland <swetland@google.com>
*
@@ -1109,7 +1109,6 @@
struct msm_endpoint *ept = ui->ept + bit;
struct msm_request *req;
unsigned long flags;
- int req_dequeue = 1;
unsigned info;
/*
@@ -1129,23 +1128,12 @@
break;
}
-dequeue:
/* clean speculative fetches on req->item->info */
dma_coherent_post_ops();
info = req->item->info;
/* if the transaction is still in-flight, stop here */
- if (info & INFO_ACTIVE) {
- if (req_dequeue) {
- req_dequeue = 0;
- ui->dTD_update_fail_count++;
- ept->dTD_update_fail_count++;
- udelay(10);
- goto dequeue;
- } else {
- break;
- }
- }
- req_dequeue = 0;
+ if (info & INFO_ACTIVE)
+ break;
del_timer(&ept->prime_timer);
/* advance ept queue to the next request */
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
new file mode 100644
index 0000000..73b4e75
--- /dev/null
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -0,0 +1,328 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/usb/gadget.h>
+
+#include <mach/bam_dmux.h>
+#include <mach/usb_gadget_xport.h>
+#include <mach/usb_bam.h>
+
+#define BAM2BAM_DATA_N_PORTS 1
+
+static struct workqueue_struct *bam_data_wq;
+static int n_bam2bam_data_ports;
+
+#define SPS_PARAMS_SPS_MODE BIT(5)
+#define SPS_PARAMS_TBE BIT(6)
+#define MSM_VENDOR_ID BIT(16)
+
+struct data_port {
+ struct usb_function func;
+ struct usb_ep *in;
+ struct usb_ep *out;
+};
+
+struct bam_data_ch_info {
+ unsigned long flags;
+ unsigned id;
+
+ struct bam_data_port *port;
+ struct work_struct write_tobam_w;
+
+ struct usb_request *rx_req;
+ struct usb_request *tx_req;
+
+ u8 src_pipe_idx;
+ u8 dst_pipe_idx;
+ u8 connection_idx;
+};
+
+struct bam_data_port {
+ unsigned port_num;
+ struct data_port *port_usb;
+ struct bam_data_ch_info data_ch;
+
+ struct work_struct connect_w;
+ struct work_struct disconnect_w;
+};
+
+struct bam_data_port *bam2bam_data_ports[BAM2BAM_DATA_N_PORTS];
+
+/*------------data_path----------------------------*/
+
+static void bam_data_endless_rx_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ int status = req->status;
+
+ pr_info("status: %d\n", status);
+}
+
+static void bam_data_endless_tx_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ int status = req->status;
+
+ pr_info("status: %d\n", status);
+}
+
+static void bam_data_start_endless_rx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
+ if (status)
+ pr_err("error enqueuing transfer, %d\n", status);
+}
+
+static void bam_data_start_endless_tx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
+ if (status)
+ pr_err("error enqueuing transfer, %d\n", status);
+}
+
+static void bam2bam_data_disconnect_work(struct work_struct *w)
+{
+ struct bam_data_port *port =
+ container_of(w, struct bam_data_port, disconnect_w);
+
+ pr_info("Enter");
+
+ /* disable endpoints */
+ if (!port->port_usb || !port->port_usb->out || !port->port_usb->in) {
+ pr_err("port_usb->out/in == NULL. Exit");
+ return;
+ }
+ usb_ep_disable(port->port_usb->out);
+ usb_ep_disable(port->port_usb->in);
+
+ port->port_usb->in->driver_data = NULL;
+ port->port_usb->out->driver_data = NULL;
+
+ port->port_usb = 0;
+
+ pr_info("Exit");
+}
+
+static void bam2bam_data_connect_work(struct work_struct *w)
+{
+ struct bam_data_port *port = container_of(w, struct bam_data_port,
+ connect_w);
+ struct bam_data_ch_info *d = &port->data_ch;
+ u32 sps_params;
+ int ret;
+
+ pr_info("Enter");
+
+ ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
+ &d->dst_pipe_idx);
+ d->src_pipe_idx = 11;
+ d->dst_pipe_idx = 10;
+
+ if (ret) {
+ pr_err("usb_bam_connect failed: err:%d\n", ret);
+ return;
+ }
+
+ if (!port->port_usb) {
+ pr_err("port_usb is NULL");
+ return;
+ }
+
+ if (!port->port_usb->out) {
+ pr_err("port_usb->out (bulk out ep) is NULL");
+ return;
+ }
+
+ d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
+ if (!d->rx_req)
+ return;
+
+ d->rx_req->context = port;
+ d->rx_req->complete = bam_data_endless_rx_complete;
+ d->rx_req->length = 0;
+ sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx |
+ MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+ d->rx_req->udc_priv = sps_params;
+ d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL);
+ if (!d->tx_req)
+ return;
+
+ d->tx_req->context = port;
+ d->tx_req->complete = bam_data_endless_tx_complete;
+ d->tx_req->length = 0;
+ sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
+ MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
+ d->tx_req->udc_priv = sps_params;
+
+ /* queue in & out requests */
+ bam_data_start_endless_rx(port);
+ bam_data_start_endless_tx(port);
+
+ pr_info("Done\n");
+}
+
+static void bam2bam_data_port_free(int portno)
+{
+ kfree(bam2bam_data_ports[portno]);
+ bam2bam_data_ports[portno] = NULL;
+}
+
+static int bam2bam_data_port_alloc(int portno)
+{
+ struct bam_data_port *port = NULL;
+ struct bam_data_ch_info *d = NULL;
+
+ port = kzalloc(sizeof(struct bam_data_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->port_num = portno;
+
+ INIT_WORK(&port->connect_w, bam2bam_data_connect_work);
+ INIT_WORK(&port->disconnect_w, bam2bam_data_disconnect_work);
+
+ /* data ch */
+ d = &port->data_ch;
+ d->port = port;
+ bam2bam_data_ports[portno] = port;
+
+ pr_info("port:%p portno:%d\n", port, portno);
+
+ return 0;
+}
+
+void bam_data_disconnect(struct data_port *gr, u8 port_num)
+{
+ struct bam_data_port *port;
+ struct bam_data_ch_info *d;
+
+ pr_info("dev:%p port#%d\n", gr, port_num);
+
+ if (port_num >= n_bam2bam_data_ports) {
+ pr_err("invalid bam2bam portno#%d\n", port_num);
+ return;
+ }
+
+ if (!gr) {
+ pr_err("mbim data port is null\n");
+ return;
+ }
+
+ port = bam2bam_data_ports[port_num];
+
+ d = &port->data_ch;
+ port->port_usb = gr;
+
+ queue_work(bam_data_wq, &port->disconnect_w);
+}
+
+int bam_data_connect(struct data_port *gr, u8 port_num,
+ u8 connection_idx)
+{
+ struct bam_data_port *port;
+ struct bam_data_ch_info *d;
+ int ret;
+
+ pr_info("dev:%p port#%d\n", gr, port_num);
+
+ if (port_num >= n_bam2bam_data_ports) {
+ pr_err("invalid portno#%d\n", port_num);
+ return -ENODEV;
+ }
+
+ if (!gr) {
+ pr_err("mbim data port is null\n");
+ return -ENODEV;
+ }
+
+ port = bam2bam_data_ports[port_num];
+
+ d = &port->data_ch;
+
+ ret = usb_ep_enable(gr->in);
+ if (ret) {
+ pr_err("usb_ep_enable failed eptype:IN ep:%p", gr->in);
+ return ret;
+ }
+ gr->in->driver_data = port;
+
+ ret = usb_ep_enable(gr->out);
+ if (ret) {
+ pr_err("usb_ep_enable failed eptype:OUT ep:%p", gr->out);
+ gr->in->driver_data = 0;
+ return ret;
+ }
+ gr->out->driver_data = port;
+
+ port->port_usb = gr;
+
+ d->connection_idx = connection_idx;
+
+ queue_work(bam_data_wq, &port->connect_w);
+
+ return 0;
+}
+
+int bam_data_setup(unsigned int no_bam2bam_port)
+{
+ int i;
+ int ret;
+
+ pr_info("requested %d BAM2BAM ports", no_bam2bam_port);
+
+ if (!no_bam2bam_port || no_bam2bam_port > BAM2BAM_DATA_N_PORTS) {
+ pr_err("Invalid num of ports count:%d\n", no_bam2bam_port);
+ return -EINVAL;
+ }
+
+ bam_data_wq = alloc_workqueue("k_bam_data",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!bam_data_wq) {
+ pr_err("Failed to create workqueue\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < no_bam2bam_port; i++) {
+ n_bam2bam_data_ports++;
+ ret = bam2bam_data_port_alloc(i);
+ if (ret) {
+ n_bam2bam_data_ports--;
+ pr_err("Failed to alloc port:%d\n", i);
+ goto free_bam_ports;
+ }
+ }
+
+ return 0;
+
+free_bam_ports:
+ for (i = 0; i < n_bam2bam_data_ports; i++)
+ bam2bam_data_port_free(i);
+ destroy_workqueue(bam_data_wq);
+
+ return ret;
+}
+
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 534aa7b..89d2887 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -34,8 +34,8 @@
#define GHSIC_DATA_RMNET_RX_Q_SIZE 50
#define GHSIC_DATA_RMNET_TX_Q_SIZE 300
-#define GHSIC_DATA_SERIAL_RX_Q_SIZE 2
-#define GHSIC_DATA_SERIAL_TX_Q_SIZE 2
+#define GHSIC_DATA_SERIAL_RX_Q_SIZE 10
+#define GHSIC_DATA_SERIAL_TX_Q_SIZE 20
#define GHSIC_DATA_RX_REQ_SIZE 2048
#define GHSIC_DATA_TX_INTR_THRESHOLD 20
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index cce819f..bf8e5f4 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -266,6 +266,7 @@
if (retval)
goto fail;
+ usb_mark_last_busy(dev->udev);
return 0;
fail:
usb_unanchor_urb(rx_urb);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index bf3c6d5..7aa0430 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -49,8 +49,7 @@
#define MSM_USB_BASE (motg->regs)
#define DRIVER_NAME "msm_otg"
-#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(2000))
-#define ID_TIMER_INITIAL_FREQ (jiffies + msecs_to_jiffies(1000))
+#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
@@ -93,6 +92,7 @@
static struct regulator *hsusb_1p8;
static struct regulator *hsusb_vddcx;
static struct regulator *vbus_otg;
+static struct regulator *mhl_analog_switch;
static bool aca_id_turned_on;
static inline bool aca_enabled(void)
@@ -109,7 +109,7 @@
int ret = 0;
if (init) {
- hsusb_vddcx = regulator_get(motg->otg.dev, "HSUSB_VDDCX");
+ hsusb_vddcx = devm_regulator_get(motg->otg.dev, "HSUSB_VDDCX");
if (IS_ERR(hsusb_vddcx)) {
dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
return PTR_ERR(hsusb_vddcx);
@@ -121,7 +121,6 @@
if (ret) {
dev_err(motg->otg.dev, "unable to set the voltage "
"for hsusb vddcx\n");
- regulator_put(hsusb_vddcx);
return ret;
}
@@ -129,7 +128,6 @@
if (ret) {
regulator_set_voltage(hsusb_vddcx, 0,
USB_PHY_VDD_DIG_VOL_MIN);
- regulator_put(hsusb_vddcx);
dev_err(motg->otg.dev, "unable to enable the hsusb vddcx\n");
return ret;
}
@@ -149,8 +147,6 @@
"for hsusb vddcx\n");
return ret;
}
-
- regulator_put(hsusb_vddcx);
}
return ret;
@@ -161,7 +157,7 @@
int rc = 0;
if (init) {
- hsusb_3p3 = regulator_get(motg->otg.dev, "HSUSB_3p3");
+ hsusb_3p3 = devm_regulator_get(motg->otg.dev, "HSUSB_3p3");
if (IS_ERR(hsusb_3p3)) {
dev_err(motg->otg.dev, "unable to get hsusb 3p3\n");
return PTR_ERR(hsusb_3p3);
@@ -172,9 +168,9 @@
if (rc) {
dev_err(motg->otg.dev, "unable to set voltage level for"
"hsusb 3p3\n");
- goto put_3p3;
+ return rc;
}
- hsusb_1p8 = regulator_get(motg->otg.dev, "HSUSB_1p8");
+ hsusb_1p8 = devm_regulator_get(motg->otg.dev, "HSUSB_1p8");
if (IS_ERR(hsusb_1p8)) {
dev_err(motg->otg.dev, "unable to get hsusb 1p8\n");
rc = PTR_ERR(hsusb_1p8);
@@ -193,11 +189,8 @@
put_1p8:
regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
- regulator_put(hsusb_1p8);
put_3p3_lpm:
regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
-put_3p3:
- regulator_put(hsusb_3p3);
return rc;
}
@@ -314,30 +307,22 @@
static void msm_hsusb_mhl_switch_enable(struct msm_otg *motg, bool on)
{
- static struct regulator *mhl_analog_switch;
struct msm_otg_platform_data *pdata = motg->pdata;
if (!pdata->mhl_enable)
return;
- if (on) {
- mhl_analog_switch = regulator_get(motg->otg.dev,
- "mhl_ext_3p3v");
- if (IS_ERR(mhl_analog_switch)) {
- pr_err("Unable to get mhl_analog_switch\n");
- return;
- }
-
- if (regulator_enable(mhl_analog_switch)) {
- pr_err("unable to enable mhl_analog_switch\n");
- goto put_analog_switch;
- }
+ if (!mhl_analog_switch) {
+ pr_err("%s: mhl_analog_switch is NULL.\n", __func__);
return;
}
- regulator_disable(mhl_analog_switch);
-put_analog_switch:
- regulator_put(mhl_analog_switch);
+ if (on) {
+ if (regulator_enable(mhl_analog_switch))
+ pr_err("unable to enable mhl_analog_switch\n");
+ } else {
+ regulator_disable(mhl_analog_switch);
+ }
}
static int ulpi_read(struct otg_transceiver *otg, u32 reg)
@@ -781,6 +766,7 @@
int cnt = 0;
bool host_bus_suspend, dcp;
u32 phy_ctrl_val = 0, cmd_val;
+ unsigned ret;
u32 portsc;
if (atomic_read(&motg->in_lpm))
@@ -882,7 +868,10 @@
clk_disable_unprepare(motg->core_clk);
/* usb phy no more require TCXO clock, hence vote for TCXO disable */
- clk_disable_unprepare(motg->xo_handle);
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ dev_err(otg->dev, "%s failed to devote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
!host_bus_suspend && !dcp) {
@@ -927,7 +916,7 @@
wake_lock(&motg->wlock);
/* Vote for TCXO when waking up the phy */
- ret = clk_prepare_enable(motg->xo_handle);
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
if (ret)
dev_err(otg->dev, "%s failed to vote for "
"TCXO D0 buffer%d\n", __func__, ret);
@@ -1253,7 +1242,7 @@
}
if (!motg->pdata->vbus_power && host) {
- vbus_otg = regulator_get(motg->otg.dev, "vbus_otg");
+ vbus_otg = devm_regulator_get(motg->otg.dev, "vbus_otg");
if (IS_ERR(vbus_otg)) {
pr_err("Unable to get vbus_otg\n");
return -ENODEV;
@@ -1273,9 +1262,6 @@
otg->host = NULL;
}
- if (vbus_otg)
- regulator_put(vbus_otg);
-
return 0;
}
@@ -2305,7 +2291,7 @@
msm_otg_start_host(otg, 1);
msm_chg_enable_aca_det(motg);
msm_chg_disable_aca_intr(motg);
- mod_timer(&motg->id_timer, ID_TIMER_INITIAL_FREQ);
+ mod_timer(&motg->id_timer, ID_TIMER_FREQ);
if (msm_chg_check_aca_intr(motg))
work = 1;
}
@@ -3270,7 +3256,7 @@
goto free_regs;
}
- motg->xo_handle = clk_get(&pdev->dev, "xo");
+ motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
if (IS_ERR(motg->xo_handle)) {
dev_err(&pdev->dev, "%s not able to get the handle "
"to vote for TCXO D0 buffer\n", __func__);
@@ -3278,7 +3264,7 @@
goto free_regs;
}
- ret = clk_prepare_enable(motg->xo_handle);
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
if (ret) {
dev_err(&pdev->dev, "%s failed to vote for TCXO "
"D0 buffer%d\n", __func__, ret);
@@ -3305,6 +3291,15 @@
goto free_init_vddcx;
}
+ if (pdata->mhl_enable) {
+ mhl_analog_switch = devm_regulator_get(motg->otg.dev,
+ "mhl_ext_3p3v");
+ if (IS_ERR(mhl_analog_switch)) {
+ dev_err(&pdev->dev, "Unable to get mhl_analog_switch\n");
+ goto free_ldo_init;
+ }
+ }
+
ret = msm_hsusb_ldo_enable(motg, 1);
if (ret) {
dev_err(&pdev->dev, "hsusb vreg enable failed\n");
@@ -3421,9 +3416,9 @@
msm_hsusb_init_vddcx(motg, 0);
devote_xo_handle:
clk_disable_unprepare(motg->pclk);
- clk_disable_unprepare(motg->xo_handle);
+ msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
free_xo_handle:
- clk_put(motg->xo_handle);
+ msm_xo_put(motg->xo_handle);
free_regs:
iounmap(motg->regs);
put_pclk:
@@ -3489,7 +3484,7 @@
clk_disable_unprepare(motg->pclk);
clk_disable_unprepare(motg->core_clk);
- clk_put(motg->xo_handle);
+ msm_xo_put(motg->xo_handle);
msm_hsusb_ldo_enable(motg, 0);
msm_hsusb_ldo_init(motg, 0);
msm_hsusb_init_vddcx(motg, 0);
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 606d349..b3b4d53 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -35,11 +35,16 @@
bool "Support for triple frame buffer"
default n
+config FB_MSM_MDP_HW
+ bool
+ default n
+
choice
prompt "MDP HW version"
default FB_MSM_MDP22
config FB_MSM_MDP22
+ select FB_MSM_MDP_HW
bool "MDP HW ver2.2"
---help---
Support for MSM MDP HW revision 2.2
@@ -54,6 +59,7 @@
config FB_MSM_MDP303
depends on FB_MSM_MDP30
+ select FB_MSM_MDP_HW
bool "MDP HW ver3.03"
default n
---help---
@@ -64,6 +70,7 @@
config FB_MSM_MDP31
select FB_MSM_LCDC_HW
+ select FB_MSM_MDP_HW
bool "MDP HW ver3.1"
---help---
Support for MSM MDP HW revision 3.1
@@ -71,10 +78,17 @@
config FB_MSM_MDP40
select FB_MSM_LCDC_HW
+ select FB_MSM_MDP_HW
bool "MDP HW ver4.0"
---help---
Support for MSM MDP HW revision 4.0
Say Y here if this is msm7x30 variant platform.
+
+config FB_MSM_MDP_NONE
+ bool "MDP HW None"
+ ---help---
+ Say Y here if this is mdm platform.
+
endchoice
config FB_MSM_EBI2
@@ -885,4 +899,17 @@
endchoice
+config FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL
+ bool "EBI2 Epson QVGA Panel"
+ select FB_MSM_EBI2
+ default n
+ ---help---
+ Support for EBI2 Epson QVGA (240x320) panel
+
+config FB_MSM_EBI2_PANEL_DETECT
+ bool "EBI2 Panel Detect"
+ select FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL
+ default n
+ ---help---
+ Support for EBI2 panel auto detect
endif
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index e6c869f..5a72ad4 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -3,6 +3,8 @@
obj-$(CONFIG_FB_MSM_LOGO) += logo.o
obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
+ifeq ($(CONFIG_FB_MSM_MDP_HW),y)
+
# MDP
obj-y += mdp.o
@@ -177,6 +179,12 @@
obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
obj-$(CONFIG_MSM_VIDC_720P) += vidc/
+else
+obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o
+obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
+obj-y += msm_fb_panel.o
+obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o
+endif
clean:
rm *.o .*cmd
diff --git a/drivers/video/msm/adv7520.c b/drivers/video/msm/adv7520.c
index 7386983..df501dd 100644
--- a/drivers/video/msm/adv7520.c
+++ b/drivers/video/msm/adv7520.c
@@ -874,11 +874,11 @@
} else
DEV_ERR("adv7520_probe: failed to add fb device\n");
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- external_common_state->sdev.name = "hdmi_as_primary";
-#else
- external_common_state->sdev.name = "hdmi";
-#endif
+ if (hdmi_prim_display)
+ external_common_state->sdev.name = "hdmi_as_primary";
+ else
+ external_common_state->sdev.name = "hdmi";
+
if (switch_dev_register(&external_common_state->sdev) < 0)
DEV_ERR("Hdmi switch registration failed\n");
diff --git a/drivers/video/msm/ebi2_epson_s1d_qvga.c b/drivers/video/msm/ebi2_epson_s1d_qvga.c
new file mode 100644
index 0000000..8821eab
--- /dev/null
+++ b/drivers/video/msm/ebi2_epson_s1d_qvga.c
@@ -0,0 +1,374 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 "msm_fb.h"
+
+#include <linux/memory.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#define CMD_NOP_C 0x00
+#define CMD_SOFT_RESET_C 0x99
+#define CMD_DISPLAY_ON_C 0xAF
+#define CMD_DISPLAY_OFF_C 0xAE
+#define CMD_SET_DISPLAY_C 0xCA
+#define CMD_SET_DISPLAY_TIMING_C 0xA1
+#define CMD_SET_DATA_C 0xBC
+#define CMD_SET_START_ADDRESS_C 0x15
+#define CMD_SET_END_ADDRESS_C 0x75
+#define CMD_RAM_WRITE_C 0x5C
+#define CMD_RAM_READ_C 0x5D
+#define CMD_SET_AREA_SCROLLING_C 0xAA
+#define CMD_SET_DISPLAY_START_LINE_C 0xAB
+#define CMD_PARTIAL_DISPLAY_IN_C 0xA8
+#define CMD_PARTIAL_DISPLAY_OUT_C 0xA9
+#define CMD_SET_DISPLAY_DATA_INTERFACE_C 0x31
+#define CMD_SET_DISPLAY_COLOR_MODE_C 0x8B
+#define CMD_SELECT_MTP_ROM_MODE_C 0x65
+#define CMD_MTP_ROM_MODE_IN_C 0x67
+#define CMD_MTP_ROM_MODE_OUT_C 0x68
+#define CMD_MTP_ROM_OPERATION_IN_C 0x69
+#define CMD_MTP_ROM_OPERATION_OUT_C 0x70
+#define CMD_GATE_LINE_SCAN_MODE_C 0x6F
+#define CMD_SET_AC_OPERATION_DRIVE_C 0x8C
+#define CMD_SET_ELECTRONIC_CONTROL_C 0x20
+#define CMD_SET_POSITIVE_CORRECTION_CHARS_C 0x22
+#define CMD_SET_NEGATIVE_CORRECTION_CHARS_C 0x25
+#define CMD_SET_POWER_CONTROL_C 0x21
+#define CMD_SET_PARTIAL_POWER_CONTROL_C 0x23
+#define CMD_SET_8_COLOR_CONTROL_C 0x24
+#define CMD_SLEEP_IN_C 0x95
+#define CMD_SLEEP_OUT_C 0x94
+#define CMD_VDD_OFF_C 0x97
+#define CMD_VDD_ON_C 0x96
+#define CMD_STOP_OSCILLATION_C 0x93
+#define CMD_START_OSCILLATION_C 0x92
+#define CMD_TEST_SOURCE_C 0xFD
+#define CMD_TEST_FUSE_C 0xFE
+#define CMD_TEST_C 0xFF
+#define CMD_STATUS_READ_C 0xE8
+#define CMD_REVISION_READ_C 0xE9
+
+#define PANEL_WIDTH 240
+#define PANEL_HEIGHT 320
+#define ACTIVE_WIN_WIDTH PANEL_WIDTH
+#define ACTIVE_WIN_HEIGHT PANEL_HEIGHT
+
+#define ACTIVE_WIN_H_START 0
+#define ACTIVE_WIN_V_START 0
+
+#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, (cmd << 1));
+#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, (data << 1));
+#define DISP_DATA_IN() inpw(DISP_DATA_PORT);
+
+static void *DISP_CMD_PORT;
+static void *DISP_DATA_PORT;
+static boolean disp_initialized;
+static boolean display_on;
+static struct msm_panel_common_pdata *ebi2_epson_pdata;
+
+static void epson_s1d_disp_init(struct platform_device *pdev);
+static int epson_s1d_disp_off(struct platform_device *pdev);
+static int epson_s1d_disp_on(struct platform_device *pdev);
+static void epson_s1d_disp_set_rect(int x, int y, int xres, int yres);
+
+static void epson_s1d_disp_set_rect(int x, int y, int xres, int yres)
+{
+ int right, bottom;
+
+ if (!disp_initialized)
+ return;
+
+ right = x + xres - 1;
+ bottom = y + yres - 1;
+
+ x += ACTIVE_WIN_H_START;
+ y += ACTIVE_WIN_V_START;
+ right += ACTIVE_WIN_H_START;
+ bottom += ACTIVE_WIN_V_START;
+
+ if ((PANEL_WIDTH > x) &&
+ (PANEL_HEIGHT > y) &&
+ (PANEL_WIDTH > right) &&
+ (PANEL_HEIGHT > bottom)) {
+ DISP_CMD_OUT(CMD_SET_START_ADDRESS_C);
+ DISP_DATA_OUT((uint8)x);
+ DISP_DATA_OUT((uint8)(y>>8));
+ DISP_DATA_OUT((uint8)y);
+
+ DISP_CMD_OUT(CMD_SET_END_ADDRESS_C);
+ DISP_DATA_OUT((uint8)right);
+ DISP_DATA_OUT((uint8)(bottom>>8));
+ DISP_DATA_OUT((uint8)bottom);
+ DISP_CMD_OUT(CMD_RAM_WRITE_C);
+ }
+}
+
+static void epson_s1d_disp_init(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ if (disp_initialized)
+ return;
+
+ mfd = platform_get_drvdata(pdev);
+
+ DISP_CMD_PORT = mfd->cmd_port;
+ DISP_DATA_PORT = mfd->data_port;
+
+ disp_initialized = TRUE;
+}
+
+static int epson_s1d_disp_off(struct platform_device *pdev)
+{
+ if (!disp_initialized)
+ epson_s1d_disp_init(pdev);
+
+ if (display_on) {
+ DISP_CMD_OUT(CMD_SOFT_RESET_C);
+ DISP_CMD_OUT(CMD_VDD_OFF_C);
+ display_on = FALSE;
+ }
+
+ return 0;
+}
+
+static int epson_s1d_disp_on(struct platform_device *pdev)
+{
+ int i;
+ if (!disp_initialized)
+ epson_s1d_disp_init(pdev);
+
+ if (!display_on) {
+ /* Enable Vdd regulator */
+ DISP_CMD_OUT(CMD_VDD_ON_C);
+ msleep(20);
+
+ /* Soft Reset before configuring display */
+ DISP_CMD_OUT(CMD_SOFT_RESET_C);
+ msleep(20);
+
+ /* Set display attributes */
+
+ /* GATESCAN */
+ DISP_CMD_OUT(CMD_GATE_LINE_SCAN_MODE_C);
+ DISP_DATA_OUT(0x0);
+
+ /* DISSET */
+ DISP_CMD_OUT(CMD_SET_DISPLAY_C);
+ DISP_DATA_OUT(0x31);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT((uint8)((PANEL_HEIGHT - 1)>>8));
+ DISP_DATA_OUT((uint8)(PANEL_HEIGHT - 1));
+ DISP_DATA_OUT(0x03);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x08);
+
+ /* VOLSET */
+ DISP_CMD_OUT(
+ CMD_SET_ELECTRONIC_CONTROL_C);
+ DISP_DATA_OUT(0x10);
+ DISP_DATA_OUT(0x80);
+ DISP_DATA_OUT(0x11);
+ DISP_DATA_OUT(0x1B);
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x0D);
+ DISP_DATA_OUT(0x00);
+
+ /* PWRCTL */
+ DISP_CMD_OUT(CMD_SET_POWER_CONTROL_C);
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x24);
+ DISP_DATA_OUT(0x0F);
+ DISP_DATA_OUT(0xFE);
+ DISP_DATA_OUT(0x33);
+ DISP_DATA_OUT(0x31);
+ DISP_DATA_OUT(0xFF);
+ DISP_DATA_OUT(0x03);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x77);
+ DISP_DATA_OUT(0x33);
+ DISP_DATA_OUT(0x11);
+ DISP_DATA_OUT(0x44);
+ DISP_DATA_OUT(0x00);
+
+ /* PPWRCTL */
+ DISP_CMD_OUT(CMD_SET_PARTIAL_POWER_CONTROL_C);
+ DISP_DATA_OUT(0x33);
+ DISP_DATA_OUT(0xFF);
+ DISP_DATA_OUT(0x03);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x44);
+ DISP_DATA_OUT(0x00);
+
+ /* SPLOUT */
+ DISP_CMD_OUT(CMD_SLEEP_OUT_C);
+ msleep(100);
+
+ /* DATSET */
+ DISP_CMD_OUT(CMD_SET_DATA_C);
+ DISP_DATA_OUT(0x00);
+
+ /* DISTMEMSET */
+ DISP_CMD_OUT(CMD_SET_DISPLAY_TIMING_C);
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x2E);
+ DISP_DATA_OUT(0x0A);
+ DISP_DATA_OUT(0x2C);
+ DISP_DATA_OUT(0x23);
+ DISP_DATA_OUT(0x2F);
+ DISP_DATA_OUT(0x00);
+
+ /* GAMSETP */
+ DISP_CMD_OUT(CMD_SET_POSITIVE_CORRECTION_CHARS_C);
+ DISP_DATA_OUT(0x37);
+ DISP_DATA_OUT(0xFF);
+ DISP_DATA_OUT(0x7F);
+ DISP_DATA_OUT(0x15);
+ DISP_DATA_OUT(0x37);
+ DISP_DATA_OUT(0x05);
+
+ /* GAMSETN */
+ DISP_CMD_OUT(CMD_SET_NEGATIVE_CORRECTION_CHARS_C);
+ DISP_DATA_OUT(0x37);
+ DISP_DATA_OUT(0xFF);
+ DISP_DATA_OUT(0x7F);
+ DISP_DATA_OUT(0x15);
+ DISP_DATA_OUT(0x37);
+ DISP_DATA_OUT(0x05);
+
+ /* ACDRIVE */
+ DISP_CMD_OUT(CMD_SET_AC_OPERATION_DRIVE_C);
+ DISP_DATA_OUT(0x00);
+
+ /* TEST */
+ DISP_CMD_OUT(CMD_TEST_C);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x01);
+
+ /* COLMOD */
+ DISP_CMD_OUT(CMD_SET_DISPLAY_COLOR_MODE_C);
+ DISP_DATA_OUT(0x00);
+
+ /* STADDSET */
+ DISP_CMD_OUT(CMD_SET_START_ADDRESS_C);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x00);
+
+ /* EDADDSET */
+ DISP_CMD_OUT(CMD_SET_END_ADDRESS_C);
+ DISP_DATA_OUT(0xEF);
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x3F);
+
+ /* Set Display Start Line */
+ DISP_CMD_OUT(CMD_SET_DISPLAY_START_LINE_C);
+ DISP_DATA_OUT(0x00);
+
+ /* Set Display Data Interface */
+ DISP_CMD_OUT(CMD_SET_DISPLAY_DATA_INTERFACE_C);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x04);
+
+ epson_s1d_disp_set_rect(0,
+ 0,
+ ACTIVE_WIN_WIDTH,
+ ACTIVE_WIN_HEIGHT);
+
+ for (i = 0; i < (ACTIVE_WIN_WIDTH * ACTIVE_WIN_HEIGHT); i++)
+ outpdw(DISP_DATA_PORT, 0);
+
+ /* DISON */
+ DISP_CMD_OUT(CMD_DISPLAY_ON_C);
+ msleep(60);
+
+ display_on = TRUE;
+ }
+
+ return 0;
+}
+
+static int epson_s1d_probe(struct platform_device *pdev)
+{
+ if (pdev->id == 0) {
+ ebi2_epson_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+
+ msm_fb_add_device(pdev);
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = epson_s1d_probe,
+ .driver = {
+ .name = "ebi2_epson_s1d_qvga",
+ },
+};
+
+static struct msm_fb_panel_data epson_s1d_panel_data = {
+ .on = epson_s1d_disp_on,
+ .off = epson_s1d_disp_off,
+ .set_rect = epson_s1d_disp_set_rect,
+};
+
+static struct platform_device this_device = {
+ .name = "ebi2_epson_s1d_qvga",
+ .id = 1,
+ .dev = {
+ .platform_data = &epson_s1d_panel_data,
+ }
+};
+
+static int __init epson_s1d_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ pinfo = &epson_s1d_panel_data.panel_info;
+ pinfo->xres = PANEL_WIDTH;
+ pinfo->yres = PANEL_HEIGHT;
+ MSM_FB_SINGLE_MODE_PANEL(pinfo);
+ pinfo->type = EBI2_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0x048423E8;
+ pinfo->bpp = 18;
+ pinfo->fb_num = 2;
+ pinfo->lcd.vsync_enable = FALSE;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(epson_s1d_init);
diff --git a/drivers/video/msm/ebi2_host.c b/drivers/video/msm/ebi2_host.c
new file mode 100644
index 0000000..8ba5506
--- /dev/null
+++ b/drivers/video/msm/ebi2_host.c
@@ -0,0 +1,307 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/clk.h>
+#include <mach/hardware.h>
+#include "msm_fb.h"
+
+struct mdp_ccs mdp_ccs_rgb2yuv;
+struct mdp_ccs mdp_ccs_yuv2rgb;
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+static int ebi2_host_resource_initialized;
+static struct msm_panel_common_pdata *ebi2_host_pdata;
+
+static int ebi2_host_probe(struct platform_device *pdev);
+static int ebi2_host_remove(struct platform_device *pdev);
+
+static int ebi2_host_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: suspending...\n");
+ return 0;
+}
+
+static int ebi2_host_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: resuming...\n");
+ return 0;
+}
+
+static const struct dev_pm_ops ebi2_host_dev_pm_ops = {
+ .runtime_suspend = ebi2_host_runtime_suspend,
+ .runtime_resume = ebi2_host_runtime_resume,
+};
+
+
+static struct platform_driver ebi2_host_driver = {
+ .probe = ebi2_host_probe,
+ .remove = ebi2_host_remove,
+ .shutdown = NULL,
+ .driver = {
+ /*
+ * Simulate mdp hw
+ */
+ .name = "mdp",
+ .pm = &ebi2_host_dev_pm_ops,
+ },
+};
+
+void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
+ boolean isr)
+{
+ return;
+}
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req)
+{
+ return 0;
+}
+int mdp_start_histogram(struct fb_info *info)
+{
+ return 0;
+}
+int mdp_stop_histogram(struct fb_info *info)
+{
+ return 0;
+}
+void mdp_refresh_screen(unsigned long data)
+{
+ return;
+}
+
+static int ebi2_host_off(struct platform_device *pdev)
+{
+ int ret;
+ ret = panel_next_off(pdev);
+ return ret;
+}
+
+static int ebi2_host_on(struct platform_device *pdev)
+{
+ int ret;
+ ret = panel_next_on(pdev);
+ return ret;
+}
+
+
+static int ebi2_host_probe(struct platform_device *pdev)
+{
+ struct platform_device *msm_fb_dev = NULL;
+ struct msm_fb_data_type *mfd;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+
+ if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+
+ ebi2_host_pdata = pdev->dev.platform_data;
+
+ ebi2_host_resource_initialized = 1;
+ return 0;
+ }
+
+ ebi2_host_resource_initialized = 1;
+ if (!ebi2_host_resource_initialized)
+ return -EPERM;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ msm_fb_dev = platform_device_alloc("msm_fb", pdev->id);
+ if (!msm_fb_dev)
+ return -ENOMEM;
+
+ /* link to the latest pdev */
+ mfd->pdev = msm_fb_dev;
+
+ if (ebi2_host_pdata) {
+ mfd->mdp_rev = ebi2_host_pdata->mdp_rev;
+ mfd->mem_hid = ebi2_host_pdata->mem_hid;
+ }
+
+ /* add panel data */
+ if (platform_device_add_data
+ (msm_fb_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ pr_err("ebi2_host_probe: platform_device_add_data failed!\n");
+ rc = -ENOMEM;
+ goto ebi2_host_probe_err;
+ }
+ /* data chain */
+ pdata = msm_fb_dev->dev.platform_data;
+ pdata->on = ebi2_host_on;
+ pdata->off = ebi2_host_off;
+ pdata->next = pdev;
+
+ /* set driver data */
+ platform_set_drvdata(msm_fb_dev, mfd);
+
+ rc = platform_device_add(msm_fb_dev);
+ if (rc)
+ goto ebi2_host_probe_err;
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ pdev_list[pdev_list_cnt++] = pdev;
+ return 0;
+
+ebi2_host_probe_err:
+ platform_device_put(msm_fb_dev);
+ return rc;
+}
+
+void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
+ boolean sync)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct fb_info *fbi = mfd->fbi;
+ struct msm_panel_info *panel_info = &mfd->panel_info;
+ MDPIBUF *iBuf;
+ int bpp = info->var.bits_per_pixel / 8;
+ int yres, remainder;
+
+ if (panel_info->mode2_yres != 0) {
+ yres = panel_info->mode2_yres;
+ remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
+ } else {
+ yres = panel_info->yres;
+ remainder = (fbi->fix.line_length*yres)%PAGE_SIZE;
+ }
+
+ if (!remainder)
+ remainder = PAGE_SIZE;
+
+ down(&mfd->sem);
+
+ iBuf = &mfd->ibuf;
+ /* use virtual address */
+ iBuf->buf = (uint8 *) fbi->screen_base;
+
+ if (fbi->var.yoffset < yres) {
+ iBuf->buf += fbi->var.xoffset * bpp;
+ } else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) {
+ iBuf->buf += fbi->var.xoffset * bpp + yres *
+ fbi->fix.line_length + PAGE_SIZE - remainder;
+ } else {
+ iBuf->buf += fbi->var.xoffset * bpp + 2 * yres *
+ fbi->fix.line_length + 2 * (PAGE_SIZE - remainder);
+ }
+
+ iBuf->ibuf_width = info->var.xres_virtual;
+ iBuf->bpp = bpp;
+
+ iBuf->vsync_enable = sync;
+
+ if (dirty) {
+ /*
+ * ToDo: dirty region check inside var.xoffset+xres
+ * <-> var.yoffset+yres
+ */
+ iBuf->dma_x = dirty->xoffset % info->var.xres;
+ iBuf->dma_y = dirty->yoffset % info->var.yres;
+ iBuf->dma_w = dirty->width;
+ iBuf->dma_h = dirty->height;
+ } else {
+ iBuf->dma_x = 0;
+ iBuf->dma_y = 0;
+ iBuf->dma_w = info->var.xres;
+ iBuf->dma_h = info->var.yres;
+ }
+ mfd->ibuf_flushed = FALSE;
+ up(&mfd->sem);
+}
+
+void mdp_dma_pan_update(struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ MDPIBUF *iBuf;
+ int i, j;
+ uint32 data;
+ uint8 *src;
+ struct msm_fb_panel_data *pdata =
+ (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ struct fb_info *fbi = mfd->fbi;
+
+ iBuf = &mfd->ibuf;
+
+ invalidate_caches((unsigned long)fbi->screen_base,
+ (unsigned long)info->fix.smem_len,
+ (unsigned long)info->fix.smem_start);
+
+ pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
+ iBuf->dma_h);
+ for (i = 0; i < iBuf->dma_h; i++) {
+ src = iBuf->buf + (fbi->fix.line_length * (iBuf->dma_y + i))
+ + (iBuf->dma_x * iBuf->bpp);
+ for (j = 0; j < iBuf->dma_w; j++) {
+ data = (uint32)(*src++ >> 2) << 12;
+ data |= (uint32)(*src++ >> 2) << 6;
+ data |= (uint32)(*src++ >> 2);
+ data = ((data&0x1FF)<<16) | ((data&0x3FE00)>>9);
+ outpdw(mfd->data_port, data);
+ }
+ }
+}
+
+static int ebi2_host_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int ebi2_host_register_driver(void)
+{
+ return platform_driver_register(&ebi2_host_driver);
+}
+
+static int __init ebi2_host_driver_init(void)
+{
+ int ret;
+
+ ret = ebi2_host_register_driver();
+ if (ret) {
+ pr_err("ebi2_host_register_driver() failed!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+module_init(ebi2_host_driver_init);
diff --git a/drivers/video/msm/ebi2_lcd.c b/drivers/video/msm/ebi2_lcd.c
index 68590af..966f974 100644
--- a/drivers/video/msm/ebi2_lcd.c
+++ b/drivers/video/msm/ebi2_lcd.c
@@ -56,8 +56,6 @@
.probe = ebi2_lcd_probe,
.remove = ebi2_lcd_remove,
.suspend = NULL,
- .suspend_late = NULL,
- .resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
@@ -71,17 +69,42 @@
static void *ebi2_lcd_cfg1;
static void __iomem *lcd01_base;
static void __iomem *lcd02_base;
+static int lcd01_base_phys;
static int ebi2_lcd_resource_initialized;
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
+static struct lcdc_platform_data *ebi2_pdata;
+
+static int ebi2_lcd_on(struct platform_device *pdev)
+{
+ int ret;
+
+ if (ebi2_pdata && ebi2_pdata->lcdc_power_save)
+ ebi2_pdata->lcdc_power_save(1);
+
+ ret = panel_next_on(pdev);
+ return ret;
+}
+
+static int ebi2_lcd_off(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = panel_next_off(pdev);
+
+ if (ebi2_pdata && ebi2_pdata->lcdc_power_save)
+ ebi2_pdata->lcdc_power_save(0);
+
+ return ret;
+}
static int ebi2_lcd_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
- int rc, i;
+ int rc, i, hw_version;
if (pdev->id == 0) {
for (i = 0; i < pdev->num_resources; i++) {
@@ -98,6 +121,7 @@
ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
} else if (!strncmp(pdev->resource[i].name,
"lcd01", 5)) {
+ lcd01_base_phys = pdev->resource[i].start;
lcd01_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
@@ -118,7 +142,9 @@
}
}
}
+ ebi2_pdata = pdev->dev.platform_data;
ebi2_lcd_resource_initialized = 1;
+
return 0;
}
@@ -158,15 +184,19 @@
/* data chain */
pdata = mdp_dev->dev.platform_data;
- pdata->on = panel_next_on;
- pdata->off = panel_next_off;
+ pdata->on = ebi2_lcd_on;
+ pdata->off = ebi2_lcd_off;
pdata->next = pdev;
/* get/set panel specific fb info */
mfd->panel_info = pdata->panel_info;
+ hw_version = inp32((int)ebi2_base + 8);
+
if (mfd->panel_info.bpp == 24)
mfd->fb_imgType = MDP_RGB_888;
+ else if (mfd->panel_info.bpp == 18)
+ mfd->fb_imgType = MDP_RGB_888;
else
mfd->fb_imgType = MDP_RGB_565;
@@ -181,10 +211,12 @@
* configure both.
*/
outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
- if (mfd->panel_info.bpp == 18)
- outp32(ebi2_lcd_cfg1, 0x01000000);
- else
- outp32(ebi2_lcd_cfg1, 0x0);
+ if (hw_version < 0x2020) {
+ if (mfd->panel_info.bpp == 18)
+ outp32(ebi2_lcd_cfg1, 0x01000000);
+ else
+ outp32(ebi2_lcd_cfg1, 0x0);
+ }
} else {
#ifdef DEBUG_EBI2_LCD
/*
@@ -201,10 +233,18 @@
*/
if (mfd->panel_info.pdest == DISPLAY_1) {
mfd->cmd_port = lcd01_base;
- mfd->data_port =
- (void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
- mfd->data_port_phys =
- (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
+ if (hw_version >= 0x2020) {
+ mfd->data_port =
+ (void *)((uint32) mfd->cmd_port + 0x80);
+ mfd->data_port_phys =
+ (void *)(lcd01_base_phys + 0x80);
+ } else {
+ mfd->data_port =
+ (void *)((uint32) mfd->cmd_port +
+ EBI2_PRIM_LCD_RS_PIN);
+ mfd->data_port_phys =
+ (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
+ }
} else {
mfd->cmd_port = lcd01_base;
mfd->data_port =
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index d6f59aa..29d500a 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -18,6 +18,9 @@
/* #define DEBUG */
#define DEV_DBG_PREFIX "EXT_COMMON: "
+/* The start of the data block collection within the CEA Extension Version 3 */
+#define DBC_START_OFFSET 4
+
#include "msm_fb.h"
#include "hdmi_msm.h"
#include "external_common.h"
@@ -317,6 +320,109 @@
return ret;
}
+static ssize_t hdmi_common_rda_edid_physical_address(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ external_common_state->physical_address);
+
+ DEV_DBG("%s: '%d'\n", __func__,
+ external_common_state->physical_address);
+ return ret;
+}
+
+
+static ssize_t hdmi_common_rda_edid_scan_info(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n",
+ external_common_state->pt_scan_info,
+ external_common_state->it_scan_info,
+ external_common_state->ce_scan_info);
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+ return ret;
+}
+
+static ssize_t hdmi_common_wta_vendor_name(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint8 *s = (uint8 *) buf;
+ uint8 *d = external_common_state->spd_vendor_name;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ ret = (ret > 8) ? 8 : ret;
+
+ memset(external_common_state->spd_vendor_name, 0, 8);
+ while (*s) {
+ if (*s & 0x60 && *s ^ 0x7f) {
+ *d = *s;
+ } else {
+ /* stop copying if control character found */
+ break;
+ }
+
+ if (++s > (uint8 *) (buf + ret))
+ break;
+
+ d++;
+ }
+
+ DEV_DBG("%s: '%s'\n", __func__,
+ external_common_state->spd_vendor_name);
+
+ return ret;
+}
+
+static ssize_t hdmi_common_rda_vendor_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = snprintf(buf, PAGE_SIZE, "%s\n",
+ external_common_state->spd_vendor_name);
+ DEV_DBG("%s: '%s'\n", __func__,
+ external_common_state->spd_vendor_name);
+
+ return ret;
+}
+
+static ssize_t hdmi_common_wta_product_description(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint8 *s = (uint8 *) buf;
+ uint8 *d = external_common_state->spd_product_description;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ ret = (ret > 16) ? 16 : ret;
+
+ memset(external_common_state->spd_product_description, 0, 16);
+ while (*s) {
+ if (*s & 0x60 && *s ^ 0x7f) {
+ *d = *s;
+ } else {
+ /* stop copying if control character found */
+ break;
+ }
+
+ if (++s > (uint8 *) (buf + ret))
+ break;
+
+ d++;
+ }
+
+ DEV_DBG("%s: '%s'\n", __func__,
+ external_common_state->spd_product_description);
+
+ return ret;
+}
+
+static ssize_t hdmi_common_rda_product_description(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = snprintf(buf, PAGE_SIZE, "%s\n",
+ external_common_state->spd_product_description);
+ DEV_DBG("%s: '%s'\n", __func__,
+ external_common_state->spd_product_description);
+
+ return ret;
+}
+
static ssize_t hdmi_common_rda_hdcp(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -400,6 +506,14 @@
mutex_lock(&hdmi_msm_state_mutex);
hdmi_msm_state->cec_enabled = true;
hdmi_msm_state->cec_logical_addr = 4;
+
+ /* flush CEC queue */
+ hdmi_msm_state->cec_queue_wr = hdmi_msm_state->cec_queue_start;
+ hdmi_msm_state->cec_queue_rd = hdmi_msm_state->cec_queue_start;
+ hdmi_msm_state->cec_queue_full = false;
+ memset(hdmi_msm_state->cec_queue_rd, 0,
+ sizeof(struct hdmi_msm_cec_msg)*CEC_QUEUE_SIZE);
+
mutex_unlock(&hdmi_msm_state_mutex);
hdmi_msm_cec_init();
hdmi_msm_cec_write_logical_addr(
@@ -492,7 +606,7 @@
if (hdmi_msm_state->fsm_reset_done)
retry++;
mutex_unlock(&hdmi_msm_state_mutex);
- msleep(360);
+ msleep(20);
} else
break;
}
@@ -673,6 +787,15 @@
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUGO, hdmi_common_rda_hpd,
hdmi_common_wta_hpd);
static DEVICE_ATTR(hdcp, S_IRUGO, hdmi_common_rda_hdcp, NULL);
+static DEVICE_ATTR(pa, S_IRUGO,
+ hdmi_common_rda_edid_physical_address, NULL);
+static DEVICE_ATTR(scan_info, S_IRUGO,
+ hdmi_common_rda_edid_scan_info, NULL);
+static DEVICE_ATTR(vendor_name, S_IRUGO | S_IWUSR, hdmi_common_rda_vendor_name,
+ hdmi_common_wta_vendor_name);
+static DEVICE_ATTR(product_description, S_IRUGO | S_IWUSR,
+ hdmi_common_rda_product_description,
+ hdmi_common_wta_product_description);
static DEVICE_ATTR(3d_present, S_IRUGO, hdmi_common_rda_3d_present, NULL);
static DEVICE_ATTR(hdcp_present, S_IRUGO, hdmi_common_rda_hdcp_present, NULL);
#endif
@@ -691,6 +814,10 @@
&dev_attr_edid_modes.attr,
&dev_attr_hdcp.attr,
&dev_attr_hpd.attr,
+ &dev_attr_pa.attr,
+ &dev_attr_scan_info.attr,
+ &dev_attr_vendor_name.attr,
+ &dev_attr_product_description.attr,
&dev_attr_3d_present.attr,
&dev_attr_hdcp_present.attr,
#endif
@@ -918,11 +1045,12 @@
31500, 60000, 108108, 60000, TRUE},
};
-static const uint8 *hdmi_edid_find_block(const uint8 *in_buf, uint8 type,
- uint8 *len)
+static const uint8 *hdmi_edid_find_block(const uint8 *in_buf,
+ uint32 start_offset, uint8 type, uint8 *len)
{
/* the start of data block collection, start of Video Data Block */
- uint32 offset = 4;
+ uint32 offset = start_offset;
+ uint32 end_dbc_offset = in_buf[2];
*len = 0;
@@ -930,11 +1058,11 @@
present.
edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block collection
present and no DTD data present.*/
- if ((in_buf[2] == 0) || (in_buf[2] == 4)) {
+ if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) {
DEV_WARN("EDID: no DTD or non-DTD data present\n");
return NULL;
}
- while (offset < 0x80) {
+ while (offset < end_dbc_offset) {
uint8 block_len = in_buf[offset] & 0x1F;
if ((in_buf[offset] >> 5) == type) {
*len = block_len;
@@ -962,20 +1090,24 @@
static uint32 hdmi_edid_extract_ieee_reg_id(const uint8 *in_buf)
{
uint8 len;
- const uint8 *vsd = hdmi_edid_find_block(in_buf, 3, &len);
+ const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3,
+ &len);
if (vsd == NULL)
return 0;
DEV_DBG("EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n",
- ((uint32)vsd[6] << 8) + (uint32)vsd[5], (uint32)vsd[7] * 5);
+ ((uint32)vsd[4] << 8) + (uint32)vsd[5], (uint32)vsd[7] * 5);
+ external_common_state->physical_address =
+ ((uint16)vsd[4] << 8) + (uint16)vsd[5];
return ((uint32)vsd[3] << 16) + ((uint32)vsd[2] << 8) + (uint32)vsd[1];
}
static void hdmi_edid_extract_3d_present(const uint8 *in_buf)
{
uint8 len, offset;
- const uint8 *vsd = hdmi_edid_find_block(in_buf, 3, &len);
+ const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3,
+ &len);
external_common_state->present_3d = 0;
if (vsd == NULL || len < 9) {
@@ -995,7 +1127,8 @@
static void hdmi_edid_extract_latency_fields(const uint8 *in_buf)
{
uint8 len;
- const uint8 *vsd = hdmi_edid_find_block(in_buf, 3, &len);
+ const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3,
+ &len);
if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
external_common_state->video_latency = (uint16)-1;
@@ -1013,7 +1146,8 @@
static void hdmi_edid_extract_speaker_allocation_data(const uint8 *in_buf)
{
uint8 len;
- const uint8 *sad = hdmi_edid_find_block(in_buf, 4, &len);
+ const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4,
+ &len);
if (sad == NULL)
return;
@@ -1033,7 +1167,8 @@
static void hdmi_edid_extract_audio_data_blocks(const uint8 *in_buf)
{
uint8 len;
- const uint8 *sad = hdmi_edid_find_block(in_buf, 1, &len);
+ const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1,
+ &len);
uint32 *adb = external_common_state->audio_data_blocks;
if (sad == NULL)
@@ -1052,6 +1187,63 @@
}
}
+static void hdmi_edid_extract_extended_data_blocks(const uint8 *in_buf)
+{
+ uint8 len = 0;
+ uint8 const *prev_etag = in_buf;
+ uint32 start_offset = DBC_START_OFFSET;
+
+ /* A Tage code of 7 identifies extended data blocks */
+ uint8 const *etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+
+ while (etag != NULL) {
+ /* The extended data block should at least be 2 bytes long */
+ if (len < 2) {
+ DEV_DBG("EDID: Found an extended data block of length"
+ "less than 2 bytes. Ignoring ...\n");
+ } else {
+ /*
+ * The second byte of the extended data block has the
+ * extended tag code
+ */
+ switch (etag[1]) {
+ case 0:
+ /* Video Capability Data Block */
+ DEV_DBG("EDID: VCDB=%02X %02X\n", etag[1],
+ etag[2]);
+
+ /*
+ * Check if the sink specifies underscan
+ * support for:
+ * BIT 5: preferred video format
+ * BIT 3: IT video format
+ * BIT 1: CE video format
+ */
+ external_common_state->pt_scan_info = (etag[2] &
+ (BIT(4) | BIT(5))) >> 4;
+ external_common_state->it_scan_info = (etag[2] &
+ (BIT(3) | BIT(2))) >> 2;
+ external_common_state->ce_scan_info = etag[2] &
+ (BIT(1) | BIT(0));
+ DEV_DBG("EDID: Scan Information (pt|it|ce): "
+ "(%d|%d|%d)",
+ external_common_state->pt_scan_info,
+ external_common_state->it_scan_info,
+ external_common_state->ce_scan_info);
+ break;
+ default:
+ DEV_DBG("EDID: Extend Tag Code %d not"
+ "supported\n", etag[1]);
+ break;
+ }
+ }
+
+ /* There could be more that one extended data block */
+ start_offset = etag - prev_etag + len + 1;
+ prev_etag = etag;
+ etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+ }
+}
static void hdmi_edid_detail_desc(const uint8 *data_buf, uint32 *disp_mode)
{
@@ -1196,7 +1388,8 @@
const uint8 *edid_blk0 = &data_buf[0x0];
const uint8 *edid_blk1 = &data_buf[0x80];
const uint8 *svd = num_og_cea_blocks ?
- hdmi_edid_find_block(data_buf+0x80, 2, &len) : NULL;
+ hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+ 2, &len) : NULL;
disp_mode_list->num_of_elements = 0;
if (svd != NULL) {
@@ -1208,6 +1401,11 @@
video_format = (*svd & 0x7F) - 1;
add_supported_video_format(disp_mode_list,
video_format);
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ external_common_state->preferred_video_format =
+ video_format;
+ }
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = TRUE;
}
@@ -1230,6 +1428,11 @@
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = TRUE;
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ external_common_state->preferred_video_format =
+ video_format;
+ }
desc_offset += 0x12;
++i;
}
@@ -1250,6 +1453,11 @@
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = TRUE;
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ external_common_state->preferred_video_format =
+ video_format;
+ }
desc_offset += 0x12;
++i;
}
@@ -1273,6 +1481,11 @@
video_format);
if (video_format == HDMI_VFRMT_640x480p60_4_3)
has480p = TRUE;
+ /* Make a note of the preferred video format */
+ if (i == 0) {
+ external_common_state->preferred_video_format =
+ video_format;
+ }
desc_offset += 0x12;
++i;
}
@@ -1351,6 +1564,7 @@
/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
uint8 edid_buf[0x80 * 4];
+ external_common_state->preferred_video_format = 0;
external_common_state->present_3d = 0;
memset(&external_common_state->disp_mode_list, 0,
sizeof(external_common_state->disp_mode_list));
@@ -1402,6 +1616,7 @@
edid_buf+0x80);
hdmi_edid_extract_audio_data_blocks(edid_buf+0x80);
hdmi_edid_extract_3d_present(edid_buf+0x80);
+ hdmi_edid_extract_extended_data_blocks(edid_buf+0x80);
}
break;
case 2:
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index c9ab88e..0f44da5 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -216,6 +216,13 @@
uint8 speaker_allocation_block;
uint16 video_latency, audio_latency;
uint8 audio_data_block_cnt;
+ uint16 physical_address;
+ uint32 preferred_video_format;
+ uint8 pt_scan_info;
+ uint8 it_scan_info;
+ uint8 ce_scan_info;
+ uint8 spd_vendor_name[8];
+ uint8 spd_product_description[16];
boolean present_3d;
boolean present_hdcp;
uint32 audio_data_blocks[16];
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 7c5a653..354add7 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -132,12 +132,6 @@
| HDMI_MSM_CEC_REFTIMER_REFTIMER(27 * 50)
);
- /* 0x02A4 CEC_TIME */
- HDMI_OUTP(0x02A4,
- HDMI_MSM_CEC_TIME_SIGNAL_FREE_TIME(350)
- | HDMI_MSM_CEC_TIME_ENABLE
- );
-
/*
* 0x02A0 CEC_ADDR
* Starting with a default address of 4
@@ -227,8 +221,13 @@
/* 0x0294 HDMI_MSM_CEC_RETRANSMIT */
HDMI_OUTP(0x0294,
+#ifdef DRVR_ONLY_CECT_NO_DAEMON
HDMI_MSM_CEC_RETRANSMIT_NUM(msg->retransmit)
| (msg->retransmit > 0) ? HDMI_MSM_CEC_RETRANSMIT_ENABLE : 0);
+#else
+ HDMI_MSM_CEC_RETRANSMIT_NUM(0) |
+ HDMI_MSM_CEC_RETRANSMIT_ENABLE);
+#endif
/* 0x028C CEC_CTRL */
HDMI_OUTP(0x028C, 0x1 | msg->frame_size << 4);
@@ -2218,6 +2217,9 @@
{
int hdcp_link_status = HDMI_INP(0x011C);
+ /* Disable HDCP interrupts */
+ HDMI_OUTP(0x0118, 0x0);
+
external_common_state->hdcp_active = FALSE;
/* 0x0130 HDCP_RESET
[0] LINK0_DEAUTHENTICATE */
@@ -2231,9 +2233,6 @@
if (hdcp_link_status & 0x00000004)
hdcp_auth_info((hdcp_link_status & 0x000000F0) >> 4);
-
- /* Disable HDCP interrupts */
- HDMI_OUTP(0x0118, 0x0);
}
static void check_and_clear_HDCP_DDC_Failure(void)
@@ -2472,6 +2471,7 @@
__func__, __LINE__,
(HDMI_INP_ND(0x011C) & BIT(8)) >> 8,
(HDMI_INP_ND(0x011C) & BIT(9)) >> 9);
+ mutex_unlock(&hdcp_auth_state_mutex);
goto error;
}
@@ -3674,6 +3674,7 @@
uint32 regVal;
int i;
int mode = 0;
+ boolean use_ce_scan_info = TRUE;
switch (external_common_state->video_resolution) {
case HDMI_VFRMT_720x480p60_4_3:
@@ -3739,6 +3740,48 @@
/* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */
aviInfoFrame[3] = hdmi_msm_avi_iframe_lut[0][mode];
+
+ /*
+ * If the sink specified support for both underscan/overscan
+ * then, by default, set the underscan bit.
+ * Only checking underscan support for preferred format and cea formats
+ */
+ if ((external_common_state->video_resolution ==
+ external_common_state->preferred_video_format)) {
+ use_ce_scan_info = FALSE;
+ switch (external_common_state->pt_scan_info) {
+ case 0:
+ /*
+ * Need to use the info specified for the corresponding
+ * IT or CE format
+ */
+ DEV_DBG("%s: No underscan information specified for the"
+ " preferred video format\n", __func__);
+ use_ce_scan_info = TRUE;
+ break;
+ case 3:
+ DEV_DBG("%s: Setting underscan bit for the preferred"
+ " video format\n", __func__);
+ aviInfoFrame[3] |= 0x02;
+ break;
+ default:
+ DEV_DBG("%s: Underscan information not set for the"
+ " preferred video format\n", __func__);
+ break;
+ }
+ }
+
+ if (use_ce_scan_info) {
+ if (3 == external_common_state->ce_scan_info) {
+ DEV_DBG("%s: Setting underscan bit for the CE video"
+ " format\n", __func__);
+ aviInfoFrame[3] |= 0x02;
+ } else {
+ DEV_DBG("%s: Not setting underscan bit for the CE video"
+ " format\n", __func__);
+ }
+ }
+
/* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */
aviInfoFrame[4] = hdmi_msm_avi_iframe_lut[1][mode];
/* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */
@@ -3894,6 +3937,137 @@
}
#endif
+#define IFRAME_CHECKSUM_32(d) \
+ ((d & 0xff) + ((d >> 8) & 0xff) + \
+ ((d >> 16) & 0xff) + ((d >> 24) & 0xff))
+
+static void hdmi_msm_spd_infoframe_packetsetup(void)
+{
+ uint32 packet_header = 0;
+ uint32 check_sum = 0;
+ uint32 packet_payload = 0;
+ uint32 packet_control = 0;
+
+ uint8 *vendor_name = external_common_state->spd_vendor_name;
+ uint8 *product_description =
+ external_common_state->spd_product_description;
+
+ /* 0x00A4 GENERIC1_HDR
+ * HB0 7:0 NUM
+ * HB1 15:8 NUM
+ * HB2 23:16 NUM */
+ /* Setup Packet header and payload */
+ /* 0x83 InfoFrame Type Code
+ 0x01 InfoFrame Version Number
+ 0x19 Length of Source Product Description InfoFrame
+ */
+ packet_header = 0x83 | (0x01 << 8) | (0x19 << 16);
+ HDMI_OUTP(0x00A4, packet_header);
+ check_sum += IFRAME_CHECKSUM_32(packet_header);
+
+ /* Vendor Name (7bit ASCII code) */
+ /* 0x00A8 GENERIC1_0
+ * BYTE0 7:0 CheckSum
+ * BYTE1 15:8 VENDOR_NAME[0]
+ * BYTE2 23:16 VENDOR_NAME[1]
+ * BYTE3 31:24 VENDOR_NAME[2] */
+ packet_payload = ((vendor_name[0] & 0x7f) << 8)
+ | ((vendor_name[1] & 0x7f) << 16)
+ | ((vendor_name[2] & 0x7f) << 24);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+ packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
+ HDMI_OUTP(0x00A8, packet_payload);
+
+ /* 0x00AC GENERIC1_1
+ * BYTE4 7:0 VENDOR_NAME[3]
+ * BYTE5 15:8 VENDOR_NAME[4]
+ * BYTE6 23:16 VENDOR_NAME[5]
+ * BYTE7 31:24 VENDOR_NAME[6] */
+ packet_payload = (vendor_name[3] & 0x7f)
+ | ((vendor_name[4] & 0x7f) << 8)
+ | ((vendor_name[5] & 0x7f) << 16)
+ | ((vendor_name[6] & 0x7f) << 24);
+ HDMI_OUTP(0x00AC, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* Product Description (7-bit ASCII code) */
+ /* 0x00B0 GENERIC1_2
+ * BYTE8 7:0 VENDOR_NAME[7]
+ * BYTE9 15:8 PRODUCT_NAME[ 0]
+ * BYTE10 23:16 PRODUCT_NAME[ 1]
+ * BYTE11 31:24 PRODUCT_NAME[ 2] */
+ packet_payload = (vendor_name[7] & 0x7f)
+ | ((product_description[0] & 0x7f) << 8)
+ | ((product_description[1] & 0x7f) << 16)
+ | ((product_description[2] & 0x7f) << 24);
+ HDMI_OUTP(0x00B0, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* 0x00B4 GENERIC1_3
+ * BYTE12 7:0 PRODUCT_NAME[ 3]
+ * BYTE13 15:8 PRODUCT_NAME[ 4]
+ * BYTE14 23:16 PRODUCT_NAME[ 5]
+ * BYTE15 31:24 PRODUCT_NAME[ 6] */
+ packet_payload = (product_description[3] & 0x7f)
+ | ((product_description[4] & 0x7f) << 8)
+ | ((product_description[5] & 0x7f) << 16)
+ | ((product_description[6] & 0x7f) << 24);
+ HDMI_OUTP(0x00B4, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* 0x00B8 GENERIC1_4
+ * BYTE16 7:0 PRODUCT_NAME[ 7]
+ * BYTE17 15:8 PRODUCT_NAME[ 8]
+ * BYTE18 23:16 PRODUCT_NAME[ 9]
+ * BYTE19 31:24 PRODUCT_NAME[10] */
+ packet_payload = (product_description[7] & 0x7f)
+ | ((product_description[8] & 0x7f) << 8)
+ | ((product_description[9] & 0x7f) << 16)
+ | ((product_description[10] & 0x7f) << 24);
+ HDMI_OUTP(0x00B8, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* 0x00BC GENERIC1_5
+ * BYTE20 7:0 PRODUCT_NAME[11]
+ * BYTE21 15:8 PRODUCT_NAME[12]
+ * BYTE22 23:16 PRODUCT_NAME[13]
+ * BYTE23 31:24 PRODUCT_NAME[14] */
+ packet_payload = (product_description[11] & 0x7f)
+ | ((product_description[12] & 0x7f) << 8)
+ | ((product_description[13] & 0x7f) << 16)
+ | ((product_description[14] & 0x7f) << 24);
+ HDMI_OUTP(0x00BC, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* 0x00C0 GENERIC1_6
+ * BYTE24 7:0 PRODUCT_NAME[15]
+ * BYTE25 15:8 Source Device Information
+ * BYTE26 23:16 NUM
+ * BYTE27 31:24 NUM */
+ /* Source Device Information
+ * 00h unknown
+ * 01h Digital STB
+ * 02h DVD
+ * 03h D-VHS
+ * 04h HDD Video
+ * 05h DVC
+ * 06h DSC
+ * 07h Video CD
+ * 08h Game
+ * 09h PC general */
+ packet_payload = (product_description[15] & 0x7f) | 0x00 << 8;
+ HDMI_OUTP(0x00C0, packet_payload);
+ check_sum += IFRAME_CHECKSUM_32(packet_payload);
+
+ /* GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
+ * Setup HDMI TX generic packet control
+ * Enable this packet to transmit every frame
+ * Enable HDMI TX engine to transmit Generic packet 1 */
+ packet_control = HDMI_INP_ND(0x0034);
+ packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4));
+ HDMI_OUTP(0x0034, packet_control);
+}
+
int hdmi_msm_clk(int on)
{
int rc;
@@ -3969,6 +4143,7 @@
#ifdef CONFIG_FB_MSM_HDMI_3D
hdmi_msm_vendor_infoframe_packetsetup();
#endif
+ hdmi_msm_spd_infoframe_packetsetup();
/* set timeout to 4.1ms (max) for hardware debounce */
hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
@@ -4413,11 +4588,10 @@
queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_read_work);
/* Initialize hdmi node and register with switch driver */
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- external_common_state->sdev.name = "hdmi_as_primary";
-#else
- external_common_state->sdev.name = "hdmi";
-#endif
+ if (hdmi_prim_display)
+ external_common_state->sdev.name = "hdmi_as_primary";
+ else
+ external_common_state->sdev.name = "hdmi";
if (switch_dev_register(&external_common_state->sdev) < 0)
DEV_ERR("Hdmi switch registration failed\n");
@@ -4545,6 +4719,10 @@
#ifdef CONFIG_FB_MSM_HDMI_3D
external_common_state->switch_3d = hdmi_msm_switch_3d;
#endif
+ memset(external_common_state->spd_vendor_name, 0,
+ sizeof(external_common_state->spd_vendor_name));
+ memset(external_common_state->spd_product_description, 0,
+ sizeof(external_common_state->spd_product_description));
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
hdmi_msm_state->cec_queue_start =
diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 9675fd5..5195f2c 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -98,7 +98,7 @@
#define CEC_QUEUE_SIZE 16
#define CEC_QUEUE_END (hdmi_msm_state->cec_queue_start + CEC_QUEUE_SIZE)
-#define RETRANSMIT_MAX_NUM 7
+#define RETRANSMIT_MAX_NUM 5
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */
int irq;
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index e93b238..d9785d8 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -181,6 +181,8 @@
lvds_intf = 0x0001078c;
lvds_phy_cfg0 = BIT(6);
}
+ } else {
+ BUG();
}
/* MDP_LVDSPHY_CFG0 */
diff --git a/drivers/video/msm/mddihosti.c b/drivers/video/msm/mddihosti.c
index 4989d35..1a5a3fd 100644
--- a/drivers/video/msm/mddihosti.c
+++ b/drivers/video/msm/mddihosti.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2010, 2012 Code Aurora Forum. 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
@@ -1874,42 +1874,6 @@
MDDI_MSG_ERR("mddi_client_power return %d", ret);
}
-#if 0
- switch (mddi_client_capability_pkt.Mfr_Name) {
- case 0x4474:
- if ((mddi_client_capability_pkt.Product_Code != 0x8960) &&
- (target == DISPLAY_1)) {
- ret = PRISM_WVGA;
- }
- break;
-
- case 0xD263:
- if (target == DISPLAY_1)
- ret = TOSHIBA_VGA_PRIM;
- else if (target == DISPLAY_2)
- ret = TOSHIBA_QCIF_SECD;
- break;
-
- case 0:
- if (mddi_client_capability_pkt.Product_Code == 0x8835) {
- if (target == DISPLAY_1)
- ret = SHARP_QVGA_PRIM;
- else if (target == DISPLAY_2)
- ret = SHARP_128x128_SECD;
- }
- break;
-
- default:
- break;
- }
-
- if ((!client_detection_try) && (ret != TOSHIBA_VGA_PRIM)
- && (ret != TOSHIBA_QCIF_SECD)) {
- /* Not a Toshiba display, so change drive_lo back to default value */
- mddi_host_reg_out(DRIVE_LO, 0x0032);
- }
-#endif
-
#endif
return mddi_client_id;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 6c05833..79464bf 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -988,9 +988,6 @@
/* DMA update timestamp */
mdp_dma2_last_update_time = ktime_get_real();
/* let's turn on DMA2 block */
-#if 0
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-#endif
#ifdef CONFIG_FB_MSM_MDP22
outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */
#else
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index a5165ab..be57ee0 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -794,4 +794,10 @@
}
#endif
+int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
+int mdp_ppp_v4l2_overlay_clear(void);
+int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
+ unsigned long srcp0_addr, unsigned long srcp0_size,
+ unsigned long srcp1_addr, unsigned long srcp1_size);
+
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 9d8c205..9c047e5 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -747,4 +747,12 @@
int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
+void mdp4_iommu_attach(void);
+int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
+ struct mdp4_overlay_pipe **ppipe);
+void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
+int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
+ unsigned long srcp0_addr, unsigned long srcp1_addr,
+ unsigned long srcp2_addr);
+
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 36cfd16..7f155c2 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <mach/hardware.h>
#include <mach/iommu_domains.h>
+#include <mach/iommu.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/fb.h>
@@ -1454,8 +1455,6 @@
pipe_cnt++;
mdp4_mixer_blend_setup(pipe);
- if (i == mixer && pipe->pipe_num <= OVERLAY_PIPE_RGB2)
- flush_bits |= (1 << (2 + pipe->pipe_num));
}
}
@@ -1691,15 +1690,23 @@
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
{
+ struct mdp4_overlay_pipe *bg_pipe;
uint32 bits = 0;
- if (pipe->mixer_num == MDP4_MIXER1)
- bits |= 0x02;
- else
- bits |= 0x01;
+ if (all) {
+ if (pipe->mixer_num == MDP4_MIXER1)
+ bits |= 0x02;
+ else
+ bits |= 0x01;
+ }
- if (all && pipe->pipe_num <= OVERLAY_PIPE_RGB2)
+ if (pipe->pipe_num <= OVERLAY_PIPE_RGB2)
bits |= 1 << (2 + pipe->pipe_num);
+ if (pipe->is_fg && pipe->alpha == 0xFF) {
+ bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
+ MDP4_MIXER_STAGE_BASE);
+ bits |= 1 << (2 + bg_pipe->pipe_num);
+ }
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */
@@ -2428,6 +2435,15 @@
if (ctrl->panel_mode & MDP4_PANEL_DTV &&
pipe->mixer_num == MDP4_MIXER1) {
u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
+
+ if (hdmi_prim_display) {
+ if (!mdp4_overlay_is_rgb_type(req->src.format) &&
+ pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
+ (req->src_rect.h > req->dst_rect.h ||
+ req->src_rect.w > req->dst_rect.w))
+ use_blt = 1;
+ }
+
mdp4_overlay_dtv_set(mfd, pipe);
mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
@@ -2506,9 +2522,13 @@
#endif
}
- if (mfd->mdp_rev >= MDP_REV_41 && !mfd->use_ov0_blt &&
+ if (mfd->mdp_rev >= MDP_REV_42 && !mfd->use_ov0_blt &&
(pipe->mixer_num == MDP4_MIXER0)) {
- ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
+ ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
+ } else if (mfd->mdp_rev == MDP_REV_41 &&
+ mdp4_overlay_is_rgb_type(pipe->src_format) &&
+ !mfd->use_ov0_blt && (pipe->mixer_num == MDP4_MIXER0)) {
+ ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
} else {
mdp4_mixer_stage_down(pipe);
@@ -2813,6 +2833,7 @@
/* primary interface */
ctrl->mixer0_played++;
if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+ mdp4_overlay_reg_flush(pipe, 0);
if (!mfd->use_ov0_blt)
mdp4_overlay_update_blt_mode(mfd);
mdp4_overlay_lcdc_start();
@@ -2820,6 +2841,7 @@
}
#ifdef CONFIG_FB_MSM_MIPI_DSI
else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+ mdp4_overlay_reg_flush(pipe, 0);
if (!mfd->use_ov0_blt)
mdp4_overlay_update_blt_mode(mfd);
mdp4_overlay_dsi_video_start();
@@ -2835,6 +2857,7 @@
}
#ifdef CONFIG_FB_MSM_MIPI_DSI
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+ mdp4_iommu_attach();
mdp4_dsi_cmd_dma_busy_wait(mfd);
mdp4_dsi_cmd_kickoff_video(mfd, pipe);
}
@@ -2868,3 +2891,171 @@
fput_light(srcp0_file, ps0_need);
return ret;
}
+
+static struct {
+ char *name;
+ int domain;
+} msm_iommu_ctx_names[] = {
+ /* Display */
+ {
+ .name = "mdp_vg1",
+ .domain = DISPLAY_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_vg2",
+ .domain = DISPLAY_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_rgb1",
+ .domain = DISPLAY_DOMAIN,
+ },
+ /* Display */
+ {
+ .name = "mdp_rgb2",
+ .domain = DISPLAY_DOMAIN,
+ },
+};
+
+void mdp4_iommu_attach(void)
+{
+ static int done;
+ struct iommu_domain *domain;
+ int i;
+
+ if (!done) {
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+ int domain_idx;
+ struct device *ctx = msm_iommu_get_ctx(
+ msm_iommu_ctx_names[i].name);
+
+ if (!ctx)
+ continue;
+
+ domain_idx = msm_iommu_ctx_names[i].domain;
+
+ domain = msm_get_iommu_domain(domain_idx);
+ if (!domain)
+ continue;
+
+ if (iommu_attach_device(domain, ctx)) {
+ WARN(1, "%s: could not attach domain %d to context %s."
+ " iommu programming will not occur.\n",
+ __func__, domain_idx,
+ msm_iommu_ctx_names[i].name);
+ continue;
+ }
+ }
+ done = 1;
+ }
+}
+
+int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
+ struct mdp4_overlay_pipe **ppipe)
+{
+ struct mdp4_overlay_pipe *pipe;
+ int err;
+ struct msm_fb_data_type *mfb = info->par;
+
+ req->z_order = 0;
+ req->id = MSMFB_NEW_REQUEST;
+ req->is_fg = false;
+ req->alpha = 0xff;
+ err = mdp4_overlay_req2pipe(req, MDP4_MIXER0, &pipe, mfb);
+ if (err < 0) {
+ pr_err("%s:Could not allocate MDP overlay pipe\n", __func__);
+ return err;
+ }
+
+ mdp4_mixer_blend_setup(pipe);
+ *ppipe = pipe;
+
+ return 0;
+}
+
+void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe)
+{
+ mdp4_mixer_stage_down(pipe);
+ mdp4_overlay_pipe_free(pipe);
+}
+
+int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
+ unsigned long srcp0_addr, unsigned long srcp1_addr,
+ unsigned long srcp2_addr)
+{
+ struct msm_fb_data_type *mfd = info->par;
+ int err;
+
+ if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
+ return -EINTR;
+
+ switch (pipe->src_format) {
+ case MDP_Y_CR_CB_H2V2:
+ /* YUV420 */
+ pipe->srcp0_addr = srcp0_addr;
+ pipe->srcp0_ystride = pipe->src_width;
+ /*
+ * For YUV420, the luma plane is 1 byte per pixel times
+ * num of pixels in the image Also, the planes are
+ * switched in MDP, srcp2 is actually first chroma plane
+ */
+ pipe->srcp2_addr = srcp1_addr ? srcp1_addr :
+ pipe->srcp0_addr + (pipe->src_width * pipe->src_height);
+ pipe->srcp2_ystride = pipe->src_width/2;
+ /*
+ * The chroma planes are half the size of the luma
+ * planes
+ */
+ pipe->srcp1_addr = srcp2_addr ? srcp2_addr :
+ pipe->srcp2_addr +
+ (pipe->src_width * pipe->src_height / 4);
+ pipe->srcp1_ystride = pipe->src_width/2;
+ break;
+ case MDP_Y_CRCB_H2V2:
+ /* NV12 */
+ pipe->srcp0_addr = srcp0_addr;
+ pipe->srcp0_ystride = pipe->src_width;
+ pipe->srcp1_addr = srcp1_addr ? srcp1_addr :
+ pipe->srcp0_addr +
+ (pipe->src_width * pipe->src_height);
+ pipe->srcp1_ystride = pipe->src_width;
+ break;
+ default:
+ pr_err("%s: format (%u) is not supported\n", __func__,
+ pipe->src_format);
+ err = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: pipe ndx=%d stage=%d format=%x\n", __func__,
+ pipe->pipe_ndx, pipe->mixer_stage, pipe->src_format);
+
+ if (pipe->pipe_type == OVERLAY_TYPE_VIDEO)
+ mdp4_overlay_vg_setup(pipe);
+ else
+ mdp4_overlay_rgb_setup(pipe);
+
+ mdp4_mixer_stage_up(pipe);
+
+ if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_overlay_lcdc_vsync_push(mfd, pipe);
+ } else {
+#ifdef CONFIG_FB_MSM_MIPI_DSI
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+ mdp4_dsi_cmd_dma_busy_wait(mfd);
+ mdp4_dsi_cmd_kickoff_video(mfd, pipe);
+ }
+#else
+ if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
+ mdp4_mddi_dma_busy_wait(mfd);
+ mdp4_mddi_kickoff_video(mfd, pipe);
+ }
+#endif
+ }
+done:
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return err;
+}
+
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index f8200a8..dd827aa 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -117,6 +117,8 @@
mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+
if (ret == 0)
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -184,6 +186,7 @@
}
mdp4_overlay_rgb_setup(pipe);
mdp4_mixer_stage_up(pipe);
+ mdp4_overlay_reg_flush(pipe, 0);
printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
(int)pipe, pipe->pipe_ndx);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 299763f..a5b4b3e 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -672,6 +672,7 @@
mdp4_overlay_update_dsi_cmd(mfd);
+ mdp4_iommu_attach();
mdp4_dsi_cmd_kickoff_ui(mfd, dsi_pipe);
mdp4_iommu_unmap(dsi_pipe);
/* signal if pan function is waiting for the update completion */
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index e729a55..f06f380 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -273,6 +273,7 @@
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp_histogram_ctrl(TRUE);
ret = panel_next_on(pdev);
@@ -495,6 +496,7 @@
{
if (!dsi_video_enabled) {
/* enable DSI block */
+ mdp4_iommu_attach();
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1);
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 2dd7436..b94d1a4 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -350,6 +350,7 @@
}
mdp4_mixer_stage_up(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
dtv_pipe = pipe; /* keep it */
}
@@ -484,6 +485,7 @@
void mdp4_overlay_dtv_start(void)
{
if (!dtv_enabled) {
+ mdp4_iommu_attach();
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* enable DTV block */
MDP_OUTP(MDP_BASE + DTV_BASE, 1);
@@ -560,7 +562,7 @@
*/
temp_src_format = inpdw(rgb_base + 0x0050);
MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
- mdp4_mixer_stage_up(dtv_pipe);
+ mdp4_overlay_reg_flush(dtv_pipe, 0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index d9716bd..ed4553d 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -242,6 +242,8 @@
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
+ mdp4_overlay_reg_flush(pipe, 1);
+
#ifdef CONFIG_MSM_BUS_SCALING
mdp_bus_scale_update_request(2);
#endif
@@ -396,6 +398,7 @@
{
if (!lcdc_enabled) {
/* enable LCDC block */
+ mdp4_iommu_attach();
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + LCDC_BASE, 1);
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 9b8f60f..1f5904b 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -592,7 +592,7 @@
};
static uint32 vg_qseed_table1[] = {
- 0x76543210, 0xfedcba98
+ 0x00000000, 0x20000000,
};
static uint32 vg_qseed_table2[] = {
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
index 199e472..4009ffc 100644
--- a/drivers/video/msm/mdp_ppp.c
+++ b/drivers/video/msm/mdp_ppp.c
@@ -1314,39 +1314,21 @@
}
-int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req)
+static int mdp_ppp_blit_addr(struct fb_info *info, struct mdp_blit_req *req,
+ unsigned long srcp0_start, unsigned long srcp0_len,
+ unsigned long srcp1_start, unsigned long srcp1_len,
+ unsigned long dst_start, unsigned long dst_len,
+ struct file *p_src_file, struct file *p_dst_file)
{
- unsigned long src_start, dst_start;
- unsigned long src_len = 0;
- unsigned long dst_len = 0;
MDPIBUF iBuf;
u32 dst_width, dst_height;
- struct file *p_src_file = 0 , *p_dst_file = 0;
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_data_type *mfd = info->par;
if (req->dst.format == MDP_FB_FORMAT)
req->dst.format = mfd->fb_imgType;
if (req->src.format == MDP_FB_FORMAT)
req->src.format = mfd->fb_imgType;
- if (req->flags & MDP_BLIT_SRC_GEM)
- get_gem_img(&req->src, &src_start, &src_len);
- else
- get_img(&req->src, info, &src_start, &src_len, &p_src_file);
- if (src_len == 0) {
- printk(KERN_ERR "mdp_ppp: could not retrieve image from "
- "memory\n");
- return -1;
- }
- if (req->flags & MDP_BLIT_DST_GEM)
- get_gem_img(&req->dst, &dst_start, &dst_len);
- else
- get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
- if (dst_len == 0) {
- put_img(p_src_file);
- printk(KERN_ERR "mdp_ppp: could not retrieve image from "
- "memory\n");
- return -1;
- }
+
if (mdp_ppp_verify_req(req)) {
printk(KERN_ERR "mdp_ppp: invalid image!\n");
put_img(p_src_file);
@@ -1375,17 +1357,17 @@
iBuf.mdpImg.width = req->src.width;
iBuf.mdpImg.imgType = req->src.format;
- iBuf.mdpImg.bmy_addr = (uint32 *) (src_start + req->src.offset);
+ iBuf.mdpImg.bmy_addr = (uint32 *) (srcp0_start + req->src.offset);
if (iBuf.mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO)
iBuf.mdpImg.cbcr_addr =
(uint32 *) ((uint32) iBuf.mdpImg.bmy_addr +
ALIGN((ALIGN(req->src.width, 32) *
ALIGN(req->src.height, 32)), 4096));
else
- iBuf.mdpImg.cbcr_addr =
+ iBuf.mdpImg.cbcr_addr = srcp1_start ? (uint32 *)srcp1_start :
(uint32 *) ((uint32) iBuf.mdpImg.bmy_addr +
- req->src.width * req->src.height);
+ req->src.width * req->src.height);
iBuf.mdpImg.mdpOp = MDPOP_NOP;
@@ -1417,7 +1399,7 @@
iBuf.mdpImg.mdpOp |= MDPOP_DITHER;
if (req->flags & MDP_BLEND_FG_PREMULT) {
-#ifdef CONFIG_FB_MSM_MDP31
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP303)
iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA;
#else
put_img(p_src_file);
@@ -1589,3 +1571,116 @@
put_img(p_dst_file);
return 0;
}
+
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req)
+{
+ unsigned long src_start, dst_start;
+ unsigned long src_len = 0;
+ unsigned long dst_len = 0;
+ struct file *p_src_file = 0 , *p_dst_file = 0;
+
+ if (req->flags & MDP_BLIT_SRC_GEM)
+ get_gem_img(&req->src, &src_start, &src_len);
+ else
+ get_img(&req->src, info, &src_start, &src_len, &p_src_file);
+ if (src_len == 0) {
+ printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+ "memory\n");
+ return -EINVAL;
+ }
+ if (req->flags & MDP_BLIT_DST_GEM)
+ get_gem_img(&req->dst, &dst_start, &dst_len);
+ else
+ get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
+ if (dst_len == 0) {
+ put_img(p_src_file);
+ printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+ "memory\n");
+ return -EINVAL;
+ }
+
+ return mdp_ppp_blit_addr(info, req, src_start, src_len, 0, 0, dst_start,
+ dst_len, p_src_file, p_dst_file);
+}
+
+static struct mdp_blit_req overlay_req;
+static bool mdp_overlay_req_set;
+
+int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req)
+{
+ memset(&overlay_req, 0, sizeof(struct mdp_blit_req));
+
+ overlay_req.src.width = req->src.width;
+ overlay_req.src.height = req->src.height;
+ overlay_req.src.format = req->src.format;
+
+
+ overlay_req.dst.width = req->dst_rect.w;
+ overlay_req.dst.height = req->dst_rect.h;
+ overlay_req.dst.format = MDP_FB_FORMAT;
+ overlay_req.transp_mask = req->transp_mask;
+ overlay_req.flags = req->flags;
+ overlay_req.alpha = req->alpha;
+
+ overlay_req.src_rect.x = req->src_rect.x;
+ overlay_req.src_rect.y = req->src_rect.y;
+ overlay_req.src_rect.w = req->src_rect.w;
+ overlay_req.src_rect.h = req->src_rect.h;
+ overlay_req.dst_rect.x = req->dst_rect.x;
+ overlay_req.dst_rect.y = req->dst_rect.y;
+ overlay_req.dst_rect.w = req->dst_rect.w;
+ overlay_req.dst_rect.h = req->dst_rect.h;
+ mdp_overlay_req_set = true;
+
+ pr_debug("%s: Overlay parameters:", __func__);
+ pr_debug("Src_Image (%u %u)\n", overlay_req.src.width,
+ overlay_req.src.height);
+
+ if (overlay_req.src.format == MDP_Y_CRCB_H2V2)
+ pr_debug("Overlay format MDP_Y_CRCB_H2V2\n");
+ else if (overlay_req.src.format == MDP_RGB_565)
+ pr_debug("Overlay format MDP_RGB_565\n");
+ else
+ pr_debug("Overlay format(%u) unknown\n",
+ overlay_req.src.format);
+
+ pr_debug("Dst_Image (%u %u)\n", overlay_req.dst.width,
+ overlay_req.dst.height);
+ pr_debug("Src rect: (%u,%u,%u,%u), Dst rect: (%u,%u,%u,%u)\n",
+ overlay_req.src_rect.x, overlay_req.src_rect.y,
+ overlay_req.src_rect.w, overlay_req.src_rect.h,
+ overlay_req.dst_rect.x, overlay_req.dst_rect.y,
+ overlay_req.dst_rect.w, overlay_req.dst_rect.h);
+ return 0;
+}
+
+int mdp_ppp_v4l2_overlay_clear(void)
+{
+ memset(&overlay_req, 0, sizeof(struct mdp_overlay));
+ mdp_overlay_req_set = false;
+ return 0;
+}
+
+int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
+ unsigned long srcp0_addr, unsigned long srcp0_size,
+ unsigned long srcp1_addr, unsigned long srcp1_size)
+{
+ int ret;
+
+ if (!mdp_overlay_req_set) {
+ pr_err("mdp_ppp:v4l2:No overlay set, ignore play req\n");
+ return -EINVAL;
+ }
+
+ overlay_req.dst.width = info->var.xres;
+ overlay_req.dst.height = info->var.yres;
+
+ ret = mdp_ppp_blit_addr(info, &overlay_req,
+ srcp0_addr, srcp0_size, srcp1_addr, srcp1_size,
+ info->fix.smem_start, info->fix.smem_len, NULL, NULL);
+
+ if (ret)
+ pr_err("%s:Blitting overlay failed(%d)\n", __func__, ret);
+
+ return ret;
+}
diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c
index e2a6564..fe237ee 100644
--- a/drivers/video/msm/mdp_ppp_v20.c
+++ b/drivers/video/msm/mdp_ppp_v20.c
@@ -2177,26 +2177,8 @@
*pppop_reg_ptr |=
(PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
- /* let's use SHIM logic to calculate the partial ROI scaling */
-#if 0
- phasex_step =
- (uint32) mdp_do_div(0x20000000 * iBuf->roi.width,
- dst_roi_width_scale);
- phasey_step =
- (uint32) mdp_do_div(0x20000000 * iBuf->roi.height,
- dst_roi_height_scale);
-
-/*
- phasex_step= ((long long) iBuf->roi.width * 0x20000000)/dst_roi_width_scale;
- phasey_step= ((long long)iBuf->roi.height * 0x20000000)/dst_roi_height_scale;
-*/
-
- phasex_init =
- (((long long)phasex_step - 0x20000000) >> 1);
- phasey_init =
- (((long long)phasey_step - 0x20000000) >> 1);
-
-#else
+ /* let's use SHIM logic to calculate the
+ partial ROI scaling */
mdp_calc_scale_params(iBuf->roi.x, iBuf->roi.width,
dst_roi_width_scale, 1,
&phasex_init, &phasex_step,
@@ -2205,7 +2187,6 @@
dst_roi_height_scale, 0,
&phasey_init, &phasey_step,
&dummy, &dummy);
-#endif
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c,
phasex_init);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140,
@@ -2448,37 +2429,102 @@
uint32 *tpVal,
uint32 perPixelAlpha, uint32 *pppop_reg_ptr)
{
- if (perPixelAlpha) {
- *pppop_reg_ptr |= PPP_OP_ROT_ON |
- PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
+ if (mdp_rev == MDP_REV_303) {
+ int bg_alpha;
+
+ *alpha = iBuf->mdpImg.alpha;
+ *tpVal = iBuf->mdpImg.tpVal;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) {
+ if (perPixelAlpha) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ } else {
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.alpha == 0xff)) {
+ iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
+ }
+
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+ }
+
+ bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
+ PPP_BLEND_BG_ALPHA_REVERSE;
+
+ if (perPixelAlpha) {
+ bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
+ } else {
+ bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
+ bg_alpha |= iBuf->mdpImg.alpha << 24;
+ }
+ outpdw(MDP_BASE + 0x70010, bg_alpha);
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
+ *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+ } else if (perPixelAlpha) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_SRCPIXEL_ALPHA;
+ } else {
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.alpha == 0xff)) {
+ iBuf->mdpImg.mdpOp &=
+ ~(MDPOP_ALPHAB);
+ }
+
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
+ *pppop_reg_ptr |=
+ PPP_BLEND_CALPHA_TRNASP;
+ }
} else {
- if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
- && (iBuf->mdpImg.alpha == 0xff)) {
- iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
- }
-
- if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
- && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
- *pppop_reg_ptr |=
- PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
- PPP_OP_BLEND_CONSTANT_ALPHA |
- PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
- PPP_BLEND_CALPHA_TRNASP;
-
- *alpha = iBuf->mdpImg.alpha;
- *tpVal = iBuf->mdpImg.tpVal;
+ if (perPixelAlpha) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
} else {
- if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) {
- *pppop_reg_ptr |= PPP_OP_ROT_ON |
- PPP_OP_BLEND_ON |
- PPP_OP_BLEND_SRCPIXEL_TRANSP;
- *tpVal = iBuf->mdpImg.tpVal;
- } else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) {
- *pppop_reg_ptr |= PPP_OP_ROT_ON |
- PPP_OP_BLEND_ON |
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.alpha == 0xff)) {
+ iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
+ }
+
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+ *pppop_reg_ptr |=
+ PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
- PPP_OP_BLEND_CONSTANT_ALPHA;
+ PPP_BLEND_CALPHA_TRNASP;
+
*alpha = iBuf->mdpImg.alpha;
+ *tpVal = iBuf->mdpImg.tpVal;
+ } else {
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_SRCPIXEL_TRANSP;
+ *tpVal = iBuf->mdpImg.tpVal;
+ } else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ *alpha = iBuf->mdpImg.alpha;
+ }
}
}
}
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 930b4e9..c6f531e 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -18,6 +18,7 @@
static struct msm_panel_common_pdata *mipi_nt35510_pdata;
static struct dsi_buf nt35510_tx_buf;
static struct dsi_buf nt35510_rx_buf;
+spinlock_t bl_spinlock;
#define NT35510_SLEEP_OFF_DELAY 150
#define NT35510_DISPLAY_ON_DELAY 150
@@ -506,6 +507,8 @@
if (pdev->id == 0) {
mipi_nt35510_pdata = pdev->dev.platform_data;
+ if (mipi_nt35510_pdata->bl_lock)
+ spin_lock_init(&bl_spinlock);
return 0;
}
@@ -523,8 +526,16 @@
static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
{
- /* Add backlight changes later*/
- return;
+ int bl_level;
+ unsigned long flags;
+ bl_level = mfd->bl_level;
+
+ if (mipi_nt35510_pdata->bl_lock) {
+ spin_lock_irqsave(&bl_spinlock, flags);
+ mipi_nt35510_pdata->pmic_backlight(bl_level);
+ spin_unlock_irqrestore(&bl_spinlock, flags);
+ } else
+ mipi_nt35510_pdata->pmic_backlight(bl_level);
}
static struct msm_fb_panel_data nt35510_panel_data = {
@@ -564,7 +575,6 @@
return -ENOMEM;
nt35510_panel_data.panel_info = *pinfo;
-
ret = platform_device_add_data(pdev, &nt35510_panel_data,
sizeof(nt35510_panel_data));
if (ret) {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index 2c4ee3e..f052e93 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 100;
+ pinfo.bl_max = 31;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 82e03b2..4e97d99 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
delayed from VSYNC active edge */
pinfo.lcdc.hsync_skew = 0;
pinfo.clk_rate = 499000000;
- pinfo.bl_max = 100; /*16; CHECK THIS!!!*/
+ pinfo.bl_max = 31;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index c826483..dbf45b0 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -39,7 +39,6 @@
#include "mdp.h"
#include "mdp4.h"
-int mipi_dsi_clk_on;
static struct completion dsi_dma_comp;
static struct completion dsi_mdp_comp;
static struct dsi_buf dsi_tx_buf;
@@ -147,11 +146,6 @@
void mipi_dsi_turn_on_clks(void)
{
- if (mipi_dsi_clk_on) {
- pr_err("%s: mipi_dsi_clks already ON\n", __func__);
- return;
- }
- mipi_dsi_clk_on = 1;
local_bh_disable();
mipi_dsi_ahb_ctrl(1);
mipi_dsi_clk_enable();
@@ -160,11 +154,6 @@
void mipi_dsi_turn_off_clks(void)
{
- if (mipi_dsi_clk_on == 0) {
- pr_err("%s: mipi_dsi_clks already OFF\n", __func__);
- return;
- }
- mipi_dsi_clk_on = 0;
local_bh_disable();
mipi_dsi_clk_disable();
mipi_dsi_ahb_ctrl(0);
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index ed0dee4..0070757 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -14,6 +14,7 @@
#ifdef CONFIG_SPI_QUP
#include <linux/spi/spi.h>
#endif
+#include <linux/leds.h>
#include "msm_fb.h"
#include "mipi_dsi.h"
#include "mipi_novatek.h"
@@ -26,6 +27,8 @@
static struct dsi_buf novatek_rx_buf;
static int mipi_novatek_lcd_init(void);
+static int wled_trigger_initialized;
+
#define MIPI_DSI_NOVATEK_SPI_DEVICE_NAME "dsi_novatek_3d_panel_spi"
#define HPCI_FPGA_READ_CMD 0x84
#define HPCI_FPGA_WRITE_CMD 0x04
@@ -427,12 +430,17 @@
return 0;
}
-
+DEFINE_LED_TRIGGER(bkl_led_trigger);
static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
{
struct mipi_panel_info *mipi;
+ if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
+ && (wled_trigger_initialized)) {
+ led_trigger_event(bkl_led_trigger, mfd->bl_level);
+ return;
+ }
mipi = &mfd->panel_info.mipi;
mutex_lock(&mfd->dma->ov_mutex);
@@ -639,6 +647,10 @@
pr_info("%s: SUCCESS (SPI)\n", __func__);
#endif
+ led_trigger_register_simple("bkl_trigger", &bkl_led_trigger);
+ pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__);
+ wled_trigger_initialized = 1;
+
mipi_dsi_buf_alloc(&novatek_tx_buf, DSI_BUF_SIZE);
mipi_dsi_buf_alloc(&novatek_rx_buf, DSI_BUF_SIZE);
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index 937a598..30e255e 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -59,7 +59,7 @@
/* add 0X BD command */
static char cmd26_2[6] = {
- 0xBD, 0x01, 0x60, 0x10, 0x38, 0x01 /* 55 HZ */
+ 0xBD, 0x01, 0x48, 0x10, 0x38, 0x01 /* 59 HZ */
};
static char cmd5[5] = {
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
index 82efbef..b3805c5 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -64,7 +64,7 @@
pinfo.lcd.vsync_enable = TRUE;
pinfo.lcd.hw_vsync_mode = TRUE;
- pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */
+ pinfo.lcd.refx100 = 6100; /* adjust refx100 to prevent tearing */
pinfo.mipi.mode = DSI_CMD_MODE;
pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888;
diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c
index f17ba0b..193b89c 100644
--- a/drivers/video/msm/msm_dss_io_7x27a.c
+++ b/drivers/video/msm/msm_dss_io_7x27a.c
@@ -30,6 +30,7 @@
static struct clk *ahb_m_clk;
static struct clk *ahb_s_clk;
static struct clk *ebi1_dsi_clk;
+int mipi_dsi_clk_on;
void mipi_dsi_clk_init(struct platform_device *pdev)
{
@@ -300,14 +301,25 @@
void mipi_dsi_ahb_ctrl(u32 enable)
{
+ static int ahb_ctrl_done;
if (enable) {
+ if (ahb_ctrl_done) {
+ pr_info("%s: ahb clks already ON\n", __func__);
+ return;
+ }
clk_enable(dsi_ref_clk);
clk_enable(ahb_m_clk);
clk_enable(ahb_s_clk);
+ ahb_ctrl_done = 1;
} else {
+ if (ahb_ctrl_done == 0) {
+ pr_info("%s: ahb clks already OFF\n", __func__);
+ return;
+ }
clk_disable(ahb_m_clk);
clk_disable(ahb_s_clk);
clk_disable(dsi_ref_clk);
+ ahb_ctrl_done = 0;
}
}
@@ -316,6 +328,10 @@
unsigned data = 0;
uint32 pll_ctrl;
+ if (mipi_dsi_clk_on) {
+ pr_info("%s: mipi_dsi_clks already ON\n", __func__);
+ return;
+ }
if (clk_set_rate(ebi1_dsi_clk, 65000000)) /* 65 MHz */
pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__);
clk_enable(ebi1_dsi_clk);
@@ -331,10 +347,15 @@
clk_enable(dsi_esc_clk);
mipi_dsi_pclk_ctrl(&dsi_pclk, 1);
mipi_dsi_clk_ctrl(&dsicore_clk, 1);
+ mipi_dsi_clk_on = 1;
}
void mipi_dsi_clk_disable(void)
{
+ if (mipi_dsi_clk_on == 0) {
+ pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
+ return;
+ }
mipi_dsi_pclk_ctrl(&dsi_pclk, 0);
mipi_dsi_clk_ctrl(&dsicore_clk, 0);
clk_disable(dsi_esc_clk);
@@ -345,6 +366,7 @@
if (clk_set_rate(ebi1_dsi_clk, 0))
pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__);
clk_disable(ebi1_dsi_clk);
+ mipi_dsi_clk_on = 0;
}
void mipi_dsi_phy_ctrl(int on)
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 3f74abd..a6f1d36 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -62,6 +62,7 @@
static struct clk *dsi_s_pclk;
static struct clk *amp_pclk;
+int mipi_dsi_clk_on;
static int cont_splash_clks_enabled;
@@ -551,22 +552,37 @@
void mipi_dsi_ahb_ctrl(u32 enable)
{
+ static int ahb_ctrl_done;
if (enable) {
+ if (ahb_ctrl_done) {
+ pr_info("%s: ahb clks already ON\n", __func__);
+ return;
+ }
clk_enable(amp_pclk); /* clock for AHB-master to AXI */
clk_enable(dsi_m_pclk);
clk_enable(dsi_s_pclk);
mipi_dsi_ahb_en();
mipi_dsi_sfpb_cfg();
+ ahb_ctrl_done = 1;
} else {
+ if (ahb_ctrl_done == 0) {
+ pr_info("%s: ahb clks already OFF\n", __func__);
+ return;
+ }
clk_disable(dsi_m_pclk);
clk_disable(dsi_s_pclk);
clk_disable(amp_pclk); /* clock for AHB-master to AXI */
+ ahb_ctrl_done = 0;
}
}
void mipi_dsi_clk_enable(void)
{
u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200);
+ if (mipi_dsi_clk_on) {
+ pr_info("%s: mipi_dsi_clks already ON\n", __func__);
+ return;
+ }
MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01);
mipi_dsi_phy_rdy_poll();
@@ -580,17 +596,23 @@
mipi_dsi_clk_ctrl(&dsicore_clk, 1);
clk_enable(dsi_byte_div_clk);
clk_enable(dsi_esc_clk);
+ mipi_dsi_clk_on = 1;
mdp4_stat.dsi_clk_on++;
}
void mipi_dsi_clk_disable(void)
{
+ if (mipi_dsi_clk_on == 0) {
+ pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
+ return;
+ }
clk_disable(dsi_esc_clk);
clk_disable(dsi_byte_div_clk);
mipi_dsi_pclk_ctrl(&dsi_pclk, 0);
mipi_dsi_clk_ctrl(&dsicore_clk, 0);
/* DSIPHY_PLL_CTRL_0, disable dsi pll */
MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x0);
+ mipi_dsi_clk_on = 0;
mdp4_stat.dsi_clk_off++;
}
diff --git a/drivers/video/msm/msm_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c
index 7909a92..2231bce 100644
--- a/drivers/video/msm/msm_dss_io_8x60.c
+++ b/drivers/video/msm/msm_dss_io_8x60.c
@@ -32,6 +32,7 @@
static struct clk *dsi_s_pclk;
static struct clk *amp_pclk;
+int mipi_dsi_clk_on;
void mipi_dsi_clk_init(struct platform_device *pdev)
{
@@ -396,22 +397,37 @@
void mipi_dsi_ahb_ctrl(u32 enable)
{
+ static int ahb_ctrl_done;
if (enable) {
+ if (ahb_ctrl_done) {
+ pr_info("%s: ahb clks already ON\n", __func__);
+ return;
+ }
clk_enable(amp_pclk); /* clock for AHB-master to AXI */
clk_enable(dsi_m_pclk);
clk_enable(dsi_s_pclk);
mipi_dsi_ahb_en();
mipi_dsi_sfpb_cfg();
+ ahb_ctrl_done = 1;
} else {
+ if (ahb_ctrl_done == 0) {
+ pr_info("%s: ahb clks already OFF\n", __func__);
+ return;
+ }
clk_disable(dsi_m_pclk);
clk_disable(dsi_s_pclk);
clk_disable(amp_pclk); /* clock for AHB-master to AXI */
+ ahb_ctrl_done = 0;
}
}
void mipi_dsi_clk_enable(void)
{
u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200);
+ if (mipi_dsi_clk_on) {
+ pr_info("%s: mipi_dsi_clks already ON\n", __func__);
+ return;
+ }
MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01);
mb();
@@ -421,10 +437,15 @@
mipi_dsi_clk_ctrl(&dsicore_clk, 1);
clk_enable(dsi_byte_div_clk);
clk_enable(dsi_esc_clk);
+ mipi_dsi_clk_on = 1;
}
void mipi_dsi_clk_disable(void)
{
+ if (mipi_dsi_clk_on == 0) {
+ pr_info("%s: mipi_dsi_clks already OFF\n", __func__);
+ return;
+ }
clk_disable(dsi_esc_clk);
clk_disable(dsi_byte_div_clk);
@@ -432,6 +453,7 @@
mipi_dsi_clk_ctrl(&dsicore_clk, 0);
/* DSIPHY_PLL_CTRL_0, disable dsi pll */
MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x40);
+ mipi_dsi_clk_on = 0;
}
void mipi_dsi_phy_ctrl(int on)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index f8cc926..74f7ead 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1239,6 +1239,8 @@
snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
#elif defined(CONFIG_FB_MSM_MDP40)
snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
+#elif defined(CONFIG_FB_MSM_MDP_NONE)
+ snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
#else
error CONFIG_FB_MSM_MDP undefined !
#endif
@@ -2187,6 +2189,8 @@
/* blit first region */
if (((splitreq.flags & 0x07) == 0x07) ||
+ ((splitreq.flags & 0x07) == 0x05) ||
+ ((splitreq.flags & 0x07) == 0x02) ||
((splitreq.flags & 0x07) == 0x0)) {
if (splitreq.flags & MDP_ROT_90) {
@@ -2267,6 +2271,8 @@
/* blit second region */
if (((splitreq.flags & 0x07) == 0x07) ||
+ ((splitreq.flags & 0x07) == 0x05) ||
+ ((splitreq.flags & 0x07) == 0x02) ||
((splitreq.flags & 0x07) == 0x0)) {
splitreq.src_rect.h = s_h_1;
splitreq.src_rect.y = s_y_1;
@@ -3597,4 +3603,58 @@
return 0;
}
+/* Called by v4l2 driver to enable/disable overlay pipe */
+int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par)
+{
+ int err = 0;
+#ifdef CONFIG_FB_MSM_MDP40
+ struct mdp4_overlay_pipe *pipe;
+ if (enable) {
+
+ err = mdp4_v4l2_overlay_set(fbi_list[0], req, &pipe);
+
+ *(struct mdp4_overlay_pipe **)par = pipe;
+
+ } else {
+ pipe = *(struct mdp4_overlay_pipe **)par;
+ mdp4_v4l2_overlay_clear(pipe);
+ }
+#else
+#ifdef CONFIG_FB_MSM_MDP30
+ if (enable)
+ err = mdp_ppp_v4l2_overlay_set(fbi_list[0], req);
+ else
+ err = mdp_ppp_v4l2_overlay_clear();
+#else
+ err = -EINVAL;
+#endif
+#endif
+
+ return err;
+}
+EXPORT_SYMBOL(msm_fb_v4l2_enable);
+
+/* Called by v4l2 driver to provide a frame for display */
+int msm_fb_v4l2_update(void *par,
+ unsigned long srcp0_addr, unsigned long srcp0_size,
+ unsigned long srcp1_addr, unsigned long srcp1_size,
+ unsigned long srcp2_addr, unsigned long srcp2_size)
+{
+#ifdef CONFIG_FB_MSM_MDP40
+ struct mdp4_overlay_pipe *pipe = (struct mdp4_overlay_pipe *)par;
+ return mdp4_v4l2_overlay_play(fbi_list[0], pipe,
+ srcp0_addr, srcp1_addr,
+ srcp2_addr);
+#else
+#ifdef CONFIG_FB_MSM_MDP30
+ return mdp_ppp_v4l2_overlay_play(fbi_list[0],
+ srcp0_addr, srcp0_size,
+ srcp1_addr, srcp1_size);
+#else
+ return -EINVAL;
+#endif
+#endif
+}
+EXPORT_SYMBOL(msm_fb_v4l2_update);
+
module_init(msm_fb_init);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 40c5408..d6749e2 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1764,7 +1764,7 @@
}
memset(output_buf_req, 0,
sizeof(struct vcd_buffer_requirement));
- if (!estimate && !decoder->idr_only_decoding && !decoder->cont_mode)
+ if (!decoder->idr_only_decoding && !decoder->cont_mode)
output_buf_req->actual_count = min_dpb + 4;
else
output_buf_req->actual_count = min_dpb;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6f7e8d1..eec83b6b 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -1887,6 +1887,7 @@
struct vcd_transc *transc;
struct ddl_frame_data_tag *frame =
(struct ddl_frame_data_tag *) payload;
+ struct vcd_buffer_entry *orig_frame = NULL;
u32 rc;
if (!cctxt->status.frame_submitted &&
@@ -1901,6 +1902,8 @@
VCD_FAILED_RETURN(rc, "Bad input done payload");
transc = (struct vcd_transc *)frame->vcd_frm.ip_frm_tag;
+ orig_frame = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
+ transc->ip_buf_entry->virtual);
if ((transc->ip_buf_entry->frame.virtual !=
frame->vcd_frm.virtual)
@@ -1919,8 +1922,17 @@
sizeof(struct vcd_frame_data),
cctxt, cctxt->client_data);
- transc->ip_buf_entry->in_use = false;
+ orig_frame->in_use--;
VCD_BUFFERPOOL_INUSE_DECREMENT(cctxt->in_buf_pool.in_use);
+
+ if (cctxt->decoding && orig_frame->in_use) {
+ VCD_MSG_ERROR("When decoding same input buffer not "
+ "supposed to be queued multiple times");
+ return VCD_ERR_FAIL;
+ }
+
+ if (orig_frame != transc->ip_buf_entry)
+ kfree(transc->ip_buf_entry);
transc->ip_buf_entry = NULL;
transc->input_done = true;
@@ -2640,7 +2652,7 @@
struct vcd_frame_data *input_frame)
{
struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
- struct vcd_buffer_entry *buf_entry;
+ struct vcd_buffer_entry *buf_entry, *orig_frame;
struct vcd_frame_data *frm_entry;
u32 rc = VCD_S_SUCCESS;
u32 eos_handled = false;
@@ -2686,18 +2698,49 @@
}
VCD_FAILED_RETURN(rc, "Failed: First frame handling");
- buf_entry = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
+ orig_frame = vcd_find_buffer_pool_entry(&cctxt->in_buf_pool,
input_frame->virtual);
- if (!buf_entry) {
+ if (!orig_frame) {
VCD_MSG_ERROR("Bad buffer addr: %p", input_frame->virtual);
return VCD_ERR_FAIL;
}
- if (buf_entry->in_use) {
- VCD_MSG_ERROR("An inuse input frame is being"
- "re-queued to scheduler");
- return VCD_ERR_FAIL;
- }
+ if (orig_frame->in_use) {
+ /*
+ * This path only allowed for enc., dec. not allowed
+ * to queue same buffer multiple times
+ */
+ if (cctxt->decoding) {
+ VCD_MSG_ERROR("An inuse input frame is being "
+ "re-queued to scheduler");
+ return VCD_ERR_FAIL;
+ }
+
+ buf_entry = kzalloc(sizeof(*buf_entry), GFP_KERNEL);
+ if (!buf_entry) {
+ VCD_MSG_ERROR("Unable to alloc memory");
+ return VCD_ERR_FAIL;
+ }
+
+ INIT_LIST_HEAD(&buf_entry->sched_list);
+ /*
+ * Pre-emptively poisoning this, as these dupe entries
+ * shouldn't get added to any list
+ */
+ INIT_LIST_HEAD(&buf_entry->list);
+ buf_entry->list.next = LIST_POISON1;
+ buf_entry->list.prev = LIST_POISON2;
+
+ buf_entry->valid = orig_frame->valid;
+ buf_entry->alloc = orig_frame->alloc;
+ buf_entry->virtual = orig_frame->virtual;
+ buf_entry->physical = orig_frame->physical;
+ buf_entry->sz = orig_frame->sz;
+ buf_entry->allocated = orig_frame->allocated;
+ buf_entry->in_use = 1; /* meaningless for the dupe buffers */
+ buf_entry->frame = orig_frame->frame;
+ } else
+ buf_entry = orig_frame;
if (input_frame->alloc_len > buf_entry->sz) {
VCD_MSG_ERROR("Bad buffer Alloc_len %d, Actual sz=%d",
@@ -2726,7 +2769,7 @@
cctxt->sched_clnt_hdl, buf_entry, true);
VCD_FAILED_RETURN(rc, "Failed: vcd_sched_queue_buffer");
- buf_entry->in_use = true;
+ orig_frame->in_use++;
cctxt->in_buf_pool.in_use++;
vcd_try_submit_frame(dev_ctxt);
return rc;
diff --git a/include/linux/device.h b/include/linux/device.h
index e4f62d8..b44a3b1 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -506,6 +506,10 @@
* @mutex: Mutex to synchronize calls to its driver.
* @bus: Type of bus device is on.
* @driver: Which driver has allocated this
+ * @deferred_probe: entry in deferred_probe_list which is used to retry the
+ * binding of drivers which were unable to get all the resources
+ * needed by the device; typically because it depends on another
+ * driver getting probed first.
* @platform_data: Platform data specific to the device.
* Example: For devices on custom boards, as typical of embedded
* and SOC based hardware, Linux often uses platform_data to point
@@ -564,6 +568,7 @@
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
+ struct list_head deferred_probe;
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
diff --git a/include/linux/errno.h b/include/linux/errno.h
index 4668583..2d09bfa 100644
--- a/include/linux/errno.h
+++ b/include/linux/errno.h
@@ -16,6 +16,7 @@
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
+#define EPROBE_DEFER 517 /* Driver requests probe retry */
/* Defined for the NFSv3 protocol */
#define EBADHANDLE 521 /* Illegal NFS file handle */
diff --git a/include/linux/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h
index 18e6398..60755de 100644
--- a/include/linux/leds-pm8xxx.h
+++ b/include/linux/leds-pm8xxx.h
@@ -35,6 +35,9 @@
PM8XXX_ID_FLASH_LED_0,
PM8XXX_ID_FLASH_LED_1,
PM8XXX_ID_WLED,
+ PM8XXX_ID_RGB_LED_RED,
+ PM8XXX_ID_RGB_LED_GREEN,
+ PM8XXX_ID_RGB_LED_BLUE,
PM8XXX_ID_MAX,
};
diff --git a/include/linux/libra_sdioif.h b/include/linux/libra_sdioif.h
index 99e6f72..99b7d04 100644
--- a/include/linux/libra_sdioif.h
+++ b/include/linux/libra_sdioif.h
@@ -35,6 +35,7 @@
typedef int (suspend_handler_t)(struct sdio_func *);
typedef void (resume_handler_t)(struct sdio_func *);
typedef void (notify_card_removal_t)(void);
+typedef void (shutdown_handler_t)(void);
int libra_enable_sdio_irq_in_chip(struct sdio_func *func, u8 enable);
int libra_sdio_configure(sdio_irq_handler_t libra_sdio_rxhandler,
@@ -77,4 +78,6 @@
int libra_disable_sdio_irq_capability(struct sdio_func *func, u8 disable);
int libra_sdio_notify_card_removal(
notify_card_removal_t *libra_sdio_notify_card_removal_hdlr);
+int libra_sdio_register_shutdown_hdlr(
+ shutdown_handler_t *libra_shutdown_hdlr);
#endif /* __LIBRA_SDIOIF_H__ */
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index e7bf820..b907219 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -42,6 +42,8 @@
#define PM8XXX_REVISION_8901_1p1 2
#define PM8XXX_REVISION_8901_2p0 3
#define PM8XXX_REVISION_8901_2p1 4
+#define PM8XXX_REVISION_8901_2p2 5
+#define PM8XXX_REVISION_8901_2p3 6
#define PM8XXX_REVISION_8921_TEST 0
#define PM8XXX_REVISION_8921_1p0 1
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index c90d8d1..77683ce 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -79,7 +79,7 @@
};
enum pm8xxx_aux_clk_div {
- X0_DIV_NONE,
+ XO_DIV_NONE,
XO_DIV_1,
XO_DIV_2,
XO_DIV_4,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index dedbe5c..0fcae7c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -227,7 +227,6 @@
struct sdio_cccr cccr; /* common card info */
struct sdio_cis cis; /* common tuple info */
struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
- struct sdio_func *sdio_single_irq; /* SDIO function when only one IRQ active */
unsigned num_info; /* number of info strings */
const char **info; /* info strings */
struct sdio_func_tuple *tuples; /* unknown common tuples */
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 0e62644..8739122 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
#define _MSM_KGSL_H
#define KGSL_VERSION_MAJOR 3
-#define KGSL_VERSION_MINOR 8
+#define KGSL_VERSION_MINOR 9
/*context flags */
#define KGSL_CONTEXT_SAVE_GMEM 1
@@ -164,12 +164,14 @@
int num_levels;
int (*set_grp_async)(void);
unsigned int idle_timeout;
+ bool strtstp_sleepwake;
unsigned int nap_allowed;
unsigned int clk_map;
unsigned int idle_needed;
struct msm_bus_scale_pdata *bus_scale_table;
struct kgsl_device_iommu_data *iommu_data;
int iommu_count;
+ struct msm_dcvs_core_info *core_info;
};
#endif
@@ -454,6 +456,14 @@
int handle; /* Handle of the genlock lock to release */
};
+/*
+ * Set a property within the kernel. Uses the same structure as
+ * IOCTL_KGSL_GETPROPERTY
+ */
+
+#define IOCTL_KGSL_SETPROPERTY \
+ _IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty)
+
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 56e8438..aa54b71 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -25,7 +25,7 @@
#define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int)
#define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor)
#define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap)
-#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram)
+#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram_data)
/* new ioctls's for set/get ccs matrix */
#define MSMFB_GET_CCS_MATRIX _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs)
#define MSMFB_SET_CCS_MATRIX _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs)
@@ -44,8 +44,9 @@
#define MSMFB_OVERLAY_BLT _IOWR(MSMFB_IOCTL_MAGIC, 142, \
struct msmfb_overlay_blt)
#define MSMFB_OVERLAY_BLT_OFFSET _IOW(MSMFB_IOCTL_MAGIC, 143, unsigned int)
-#define MSMFB_HISTOGRAM_START _IO(MSMFB_IOCTL_MAGIC, 144)
-#define MSMFB_HISTOGRAM_STOP _IO(MSMFB_IOCTL_MAGIC, 145)
+#define MSMFB_HISTOGRAM_START _IOR(MSMFB_IOCTL_MAGIC, 144, \
+ struct mdp_histogram_start_req)
+#define MSMFB_HISTOGRAM_STOP _IOR(MSMFB_IOCTL_MAGIC, 145, unsigned int)
#define MSMFB_NOTIFY_UPDATE _IOW(MSMFB_IOCTL_MAGIC, 146, unsigned int)
#define MSMFB_OVERLAY_3D _IOWR(MSMFB_IOCTL_MAGIC, 147, \
@@ -328,6 +329,32 @@
MDP_BLOCK_MAX,
};
+/*
+ * mdp_histogram_start_req is used to provide the parameters for
+ * histogram start request
+ */
+
+struct mdp_histogram_start_req {
+ uint32_t block;
+ uint8_t frame_cnt;
+ uint8_t bit_mask;
+ uint8_t num_bins;
+};
+
+/*
+ * mdp_histogram_data is used to return the histogram data, once
+ * the histogram is done/stopped/cance
+ */
+
+struct mdp_histogram_data {
+ uint32_t block;
+ uint8_t bin_cnt;
+ uint32_t *c0;
+ uint32_t *c1;
+ uint32_t *c2;
+ uint32_t extra_info[2];
+};
+
struct mdp_pcc_coeff {
uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1;
};
diff --git a/include/linux/of.h b/include/linux/of.h
index b904f7e..452ed98 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -249,6 +249,12 @@
#define for_each_child_of_node(parent, child) \
while (0)
+static inline int of_device_is_compatible(const struct device_node *device,
+ const char *name)
+{
+ return 0;
+}
+
static inline struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
@@ -288,6 +294,13 @@
return NULL;
}
+static inline struct device_node *of_parse_phandle(struct device_node *np,
+ const char *phandle_name,
+ int index)
+{
+ return NULL;
+}
+
#endif /* CONFIG_OF */
static inline int of_property_read_u32(const struct device_node *np,
diff --git a/include/linux/of_slimbus.h b/include/linux/of_slimbus.h
new file mode 100644
index 0000000..8e1dc65
--- /dev/null
+++ b/include/linux/of_slimbus.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/slimbus/slimbus.h>
+#include <linux/of_irq.h>
+
+#ifdef CONFIG_OF_SLIMBUS
+/*
+ * of_slim_register_devices() - Register devices in the SLIMbus Device Tree
+ * @ctrl: slim_controller which devices should be registered to.
+ *
+ * This routine scans the SLIMbus Device Tree, allocating resources and
+ * creating slim_devices according to the SLIMbus Device Tree
+ * hierarchy. Details of this hierarchy can be found in
+ * Documentation/devicetree/bindings/slimbus. This routine is normally
+ * called from the probe routine of the driver registering as a
+ * slim_controller.
+ */
+extern int of_register_slim_devices(struct slim_controller *ctrl);
+#else
+static int of_register_slim_devices(struct slim_controller *ctrl)
+{
+ return 0;
+}
+#endif /* CONFIG_OF_SLIMBUS */
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 6c433b8..956a331 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -153,6 +153,7 @@
* this type.
*
* @name: Identifying name for the regulator.
+ * @supply_name: Identifying the regulator supply
* @id: Numerical identifier for the regulator.
* @n_voltages: Number of selectors available for ops.list_voltage().
* @ops: Regulator operations table.
@@ -162,6 +163,7 @@
*/
struct regulator_desc {
const char *name;
+ const char *supply_name;
int id;
unsigned n_voltages;
struct regulator_ops *ops;
@@ -210,7 +212,7 @@
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, const struct regulator_init_data *init_data,
- void *driver_data);
+ void *driver_data, struct device_node *of_node);
void regulator_unregister(struct regulator_dev *rdev);
int regulator_notifier_call_chain(struct regulator_dev *rdev,
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 6804ef3..22a832a 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -95,7 +95,7 @@
*/
struct regulation_constraints {
- char *name;
+ const char *name;
/* voltage output range (inclusive) - for voltage control */
int min_uV;
diff --git a/include/linux/regulator/of_regulator.h b/include/linux/regulator/of_regulator.h
new file mode 100644
index 0000000..d83a98d
--- /dev/null
+++ b/include/linux/regulator/of_regulator.h
@@ -0,0 +1,20 @@
+/*
+ * OpenFirmware regulator support routines
+ *
+ */
+
+#ifndef __LINUX_OF_REG_H
+#define __LINUX_OF_REG_H
+
+#if defined(CONFIG_OF)
+extern struct regulator_init_data
+ *of_get_regulator_init_data(struct device *dev);
+#else
+static inline struct regulator_init_data
+ *of_get_regulator_init_data(struct device *dev)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF */
+
+#endif /* __LINUX_OF_REG_H */
diff --git a/include/linux/regulator/stub-regulator.h b/include/linux/regulator/stub-regulator.h
index 1119c51..e7f4110 100644
--- a/include/linux/regulator/stub-regulator.h
+++ b/include/linux/regulator/stub-regulator.h
@@ -30,4 +30,6 @@
int hpm_min_load;
int system_uA;
};
+
+int __init regulator_stub_init(void);
#endif
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 81a9279..2b39f69 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -53,6 +53,7 @@
#define USB_CDC_DMM_TYPE 0x14
#define USB_CDC_OBEX_TYPE 0x15
#define USB_CDC_NCM_TYPE 0x1a
+#define USB_CDC_MBB_TYPE 0x1b /* mbb_desc */
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct usb_cdc_header_desc {
@@ -187,6 +188,21 @@
__le16 bcdNcmVersion;
__u8 bmNetworkCapabilities;
} __attribute__ ((packed));
+
+/* "MBIM Functional Descriptor" */
+struct usb_cdc_mbb_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdMbbVersion;
+ __le16 wMaxControlMessage;
+ __u8 bNumberFilters;
+ __u8 bMaxFilterSize;
+ __le16 wMaxSegmentSize;
+ __u8 bmNetworkCapabilities;
+} __packed;
+
/*-------------------------------------------------------------------------*/
/*
@@ -201,6 +217,7 @@
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define USB_CDC_RESET_FUNCTION 0x05
#define USB_CDC_REQ_SET_LINE_CODING 0x20
#define USB_CDC_REQ_GET_LINE_CODING 0x21
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 5845cb6..bb6a01d 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -295,7 +295,7 @@
unsigned mA_port;
struct timer_list id_timer;
unsigned long caps;
- struct clk *xo_handle;
+ struct msm_xo_voter *xo_handle;
uint32_t bus_perf_client;
/*
* Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 175b54f..0a0fb1b 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -652,6 +652,10 @@
#define V4L2_BUF_FLAG_ERROR 0x0040
#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */
#define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */
+#define V4L2_BUF_FLAG_PREPARED 0x0400 /* Buffer is prepared for queuing */
+/* Cache handling flags */
+#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800
+#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000
/*
* O V E R L A Y P R E V I E W
@@ -2035,6 +2039,15 @@
__u32 revision; /* chip revision, chip specific */
} __attribute__ ((packed));
+/* VIDIOC_CREATE_BUFS */
+struct v4l2_create_buffers {
+ __u32 index; /* output: buffers index...index + count - 1 have been created */
+ __u32 count;
+ enum v4l2_memory memory;
+ struct v4l2_format format; /* "type" is used always, the rest if sizeimage == 0 */
+ __u32 reserved[8];
+};
+
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
@@ -2125,6 +2138,11 @@
#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription)
#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)
+/* Experimental, the below two ioctls may change over the next couple of kernel
+ versions */
+#define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers)
+#define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer)
+
/* Reminder: when adding new ioctls please add support for them to
drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/include/media/Kbuild b/include/media/Kbuild
index f4a8a86..a60b86c 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -3,3 +3,4 @@
header-y += msm_camera.h
header-y += msm_isp.h
header-y += msm_gemini.h
+header-y += msm_v4l2_overlay.h
diff --git a/include/media/gpio-ir-recv.h b/include/media/gpio-ir-recv.h
index 3eab611..61a7fbb 100644
--- a/include/media/gpio-ir-recv.h
+++ b/include/media/gpio-ir-recv.h
@@ -16,7 +16,6 @@
struct gpio_ir_recv_platform_data {
unsigned int gpio_nr;
bool active_low;
- bool can_wakeup;
};
#endif /* __GPIO_IR_RECV_H__ */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a448df6..622c7d0 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1224,6 +1224,8 @@
struct msm_camsensor_info {
char name[MAX_SENSOR_NAME];
uint8_t flash_enabled;
+ uint8_t strobe_flash_enabled;
+ uint8_t actuator_enabled;
int8_t total_steps;
uint8_t support_3d;
enum flash_type flashtype;
diff --git a/include/media/msm_v4l2_overlay.h b/include/media/msm_v4l2_overlay.h
new file mode 100644
index 0000000..c83cfb7
--- /dev/null
+++ b/include/media/msm_v4l2_overlay.h
@@ -0,0 +1,9 @@
+#ifndef LINUX_MSM_V4L2_OVERLAY
+#define LINUX_MSM_V4L2_OVERLAY
+
+#include <linux/videodev2.h>
+
+#define VIDIOC_MSM_USERPTR_QBUF \
+_IOWR('V', BASE_VIDIOC_PRIVATE, struct v4l2_buffer)
+
+#endif
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index de2b356..dfad18d 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -44,7 +44,14 @@
/* default data access */
#define DEFAULT_DATA_OFFSET 2
#define DEFAULT_DATA_SIZE 249
-
+/* Power levels are 0-7, but SOC will expect values from 0-255
+ * So the each level step size will be 255/7 = 36 */
+#define FM_TX_PWR_LVL_STEP_SIZE 36
+#define FM_TX_PWR_LVL_0 0 /* Lowest power lvl that can be set for Tx */
+#define FM_TX_PWR_LVL_MAX 7 /* Max power lvl for Tx */
+#define FM_TX_PHY_CFG_MODE 0x3c
+#define FM_TX_PHY_CFG_LEN 0x10
+#define FM_TX_PWR_GAIN_OFFSET 14
/* HCI timeouts */
#define RADIO_HCI_TIMEOUT (10000) /* 10 seconds */
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 226ea68..2114287 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -114,6 +114,7 @@
#define RC_MAP_NORWOOD "rc-norwood"
#define RC_MAP_NPGTECH "rc-npgtech"
#define RC_MAP_PCTV_SEDNA "rc-pctv-sedna"
+#define RC_MAP_RC6_PHILIPS "rc-philips"
#define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color"
#define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey"
#define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd"
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index dd9f1e7..4d1c74a 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -122,6 +122,8 @@
int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
+ int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b);
+ int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b);
int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
int (*vidioc_g_fbuf) (struct file *file, void *fh,
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 0c7cf8c..822dd69 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -56,8 +56,6 @@
int dirty;
unsigned int count;
void *alloc_ctx;
- struct msm_mapped_buffer *msm_buffer;
- int subsys_id;
unsigned long mapped_phyaddr;
struct ion_handle *ion_handle;
struct ion_client *client;
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index 0a2849a..ec517b0 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2010-2012 Code Aurora Forum. 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
@@ -115,7 +115,7 @@
void amp_exit(void);
/* L2CAP-AMP fixed channel interface */
-void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb);
+void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb);
/* L2CAP-AMP link interface */
void amp_create_physical(struct l2cap_conn *conn, struct sock *sk);
@@ -256,7 +256,7 @@
};
struct amp_work_conn_ind {
struct work_struct work;
- struct l2cap_conn *conn;
+ struct hci_conn *hcon;
struct sk_buff *skb;
};
struct amp_work_create_physical {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4c86f24..d98a79d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -586,10 +586,7 @@
}
int hci_chan_put(struct hci_chan *chan);
-struct hci_chan *hci_chan_accept(struct hci_conn *hcon,
- struct hci_ext_fs *tx_fs,
- struct hci_ext_fs *rx_fs);
-struct hci_chan *hci_chan_create(struct hci_conn *hcon,
+struct hci_chan *hci_chan_create(struct hci_chan *chan,
struct hci_ext_fs *tx_fs,
struct hci_ext_fs *rx_fs);
void hci_chan_modify(struct hci_chan *chan,
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index d5c4189..b903c5c 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -51,7 +51,7 @@
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
-#define L2CAP_MOVE_TIMEOUT (2*HZ) /* 2 seconds */
+#define L2CAP_MOVE_TIMEOUT (4*HZ) /* 4 seconds */
#define L2CAP_MOVE_ERTX_TIMEOUT (60*HZ) /* 60 seconds */
/* L2CAP socket address */
diff --git a/kernel/sched.c b/kernel/sched.c
index 1e633e6..f8289fc 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4149,8 +4149,6 @@
*/
static noinline void __schedule_bug(struct task_struct *prev)
{
- struct pt_regs *regs = get_irq_regs();
-
printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n",
prev->comm, prev->pid, preempt_count());
@@ -4158,11 +4156,7 @@
print_modules();
if (irqs_disabled())
print_irqtrace_events(prev);
-
- if (regs)
- show_regs(regs);
- else
- dump_stack();
+ dump_stack();
}
/*
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 0a3b91d..df80c42 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010-2011 Code Aurora Forum. All rights reserved.
+ Copyright (c) 2010-2012 Code Aurora Forum. 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
@@ -87,15 +87,15 @@
return found;
}
-static struct amp_mgr *get_create_amp_mgr(struct l2cap_conn *conn,
+static struct amp_mgr *get_create_amp_mgr(struct hci_conn *hcon,
struct sk_buff *skb)
{
struct amp_mgr *mgr;
write_lock(&_mgr_list_lock);
list_for_each_entry(mgr, &_mgr_list, list) {
- if (mgr->l2cap_conn == conn) {
- BT_DBG("conn %p found %p", conn, mgr);
+ if (mgr->l2cap_conn == hcon->l2cap_data) {
+ BT_DBG("found %p", mgr);
write_unlock(&_mgr_list_lock);
goto gc_finished;
}
@@ -106,13 +106,13 @@
if (!mgr)
return NULL;
- mgr->l2cap_conn = conn;
+ mgr->l2cap_conn = hcon->l2cap_data;
mgr->next_ident = 1;
INIT_LIST_HEAD(&mgr->ctx_list);
rwlock_init(&mgr->ctx_list_lock);
mgr->skb = skb;
- BT_DBG("conn %p mgr %p", conn, mgr);
- mgr->a2mp_sock = open_fixed_channel(conn->src, conn->dst);
+ BT_DBG("hcon %p mgr %p", hcon, mgr);
+ mgr->a2mp_sock = open_fixed_channel(&hcon->hdev->bdaddr, &hcon->dst);
if (!mgr->a2mp_sock) {
kfree(mgr);
return NULL;
@@ -484,7 +484,7 @@
struct amp_ctx *ctx = NULL;
BT_DBG("conn %p", conn);
- mgr = get_create_amp_mgr(conn, NULL);
+ mgr = get_create_amp_mgr(conn->hcon, NULL);
if (!mgr)
goto cp_finished;
BT_DBG("mgr %p", mgr);
@@ -514,7 +514,7 @@
if (!hdev)
goto ap_finished;
BT_DBG("hdev %p", hdev);
- mgr = get_create_amp_mgr(lcon, NULL);
+ mgr = get_create_amp_mgr(lcon->hcon, NULL);
if (!mgr)
goto ap_finished;
BT_DBG("mgr %p", mgr);
@@ -1773,12 +1773,13 @@
static void conn_ind_worker(struct work_struct *w)
{
struct amp_work_conn_ind *work = (struct amp_work_conn_ind *) w;
- struct l2cap_conn *conn = work->conn;
+ struct hci_conn *hcon = work->hcon;
struct sk_buff *skb = work->skb;
struct amp_mgr *mgr;
- mgr = get_create_amp_mgr(conn, skb);
+ mgr = get_create_amp_mgr(hcon, skb);
BT_DBG("mgr %p", mgr);
+ hci_conn_put(hcon);
kfree(work);
}
@@ -1804,17 +1805,20 @@
/* L2CAP Fixed Channel interface */
-void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb)
+void amp_conn_ind(struct hci_conn *hcon, struct sk_buff *skb)
{
struct amp_work_conn_ind *work;
- BT_DBG("conn %p, skb %p", conn, skb);
+ BT_DBG("hcon %p, skb %p", hcon, skb);
work = kmalloc(sizeof(*work), GFP_ATOMIC);
if (work) {
INIT_WORK((struct work_struct *) work, conn_ind_worker);
- work->conn = conn;
+ hci_conn_hold(hcon);
+ work->hcon = hcon;
work->skb = skb;
- if (queue_work(amp_workqueue, (struct work_struct *) work) == 0)
+ if (!queue_work(amp_workqueue, (struct work_struct *) work)) {
+ hci_conn_put(hcon);
kfree(work);
+ }
}
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 2854395..f87be20 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -520,6 +520,7 @@
return chan;
}
+EXPORT_SYMBOL(hci_chan_add);
int hci_chan_del(struct hci_chan *chan)
{
@@ -1001,18 +1002,12 @@
}
}
-struct hci_chan *hci_chan_accept(struct hci_conn *conn,
+struct hci_chan *hci_chan_create(struct hci_chan *chan,
struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
{
- struct hci_chan *chan;
struct hci_cp_create_logical_link cp;
- chan = hci_chan_add(conn->hdev);
- if (!chan)
- return NULL;
-
chan->state = BT_CONNECT;
- chan->conn = conn;
chan->tx_fs = *tx_fs;
chan->rx_fs = *rx_fs;
cp.phy_handle = chan->conn->handle;
@@ -1029,40 +1024,12 @@
cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
hci_conn_hold(chan->conn);
- hci_send_cmd(conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), &cp);
- return chan;
-}
-EXPORT_SYMBOL(hci_chan_accept);
-
-struct hci_chan *hci_chan_create(struct hci_conn *conn,
- struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
-{
- struct hci_chan *chan;
- struct hci_cp_create_logical_link cp;
-
- chan = hci_chan_add(conn->hdev);
- if (!chan)
- return NULL;
-
- chan->state = BT_CONNECT;
- chan->conn = conn;
- chan->tx_fs = *tx_fs;
- chan->rx_fs = *rx_fs;
- cp.phy_handle = chan->conn->handle;
- cp.tx_fs.id = chan->tx_fs.id;
- cp.tx_fs.type = chan->tx_fs.type;
- cp.tx_fs.max_sdu = cpu_to_le16(chan->tx_fs.max_sdu);
- cp.tx_fs.sdu_arr_time = cpu_to_le32(chan->tx_fs.sdu_arr_time);
- cp.tx_fs.acc_latency = cpu_to_le32(chan->tx_fs.acc_latency);
- cp.tx_fs.flush_to = cpu_to_le32(chan->tx_fs.flush_to);
- cp.rx_fs.id = chan->rx_fs.id;
- cp.rx_fs.type = chan->rx_fs.type;
- cp.rx_fs.max_sdu = cpu_to_le16(chan->rx_fs.max_sdu);
- cp.rx_fs.sdu_arr_time = cpu_to_le32(chan->rx_fs.sdu_arr_time);
- cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
- cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
- hci_conn_hold(chan->conn);
- hci_send_cmd(conn->hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), &cp);
+ if (chan->conn->out)
+ hci_send_cmd(chan->conn->hdev, HCI_OP_CREATE_LOGICAL_LINK,
+ sizeof(cp), &cp);
+ else
+ hci_send_cmd(chan->conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK,
+ sizeof(cp), &cp);
return chan;
}
EXPORT_SYMBOL(hci_chan_create);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f57113b..74d0851 100755
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2783,6 +2783,12 @@
if (!conn->ssp_mode && conn->auth_initiator &&
(conn->pending_sec_level == BT_SECURITY_HIGH))
conn->pending_sec_level = BT_SECURITY_MEDIUM;
+
+ if (conn->ssp_mode && conn->auth_initiator &&
+ conn->io_capability != 0x03) {
+ conn->pending_sec_level = BT_SECURITY_HIGH;
+ conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+ }
}
if (conn->state != BT_CONFIG)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 0ad64a0..de3ab22 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3186,8 +3186,9 @@
return 1;
}
-static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct l2cap_pinfo *pi)
+static struct hci_chan *l2cap_chan_admit(u8 amp_id, struct sock *sk)
{
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
struct hci_dev *hdev;
struct hci_conn *hcon;
struct hci_chan *chan;
@@ -3207,19 +3208,23 @@
chan = hci_chan_list_lookup_id(hdev, hcon->handle);
if (chan) {
l2cap_aggregate(chan, pi);
+ sock_hold(sk);
+ chan->l2cap_sk = sk;
+ hci_chan_hold(chan);
+ pi->ampchan = chan;
goto done;
}
- if (bt_sk(pi)->parent) {
- /* Incoming connection */
- chan = hci_chan_accept(hcon,
- (struct hci_ext_fs *) &pi->local_fs,
- (struct hci_ext_fs *) &pi->remote_fs);
- } else {
- /* Outgoing connection */
- chan = hci_chan_create(hcon,
- (struct hci_ext_fs *) &pi->local_fs,
- (struct hci_ext_fs *) &pi->remote_fs);
+ chan = hci_chan_add(hdev);
+ if (chan) {
+ chan->conn = hcon;
+ sock_hold(sk);
+ chan->l2cap_sk = sk;
+ hci_chan_hold(chan);
+ pi->ampchan = chan;
+ hci_chan_create(chan,
+ (struct hci_ext_fs *) &pi->local_fs,
+ (struct hci_ext_fs *) &pi->remote_fs);
}
done:
hci_dev_put(hdev);
@@ -3625,14 +3630,10 @@
struct hci_chan *chan;
/* Trigger logical link creation only on AMP */
- chan = l2cap_chan_admit(pi->amp_id, pi);
+ chan = l2cap_chan_admit(pi->amp_id, sk);
if (!chan)
return -ECONNREFUSED;
- hci_chan_hold(chan);
- pi->ampchan = chan;
- chan->l2cap_sk = sk;
-
if (chan->state == BT_CONNECTED)
l2cap_create_cfm(chan, 0);
}
@@ -4466,17 +4467,13 @@
/* Already sent a 'pending' response, so set up
* the logical link now
*/
- chan = l2cap_chan_admit(pi->amp_id, pi);
+ chan = l2cap_chan_admit(pi->amp_id, sk);
if (!chan) {
l2cap_send_disconn_req(pi->conn, sk,
ECONNRESET);
goto done;
}
- hci_chan_hold(chan);
- pi->ampchan = chan;
- chan->l2cap_sk = sk;
-
if (chan->state == BT_CONNECTED)
l2cap_create_cfm(chan, 0);
}
@@ -5004,7 +5001,7 @@
}
pi->remote_fs = default_fs;
pi->local_fs = default_fs;
- chan = l2cap_chan_admit(pi->amp_move_id, pi);
+ chan = l2cap_chan_admit(pi->amp_move_id, sk);
if (!chan) {
/* Logical link not available */
l2cap_send_move_chan_cfm(conn, pi, pi->scid,
@@ -5012,10 +5009,6 @@
break;
}
- hci_chan_hold(chan);
- pi->ampchan = chan;
- chan->l2cap_sk = sk;
-
if (chan->state == BT_CONNECTED) {
/* Logical link is already ready to go */
pi->ampcon = chan->conn;
@@ -5323,12 +5316,8 @@
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
pi->remote_fs = default_fs;
pi->local_fs = default_fs;
- chan = l2cap_chan_admit(local_id, pi);
+ chan = l2cap_chan_admit(local_id, sk);
if (chan) {
- hci_chan_hold(chan);
- pi->ampchan = chan;
- chan->l2cap_sk = sk;
-
if (chan->state == BT_CONNECTED) {
/* Logical link is ready to go */
pi->ampcon = chan->conn;
@@ -5465,7 +5454,9 @@
} else if ((pi->amp_move_state !=
L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS) &&
(pi->amp_move_state !=
- L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM)) {
+ L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM) &&
+ (pi->amp_move_state !=
+ L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP)) {
/* Move was not in expected state, free the channel */
ampchan = pi->ampchan;
ampcon = pi->ampcon;
@@ -5544,9 +5535,7 @@
{
struct l2cap_logical_link_work *amp_work;
- if (chan->l2cap_sk) {
- sock_hold(chan->l2cap_sk);
- } else {
+ if (!chan->l2cap_sk) {
BT_ERR("Expected l2cap_sk to point to connecting socket");
return -EFAULT;
}
@@ -7361,7 +7350,7 @@
bh_unlock_sock(sk);
} else if (cid == L2CAP_CID_A2MP) {
BT_DBG("A2MP");
- amp_conn_ind(conn, skb);
+ amp_conn_ind(conn->hcon, skb);
} else {
BT_DBG("unknown cid 0x%4.4x", cid);
kfree_skb(skb);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ddb650b..bcd0dd7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1614,13 +1614,9 @@
hci_dev_lock_bh(hdev);
io_cap = cp->io_cap;
- if (io_cap == 0x03) {
- sec_level = BT_SECURITY_MEDIUM;
- auth_type = HCI_AT_DEDICATED_BONDING;
- } else {
- sec_level = BT_SECURITY_HIGH;
- auth_type = HCI_AT_DEDICATED_BONDING_MITM;
- }
+
+ sec_level = BT_SECURITY_MEDIUM;
+ auth_type = HCI_AT_DEDICATED_BONDING;
entry = hci_find_adv_entry(hdev, &cp->bdaddr);
if (entry && entry->flags & 0x04) {
@@ -2921,7 +2917,7 @@
if (conn->rssi_update_thresh_exceed == 1) {
BT_DBG("rssi_update_thresh_exceed == 1");
- if (rssi >= conn->rssi_threshold) {
+ if (rssi > conn->rssi_threshold) {
memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr);
ev.rssi = rssi;
@@ -2934,7 +2930,7 @@
}
} else {
BT_DBG("rssi_update_thresh_exceed == 0");
- if (rssi <= conn->rssi_threshold) {
+ if (rssi < conn->rssi_threshold) {
memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr);
ev.rssi = rssi;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index c49317c..b65fd65 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -832,7 +832,7 @@
ldo->voltage = voltage;
ldo->dev = regulator_register(&ldo->desc, codec->dev,
- init_data, ldo);
+ init_data, ldo, NULL);
if (IS_ERR(ldo->dev)) {
int ret = PTR_ERR(ldo->dev);
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 65fe16d..c9c8e25 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -2283,6 +2283,10 @@
wcd9xxx_close_slim_sch_rx(sitar,
sitar_p->dai[j].ch_num,
sitar_p->dai[j].ch_tot);
+ /* Wait for remove channel to complete
+ * before derouting Rx path
+ */
+ usleep_range(15000, 15000);
sitar_p->dai[j].rate = 0;
memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
sitar_p->dai[j].ch_tot));
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 2c43792..d49e215 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -209,6 +209,15 @@
MBHC_STATE_RELEASE,
};
+struct hpf_work {
+ struct tabla_priv *tabla;
+ u32 decimator;
+ u8 tx_hpf_cut_of_freq;
+ struct delayed_work dwork;
+};
+
+static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
struct tabla_priv {
struct snd_soc_codec *codec;
struct tabla_reg_address reg_addr;
@@ -2279,6 +2288,9 @@
break;
case SND_SOC_DAPM_POST_PMU:
+
+ usleep_range(20000, 20000);
+
if (tabla->mbhc_polling_active &&
tabla->mbhc_cfg.micbias == micb_line) {
TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
@@ -2310,14 +2322,73 @@
return 0;
}
+
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+ struct delayed_work *hpf_delayed_work;
+ struct hpf_work *hpf_work;
+ struct tabla_priv *tabla;
+ struct snd_soc_codec *codec;
+ u16 tx_mux_ctl_reg;
+ u8 hpf_cut_of_freq;
+
+ hpf_delayed_work = to_delayed_work(work);
+ hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+ tabla = hpf_work->tabla;
+ codec = hpf_work->tabla->codec;
+ hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+ tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
+ (hpf_work->decimator - 1) * 8;
+
+ pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
+ hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
+#define CF_MIN_3DB_4HZ 0x0
+#define CF_MIN_3DB_75HZ 0x1
+#define CF_MIN_3DB_150HZ 0x2
+
static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u16 dec_reset_reg;
+ unsigned int decimator;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ int ret = 0;
+ u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+ u8 dec_hpf_cut_of_freq;
pr_debug("%s %d\n", __func__, event);
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
+ if (ret < 0) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+ w->name, dec_name, decimator);
+
if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
@@ -2327,14 +2398,68 @@
return -EINVAL;
}
+ tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
+ tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+
+ // Enableable TX digital mute */
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+
snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1 << w->shift);
snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+
+ dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+ dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+ tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+ dec_hpf_cut_of_freq;
+
+ if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
+
+ /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+ CF_MIN_3DB_150HZ << 4);
+ }
+
+ /* enable HPF */
+ snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
+
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+
+ /* Disable TX digital mute */
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+
+ if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+ CF_MIN_3DB_150HZ) {
+
+ schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+ msecs_to_jiffies(300));
+ }
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+ cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+ (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+
break;
}
- return 0;
+out:
+ kfree(widget_name);
+ return ret;
}
static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
@@ -3591,6 +3716,7 @@
ret = wcd9xxx_close_slim_sch_rx(tabla,
tabla_p->dai[j].ch_num,
tabla_p->dai[j].ch_tot);
+ usleep_range(5000, 5000);
tabla_p->dai[j].rate = 0;
memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
tabla_p->dai[j].ch_tot));
@@ -3857,34 +3983,54 @@
tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
- &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec1_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
- &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec2_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
- &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec3_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
- &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec4_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
- &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec5_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
- &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec6_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
- &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec7_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
- &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec8_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
- &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec9_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
- &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ &dec10_mux, tabla_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
@@ -5609,7 +5755,6 @@
tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
false);
} else {
- wcd9xxx_lock_sleep(core);
ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
if (ret != 0) {
pr_debug("%s: Complete plug insertion, Detecting plug "
@@ -6470,6 +6615,12 @@
dev_err(codec->dev, "Failed to allocate private data\n");
return -ENOMEM;
}
+ for (i = 0 ; i < NUM_DECIMATORS; i++) {
+ tx_hpf_work[i].tabla = tabla;
+ tx_hpf_work[i].decimator = i + 1;
+ INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+ tx_hpf_corner_freq_callback);
+ }
/* Make sure mbhc micbias register addresses are zeroed out */
memset(&tabla->mbhc_bias_regs, 0,
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index c45351e..3dca43b 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -24,6 +24,7 @@
#include <sound/apr_audio.h>
#include <sound/q6afe.h>
#include <sound/msm-dai-q6.h>
+#include <sound/pcm_params.h>
#include <mach/clk.h>
enum {
@@ -286,27 +287,6 @@
return 0;
}
-static int get_frame_size(u16 rate, u16 ch)
-{
- if (rate == 8000) {
- if (ch == 1)
- return 128 * 2;
- else
- return 128 * 2 * 2;
- } else if (rate == 16000) {
- if (ch == 1)
- return 128 * 2 * 2;
- else
- return 128 * 2 * 4;
- } else if (rate == 48000) {
- if (ch == 1)
- return 128 * 2 * 6;
- else
- return 128 * 2 * 12;
- } else
- return 128 * 2 * 12;
-}
-
static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
@@ -321,8 +301,7 @@
dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
dai_data->port_config.rtproxy.interleaved = 1;
- dai_data->port_config.rtproxy.frame_sz = get_frame_size(dai_data->rate,
- dai_data->port_config.rtproxy.num_ch);
+ dai_data->port_config.rtproxy.frame_sz = params_period_bytes(params);
dai_data->port_config.rtproxy.jitter =
dai_data->port_config.rtproxy.frame_sz/2;
dai_data->port_config.rtproxy.lw_mark = 0;
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index a176118..2135a35 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -63,7 +63,6 @@
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
if (prtd->start) {
- snd_pcm_period_elapsed(prtd->substream);
pr_debug("sending frame to DSP: poll_time: %d\n",
prtd->poll_time);
if (prtd->dsp_cnt == runtime->periods)
@@ -74,10 +73,6 @@
snd_pcm_lib_period_bytes(prtd->substream))),
snd_pcm_lib_period_bytes(prtd->substream));
prtd->dsp_cnt++;
- prtd->poll_time = ((unsigned long)((
- snd_pcm_lib_period_bytes(prtd->substream)
- * 1000 * 1000)/(runtime->rate
- * runtime->channels * 2)));
hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
* 1000));
@@ -99,10 +94,6 @@
* snd_pcm_lib_period_bytes(prtd->substream))),
snd_pcm_lib_period_bytes(prtd->substream));
prtd->dsp_cnt++;
- prtd->poll_time = ((unsigned long)((
- snd_pcm_lib_period_bytes(prtd->substream)
- * 1000 * 1000)/(runtime->rate
- * runtime->channels * 2)));
pr_debug("sending frame rec to DSP: poll_time: %d\n",
prtd->poll_time);
hrtimer_forward_now(hrt, ns_to_ktime(prtd->poll_time
@@ -140,11 +131,11 @@
1000 * 1000)/
(runtime->rate *
runtime->channels * 2)));
- pr_info("prtd->poll_time: %d",
+ pr_debug("prtd->poll_time: %d",
prtd->poll_time);
hrtimer_start(&prtd->hrt,
- ns_to_ktime(prtd->poll_time * 1000),
- HRTIMER_MODE_REL);
+ ns_to_ktime(0),
+ HRTIMER_MODE_REL);
break;
}
case AFE_EVENT_RTPORT_STOP:
@@ -169,6 +160,7 @@
pr_debug("write done\n");
prtd->pcm_irq_pos += snd_pcm_lib_period_bytes
(prtd->substream);
+ snd_pcm_period_elapsed(prtd->substream);
break;
default:
break;
@@ -208,9 +200,9 @@
* 1000 * 1000)/(runtime->rate
* runtime->channels * 2)));
hrtimer_start(&prtd->hrt,
- ns_to_ktime(prtd->poll_time * 1000),
- HRTIMER_MODE_REL);
- pr_info("prtd->poll_time : %d", prtd->poll_time);
+ ns_to_ktime(0),
+ HRTIMER_MODE_REL);
+ pr_debug("prtd->poll_time : %d", prtd->poll_time);
break;
}
case AFE_EVENT_RTPORT_STOP:
@@ -265,7 +257,7 @@
pr_err("afe-pcm:register for events failed\n");
return ret;
}
- pr_info("%s:success\n", __func__);
+ pr_debug("%s:success\n", __func__);
prtd->prepared++;
return ret;
}
@@ -287,7 +279,7 @@
pr_err("afe-pcm:register for events failed\n");
return ret;
}
- pr_info("%s:success\n", __func__);
+ pr_debug("%s:success\n", __func__);
prtd->prepared++;
return 0;
}
@@ -526,7 +518,7 @@
struct snd_card *card = rtd->card->snd_card;
int ret = 0;
- pr_err("%s\n", __func__);
+ pr_debug("%s\n", __func__);
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
return ret;
@@ -534,7 +526,7 @@
static int msm_afe_afe_probe(struct snd_soc_platform *platform)
{
- pr_err("%s\n", __func__);
+ pr_debug("%s\n", __func__);
return 0;
}
@@ -546,14 +538,14 @@
static __devinit int msm_afe_probe(struct platform_device *pdev)
{
- pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
}
static int msm_afe_remove(struct platform_device *pdev)
{
- pr_err("%s\n", __func__);
+ pr_debug("%s\n", __func__);
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
@@ -569,14 +561,14 @@
static int __init msm_soc_platform_init(void)
{
- pr_err("%s\n", __func__);
+ pr_debug("%s\n", __func__);
return platform_driver_register(&msm_afe_driver);
}
module_init(msm_soc_platform_init);
static void __exit msm_soc_platform_exit(void)
{
- pr_err("%s\n", __func__);
+ pr_debug("%s\n", __func__);
platform_driver_unregister(&msm_afe_driver);
}
module_exit(msm_soc_platform_exit);
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index ed880e8..dd194d6 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -638,6 +638,8 @@
return -ENOMEM;
}
buf = prtd->audio_client->port[dir].buf;
+ if (buf == NULL || buf[0].data == NULL)
+ return -ENOMEM;
pr_debug("%s:buf = %p\n", __func__, buf);
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
index 6408cef..f814a21 100644
--- a/sound/soc/msm/msm7201.c
+++ b/sound/soc/msm/msm7201.c
@@ -197,6 +197,12 @@
} req;
snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+
+ if (ucontrol->value.integer.value[1] > 1)
+ ucontrol->value.integer.value[1] = 1;
+ if (ucontrol->value.integer.value[2] > 1)
+ ucontrol->value.integer.value[2] = 1;
+
req.hdr.type = 0;
req.hdr.rpc_vers = 2;
@@ -221,6 +227,8 @@
printk(KERN_INFO "snd device connected\n");
snd_mute_ear_mute = ucontrol->value.integer.value[1];
snd_mute_mic_mute = ucontrol->value.integer.value[2];
+ printk(KERN_ERR "%s: snd_mute_ear_mute =%d, snd_mute_mic_mute = %d\n",
+ __func__, snd_mute_ear_mute, snd_mute_mic_mute);
}
return rc;
@@ -251,7 +259,7 @@
static struct snd_kcontrol_new snd_msm_controls[] = {
MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
- MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
+ MSM_EXT("device", 0, snd_msm_device_info, snd_msm_device_get, \
snd_msm_device_put, 0),
};
@@ -331,6 +339,8 @@
}
ret = msm_snd_rpc_connect();
+ snd_mute_ear_mute = 0;
+ snd_mute_mic_mute = 0;
return ret;
}
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index a3e1c13..f928c00 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -328,9 +328,7 @@
if ((open.topology_id ==
VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
(open.topology_id ==
- VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
- (open.topology_id ==
- VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY))
+ VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 3b46a50..728d856 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -1990,8 +1990,7 @@
if (v->st_enable)
voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST,
v->st_enable);
- if (v->fens_enable)
- voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_FENS,
+ voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_FENS,
v->fens_enable);
if (is_voip_session(v->session_id))
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 3063f3e..265df9e 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -60,6 +60,7 @@
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_supply] = 1,
[snd_soc_dapm_micbias] = 2,
+ [snd_soc_dapm_adc] = 3,
[snd_soc_dapm_mic] = 4,
[snd_soc_dapm_mux] = 5,
[snd_soc_dapm_virt_mux] = 5,
@@ -70,7 +71,6 @@
[snd_soc_dapm_pga] = 8,
[snd_soc_dapm_aif_in] = 8,
[snd_soc_dapm_aif_out] = 8,
- [snd_soc_dapm_adc] = 9,
[snd_soc_dapm_out_drv] = 10,
[snd_soc_dapm_hp] = 10,
[snd_soc_dapm_spk] = 10,