Merge "msm: 8960: Configure GPIO 23 as External VFR for SGLTE platforms" into msm-3.0
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
new file mode 100644
index 0000000..11af7a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -0,0 +1,15 @@
+* Qualcomm MSM VIDC
+
+Required properties:
+- compatible : one of:
+ - "qcom,msm-vidc"
+- reg : offset and length of the register set for the device.
+- interrupts : should contain the vidc interrupt.
+
+Example:
+
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0xfdc00000 0xff000>;
+ interrupts = <0 44 0>;
+ };
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 393d48b..48d5720 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -358,4 +358,36 @@
};
};
};
+
+ krait0_vreg: regulator@f9088000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait0";
+ reg = <0xf9088000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait1_vreg: regulator@f9098000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait1";
+ reg = <0xf9098000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait2_vreg: regulator@f90a8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait2";
+ reg = <0xf90a8000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait3_vreg: regulator@f90b8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait3";
+ reg = <0xf90b8000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
index 8c00535..d6e23ad 100644
--- a/arch/arm/boot/dts/msmcopper-rumi.dts
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -30,11 +30,19 @@
status = "disable";
};
- qcom,sdcc@f980b000 {
+ qcom,sdcc@f9824000 {
status = "disable";
};
- qcom,sdcc@f984b000 {
+ qcom,sdcc@f9864000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f98a4000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f98e4000 {
status = "disable";
};
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
index ab6b8ba..ae3f2dd 100644
--- a/arch/arm/boot/dts/msmcopper-sim.dts
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -17,4 +17,22 @@
/ {
model = "Qualcomm MSM Copper Simulator";
compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
+
+ qcom,sdcc@f9824000 {
+ qcom,sdcc-disable_cmd23;
+ };
+
+ qcom,sdcc@f98a4000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f9864000 {
+ qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sdcc-sup-voltages = <2950 2950>;
+ qcom,sdcc-disable_cmd23;
+ };
+
+ qcom,sdcc@f98e4000 {
+ status = "disable";
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index db44d13..69aff33 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -44,6 +44,12 @@
clock-frequency = <19200000>;
};
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0xfdc00000 0xff000>;
+ interrupts = <0 44 0>;
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -69,30 +75,50 @@
qcom,hsusb-otg-otg-control = <1>;
};
- qcom,sdcc@f980b000 {
+ qcom,sdcc@f9824000 {
cell-index = <1>;
compatible = "qcom,msm-sdcc";
- reg = <0xf980b000 0x1000>;
+ reg = <0xf9824000 0x1000>;
interrupts = <0 123 0>;
- qcom,sdcc-clk-rates = <400000 25000000 50000000 96000000 192000000>;
- qcom,sdcc-sup-voltages = <3300 3300>;
+ qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sdcc-sup-voltages = <2950 2950>;
qcom,sdcc-bus-width = <8>;
qcom,sdcc-hs200;
qcom,sdcc-nonremovable;
- qcom,sdcc-disable_cmd23;
};
- qcom,sdcc@f984b000 {
+ qcom,sdcc@f98a4000 {
+ cell-index = <2>;
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf98a4000 0x1000>;
+ interrupts = <0 125 0>;
+
+ qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sdcc-sup-voltages = <2950 2950>;
+ qcom,sdcc-bus-width = <4>;
+ };
+
+ qcom,sdcc@f9864000 {
cell-index = <3>;
compatible = "qcom,msm-sdcc";
- reg = <0xf984b000 0x1000>;
+ reg = <0xf9864000 0x1000>;
interrupts = <0 127 0>;
- qcom,sdcc-clk-rates = <400000 25000000 50000000>;
- qcom,sdcc-sup-voltages = <3300 3300>;
+ qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+ qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
- qcom,sdcc-disable_cmd23;
+ };
+
+ qcom,sdcc@f98e4000 {
+ cell-index = <4>;
+ compatible = "qcom,msm-sdcc";
+ reg = <0xf98e4000 0x1000>;
+ interrupts = <0 129 0>;
+
+ qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
+ qcom,sdcc-sup-voltages = <1800 1800>;
+ qcom,sdcc-bus-width = <4>;
};
qcom,sps@f9980000 {
@@ -265,4 +291,8 @@
qcom,firmware-name = "wcnss";
};
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm_ocmem";
+ };
};
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 875b479..99747ba 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -212,10 +212,13 @@
{
unsigned int i;
void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+ unsigned long flags;
+#endif
for (i = 0; i * 32 < gic->max_irq; i++) {
#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock(&irq_controller_lock);
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
#endif
gic->enabled_irqs[i]
= readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
@@ -225,7 +228,7 @@
writel_relaxed(gic->wakeup_irqs[i],
base + GIC_DIST_ENABLE_SET + i * 4);
#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock(&irq_controller_lock);
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
#endif
}
mb();
@@ -248,17 +251,28 @@
u32 enabled;
unsigned long pending[32];
void __iomem *base = gic_data_dist_base(gic);
+#ifdef CONFIG_ARCH_MSM8625
+ unsigned long flags;
+#endif
if (!msm_show_resume_irq_mask)
return;
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
+#else
raw_spin_lock(&irq_controller_lock);
+#endif
for (i = 0; i * 32 < gic->max_irq; i++) {
enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
pending[i] &= enabled;
}
- raw_spin_unlock(&irq_controller_lock);
+#ifdef CONFIG_ARCH_MSM8625
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+#else
+ raw_spin_lock(&irq_controller_lock);
+#endif
for (i = find_first_bit(pending, gic->max_irq);
i < gic->max_irq;
@@ -272,11 +286,13 @@
{
unsigned int i;
void __iomem *base = gic_data_dist_base(gic);
-
+#ifdef CONFIG_ARCH_MSM8625
+ unsigned long flags;
+#endif
gic_show_resume_irq(gic);
for (i = 0; i * 32 < gic->max_irq; i++) {
#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock(&irq_controller_lock);
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
#endif
/* disable all of them */
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
@@ -284,7 +300,7 @@
writel_relaxed(gic->enabled_irqs[i],
base + GIC_DIST_ENABLE_SET + i * 4);
#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock(&irq_controller_lock);
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
#endif
}
mb();
@@ -1128,8 +1144,9 @@
unsigned long value = 0;
struct gic_chip_data *gic = &gic_data[0];
void __iomem *base = gic_data_dist_base(gic);
+ unsigned long flags;
- raw_spin_lock(&irq_controller_lock);
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
/*
* PPI and SGI to be included.
* MSM8625_INT_A9_M2A_5 needs to be ignored, as A9_M2A_5
@@ -1146,13 +1163,14 @@
for (bit = 0; bit < 32; bit++) {
bit = find_next_bit(&value, 32, bit);
if ((bit + 32 * i) != MSM8625_INT_A9_M2A_5) {
- raw_spin_unlock(&irq_controller_lock);
+ raw_spin_unlock_irqrestore(
+ &irq_controller_lock, flags);
return 1;
}
}
}
}
- raw_spin_unlock(&irq_controller_lock);
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
return 0;
}
@@ -1165,14 +1183,13 @@
gic_cpu_save(0);
gic_dist_save(0);
- /* Disable all the Interrupts, if we enter from idle pc */
- if (from_idle) {
- for (i = 0; (i * 32) < gic->max_irq; i++) {
- raw_spin_lock(&irq_controller_lock);
- writel_relaxed(0xffffffff, base
- + GIC_DIST_ENABLE_CLEAR + i * 4);
- raw_spin_unlock(&irq_controller_lock);
- }
+
+ /* Disable all the Interrupts, before we enter pc */
+ for (i = 0; (i * 32) < gic->max_irq; i++) {
+ raw_spin_lock(&irq_controller_lock);
+ writel_relaxed(0xffffffff, base
+ + GIC_DIST_ENABLE_CLEAR + i * 4);
+ raw_spin_unlock(&irq_controller_lock);
}
}
@@ -1193,8 +1210,9 @@
struct gic_chip_data *gic = &gic_data[0];
void __iomem *base = gic_data_dist_base(gic);
unsigned int value = 0;
+ unsigned long flags;
- raw_spin_lock(&irq_controller_lock);
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
value |= BIT(8);
@@ -1220,6 +1238,6 @@
value |= BIT(8);
__raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
mb();
- raw_spin_unlock(&irq_controller_lock);
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
#endif
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 64451eb..c644cf9 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -44,6 +44,7 @@
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_LPASS_QDSP6V5=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_OCMEM=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -125,6 +126,12 @@
CONFIG_REGULATOR=y
CONFIG_REGULATOR_STUB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
CONFIG_ION=y
CONFIG_ION_MSM=y
CONFIG_FB=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index f195d68..9a2fa39 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -241,7 +241,7 @@
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_OV5647=y
CONFIG_AD5046_ACT=y
-CONFIG_WEBCAM_OV7692_QRD=y
+CONFIG_OV7692=y
CONFIG_WEBCAM_OV9726=y
CONFIG_MT9E013=y
CONFIG_S5K4E1=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index bc350a7..869fb6d 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -242,7 +242,7 @@
CONFIG_MSM_CAMERA_V4L2=y
CONFIG_OV5647=y
CONFIG_AD5046_ACT=y
-CONFIG_WEBCAM_OV7692_QRD=y
+CONFIG_OV7692=y
CONFIG_WEBCAM_OV9726=y
CONFIG_MT9E013=y
CONFIG_S5K4E1=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index c39b301..11b1f73 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -311,6 +311,7 @@
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
@@ -320,6 +321,7 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
CONFIG_IR_GPIO_CIR=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index dedef45..886a691 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -320,6 +320,7 @@
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
@@ -329,6 +330,7 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_USER_RC_INPUT=y
CONFIG_IR_GPIO_CIR=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
@@ -341,12 +343,12 @@
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
-CONFIG_MSM_GEMINI=y
-CONFIG_S5K3L1YX=y
-CONFIG_IMX091=y
CONFIG_MSM_EEPROM=y
CONFIG_IMX074_EEPROM=y
CONFIG_IMX091_EEPROM=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/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index dabd390..745a3a4 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -8,6 +8,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <mach/gpio.h>
+#include <mach/msm_bus.h>
#define SDC_DAT1_DISABLE 0
#define SDC_DAT1_ENABLE 1
@@ -112,6 +113,12 @@
struct msm_mmc_pad_data *pad_data;
};
+struct msm_mmc_bus_voting_data {
+ struct msm_bus_scale_pdata *use_cases;
+ unsigned int *bw_vecs;
+ unsigned int bw_vecs_size;
+};
+
struct mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
int built_in; /* built-in device flag */
@@ -153,6 +160,7 @@
bool disable_runtime_pm;
bool disable_cmd23;
u32 cpu_dma_latency;
+ struct msm_mmc_bus_voting_data *msm_bus_voting_data;
};
#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 79dd22e..c9d0000 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -8,7 +8,6 @@
select MSM_VIC
select CPU_V6
select MSM_REMOTE_SPINLOCK_SWP
- select MSM_PM if PM
config ARCH_MSM7X25
bool "MSM7x25"
@@ -17,7 +16,6 @@
select CPU_V6
select MSM_REMOTE_SPINLOCK_SWP
select MULTI_IRQ_HANDLER
- select MSM_PM if PM
config ARCH_MSM7X27
bool "MSM7x27"
@@ -36,6 +34,7 @@
select QCACHE
select MSM_PM2 if PM
select MSM_RUN_QUEUE_STATS if MSM_SOC_REV_A
+ select DONT_MAP_HOLE_AFTER_MEMBANK0
config ARCH_MSM7X30
bool "MSM7x30"
@@ -2036,10 +2035,6 @@
config MSM_NATIVE_RESTART
bool
-config MSM_PM
- depends on PM
- bool
-
config MSM_PM2
depends on PM
bool
@@ -2237,6 +2232,12 @@
instead of pmem. Selecting this may also involve userspace
dependencies as well.
+config MSM_OCMEM
+ bool "MSM On-Chip memory driver (OCMEM)"
+ help
+ Enable support for On-Chip Memory available on certain MSM chipsets.
+ OCMEM is a low latency, high performance pool shared by subsystems.
+
config MSM_RTB
bool "Register tracing"
help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 000cf43..2295679 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -152,8 +152,8 @@
obj-$(CONFIG_MSM_HW3D) += hw3d.o
obj-$(CONFIG_PM) += pm-boot.o
obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
obj-$(CONFIG_MSM_PM2) += pm2.o
-obj-$(CONFIG_MSM_PM) += pm.o
obj-$(CONFIG_MSM_NOPM) += no-pm.o
obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
@@ -318,6 +318,7 @@
ifdef CONFIG_VCM
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 041e755..a65c5b0 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -653,23 +653,23 @@
/* TODO: Update core voltages when data is available. */
static struct acpu_level acpu_freq_tbl_8930[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 925000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 937500 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 962500 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 987500 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 925000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 937500 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 962500 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 987500 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 1000000 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1037500 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1062500 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1125000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1137500 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1162500 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1187500 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1200000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1225000 },
{ 0, { 0 } }
};
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 41dccac..e24cac6 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -67,6 +67,21 @@
.src = MSM_BUS_MASTER_GRAPHICS_3D,
.dst = MSM_BUS_SLAVE_EBI_CH0,
.ab = 0,
+ .ib = KGSL_CONVERT_TO_MBPS(1000),
+ },
+ {
+ .src = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = KGSL_CONVERT_TO_MBPS(1000),
+ },
+};
+
+static struct msm_bus_vectors grp3d_nominal_low_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_GRAPHICS_3D,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
.ib = KGSL_CONVERT_TO_MBPS(2000),
},
{
@@ -117,6 +132,10 @@
grp3d_low_vectors,
},
{
+ ARRAY_SIZE(grp3d_nominal_low_vectors),
+ grp3d_nominal_low_vectors,
+ },
+ {
ARRAY_SIZE(grp3d_nominal_high_vectors),
grp3d_nominal_high_vectors,
},
@@ -177,16 +196,21 @@
.pwrlevel = {
{
.gpu_freq = 400000000,
- .bus_freq = 3,
+ .bus_freq = 4,
.io_fraction = 0,
},
{
.gpu_freq = 325000000,
- .bus_freq = 2,
+ .bus_freq = 3,
.io_fraction = 33,
},
{
.gpu_freq = 200000000,
+ .bus_freq = 2,
+ .io_fraction = 100,
+ },
+ {
+ .gpu_freq = 128000000,
.bus_freq = 1,
.io_fraction = 100,
},
@@ -196,7 +220,7 @@
},
},
.init_level = 1,
- .num_levels = 4,
+ .num_levels = 5,
.set_grp_async = NULL,
.idle_timeout = HZ/10,
.nap_allowed = true,
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index b4e7d35..72126c8 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -23,6 +23,7 @@
#include <mach/gpiomux.h>
#include "devices.h"
#include "board-8064.h"
+#include "board-storage-common-a.h"
/* APQ8064 has 4 SDCC controllers */
@@ -219,6 +220,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.uhs_caps = MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *apq8064_sdc1_pdata = &sdc1_data;
#else
@@ -249,6 +251,7 @@
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *apq8064_sdc3_pdata = &sdc3_data;
#else
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index be539d0..ed17cc4 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -427,6 +427,7 @@
apq8064_fmem_pdata.size = 0;
apq8064_fmem_pdata.reserved_size_low = 0;
apq8064_fmem_pdata.reserved_size_high = 0;
+ apq8064_fmem_pdata.align = PAGE_SIZE;
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
@@ -2252,6 +2253,11 @@
},
};
+static struct platform_device rc_input_loopback_pdev = {
+ .name = "rc-user-input",
+ .id = -1,
+};
+
static struct platform_device *mpq_devices[] __initdata = {
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
@@ -2268,6 +2274,7 @@
#ifdef CONFIG_MSM_VCAP
&msm8064_device_vcap,
#endif
+ &rc_input_loopback_pdev,
};
static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index cd4aff8..936a798 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -94,6 +94,12 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting audio_spkr_boost = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct gpiomux_setting gpio_eth_config = {
.pull = GPIOMUX_PULL_NONE,
@@ -389,6 +395,16 @@
},
};
+static struct msm_gpiomux_config msm8960_audio_spkr_configs[] __initdata = {
+ {
+ .gpio = 15,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_spkr_boost,
+ },
+ },
+};
+
+
static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
{
.gpio = 63,
@@ -636,6 +652,9 @@
msm_gpiomux_install(msm8960_audio_mbhc_configs,
ARRAY_SIZE(msm8960_audio_mbhc_configs));
+ msm_gpiomux_install(msm8960_audio_spkr_configs,
+ ARRAY_SIZE(msm8960_audio_spkr_configs));
+
msm_gpiomux_install(msm8960_audio_auxpcm_configs,
ARRAY_SIZE(msm8960_audio_auxpcm_configs));
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index ecebfa9..6dd7add 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -24,6 +24,7 @@
#include "devices.h"
#include "board-8930.h"
+#include "board-storage-common-a.h"
/* MSM8960 has 5 SDCC controllers */
enum sdcc_controllers {
@@ -235,6 +236,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -273,6 +275,7 @@
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -284,6 +287,10 @@
#endif
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
/* SDC3: External card slot */
+ if (!machine_is_msm8930_cdp()) {
+ msm8960_sdc3_data.wpswitch_gpio = 0;
+ msm8960_sdc3_data.wpswitch_polarity = 0;
+ }
msm_add_sdcc(3, &msm8960_sdc3_data);
#endif
}
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 28499dd..1c4251c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -488,6 +488,7 @@
msm8930_fmem_pdata.size = 0;
msm8930_fmem_pdata.reserved_size_low = 0;
msm8930_fmem_pdata.reserved_size_high = 0;
+ msm8930_fmem_pdata.align = PAGE_SIZE;
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index df1d846..10a6903 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -17,12 +17,12 @@
#include <linux/bootmem.h>
#include <asm/mach-types.h>
#include <asm/mach/mmc.h>
-#include <mach/msm_bus_board.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
#include "devices.h"
#include "board-8960.h"
+#include "board-storage-common-a.h"
/* MSM8960 has 5 SDCC controllers */
enum sdcc_controllers {
@@ -299,6 +299,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -316,6 +317,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC2],
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(90),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -342,6 +344,7 @@
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -359,6 +362,7 @@
.vreg_data = &mmc_slot_vreg_data[SDCC4],
.pin_data = &mmc_slot_pin_data[SDCC4],
.sdiowakeup_irq = MSM_GPIO_TO_INT(85),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 0e18918..624cf5e 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -105,6 +105,20 @@
};
#endif
+static struct gpiomux_setting wlan_active_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
+};
+
+static struct gpiomux_setting wlan_suspend_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
{
.gpio = 24,
@@ -251,6 +265,7 @@
.gpio = 16, /* GSBI5 I2C QUP SCL */
.settings = {
[GPIOMUX_SUSPENDED] = &gsbi5,
+ [GPIOMUX_ACTIVE] = &gsbi5,
},
},
{
@@ -306,6 +321,17 @@
};
#endif
+static struct msm_gpiomux_config msm9615_wlan_configs[] __initdata = {
+ {
+ .gpio = 21,/* WLAN_RESET_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wlan_active_config,
+ [GPIOMUX_SUSPENDED] = &wlan_suspend_config,
+ },
+ },
+};
+
+
int __init msm9615_init_gpiomux(void)
{
int rc;
@@ -332,6 +358,9 @@
msm_gpiomux_install(msm9615_audio_codec_configs,
ARRAY_SIZE(msm9615_audio_codec_configs));
+ msm_gpiomux_install(msm9615_wlan_configs,
+ ARRAY_SIZE(msm9615_wlan_configs));
+
#ifdef CONFIG_FB_MSM_EBI2
msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 8328501..0ece37c 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -79,6 +79,10 @@
REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla2x-slim"),
REGULATOR_SUPPLY("VDDD_CDC_D", "tabla-slim"),
REGULATOR_SUPPLY("VDDD_CDC_D", "tabla2x-slim"),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "0-000d"),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "tabla top level"),
};
VREG_CONSUMERS(S3) = {
REGULATOR_SUPPLY("8018_s3", NULL),
@@ -91,6 +95,14 @@
REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla2x-slim"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla2x-slim"),
+ REGULATOR_SUPPLY("VDDIO_CDC", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDD_CP", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla top level"),
+ REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla top level"),
+ REGULATOR_SUPPLY("VDDIO_CDC", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDD_CP", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDDA_TX", "0-000d"),
+ REGULATOR_SUPPLY("CDC_VDDA_RX", "0-000d"),
};
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8018_s4", NULL),
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 7580cc3..5bdeb94 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -22,6 +22,7 @@
#include "devices.h"
#include "board-9615.h"
+#include "board-storage-common-a.h"
#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
@@ -187,6 +188,7 @@
.uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_MAX_CURRENT_400),
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC1_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
#else
@@ -206,6 +208,7 @@
.pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
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 a8602d3..06affd4 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -51,6 +51,7 @@
#include "pm.h"
#include "acpuclock.h"
#include "pm-boot.h"
+#include <mach/gpiomux.h>
#ifdef CONFIG_ION_MSM
#define MSM_ION_AUDIO_SIZE 0xAF000
@@ -126,6 +127,103 @@
};
#endif
+struct pm8xxx_gpio_init {
+ unsigned gpio;
+ struct pm_gpio config;
+};
+
+struct pm8xxx_mpp_init {
+ unsigned mpp;
+ struct pm8xxx_mpp_config_data config;
+};
+
+#define PM8018_GPIO_INIT(_gpio, _dir, _buf, _val, _pull, _vin, _out_strength, \
+ _func, _inv, _disable) \
+{ \
+ .gpio = PM8018_GPIO_PM_TO_SYS(_gpio), \
+ .config = { \
+ .direction = _dir, \
+ .output_buffer = _buf, \
+ .output_value = _val, \
+ .pull = _pull, \
+ .vin_sel = _vin, \
+ .out_strength = _out_strength, \
+ .function = _func, \
+ .inv_int_pol = _inv, \
+ .disable_pin = _disable, \
+ } \
+}
+
+#define PM8018_MPP_INIT(_mpp, _type, _level, _control) \
+{ \
+ .mpp = PM8018_MPP_PM_TO_SYS(_mpp), \
+ .config = { \
+ .type = PM8XXX_MPP_TYPE_##_type, \
+ .level = _level, \
+ .control = PM8XXX_MPP_##_control, \
+ } \
+}
+
+#define PM8018_GPIO_DISABLE(_gpio) \
+ PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, 0, 0, 0, PM8018_GPIO_VIN_S3, \
+ 0, 0, 0, 1)
+
+#define PM8018_GPIO_OUTPUT(_gpio, _val, _strength) \
+ PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+ PM_GPIO_STRENGTH_##_strength, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_INPUT(_gpio, _pull) \
+ PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0, \
+ _pull, PM8018_GPIO_VIN_S3, \
+ PM_GPIO_STRENGTH_NO, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_FUNC(_gpio, _val, _func) \
+ PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, PM8018_GPIO_VIN_S3, \
+ PM_GPIO_STRENGTH_HIGH, \
+ _func, 0, 0)
+
+#define PM8018_GPIO_OUTPUT_VIN(_gpio, _val, _vin) \
+ PM8018_GPIO_INIT(_gpio, PM_GPIO_DIR_OUT, PM_GPIO_OUT_BUF_CMOS, _val, \
+ PM_GPIO_PULL_NO, _vin, \
+ PM_GPIO_STRENGTH_HIGH, \
+ PM_GPIO_FUNC_NORMAL, 0, 0)
+
+/* Initial PM8018 GPIO configurations */
+static struct pm8xxx_gpio_init pm8018_gpios[] __initdata = {
+ PM8018_GPIO_OUTPUT(2, 0, HIGH) /* EXT_LDO_EN_WLAN */
+};
+
+/* Initial PM8018 MPP configurations */
+static struct pm8xxx_mpp_init pm8018_mpps[] __initdata = {
+};
+
+void __init msm9615_pm8xxx_gpio_mpp_init(void)
+{
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(pm8018_gpios); i++) {
+ rc = pm8xxx_gpio_config(pm8018_gpios[i].gpio,
+ &pm8018_gpios[i].config);
+ if (rc) {
+ pr_err("%s: pm8018_gpio_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pm8018_mpps); i++) {
+ rc = pm8xxx_mpp_config(pm8018_mpps[i].mpp,
+ &pm8018_mpps[i].config);
+ if (rc) {
+ pr_err("%s: pm8018_mpp_config: rc=%d\n", __func__, rc);
+ break;
+ }
+ }
+}
+
static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
{"vcoin", CHANNEL_VCOIN, CHAN_PATH_SCALING2, AMUX_RSV1,
ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
@@ -295,6 +393,95 @@
#define TABLA_INTERRUPT_BASE (NR_MSM_IRQS + NR_GPIO_IRQS)
+/*
+ * MDM9x15 I2S.
+ */
+static struct wcd9xxx_pdata wcd9xxx_i2c_platform_data = {
+ .irq = MSM_GPIO_TO_INT(85),
+ .irq_base = TABLA_INTERRUPT_BASE,
+ .num_irqs = NR_TABLA_IRQS,
+ .reset_gpio = 84,
+ .micbias = {
+ .ldoh_v = TABLA_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .cfilt3_mv = 1800,
+ .bias1_cfilt_sel = TABLA_CFILT1_SEL,
+ .bias2_cfilt_sel = TABLA_CFILT2_SEL,
+ .bias3_cfilt_sel = TABLA_CFILT3_SEL,
+ .bias4_cfilt_sel = TABLA_CFILT3_SEL,
+ },
+ .regulator = {
+ {
+ .name = "CDC_VDD_CP",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_CDC_VDDA_CP_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_RX",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_CDC_VDDA_RX_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_TX",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_CDC_VDDA_TX_CUR_MAX,
+ },
+ {
+ .name = "VDDIO_CDC",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .optimum_uA = WCD9XXX_VDDIO_CDC_CUR_MAX,
+ },
+ {
+ .name = "VDDD_CDC_D",
+ .min_uV = 1225000,
+ .max_uV = 1225000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_A_1P2V",
+ .min_uV = 1225000,
+ .max_uV = 1225000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+ }
+ },
+};
+
+static struct i2c_board_info wcd9xxx_device_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("tabla top level", TABLA_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("tabla analog", TABLA_ANALOG_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("tabla digital1", TABLA_DIGITAL1_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+ {
+ I2C_BOARD_INFO("tabla digital2", TABLA_DIGITAL2_I2C_SLAVE_ADDR),
+ .platform_data = &wcd9xxx_i2c_platform_data,
+ },
+};
+
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+ wcd9xxx_device_info,
+ ARRAY_SIZE(wcd9xxx_device_info),
+ },
+};
+/*
+ * MDM9x15 I2S.
+ */
+
/* Micbias setting is based on 8660 CDP/MTP/FLUID requirement
* 4 micbiases are used to power various analog and digital
* microphones operating at 1800 mV. Technically, all micbiases
@@ -310,7 +497,7 @@
.name = "tabla-slave",
.e_addr = {0, 0, 0x60, 0, 0x17, 2},
},
- .irq = 85,
+ .irq = MSM_GPIO_TO_INT(85),
.irq_base = TABLA_INTERRUPT_BASE,
.num_irqs = NR_WCD9XXX_IRQS,
.reset_gpio = 84,
@@ -700,6 +887,8 @@
&msm_stub_codec,
&msm_voice,
&msm_voip,
+ &msm_i2s_cpudai0,
+ &msm_i2s_cpudai1,
&msm_pcm_hostless,
&msm_cpudai_afe_01_rx,
&msm_cpudai_afe_01_tx,
@@ -728,8 +917,27 @@
static void __init msm9615_i2c_init(void)
{
+ u8 mach_mask = 0;
+ int i;
+ /* Mask is hardcoded to SURF (CDP).
+ * works on MTP with same configuration.
+ */
+ mach_mask = I2C_SURF;
+ if (machine_is_msm9615_cdp())
+ mach_mask = I2C_SURF;
+ else if (machine_is_msm9615_mtp())
+ mach_mask = I2C_FFA;
+ else
+ pr_err("unmatched machine ID in register_i2c_devices\n");
msm9615_device_qup_i2c_gsbi5.dev.platform_data =
&msm9615_i2c_qup_gsbi5_pdata;
+ for (i = 0; i < ARRAY_SIZE(msm9615_i2c_devices); ++i) {
+ if (msm9615_i2c_devices[i].machs & mach_mask) {
+ i2c_register_board_info(msm9615_i2c_devices[i].bus,
+ msm9615_i2c_devices[i].info,
+ msm9615_i2c_devices[i].len);
+ }
+ }
}
static void __init msm9615_reserve(void)
@@ -765,7 +973,7 @@
&msm_hsic_peripheral_pdata;
msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
-
+ msm9615_pm8xxx_gpio_mpp_init();
acpuclk_init(&acpuclk_9615_soc_data);
/* Ensure ar6000pm device is registered before MMC/SDC */
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 7dd003f..80656b3 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.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
@@ -17,6 +17,34 @@
#include <linux/mfd/pm8xxx/pm8018.h>
#include <linux/regulator/gpio-regulator.h>
+/*
+ * MDM9x15 I2S.
+ */
+#ifdef CONFIG_I2C
+#define I2C_SURF 1
+#define I2C_FFA (1 << 1)
+#define I2C_RUMI (1 << 2)
+#define I2C_SIM (1 << 3)
+#define I2C_FLUID (1 << 4)
+#define I2C_LIQUID (1 << 5)
+
+struct i2c_registry {
+ u8 machs;
+ int bus;
+ struct i2c_board_info *info;
+ int len;
+};
+#endif
+/* Tabla slave address for I2C */
+#define TABLA_I2C_SLAVE_ADDR 0x0d
+#define TABLA_ANALOG_I2C_SLAVE_ADDR 0x77
+#define TABLA_DIGITAL1_I2C_SLAVE_ADDR 0x66
+#define TABLA_DIGITAL2_I2C_SLAVE_ADDR 0x55
+#define MSM_9615_GSBI5_QUP_I2C_BUS_ID 0
+/*
+ * MDM9x15 I2S.
+ */
+
/* Macros assume PMIC GPIOs and MPPs start at 1 */
#define PM8018_GPIO_BASE NR_GPIO_IRQS
#define PM8018_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8018_GPIO_BASE)
@@ -36,7 +64,7 @@
#define GPIO_VREG_ID_EXT_2P95V 0
extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
-
+uint32_t msm9615_rpm_get_swfi_latency(void);
int msm9615_init_gpiomux(void);
void msm9615_init_mmc(void);
void mdm9615_allocate_fb_region(void);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 14efac4..d33f478 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -51,7 +51,7 @@
#else
#define MSM_ION_SF_SIZE 0x2800000 /* 40 Mbytes */
#endif
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE 0xa00000 /* (10MB) */
#define MSM_ION_MM_SIZE 0x7800000 /* (120MB) */
#define MSM_ION_QSECOM_SIZE 0x100000 /* (1MB) */
#define MSM_ION_MFC_SIZE SZ_8K
@@ -463,10 +463,14 @@
"spi_qsd.1", NULL),
OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
"spmi-pmic-arb.0", NULL),
- OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF980B000, \
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
- OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF984B000, \
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
+ "msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9864000, \
"msm_sdcc.3", NULL),
+ OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98E4000, \
+ "msm_sdcc.4", NULL),
OF_DEV_AUXDATA("qcom,pil-q6v5-lpass", 0xFE200000, \
"pil-q6v5-lpass", NULL),
OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 329dcae..251c97a 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -75,7 +75,7 @@
.gpio_no_mux = 1,
};
-#ifdef CONFIG_WEBCAM_OV7692_QRD
+#ifdef CONFIG_OV7692
static struct gpio ov7692_cam_req_gpio[] = {
{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_DIR_OUT, "CAM_VGA_SHDN"},
{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_DIR_OUT, "CAM_VGA_RESET"},
@@ -86,8 +86,6 @@
{GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_LOW, 5000},
{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_HIGH, 5000},
{GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_LOW, 5000},
- {40, GPIOF_OUT_INIT_HIGH, 5000},
- {35, GPIOF_OUT_INIT_HIGH, 5000},
};
static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
@@ -196,7 +194,7 @@
};
#endif
-#ifdef CONFIG_WEBCAM_OV7692_QRD
+#ifdef CONFIG_OV7692
static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
.mount_angle = 90,
.cam_vreg = msm_cam_vreg,
@@ -212,6 +210,7 @@
.sensor_name = "ov7692",
.sensor_reset_enable = 0,
.pmic_gpio_enable = 1,
+ .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU1_CAM_VGA_RESET_N,
.sensor_pwd = GPIO_SKU1_CAM_VGA_SHDN,
.pdata = &msm_camera_device_data_csi0[0],
@@ -255,6 +254,7 @@
.sensor_name = "ov5647",
.sensor_reset_enable = 1,
.pmic_gpio_enable = 1,
+ .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
.sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
.pdata = &msm_camera_device_data_csi1[0],
@@ -1099,8 +1099,6 @@
GPIO_SKU7_CAM_VGA_SHDN;
ov7692_cam_gpio_set_tbl[0].gpio = GPIO_SKU7_CAM_VGA_SHDN;
ov7692_cam_gpio_set_tbl[1].gpio = GPIO_SKU7_CAM_VGA_SHDN;
- ov7692_cam_gpio_set_tbl[4].gpio = LCD_CAMERA_LDO_2V8 ;
- ov7692_cam_gpio_set_tbl[5].gpio = SKU7_LCD_CAMERA_LDO_1V8;
msm_camera_sensor_ov5647_data.sensor_pwd =
GPIO_SKU7_CAM_5MP_SHDN_N;
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 49945d0..23df1cf 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -125,6 +125,11 @@
KEY_VOLUMEDOWN,
};
+static const unsigned short keymap_8625_evt[] = {
+ KEY_VOLUMEDOWN,
+ KEY_VOLUMEUP,
+};
+
static struct gpio_event_matrix_info kp_matrix_info_8625 = {
.info.func = gpio_event_matrix_func,
.keymap = keymap_8625,
@@ -241,7 +246,7 @@
/* T6 Object */
0, 0, 0, 0, 0, 0,
/* T38 Object */
- 16, 0, 0, 0, 0, 0, 0, 0,
+ 16, 1, 0, 0, 0, 0, 0, 0,
/* T7 Object */
32, 16, 50,
/* T8 Object */
@@ -853,7 +858,11 @@
#endif
/* keypad */
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ if (machine_is_msm8625_evt())
+ kp_matrix_info_8625.keymap = keymap_8625_evt;
+
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt())
platform_device_register(&kp_pdev_8625);
else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
platform_device_register(&kp_pdev_sku3);
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 93a430b..43937b8 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -152,7 +152,6 @@
{
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evb()
- || machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7())
gpio_sdc1_hw_det = 42;
@@ -257,7 +256,6 @@
if (machine_is_msm7627a_qrd1() ||
machine_is_msm7627a_evb() ||
machine_is_msm8625_evb() ||
- machine_is_msm8625_evt() ||
machine_is_msm7627a_qrd3() ||
machine_is_msm8625_qrd7())
status = !gpio_get_value(gpio_sdc1_hw_det);
@@ -384,7 +382,14 @@
gpio_sdc1_config();
if (mmc_regulator_init(1, "mmc", 2850000))
return;
- sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ /* 8x25 EVT do not use hw detector */
+ if (!(machine_is_msm8625_evt()))
+ sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+ if (machine_is_msm8625_evt())
+ sdc1_plat_data.status = NULL;
+#endif
+
msm_add_sdcc(1, &sdc1_plat_data);
#endif
/* SDIO WLAN slot */
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 413a28c..4357e01 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -103,6 +103,7 @@
#endif
void __init msm7627a_camera_init(void);
+int lcd_camera_power_onoff(int on);
void __init msm7627a_add_io_devices(void);
void __init qrd7627a_add_io_devices(void);
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index df4ca83..9ec618d 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -760,9 +760,9 @@
static void msm7x27a_cfg_uart2dm_serial(void) { }
#endif
-struct fmem_platform_data fmem_pdata;
+static struct fmem_platform_data fmem_pdata;
-struct platform_device fmem_device = {
+static struct platform_device fmem_device = {
.name = "fmem",
.id = 1,
.dev = { .platform_data = &fmem_pdata },
@@ -883,6 +883,7 @@
android_pmem_audio_pdata.size = pmem_audio_size;
fmem_pdata.size = 0;
+ fmem_pdata.align = PAGE_SIZE;
/* Find pmem devices that should use FMEM (reusable) memory.
*/
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e5a31f2a..b0799c2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -102,6 +102,7 @@
#include "rpm_resources.h"
#include "acpuclock.h"
#include "pm-boot.h"
+#include "board-storage-common-a.h"
#include <linux/ion.h>
#include <mach/ion.h>
@@ -8356,6 +8357,7 @@
.msmsdcc_fmax = 48000000,
.nonremovable = 1,
.pclk_src_dfab = 1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8374,6 +8376,7 @@
#ifdef CONFIG_MSM_SDIO_AL
.is_sdio_al_client = 1,
#endif
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8395,6 +8398,7 @@
.nonremovable = 0,
.pclk_src_dfab = 1,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8409,6 +8413,7 @@
.nonremovable = 0,
.pclk_src_dfab = 1,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC4_DAT1,
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8427,6 +8432,7 @@
#ifdef CONFIG_MSM_SDIO_AL
.is_sdio_al_client = 1,
#endif
+ .msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f565075..b74b285 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -31,6 +31,7 @@
#include <linux/memblock.h>
#include <linux/input/ft5x06_ts.h>
#include <linux/msm_adc.h>
+#include <linux/fmem.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -382,6 +383,9 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
+ .request_region = request_fmem_c_region,
+ .release_region = release_fmem_c_region,
+ .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -618,6 +622,14 @@
},
};
+static struct fmem_platform_data fmem_pdata;
+
+static struct platform_device fmem_device = {
+ .name = "fmem",
+ .id = 1,
+ .dev = { .platform_data = &fmem_pdata },
+};
+
static struct platform_device *common_devices[] __initdata = {
&android_usb_device,
&android_pmem_device,
@@ -630,6 +642,7 @@
&asoc_msm_dai0,
&asoc_msm_dai1,
&msm_adc_device,
+ &fmem_device,
};
static struct platform_device *qrd7627a_devices[] __initdata = {
@@ -687,12 +700,44 @@
},
};
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+ &android_pmem_adsp_pdata,
+ &android_pmem_audio_pdata,
+ &android_pmem_pdata,
+};
+#endif
+
static void __init size_pmem_devices(void)
{
#ifdef CONFIG_ANDROID_PMEM
+ unsigned int i;
+ unsigned int reusable_count = 0;
+
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
+
+ fmem_pdata.size = 0;
+ fmem_pdata.align = PAGE_SIZE;
+
+ /* Find pmem devices that should use FMEM (reusable) memory.
+ */
+ for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+ struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+ if (!reusable_count && pdata->reusable)
+ fmem_pdata.size += pdata->size;
+
+ reusable_count += (pdata->reusable) ? 1 : 0;
+
+ if (pdata->reusable && reusable_count > 1) {
+ pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+ __func__, pdata->name);
+ pdata->reusable = 0;
+ }
+ }
+
#endif
}
@@ -704,9 +749,10 @@
static void __init reserve_pmem_memory(void)
{
#ifdef CONFIG_ANDROID_PMEM
- reserve_memory_for(&android_pmem_adsp_pdata);
- reserve_memory_for(&android_pmem_pdata);
- reserve_memory_for(&android_pmem_audio_pdata);
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+ reserve_memory_for(pmem_pdata_array[i]);
+
msm7627a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
#endif
}
diff --git a/arch/arm/mach-msm/board-storage-common-a.h b/arch/arm/mach-msm/board-storage-common-a.h
new file mode 100644
index 0000000..7737819
--- /dev/null
+++ b/arch/arm/mach-msm/board-storage-common-a.h
@@ -0,0 +1,99 @@
+/* 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 _BOARD_STORAGE_A_H
+#define _BOARD_STORAGE_A_H
+
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(num, _ib) \
+static struct msm_bus_vectors sps_to_ddr_perf_vectors_##num[] = { \
+ { \
+ .src = MSM_BUS_MASTER_SPS, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ib = (_ib), \
+ .ab = ((_ib) / 2), \
+ } \
+}
+
+#define MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(num) \
+ { \
+ ARRAY_SIZE(sps_to_ddr_perf_vectors_##num), \
+ sps_to_ddr_perf_vectors_##num, \
+ }
+
+/* no bandwidth required */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(0, 0);
+/*
+ * 13 MB/s bandwidth
+ * 4-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_UHS_SDR12
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(1, 13 * 1024 * 1024);
+/*
+ * 26 MB/s bandwidth
+ * 8-bit MMC_TIMING_LEGACY
+ * 4-bit MMC_TIMING_MMC_HS / MMC_TIMING_SD_HS /
+ * MMC_TIMING_UHS_SDR25
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(2, 26 * 1024 * 1024);
+/*
+ * 52 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS
+ * 4-bit MMC_TIMING_UHS_SDR50 / MMC_TIMING_UHS_DDR50
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(3, 52 * 1024 * 1024);
+/*
+ * 104 MB/s bandwidth
+ * 8-bit MMC_TIMING_UHS_DDR50
+ * 4-bit MMC_TIMING_UHS_SDR104 / MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(4, 104 * 1024 * 1024);
+/*
+ * 200 MB/s bandwidth
+ * 8-bit MMC_TIMING_MMC_HS200
+ */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(5, 200 * 1024 * 1024);
+/* max. possible bandwidth */
+MSM_BUS_SPS_TO_DDR_VOTE_VECTOR(6, UINT_MAX);
+
+static unsigned int sdcc_bw_vectors[] = {0, (13 * 1024 * 1024),
+ (26 * 1024 * 1024), (52 * 1024 * 1024),
+ (104 * 1024 * 1024), (200 * 1024 * 1024),
+ UINT_MAX};
+
+static struct msm_bus_paths sps_to_ddr_bus_scale_usecases[] = {
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(0),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(1),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(2),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(3),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(4),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(5),
+ MSM_BUS_SPS_TO_DDR_VOTE_VECTOR_USECASE(6),
+};
+
+static struct msm_bus_scale_pdata sps_to_ddr_bus_scale_data = {
+ sps_to_ddr_bus_scale_usecases,
+ ARRAY_SIZE(sps_to_ddr_bus_scale_usecases),
+ .name = "msm_sdcc",
+};
+
+static struct msm_mmc_bus_voting_data sps_to_ddr_bus_voting_data = {
+ .use_cases = &sps_to_ddr_bus_scale_data,
+ .bw_vecs = sdcc_bw_vectors,
+ .bw_vecs_size = sizeof(sdcc_bw_vectors),
+};
+
+#endif /* _BOARD_STORAGE_A_H */
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 1fd9b4d..a950e46 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1655,6 +1655,10 @@
"msm-dai-q6.1"),
CLK_LOOKUP("osr_clk", codec_i2s_mic_osr_clk.c,
"msm-dai-q6.1"),
+ CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
+ "msm-dai-q6.0"),
CLK_LOOKUP("bit_clk", spare_i2s_mic_bit_clk.c,
"msm-dai-q6.5"),
CLK_LOOKUP("osr_clk", spare_i2s_mic_osr_clk.c,
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 7123ffa..03667d7 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -102,6 +102,7 @@
#define MMSS_DEBUG_CLK_CTL_REG 0x0900
#define LPASS_DEBUG_CLK_CTL_REG 0x29000
#define LPASS_LPA_PLL_VOTE_APPS_REG 0x2000
+#define MSS_DEBUG_CLK_CTL_REG 0x0078
#define USB30_MASTER_CMD_RCGR 0x03D4
#define USB30_MOCK_UTMI_CMD_RCGR 0x03E8
@@ -230,6 +231,7 @@
#define BLSP2_UART5_BCR 0x0BC0
#define BLSP2_QUP6_BCR 0x0C00
#define BLSP2_UART6_BCR 0x0C40
+#define BOOT_ROM_BCR 0x0E00
#define PDM_BCR 0x0CC0
#define PRNG_BCR 0x0D00
#define BAM_DMA_BCR 0x0D40
@@ -280,6 +282,8 @@
#define OXILICX_AXI_CBCR 0x4038
#define OXILI_BCR 0x4020
#define OXILICX_BCR 0x4030
+#define LPASS_Q6SS_BCR 0x6000
+#define MSS_Q6SS_BCR 0x1068
#define OCMEM_SYS_NOC_AXI_CBCR 0x0244
#define OCMEM_NOC_CFG_AHB_CBCR 0x0248
@@ -327,6 +331,7 @@
#define BLSP1_UART6_APPS_CBCR 0x0904
#define BLSP1_UART6_SIM_CBCR 0x0908
#define BLSP2_AHB_CBCR 0x0944
+#define BOOT_ROM_AHB_CBCR 0x0E04
#define BLSP2_QUP1_SPI_APPS_CBCR 0x0984
#define BLSP2_QUP1_I2C_APPS_CBCR 0x0988
#define BLSP2_UART1_APPS_CBCR 0x09C4
@@ -469,6 +474,11 @@
#define MMSS_MISC_AHB_CBCR 0x502C
#define MMSS_S0_AXI_CBCR 0x5064
#define OCMEMNOC_CBCR 0x50B4
+#define LPASS_Q6SS_AHB_LFABIF_CBCR 0x22000
+#define LPASS_Q6SS_XO_CBCR 0x26000
+#define MSS_XO_Q6_CBCR 0x108C
+#define MSS_BUS_Q6_CBCR 0x10A4
+#define MSS_CFG_AHB_CBCR 0x0280
#define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
#define APCS_CLOCK_SLEEP_ENA_VOTE 0x1488
@@ -1625,6 +1635,19 @@
},
};
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .bcr_reg = BOOT_ROM_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
static struct local_vote_clk gcc_blsp2_ahb_clk = {
.cbcr_reg = BLSP2_AHB_CBCR,
.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
@@ -2225,6 +2248,17 @@
},
};
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
static struct clk_freq_tbl ftbl_mmss_ahb_clk[] = {
F_MM(19200000, cxo, 1, 0, 0),
F_MM(40000000, gpll0, 15, 0, 0),
@@ -4291,6 +4325,55 @@
},
};
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+ .cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahb_lfabif_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahb_lfabif_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_xo_clk = {
+ .cbcr_reg = LPASS_Q6SS_XO_CBCR,
+ .bcr_reg = LPASS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_xo_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_xo_clk.c),
+ },
+};
+
+static struct branch_clk mss_xo_q6_clk = {
+ .cbcr_reg = MSS_XO_Q6_CBCR,
+ .bcr_reg = MSS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MSS_BASE],
+ .c = {
+ .dbg_name = "mss_xo_q6_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mss_xo_q6_clk.c),
+ .depends = &gcc_mss_cfg_ahb_clk.c,
+ },
+};
+
+static struct branch_clk mss_bus_q6_clk = {
+ .cbcr_reg = MSS_BUS_Q6_CBCR,
+ .bcr_reg = MSS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MSS_BASE],
+ .c = {
+ .dbg_name = "mss_bus_q6_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mss_bus_q6_clk.c),
+ .depends = &gcc_mss_cfg_ahb_clk.c,
+ },
+};
+
#ifdef CONFIG_DEBUG_FS
struct measure_mux_entry {
@@ -4339,6 +4422,8 @@
{&gcc_blsp2_uart4_apps_clk.c, GCC_BASE, 0x00c2},
{&gcc_blsp2_uart5_apps_clk.c, GCC_BASE, 0x00c6},
{&gcc_blsp2_uart6_apps_clk.c, GCC_BASE, 0x00cb},
+ {&gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x0100},
+ {&gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
{&gcc_ce1_clk.c, GCC_BASE, 0x0140},
{&gcc_ce2_clk.c, GCC_BASE, 0x0148},
{&gcc_pdm2_clk.c, GCC_BASE, 0x00da},
@@ -4438,6 +4523,11 @@
{&audio_core_lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
{&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
{&audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e},
+ {&q6ss_xo_clk.c, LPASS_BASE, 0x002b},
+ {&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
+ {&mss_bus_q6_clk.c, MSS_BASE, 0x003c},
+ {&mss_xo_q6_clk.c, MSS_BASE, 0x0007},
+
{&dummy_clk, N_BASES, 0x0000},
};
@@ -4465,6 +4555,7 @@
clk->sample_ticks = 0x10000;
clk->multiplier = 1;
+ writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
@@ -4495,6 +4586,12 @@
writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
break;
+ case MSS_BASE:
+ clk_sel = 0x32;
+ regval = BVAL(5, 0, measure_mux[i].debug_mux);
+ writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+ break;
+
default:
return -EINVAL;
}
@@ -4807,6 +4904,13 @@
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, ""),
+ CLK_LOOKUP("core_clk", q6ss_xo_clk.c, ""),
+ CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, ""),
+ CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+
/* TODO: Remove dummy clocks as soon as they become unnecessary */
CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
@@ -5048,6 +5152,9 @@
#define LPASS_CC_PHYS 0xFE000000
#define LPASS_CC_SIZE SZ_256K
+#define MSS_CC_PHYS 0xFC980000
+#define MSS_CC_SIZE SZ_16K
+
static void __init msmcopper_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5062,6 +5169,10 @@
if (!virt_bases[LPASS_BASE])
panic("clock-copper: Unable to ioremap LPASS_CC memory!");
+ virt_bases[MSS_BASE] = ioremap(MSS_CC_PHYS, MSS_CC_SIZE);
+ if (!virt_bases[MSS_BASE])
+ panic("clock-copper: Unable to ioremap MSS_CC memory!");
+
clk_ops_local_pll.enable = copper_pll_clk_enable;
reg_init();
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index c084d29..8eb1580 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -62,6 +62,9 @@
#define MSM_PMIC1_SSBI_CMD_PHYS 0x00500000
#define MSM_PMIC_SSBI_SIZE SZ_4K
+#define MSM_GPIO_I2C_CLK 16
+#define MSM_GPIO_I2C_SDA 17
+
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
@@ -307,6 +310,19 @@
.end = GSBI5_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
+ {
+ .name = "i2c_clk",
+ .start = MSM_GPIO_I2C_CLK,
+ .end = MSM_GPIO_I2C_CLK,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "i2c_sda",
+ .start = MSM_GPIO_I2C_SDA,
+ .end = MSM_GPIO_I2C_SDA,
+ .flags = IORESOURCE_IO,
+
+ },
};
struct platform_device msm9615_device_qup_i2c_gsbi5 = {
@@ -472,6 +488,15 @@
.id = -1,
};
+struct platform_device msm_i2s_cpudai0 = {
+ .name = "msm-dai-q6",
+ .id = PRIMARY_I2S_RX,
+};
+
+struct platform_device msm_i2s_cpudai1 = {
+ .name = "msm-dai-q6",
+ .id = PRIMARY_I2S_TX,
+};
struct platform_device msm_voip = {
.name = "msm-voip-dsp",
.id = -1,
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 407554c..4184a86 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -32,4 +32,5 @@
int ar600x_wlan_power(bool on);
void __init msm8x25_spm_device_init(void);
void __init msm8x25_kgsl_3d0_init(void);
+void __iomem *core1_reset_base(void);
#endif
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 31142c1..8f42ede 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -223,6 +223,8 @@
extern struct platform_device msm_cpudai_incall_music_rx;
extern struct platform_device msm_cpudai_incall_record_rx;
extern struct platform_device msm_cpudai_incall_record_tx;
+extern struct platform_device msm_i2s_cpudai0;
+extern struct platform_device msm_i2s_cpudai1;
extern struct platform_device msm_pil_q6v3;
extern struct platform_device msm_pil_modem;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index d433b9e..d3b2274 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -59,20 +59,19 @@
int channel_active;
int sd;
size_t sd_size;
- struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT];
struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
- struct mutex lock;
- spinlock_t list_lock;
+ spinlock_t lock;
unsigned int irq;
struct clk *clk;
struct clk *pclk;
struct clk *ebiclk;
unsigned int clk_ctl;
- struct delayed_work work;
+ struct timer_list timer;
};
-static void msm_dmov_clock_work(struct work_struct *);
+static void msm_dmov_clock_timer(unsigned long);
+static int msm_dmov_clk_toggle(int, int);
#ifdef CONFIG_ARCH_MSM8X60
@@ -164,19 +163,15 @@
{
.crci_conf = adm0_crci_conf,
.chan_conf = adm0_chan_conf,
- .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
- .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+ .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
.clk_ctl = CLK_DIS,
- .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
- msm_dmov_clock_work),
+ .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
}, {
.crci_conf = adm1_crci_conf,
.chan_conf = adm1_chan_conf,
- .lock = __MUTEX_INITIALIZER(dmov_conf[1].lock),
- .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+ .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
.clk_ctl = CLK_DIS,
- .work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work,
- msm_dmov_clock_work),
+ .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
}
};
#else
@@ -184,11 +179,9 @@
{
.crci_conf = NULL,
.chan_conf = NULL,
- .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
- .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+ .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
.clk_ctl = CLK_DIS,
- .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
- msm_dmov_clock_work),
+ .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
}
};
#endif
@@ -230,153 +223,94 @@
#define PRINT_FLOW(format, args...) \
MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
-static int msm_dmov_clk_on(int adm)
+static int msm_dmov_clk_toggle(int adm, int on)
{
- int ret;
+ int ret = 0;
- ret = clk_prepare_enable(dmov_conf[adm].clk);
- if (ret)
- return ret;
- if (dmov_conf[adm].pclk) {
- ret = clk_prepare_enable(dmov_conf[adm].pclk);
- if (ret) {
- clk_disable_unprepare(dmov_conf[adm].clk);
- return ret;
+ if (on) {
+ ret = clk_enable(dmov_conf[adm].clk);
+ if (ret)
+ goto err;
+ if (dmov_conf[adm].pclk) {
+ ret = clk_enable(dmov_conf[adm].pclk);
+ if (ret) {
+ clk_disable(dmov_conf[adm].clk);
+ goto err;
+ }
}
- }
- if (dmov_conf[adm].ebiclk) {
- ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
- if (ret) {
- if (dmov_conf[adm].pclk)
- clk_disable_unprepare(dmov_conf[adm].pclk);
- clk_disable_unprepare(dmov_conf[adm].clk);
+ if (dmov_conf[adm].ebiclk) {
+ ret = clk_enable(dmov_conf[adm].ebiclk);
+ if (ret) {
+ if (dmov_conf[adm].pclk)
+ clk_disable(dmov_conf[adm].pclk);
+ clk_disable(dmov_conf[adm].clk);
+ }
}
+ } else {
+ clk_disable(dmov_conf[adm].clk);
+ if (dmov_conf[adm].pclk)
+ clk_disable(dmov_conf[adm].pclk);
+ if (dmov_conf[adm].ebiclk)
+ clk_disable(dmov_conf[adm].ebiclk);
}
+err:
return ret;
}
-static void msm_dmov_clk_off(int adm)
+static void msm_dmov_clock_timer(unsigned long adm)
{
- clk_disable_unprepare(dmov_conf[adm].clk);
- if (dmov_conf[adm].pclk)
- clk_disable_unprepare(dmov_conf[adm].pclk);
- if (dmov_conf[adm].ebiclk)
- clk_disable_unprepare(dmov_conf[adm].ebiclk);
-}
-
-static void msm_dmov_clock_work(struct work_struct *work)
-{
- struct msm_dmov_conf *conf =
- container_of(to_delayed_work(work), struct msm_dmov_conf, work);
- int adm = DMOV_IRQ_TO_ADM(conf->irq);
- mutex_lock(&conf->lock);
- if (conf->clk_ctl == CLK_TO_BE_DIS) {
- BUG_ON(conf->channel_active);
- msm_dmov_clk_off(adm);
- conf->clk_ctl = CLK_DIS;
+ unsigned long irq_flags;
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
+ BUG_ON(dmov_conf[adm].channel_active);
+ msm_dmov_clk_toggle(adm, 0);
+ dmov_conf[adm].clk_ctl = CLK_DIS;
}
- mutex_unlock(&conf->lock);
-}
-
-enum {
- NOFLUSH = 0,
- GRACEFUL,
- NONGRACEFUL,
-};
-
-/* Caller must hold the list lock */
-static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm)
-{
- struct msm_dmov_cmd *cmd;
-
- if (list_empty(&dmov_conf[adm].ready_commands[ch]))
- return NULL;
-
- cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd),
- list);
- list_del(&cmd->list);
- if (cmd->exec_func)
- cmd->exec_func(cmd);
- list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
- if (!dmov_conf[adm].channel_active)
- enable_irq(dmov_conf[adm].irq);
- dmov_conf[adm].channel_active |= BIT(ch);
- PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, ch);
- writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
-
- return cmd;
-}
-
-static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work)
-{
- struct msm_dmov_cmd *cmd =
- container_of(work, struct msm_dmov_cmd, work);
- unsigned id = cmd->id;
- unsigned status;
- unsigned long flags;
- int adm = DMOV_ID_TO_ADM(id);
- int ch = DMOV_ID_TO_CHAN(id);
-
- mutex_lock(&dmov_conf[adm].lock);
- if (dmov_conf[adm].clk_ctl == CLK_DIS) {
- status = msm_dmov_clk_on(adm);
- if (status != 0)
- goto error;
- } else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
- cancel_delayed_work_sync(&dmov_conf[adm].work);
- dmov_conf[adm].clk_ctl = CLK_EN;
-
- spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
-
- cmd = list_entry(dmov_conf[adm].staged_commands[ch].next, typeof(*cmd),
- list);
- list_del(&cmd->list);
- list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
- status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
- if (status & DMOV_STATUS_CMD_PTR_RDY) {
- PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
- id, status);
- cmd = start_ready_cmd(ch, adm);
- /*
- * We added something to the ready list, and still hold the
- * list lock. Thus, no need to check for cmd == NULL
- */
- if (cmd->toflush) {
- int flush = (cmd->toflush == GRACEFUL) ? 1 << 31 : 0;
- writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
- }
- } else {
- cmd->toflush = 0;
- if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
- !list_empty(&dmov_conf[adm].ready_commands[ch]))
- PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
- "status %x\n", id, status);
- PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
- "%x\n", id, status);
- }
- if (!dmov_conf[adm].channel_active) {
- dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- schedule_delayed_work(&dmov_conf[adm].work, HZ);
- }
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
-error:
- mutex_unlock(&dmov_conf[adm].lock);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
}
void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
{
+ unsigned long irq_flags;
+ unsigned int status;
int adm = DMOV_ID_TO_ADM(id);
int ch = DMOV_ID_TO_CHAN(id);
- unsigned long flags;
- cmd->id = id;
- cmd->toflush = 0;
- INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work);
- spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
- list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ if (dmov_conf[adm].clk_ctl == CLK_DIS) {
+ status = msm_dmov_clk_toggle(adm, 1);
+ if (status != 0)
+ goto error;
+ } else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
+ del_timer(&dmov_conf[adm].timer);
+ dmov_conf[adm].clk_ctl = CLK_EN;
- schedule_work(&cmd->work);
+ status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
+ if (status & DMOV_STATUS_CMD_PTR_RDY) {
+ PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
+ id, status);
+ if (cmd->exec_func)
+ cmd->exec_func(cmd);
+ list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+ if (!dmov_conf[adm].channel_active)
+ enable_irq(dmov_conf[adm].irq);
+ dmov_conf[adm].channel_active |= 1U << ch;
+ PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
+ writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
+ } else {
+ if (!dmov_conf[adm].channel_active) {
+ dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+ mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+ }
+ if (list_empty(&dmov_conf[adm].active_commands[ch]))
+ PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
+ "status %x\n", id, status);
+ PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
+ "%x\n", id, status);
+ list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
+ }
+error:
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
}
EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
@@ -395,18 +329,14 @@
int ch = DMOV_ID_TO_CHAN(id);
int adm = DMOV_ID_TO_ADM(id);
int flush = graceful ? DMOV_FLUSH_TYPE : 0;
- struct msm_dmov_cmd *cmd;
-
- spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
/* XXX not checking if flush cmd sent already */
if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
}
- list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list)
- cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL;
/* spin_unlock_irqrestore has the necessary barrier */
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
}
EXPORT_SYMBOL(msm_dmov_flush);
@@ -468,7 +398,7 @@
errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
}
-static irqreturn_t msm_dmov_isr(int irq, void *dev_id)
+static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
{
unsigned int int_status;
unsigned int mask;
@@ -481,12 +411,11 @@
struct msm_dmov_cmd *cmd;
int adm = DMOV_IRQ_TO_ADM(irq);
- mutex_lock(&dmov_conf[adm].lock);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
/* read and clear isr */
int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
- spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
while (int_status) {
mask = int_status & -int_status;
ch = fls(mask) - 1;
@@ -554,38 +483,51 @@
ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
adm));
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
- if (ch_status & DMOV_STATUS_CMD_PTR_RDY)
- start_ready_cmd(ch, adm);
+ if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
+ !list_empty(&dmov_conf[adm].ready_commands[ch])) {
+ cmd = list_entry(dmov_conf[adm].
+ ready_commands[ch].next, typeof(*cmd),
+ list);
+ list_del(&cmd->list);
+ if (cmd->exec_func)
+ cmd->exec_func(cmd);
+ list_add_tail(&cmd->list,
+ &dmov_conf[adm].active_commands[ch]);
+ PRINT_FLOW("msm_datamover_irq_handler id %d,"
+ "start command\n", id);
+ writel_relaxed(cmd->cmdptr,
+ DMOV_REG(DMOV_CMD_PTR(ch), adm));
+ }
} while (ch_status & DMOV_STATUS_RSLT_VALID);
if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
- list_empty(&dmov_conf[adm].ready_commands[ch]))
+ list_empty(&dmov_conf[adm].ready_commands[ch]))
dmov_conf[adm].channel_active &= ~(1U << ch);
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
}
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
if (!dmov_conf[adm].channel_active && valid) {
disable_irq_nosync(dmov_conf[adm].irq);
dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- schedule_delayed_work(&dmov_conf[adm].work, HZ);
+ mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
}
- mutex_unlock(&dmov_conf[adm].lock);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
return valid ? IRQ_HANDLED : IRQ_NONE;
}
static int msm_dmov_suspend_late(struct device *dev)
{
+ unsigned long irq_flags;
struct platform_device *pdev = to_platform_device(dev);
int adm = (pdev->id >= 0) ? pdev->id : 0;
- mutex_lock(&dmov_conf[adm].lock);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
BUG_ON(dmov_conf[adm].channel_active);
- cancel_delayed_work_sync(&dmov_conf[adm].work);
- msm_dmov_clk_off(adm);
+ del_timer(&dmov_conf[adm].timer);
+ msm_dmov_clk_toggle(adm, 0);
dmov_conf[adm].clk_ctl = CLK_DIS;
}
- mutex_unlock(&dmov_conf[adm].lock);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
return 0;
}
@@ -700,8 +642,8 @@
if (!dmov_conf[adm].base)
return -ENOMEM;
- ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr,
- IRQF_ONESHOT, "msmdatamover", NULL);
+ ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
+ 0, "msmdatamover", NULL);
if (ret) {
PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
dmov_conf[adm].irq);
@@ -713,7 +655,7 @@
PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
goto out_irq;
}
- ret = msm_dmov_clk_on(adm);
+ ret = msm_dmov_clk_toggle(adm, 1);
if (ret) {
PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
goto out_irq;
@@ -721,7 +663,6 @@
config_datamover(adm);
for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
- INIT_LIST_HEAD(&dmov_conf[adm].staged_commands[i]);
INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]);
INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]);
@@ -730,7 +671,7 @@
DMOV_REG(DMOV_RSLT_CONF(i), adm));
}
wmb();
- msm_dmov_clk_off(adm);
+ msm_dmov_clk_toggle(adm, 0);
return ret;
out_irq:
free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
new file mode 100644
index 0000000..1622e13
--- /dev/null
+++ b/arch/arm/mach-msm/idle-macros.S
@@ -0,0 +1,153 @@
+/* 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/hardware/cache-l2x0.h>
+
+/* Add 300 NOPs after 'wfi' for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+ .rept \rept
+ nop
+ .endr
+#endif
+.endm
+
+/* 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
+
+/*
+ * Enable the "L2" cache, not require to restore the controller registers
+ */
+.macro ENABLE_8x25_L2
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip_enable\@
+ ldr r0, =apps_power_collapse
+ ldr r0, [r0]
+ cmp r0, #POWER_COLLAPSED
+ bne skip_enable\@
+ ldr r0, =l2x0_base_addr
+ ldr r0, [r0]
+ mov r1, #0x1
+ str r1, [r0, #L2X0_CTRL]
+ dmb
+skip_enable\@:
+.endm
+
+/*
+ * Perform the required operation
+ * operation: type of operation on l2 cache (e.g: clean&inv or inv)
+ * l2_enable: enable or disable
+ */
+.macro DO_CACHE_OPERATION, operation, l2_enable
+ ldr r2, =l2x0_base_addr
+ ldr r2, [r2]
+ ldr r0, =0xffff
+ str r0, [r2, #\operation]
+wait\@:
+ ldr r0, [r2, #\operation]
+ ldr r1, =0xffff
+ ands r0, r0, r1
+ bne wait\@
+l2x_sync\@:
+ mov r0, #0x0
+ str r0, [r2, #L2X0_CACHE_SYNC]
+sync\@:
+ ldr r0, [r2, #L2X0_CACHE_SYNC]
+ ands r0, r0, #0x1
+ bne sync\@
+ mov r1, #\l2_enable
+ str r1, [r2, #L2X0_CTRL]
+.endm
+
+/*
+ * Clean and invalidate the L2 cache.
+ * 1. Check the target type
+ * 2. Check whether we are coming from PC are not
+ * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
+ * 4. Start L2 clean & invalidation operation
+ * 5. Disable the L2 cache
+ */
+.macro SUSPEND_8x25_L2
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip_suspend\@
+ ldr r0, =apps_power_collapse
+ ldr r0, [r0]
+ cmp r0, #POWER_COLLAPSED
+ bne skip_suspend\@
+ ldr r0, =l2x0_saved_ctrl_reg_val
+ ldr r1, =l2x0_base_addr
+ ldr r1, [r1]
+ ldr r2, [r1, #L2X0_AUX_CTRL]
+ str r2, [r0, #0x0] /* store aux_ctlr reg value */
+ ldr r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+ str r2, [r0, #0x4] /* store data latency reg value */
+ ldr r2, [r1, #L2X0_PREFETCH_CTRL]
+ str r2, [r0, #0x8] /* store prefetch_ctlr reg value */
+ DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
+ dmb
+skip_suspend\@:
+.endm
+
+/*
+ * Coming back from a successful PC
+ * 1. Check the target type
+ * 2. Check whether we are going to PC are not
+ * 3. Disable the L2 cache
+ * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
+ * 5. Invalidate the cache
+ * 6. Enable the L2 cache
+ */
+.macro RESUME_8x25_L2
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip_resume\@
+ ldr r0, =apps_power_collapse
+ ldr r0, [r0]
+ cmp r0, #POWER_COLLAPSED
+ bne skip_resume\@
+ ldr r1, =l2x0_base_addr
+ ldr r1, [r1]
+ mov r0, #0x0
+ str r0, [r1, #L2X0_CTRL]
+ ldr r0, =l2x0_saved_ctrl_reg_val
+ ldr r2, [r0, #0x0]
+ str r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
+ ldr r2, [r0, #0x4]
+ str r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+ ldr r2, [r0, #0x8]
+ str r2, [r1, #L2X0_PREFETCH_CTRL]
+ DO_CACHE_OPERATION L2X0_INV_WAY ON
+skip_resume\@:
+.endm
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index b73ddc8..b75f76f 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -20,39 +20,13 @@
#include <asm/assembler.h>
#include "idle.h"
+#include "idle-macros.S"
#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
-
-/* Add NOPs for 8x25 target */
-.macro DELAY_8x25, rept
-#ifdef CONFIG_ARCH_MSM8625
- .rept \rept
- nop
- .endr
-#endif
-.endm
-
ENTRY(msm_arch_idle)
wfi
#ifdef CONFIG_ARCH_MSM8X60
@@ -135,16 +109,19 @@
bic r0, r4, #(1 << 2) /* clear dcache bit */
bic r0, r0, #(1 << 12) /* clear icache bit */
mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
- dsb
+ isb
+ SUSPEND_8x25_L2
SET_SMP_COHERENCY OFF
wfi
DELAY_8x25 300
mcr p15, 0, r4, c1, c0, 0 /* restore d/i cache */
isb
-#endif
+ ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
SET_SMP_COHERENCY ON
+#endif
+
#if defined(CONFIG_MSM_FIQ_SUPPORT)
cpsie f
#endif
@@ -237,7 +214,6 @@
dsb
isb
- SET_SMP_COHERENCY ON
#ifdef CONFIG_ARCH_MSM_KRAIT
mrc p15, 0, r1, c0, c0, 0
ldr r3, =0xff00fc00
@@ -247,7 +223,11 @@
mrceq p15, 7, r3, c15, c0, 2
biceq r3, r3, #0x400
mcreq p15, 7, r3, c15, c0, 2
+#else
+ RESUME_8x25_L2
+ SET_SMP_COHERENCY ON
#endif
+
#ifdef CONFIG_MSM_JTAG
stmfd sp!, {lr}
bl msm_jtag_restore_state
@@ -302,6 +282,14 @@
target_type:
.long 0x0
+ .globl apps_power_collapse
+apps_power_collapse:
+ .long 0x0
+
+ .globl l2x0_base_addr
+l2x0_base_addr:
+ .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
@@ -309,3 +297,13 @@
*/
msm_pm_flush_l2_flag:
.long 0x1
+
+/*
+ * Save & restore l2x0 registers while system is entering and resuming
+ * from Power Collapse.
+ * 1. aux_ctrl_save (0x0)
+ * 2. data_latency_ctrl (0x4)
+ * 3. prefetch control (0x8)
+ */
+l2x0_saved_ctrl_reg_val:
+ .space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index bfd632f..4abdd04 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -25,6 +25,7 @@
#define ON 1
#define OFF 0
#define TARGET_IS_8625 1
+#define POWER_COLLAPSED 1
#ifndef __ASSEMBLY__
@@ -40,6 +41,8 @@
extern unsigned long msm_pm_pc_pgd;
extern unsigned long msm_pm_boot_vector[NR_CPUS];
extern uint32_t target_type;
+extern uint32_t apps_power_collapse;
+extern uint32_t *l2x0_base_addr;
#else
static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
{
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 644746e..56210d5 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -288,6 +288,7 @@
enum msm_sensor_type sensor_type;
struct msm_actuator_info *actuator_info;
int pmic_gpio_enable;
+ int (*sensor_lcd_gpio_onoff)(int on);
struct msm_eeprom_info *eeprom_info;
};
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 90d236b..ba5b8ac 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -653,7 +653,8 @@
void msm_camio_camif_pad_reg_reset_2(void);
void msm_camio_vfe_blk_reset(void);
-void msm_camio_vfe_blk_reset_2(int flag);
+void msm_camio_vfe_blk_reset_2(void);
+void msm_camio_vfe_blk_reset_3(void);
int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *sinfo);
void msm_camio_3d_disable(void);
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index ba621e6..70519ff 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -35,10 +35,7 @@
unsigned int result,
struct msm_dmov_errdata *err);
void (*exec_func)(struct msm_dmov_cmd *cmd);
- struct work_struct work;
- unsigned id; /* For internal use */
void *user; /* Pointer for caller's reference */
- u8 toflush;
};
struct msm_dmov_pdata {
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
new file mode 100644
index 0000000..bf7c338
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -0,0 +1,109 @@
+/* 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 _ARCH_ARM_MACH_MSM_OCMEM_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_H
+
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#define OCMEM_MIN_ALLOC SZ_64K
+#define OCMEM_MIN_ALIGN SZ_64K
+
+/* Maximum number of slots in DM */
+#define OCMEM_MAX_CHUNKS 32
+#define MIN_CHUNK_SIZE (SZ_1K/8)
+
+struct ocmem_buf {
+ unsigned long addr;
+ unsigned long len;
+};
+
+struct ocmem_buf_attr {
+ unsigned long paddr;
+ unsigned long len;
+};
+
+struct ocmem_chunk {
+ bool ro;
+ unsigned long ddr_paddr;
+ unsigned long size;
+};
+
+struct ocmem_map_list {
+ int num_chunks;
+ struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
+};
+
+/* List of clients that allocate/interact with OCMEM */
+/* Must be in sync with client_names */
+enum ocmem_client {
+ /* GMEM clients */
+ OCMEM_GRAPHICS = 0x0,
+ /* TCMEM clients */
+ OCMEM_VIDEO,
+ OCMEM_CAMERA,
+ /* Dummy Clients */
+ OCMEM_HP_AUDIO,
+ OCMEM_VOICE,
+ /* IMEM Clients */
+ OCMEM_LP_AUDIO,
+ OCMEM_SENSORS,
+ OCMEM_BLAST,
+ OCMEM_CLIENT_MAX,
+};
+
+/**
+ * List of OCMEM notification events which will be broadcasted
+ * to clients that optionally register for these notifications
+ * on a per allocation basis.
+ **/
+enum ocmem_notif_type {
+ OCMEM_MAP_DONE = 1,
+ OCMEM_MAP_FAIL,
+ OCMEM_UNMAP_DONE,
+ OCMEM_UNMAP_FAIL,
+ OCMEM_ALLOC_GROW,
+ OCMEM_ALLOC_SHRINK,
+ OCMEM_NOTIF_TYPE_COUNT,
+};
+
+/* APIS */
+/* Notification APIs */
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb);
+
+int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+
+/* Allocation APIs */
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+ unsigned long goal, unsigned long step);
+
+/* Free APIs */
+int ocmem_free(int client_id, struct ocmem_buf *buf);
+
+/* Dynamic Resize APIs */
+int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+int ocmem_expand(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+/* Priority Enforcement APIs */
+int ocmem_evict(int client_id);
+
+int ocmem_restore(int client_id);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
new file mode 100644
index 0000000..4b46c01
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -0,0 +1,79 @@
+/* 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 _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+
+/** All interfaces in this header should only be used by OCMEM driver
+ * Client drivers should use wrappers available in ocmem.h
+ **/
+
+#include "ocmem.h"
+#include <mach/msm_iomap.h>
+#include <asm/io.h>
+
+#define OCMEM_PHYS_BASE 0xFEC00000
+#define OCMEM_PHYS_SIZE 0x180000
+
+struct ocmem_zone;
+
+struct ocmem_zone_ops {
+ unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+ int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
+};
+
+struct ocmem_zone {
+ int owner;
+ int active_regions;
+ int max_regions;
+ struct list_head region_list;
+ unsigned long z_start;
+ unsigned long z_end;
+ unsigned long z_head;
+ unsigned long z_tail;
+ unsigned long z_free;
+ struct gen_pool *z_pool;
+ struct ocmem_zone_ops *z_ops;
+};
+
+struct ocmem_req {
+ struct rw_semaphore rw_sem;
+ /* Chain in sched queue */
+ struct list_head sched_list;
+ /* Chain in zone list */
+ struct list_head zone_list;
+ int owner;
+ int prio;
+ uint32_t req_id;
+ unsigned long req_min;
+ unsigned long req_max;
+ unsigned long req_step;
+ /* reverse pointers */
+ struct ocmem_zone *zone;
+ struct ocmem_buf *buffer;
+ unsigned long state;
+ /* Request assignments */
+ unsigned long req_start;
+ unsigned long req_end;
+ unsigned long req_sz;
+};
+
+struct ocmem_handle {
+ struct ocmem_buf buffer;
+ struct mutex handle_mutex;
+ struct ocmem_req *req;
+};
+
+struct ocmem_zone *get_zone(unsigned);
+unsigned long allocate_head(struct ocmem_zone *, unsigned long);
+int free_head(struct ocmem_zone *, unsigned long, unsigned long);
+#endif
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 0652f3b..49a3e6f 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -49,9 +49,11 @@
#define MSM_IOMMU_ATTR_CACHED_WT 0x3
-static inline void clean_pte(unsigned long *start, unsigned long *end)
+static inline void clean_pte(unsigned long *start, unsigned long *end,
+ int redirect)
{
- dmac_flush_range(start, end);
+ if (!redirect)
+ dmac_flush_range(start, end);
}
static int msm_iommu_tex_class[4];
@@ -292,6 +294,9 @@
memset(priv->pgtable, 0, SZ_16K);
domain->priv = priv;
+
+ clean_pte(priv->pgtable, priv->pgtable + NUM_FL_PTE, priv->redirect);
+
return 0;
fail_nomem:
@@ -518,8 +523,7 @@
for (i = 0; i < 16; i++)
*(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);
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
@@ -530,8 +534,7 @@
*fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
| pgprot;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
/* Need a 2nd level table */
@@ -548,12 +551,12 @@
goto fail;
}
memset(sl, 0, SZ_4K);
+ clean_pte(sl, sl + NUM_SL_PTE, priv->redirect);
*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
FL_TYPE_TABLE);
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
if (!(*fl_pte & FL_TYPE_TABLE)) {
@@ -574,8 +577,7 @@
*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);
+ clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_64K) {
@@ -591,8 +593,7 @@
*(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);
+ clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
ret = __flush_iotlb_va(domain, va);
@@ -652,15 +653,13 @@
for (i = 0; i < 16; i++)
*(fl_pte+i) = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 16);
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
@@ -671,15 +670,13 @@
for (i = 0; i < 16; i++)
*(sl_pte+i) = 0;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 16);
+ clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
if (len == SZ_4K) {
*sl_pte = 0;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 1);
+ clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_4K || len == SZ_64K) {
@@ -692,8 +689,7 @@
free_page((unsigned long)sl_table);
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
}
@@ -773,10 +769,12 @@
}
memset(sl_table, 0, SZ_4K);
+ clean_pte(sl_table, sl_table + NUM_SL_PTE,
+ priv->redirect);
+
*fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
FL_TYPE_TABLE);
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
} else
sl_table = (unsigned long *)
__va(((*fl_pte) & FL_BASE_MASK));
@@ -809,8 +807,8 @@
}
}
- if (!priv->redirect)
- clean_pte(sl_table + sl_start, sl_table + sl_offset);
+ clean_pte(sl_table + sl_start, sl_table + sl_offset,
+ priv->redirect);
fl_pte++;
sl_offset = 0;
@@ -854,8 +852,8 @@
sl_end = NUM_SL_PTE;
memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
- if (!priv->redirect)
- clean_pte(sl_table + sl_start, sl_table + sl_end);
+ clean_pte(sl_table + sl_start, sl_table + sl_end,
+ priv->redirect);
offset += (sl_end - sl_start) * SZ_4K;
@@ -879,8 +877,7 @@
free_page((unsigned long)sl_table);
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
sl_start = 0;
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index 462543e..a90be23 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -138,7 +138,7 @@
struct msm_ipc_sock {
struct sock sk;
struct msm_ipc_port *port;
- void *modem_pil;
+ void *default_pil;
};
enum write_data_type {
@@ -206,4 +206,15 @@
int msm_ipc_router_init_sockets(void);
void msm_ipc_router_exit_sockets(void);
+#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
+extern void *msm_ipc_load_default_node(void);
+
+extern void msm_ipc_unload_default_node(void *pil);
+#else
+static inline void *msm_ipc_load_default_node(void)
+{ return NULL; }
+
+static inline void msm_ipc_unload_default_node(void *pil) { }
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 0cde393..307b6ae 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <mach/msm_smd.h>
+#include <mach/peripheral-loader.h>
#include "ipc_router.h"
#include "smd_private.h"
@@ -442,6 +443,31 @@
return 0;
}
+void *msm_ipc_load_default_node(void)
+{
+ void *pil = NULL;
+ const char *peripheral;
+
+ peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
+ if (peripheral && !strncmp(peripheral, "modem", 6)) {
+ pil = pil_get(peripheral);
+ if (IS_ERR(pil)) {
+ pr_err("%s: Failed to load %s\n",
+ __func__, peripheral);
+ pil = NULL;
+ }
+ }
+ return pil;
+}
+EXPORT_SYMBOL(msm_ipc_load_default_node);
+
+void msm_ipc_unload_default_node(void *pil)
+{
+ if (pil)
+ pil_put(pil);
+}
+EXPORT_SYMBOL(msm_ipc_unload_default_node);
+
static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
{
.probe = msm_ipc_router_smd_remote_probe,
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 085b87a..d82ffe5 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -30,14 +30,10 @@
#include <net/sock.h>
-#include <mach/peripheral-loader.h>
-#include <mach/socinfo.h>
-
#include "ipc_router.h"
#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
-#define MODEM_LOAD_TIMEOUT (10 * HZ)
static int sockets_enabled;
static struct proto msm_ipc_proto;
@@ -58,45 +54,6 @@
}
#endif
-static void msm_ipc_router_unload_modem(void *pil)
-{
- if (pil)
- pil_put(pil);
-}
-
-static void *msm_ipc_router_load_modem(void)
-{
- void *pil = NULL;
- int rc;
-
- /* Load GNSS for Standalone 8064 but not for Fusion 3 */
- if (cpu_is_apq8064()) {
- if (socinfo_get_platform_subtype() == 0x0)
- pil = pil_get("gss");
- } else {
- pil = pil_get("modem");
- }
-
- if (IS_ERR(pil) || !pil) {
- pr_debug("%s: modem load failed\n", __func__);
- pil = NULL;
- } else {
- rc = wait_for_completion_interruptible_timeout(
- &msm_ipc_remote_router_up,
- MODEM_LOAD_TIMEOUT);
- if (!rc)
- rc = -ETIMEDOUT;
- if (rc < 0) {
- pr_err("%s: wait for remote router failed %d\n",
- __func__, rc);
- msm_ipc_router_unload_modem(pil);
- pil = NULL;
- }
- }
-
- return pil;
-}
-
static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
struct iovec const *msg_sect,
size_t total_len)
@@ -268,9 +225,9 @@
sock_init_data(sock, sk);
sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
- pil = msm_ipc_router_load_modem();
+ pil = msm_ipc_load_default_node();
msm_ipc_sk(sk)->port = port_ptr;
- msm_ipc_sk(sk)->modem_pil = pil;
+ msm_ipc_sk(sk)->default_pil = pil;
return 0;
}
@@ -519,12 +476,12 @@
{
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
- void *pil = msm_ipc_sk(sk)->modem_pil;
+ void *pil = msm_ipc_sk(sk)->default_pil;
int ret;
lock_sock(sk);
ret = msm_ipc_router_close_port(port_ptr);
- msm_ipc_router_unload_modem(pil);
+ msm_ipc_unload_default_node(pil);
release_sock(sk);
sock_put(sk);
sock->sk = NULL;
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index 7775740..c58b0e1 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -31,6 +31,7 @@
#define SCM_Q6_NMI_CMD 0x1
#define MODULE_NAME "lpass_8960"
+#define MAX_BUF_SIZE 0x51
/* Subsystem restart: QDSP6 data, functions */
static void lpass_fatal_fn(struct work_struct *);
@@ -86,10 +87,39 @@
.notifier_call = modem_notifier_cb,
};
+static void lpass_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[MAX_BUF_SIZE];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
+ MODULE_NAME);
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("%s: subsystem failure reason: (unknown, init value found)",
+ MODULE_NAME);
+ return;
+ }
+
+ size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
static void lpass_fatal_fn(struct work_struct *work)
{
pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
__func__);
+ lpass_log_failure_reason();
panic(MODULE_NAME ": Resetting the SoC");
}
@@ -104,6 +134,7 @@
pr_err("%s: LPASS SMSM state changed to SMSM_RESET,"
" new_state = 0x%x, old_state = 0x%x\n", __func__,
new_state, old_state);
+ lpass_log_failure_reason();
panic(MODULE_NAME ": Resetting the SoC");
}
}
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 8d99c1c..f8e187d 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -39,6 +39,7 @@
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "mdm_private.h"
+#include "sysmon.h"
#define MDM_MODEM_TIMEOUT 6000
#define MDM_MODEM_DELTA 100
@@ -47,6 +48,7 @@
static int mdm_debug_on;
static struct workqueue_struct *mdm_queue;
+static struct workqueue_struct *mdm_sfr_queue;
#define EXTERNAL_MODEM "external_modem"
@@ -58,6 +60,36 @@
static int first_boot = 1;
+#define RD_BUF_SIZE 100
+#define SFR_MAX_RETRIES 10
+#define SFR_RETRY_INTERVAL 1000
+
+static void mdm_restart_reason_fn(struct work_struct *work)
+{
+ int ret, ntries = 0;
+ char sfr_buf[RD_BUF_SIZE];
+
+ do {
+ msleep(SFR_RETRY_INTERVAL);
+ ret = sysmon_get_reason(SYSMON_SS_EXT_MODEM,
+ sfr_buf, sizeof(sfr_buf));
+ if (ret) {
+ /*
+ * The sysmon device may not have been probed as yet
+ * after the restart.
+ */
+ pr_err("%s: Error retrieving mdm restart reason, ret = %d, "
+ "%d/%d tries\n", __func__, ret,
+ ntries + 1, SFR_MAX_RETRIES);
+ } else {
+ pr_err("mdm restart reason: %s\n", sfr_buf);
+ break;
+ }
+ } while (++ntries < SFR_MAX_RETRIES);
+}
+
+static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
+
long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -253,8 +285,11 @@
msecs_to_jiffies(MDM_BOOT_TIMEOUT))) {
mdm_drv->mdm_boot_status = -ETIMEDOUT;
pr_info("%s: mdm modem restart timed out.\n", __func__);
- } else
+ } else {
pr_info("%s: mdm modem has been restarted\n", __func__);
+ /* Log the reason for the restart */
+ queue_work(mdm_sfr_queue, &sfr_reason_work);
+ }
INIT_COMPLETION(mdm_boot);
return mdm_drv->mdm_boot_status;
}
@@ -421,6 +456,16 @@
goto fatal_err;
}
+ mdm_sfr_queue = alloc_workqueue("mdm_sfr_queue", 0, 0);
+ if (!mdm_sfr_queue) {
+ pr_err("%s: could not create workqueue mdm_sfr_queue."
+ " All mdm functionality will be disabled\n",
+ __func__);
+ ret = -ENOMEM;
+ destroy_workqueue(mdm_queue);
+ goto fatal_err;
+ }
+
atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
mdm_debugfs_init();
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 191e950..b21412f 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -43,6 +43,11 @@
unsigned long event, void *ptr)
{
#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+ /*
+ * Clear the bootloader magic so the dumps aren't overwritten
+ */
+ __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
+
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
@@ -101,10 +106,9 @@
if (ret)
pr_err("%s: could not register L2 buffer ret = %d.\n",
__func__, ret);
-#else
+#endif
__raw_writel(msm_cache_dump_addr + d->l1_size,
MSM_IMEM_BASE + L2_DUMP_OFFSET);
-#endif
atomic_notifier_chain_register(&panic_notifier_list,
&msm_cache_dump_blk);
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 9b8bc61..2cff7f0 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -151,13 +151,43 @@
.notifier_call = panic_wdog_handler,
};
+struct wdog_disable_work_data {
+ struct work_struct work;
+ struct completion complete;
+};
+
+static void wdog_disable_work(struct work_struct *work)
+{
+ struct wdog_disable_work_data *work_data =
+ container_of(work, struct wdog_disable_work_data, work);
+ __raw_writel(0, msm_tmr0_base + WDT0_EN);
+ mb();
+ if (has_vic) {
+ free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+ } else {
+ disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+ if (!appsbark_fiq) {
+ free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+ percpu_pdata);
+ free_percpu(percpu_pdata);
+ }
+ }
+ enable = 0;
+ atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
+ cancel_delayed_work(&dogwork_struct);
+ /* may be suspended after the first write above */
+ __raw_writel(0, msm_tmr0_base + WDT0_EN);
+ complete(&work_data->complete);
+ pr_info("MSM Watchdog deactivated.\n");
+}
+
static int wdog_enable_set(const char *val, struct kernel_param *kp)
{
int ret = 0;
int old_val = runtime_disable;
+ struct wdog_disable_work_data work_data;
mutex_lock(&disable_lock);
-
if (!enable) {
printk(KERN_INFO "MSM Watchdog is not active.\n");
ret = -EINVAL;
@@ -165,43 +195,20 @@
}
ret = param_set_int(val, kp);
-
if (ret)
goto done;
- switch (runtime_disable) {
-
- case 1:
- if (!old_val) {
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- mb();
- if (has_vic) {
- free_irq(WDT0_ACCSCSSNBARK_INT, 0);
- } else {
- disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
- if (!appsbark_fiq) {
- free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
- percpu_pdata);
- free_percpu(percpu_pdata);
- }
- }
- enable = 0;
- atomic_notifier_chain_unregister(&panic_notifier_list,
- &panic_blk);
- cancel_delayed_work(&dogwork_struct);
- /* may be suspended after the first write above */
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- printk(KERN_INFO "MSM Watchdog deactivated.\n");
- }
- break;
-
- default:
+ if (runtime_disable == 1) {
+ if (old_val)
+ goto done;
+ init_completion(&work_data.complete);
+ INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
+ schedule_work_on(0, &work_data.work);
+ wait_for_completion(&work_data.complete);
+ } else {
runtime_disable = old_val;
ret = -EINVAL;
- break;
-
}
-
done:
mutex_unlock(&disable_lock);
return ret;
@@ -332,9 +339,49 @@
}
}
+struct fiq_handler wdog_fh = {
+ .name = MODULE_NAME,
+};
+
static void init_watchdog_work(struct work_struct *work)
{
u64 timeout = (bark_time * WDT_HZ)/1000;
+ void *stack;
+ int ret;
+
+ if (has_vic) {
+ ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
+ "apps_wdog_bark", NULL);
+ if (ret)
+ return;
+ } 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;
+ }
+
+ msm_wdog_fiq_setup(stack);
+ gic_set_irq_secure(WDT0_ACCSCSSNBARK_INT);
+ } else {
+ percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+ if (!percpu_pdata) {
+ pr_err("%s: memory allocation failed for percpu data\n",
+ __func__);
+ return;
+ }
+
+ /* Must request irq before sending scm command */
+ ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
+ wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
+ if (ret) {
+ free_percpu(percpu_pdata);
+ return;
+ }
+ }
configure_bark_dump();
@@ -358,15 +405,9 @@
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");
@@ -382,41 +423,6 @@
msm_tmr0_base = msm_timer_get_timer0_base();
- if (has_vic) {
- ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
- "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) {
- pr_err("%s: memory allocation failed for percpu data\n",
- __func__);
- return -ENOMEM;
- }
-
- *__this_cpu_ptr(percpu_pdata) = pdata;
- /* Must request irq before sending scm command */
- ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT,
- wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
- if (ret) {
- free_percpu(percpu_pdata);
- return ret;
- }
- }
-
/*
* This is only temporary till SBLs turn on the XPUs
* This initialization will be done in SBLs on a later releases
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d1c474b..a0e01b4 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -32,4 +32,16 @@
}
void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
-EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
+
+int msm_pm_idle_prepare(struct cpuidle_device *dev)
+{
+ return -ENOSYS;
+}
+
+int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+{
+ return -ENOSYS;
+}
+
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
new file mode 100644
index 0000000..203b8d1
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem.c
@@ -0,0 +1,306 @@
+/* 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 <mach/ocmem_priv.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+struct ocmem_partition {
+ const char *name;
+ int id;
+ unsigned long p_start;
+ unsigned long p_size;
+ unsigned long p_min;
+};
+
+struct ocmem_plat_data {
+ void __iomem *vbase;
+ unsigned long size;
+ unsigned long base;
+ struct ocmem_partition *parts;
+ int nr_parts;
+};
+
+struct ocmem_zone zones[OCMEM_CLIENT_MAX];
+
+struct ocmem_zone *get_zone(unsigned id)
+{
+ if (id < OCMEM_GRAPHICS || id >= OCMEM_CLIENT_MAX)
+ return NULL;
+ else
+ return &zones[id];
+}
+
+static struct ocmem_plat_data *ocmem_pdata;
+
+#define CLIENT_NAME_MAX 10
+/* Must be in sync with enum ocmem_client */
+static const char *client_names[OCMEM_CLIENT_MAX] = {
+ "graphics",
+ "video",
+ "camera",
+ "hp_audio",
+ "voice",
+ "lp_audio",
+ "sensors",
+ "blast",
+};
+
+struct ocmem_quota_table {
+ const char *name;
+ int id;
+ unsigned long start;
+ unsigned long size;
+ unsigned long min;
+};
+
+/* This static table will go away with device tree support */
+static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
+ /* name, id, start, size, min */
+ { "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000},
+ { "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000},
+ { "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0},
+ { "voice", OCMEM_VOICE, 0x0, 0x0, 0x0 },
+ { "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0},
+ { "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000},
+ { "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000},
+ { "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000},
+};
+
+static inline int get_id(const char *name)
+{
+ int i = 0;
+ for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
+ if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
+ return i;
+ }
+ return -EINVAL;
+}
+
+static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
+{
+ struct ocmem_plat_data *pdata = NULL;
+ struct ocmem_partition *parts = NULL;
+ struct device *dev = &pdev->dev;
+ int nr_parts;
+ int i;
+ int j;
+
+ pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+ GFP_KERNEL);
+
+ if (!pdata) {
+ dev_err(dev, "Unable to allocate memory for"
+ " platform data\n");
+ return NULL;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(qt); i++)
+ if (qt[i].size != 0x0)
+ nr_parts++;
+
+ if (nr_parts == 0x0) {
+ dev_err(dev, "No valid ocmem partitions\n");
+ return NULL;
+ } else
+ dev_info(dev, "Total partitions = %d\n", nr_parts);
+
+ parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
+ GFP_KERNEL);
+
+ if (!parts) {
+ dev_err(dev, "Unable to allocate memory for"
+ " partition data\n");
+ return NULL;
+ }
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
+ if (qt[i].size == 0x0) {
+ dev_dbg(dev, "Skipping creation of pool for %s\n",
+ qt[i].name);
+ continue;
+ }
+ parts[j].id = qt[i].id;
+ parts[j].p_size = qt[i].size;
+ parts[j].p_start = qt[i].start;
+ parts[j].p_min = qt[i].min;
+ j++;
+ }
+ BUG_ON(j != nr_parts);
+ pdata->nr_parts = nr_parts;
+ pdata->parts = parts;
+ pdata->base = OCMEM_PHYS_BASE;
+ pdata->size = OCMEM_PHYS_SIZE;
+ return pdata;
+}
+
+static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
+{
+ return NULL;
+}
+
+static int ocmem_zone_init(struct platform_device *pdev)
+{
+
+ int ret = -1;
+ int i = 0;
+ unsigned active_zones = 0;
+
+ struct ocmem_zone *zone = NULL;
+ struct ocmem_zone_ops *z_ops = NULL;
+ struct device *dev = &pdev->dev;
+ unsigned long start;
+ struct ocmem_plat_data *pdata = NULL;
+
+ pdata = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->nr_parts; i++) {
+ struct ocmem_partition *part = &pdata->parts[i];
+ zone = get_zone(part->id);
+
+ dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
+ i, part->p_start, part->p_size,
+ client_names[part->id]);
+
+ if (part->p_size > pdata->size) {
+ dev_alert(dev, "Quota > ocmem_size for id:%d\n",
+ part->id);
+ continue;
+ }
+
+ zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
+
+ if (!zone->z_pool) {
+ dev_alert(dev, "Creating pool failed for id:%d\n",
+ part->id);
+ return -EBUSY;
+ }
+
+ start = pdata->base + part->p_start;
+ ret = gen_pool_add(zone->z_pool, start,
+ part->p_size, -1);
+
+ if (ret < 0) {
+ gen_pool_destroy(zone->z_pool);
+ dev_alert(dev, "Unable to back pool %d with "
+ "buffer:%lx\n", part->id, part->p_size);
+ return -EBUSY;
+ }
+
+ /* Initialize zone allocators */
+ z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
+ GFP_KERNEL);
+ if (!z_ops) {
+ pr_alert("ocmem: Unable to allocate memory for"
+ "zone ops:%d\n", i);
+ return -EBUSY;
+ }
+
+ /* Initialize zone parameters */
+ zone->z_start = start;
+ zone->z_head = zone->z_start;
+ zone->z_end = start + part->p_size;
+ zone->z_tail = zone->z_end;
+ zone->z_free = part->p_size;
+ zone->owner = part->id;
+ zone->active_regions = 0;
+ zone->max_regions = 0;
+ INIT_LIST_HEAD(&zone->region_list);
+ zone->z_ops = z_ops;
+ z_ops->allocate = allocate_head;
+ z_ops->free = free_head;
+ active_zones++;
+
+ if (active_zones == 1)
+ pr_info("Physical OCMEM zone layout:\n");
+
+ pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
+ client_names[part->id], zone->z_start,
+ zone->z_end, part->p_size/SZ_1K);
+ }
+
+ dev_info(dev, "Total active zones = %d\n", active_zones);
+ return 0;
+}
+
+static int __devinit msm_ocmem_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!pdev->dev.of_node->child) {
+ dev_info(dev, "Missing Configuration in Device Tree\n");
+ ocmem_pdata = parse_static_config(pdev);
+ } else {
+ ocmem_pdata = parse_dt_config(pdev);
+ }
+
+ /* Check if we have some configuration data to start */
+ if (!ocmem_pdata)
+ return -ENODEV;
+
+ /* Sanity Checks */
+ BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
+ BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
+
+ platform_set_drvdata(pdev, ocmem_pdata);
+
+ if (ocmem_zone_init(pdev))
+ return -EBUSY;
+
+ dev_info(dev, "initialized successfully\n");
+ return 0;
+}
+
+static int __devexit msm_ocmem_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id msm_ocmem_dt_match[] = {
+ { .compatible = "qcom,msm_ocmem",
+ },
+ {}
+};
+
+static struct platform_driver msm_ocmem_driver = {
+ .probe = msm_ocmem_probe,
+ .remove = __devexit_p(msm_ocmem_remove),
+ .driver = {
+ .name = "msm_ocmem",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_ocmem_dt_match,
+ },
+};
+
+static int __init ocmem_init(void)
+{
+ return platform_driver_register(&msm_ocmem_driver);
+}
+subsys_initcall(ocmem_init);
+
+static void __exit ocmem_exit(void)
+{
+ platform_driver_unregister(&msm_ocmem_driver);
+}
+module_exit(ocmem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
new file mode 100644
index 0000000..9f073fc
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -0,0 +1,45 @@
+/* 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 <mach/ocmem.h>
+#include <mach/ocmem_priv.h>
+#include <linux/genalloc.h>
+
+/* All allocator operations are serialized by ocmem driver */
+unsigned long allocate_head(struct ocmem_zone *z, unsigned long size)
+{
+
+ unsigned long offset;
+
+ offset = gen_pool_alloc(z->z_pool, size);
+
+ if (!offset)
+ return -ENOMEM;
+
+ z->z_head += size;
+ z->z_free -= size;
+ return offset;
+}
+
+int free_head(struct ocmem_zone *z, unsigned long offset,
+ unsigned long size)
+{
+ if (offset > z->z_head) {
+ pr_err("ocmem: Detected out of order free "
+ "leading to fragmentation\n");
+ return -EINVAL;
+ }
+ gen_pool_free(z->z_pool, offset, size);
+ z->z_head -= size;
+ z->z_free += size;
+ return 0;
+}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 0ecea85..7208a48 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -137,8 +137,11 @@
const struct firmware *fw = NULL;
const u8 *data;
- if (memblock_is_region_memory(phdr->p_paddr, phdr->p_memsz)) {
- dev_err(&pil->dev, "Kernel memory would be overwritten");
+ if (memblock_overlaps_memory(phdr->p_paddr, phdr->p_memsz)) {
+ dev_err(&pil->dev,
+ "kernel memory would be overwritten [%#08lx, %#08lx)\n",
+ (unsigned long)phdr->p_paddr,
+ (unsigned long)(phdr->p_paddr + phdr->p_memsz));
return -EPERM;
}
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 393f1bd..3826b12 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -40,6 +40,7 @@
static bool cold_boot_done;
static uint32_t *msm8625_boot_vector;
+static void __iomem *reset_core1_base;
/*
* Write pen_release in a way that is guaranteed to be visible to all
@@ -155,11 +156,16 @@
__raw_writel(0x0, base_ptr);
mb();
- iounmap(base_ptr);
+ reset_core1_base = base_ptr;
return 0;
}
+void __iomem *core1_reset_base(void)
+{
+ return reset_core1_base;
+}
+
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index cc17ceb..070e2c5 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -21,11 +21,9 @@
#include <linux/ktime.h>
#include <linux/pm.h>
#include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
#include <linux/smp.h>
#include <linux/suspend.h>
#include <linux/tick.h>
-#include <linux/uaccess.h>
#include <linux/wakelock.h>
#include <linux/delay.h>
#include <mach/msm_iomap.h>
@@ -319,220 +317,6 @@
}
/******************************************************************************
- * CONFIG_MSM_IDLE_STATS
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
- MSM_PM_STAT_REQUESTED_IDLE,
- MSM_PM_STAT_IDLE_WFI,
- MSM_PM_STAT_RETENTION,
- MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_POWER_COLLAPSE,
- MSM_PM_STAT_SUSPEND,
- MSM_PM_STAT_COUNT
-};
-
-struct msm_pm_time_stats {
- const char *name;
- int64_t first_bucket_time;
- int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int count;
- int64_t total_time;
-};
-
-struct msm_pm_cpu_time_stats {
- struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
-};
-
-static DEFINE_SPINLOCK(msm_pm_stats_lock);
-static DEFINE_PER_CPU_SHARED_ALIGNED(
- struct msm_pm_cpu_time_stats, msm_pm_stats);
-
-/*
- * Add the given time data to the statistics collection.
- */
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int64_t bt;
- int i;
-
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = __get_cpu_var(msm_pm_stats).stats;
-
- stats[id].total_time += t;
- stats[id].count++;
-
- bt = t;
- do_div(bt, stats[id].first_bucket_time);
-
- if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
- (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
- i = DIV_ROUND_UP(fls((uint32_t)bt),
- CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
- else
- i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
- if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
- i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
- stats[id].bucket[i]++;
-
- if (t < stats[id].min_time[i] || !stats[id].max_time[i])
- stats[id].min_time[i] = t;
- if (t > stats[id].max_time[i])
- stats[id].max_time[i] = t;
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-}
-
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
- do { \
- if (size > 0) { \
- int ret; \
- ret = snprintf(buf, size, format, ## __VA_ARGS__); \
- if (ret > size) { \
- buf += size; \
- size = 0; \
- } else { \
- buf += ret; \
- size -= ret; \
- } \
- } \
- } while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc
- (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- unsigned int cpu = off / MSM_PM_STAT_COUNT;
- int id = off % MSM_PM_STAT_COUNT;
- char *p = page;
-
- if (count < 1024) {
- *start = (char *) 0;
- *eof = 0;
- return 0;
- }
-
- if (cpu < num_possible_cpus()) {
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int i;
- int64_t bucket_time;
- int64_t s;
- uint32_t ns;
-
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = per_cpu(msm_pm_stats, cpu).stats;
-
- s = stats[id].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- "[cpu %u] %s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- cpu, stats[id].name,
- stats[id].count,
- s, ns);
-
- bucket_time = stats[id].first_bucket_time;
- for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
- s = bucket_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- }
-
- SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- *start = (char *) 1;
- *eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
- }
-
- return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char buf[sizeof(MSM_PM_STATS_RESET)];
- int ret;
- unsigned long flags;
- unsigned int cpu;
-
- if (count < strlen(MSM_PM_STATS_RESET)) {
- ret = -EINVAL;
- goto write_proc_failed;
- }
-
- if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
- ret = -EFAULT;
- goto write_proc_failed;
- }
-
- if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
- ret = -EINVAL;
- goto write_proc_failed;
- }
-
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- for_each_possible_cpu(cpu) {
- struct msm_pm_time_stats *stats;
- int i;
-
- stats = per_cpu(msm_pm_stats, cpu).stats;
- for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
- memset(stats[i].bucket,
- 0, sizeof(stats[i].bucket));
- memset(stats[i].min_time,
- 0, sizeof(stats[i].min_time));
- memset(stats[i].max_time,
- 0, sizeof(stats[i].max_time));
- stats[i].count = 0;
- stats[i].total_time = 0;
- }
- }
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
- return count;
-
-write_proc_failed:
- return ret;
-}
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
-/******************************************************************************
* Configure Hardware before/after Low Power Mode
*****************************************************************************/
@@ -805,6 +589,38 @@
msm_timer_exit_idle((int) timer_halted);
}
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+ int time = 0;
+
+ if (msm_pm_use_qtimer)
+ return sched_clock();
+
+ time = msm_timer_get_sclk_time(period);
+ if (!time)
+ pr_err("%s: Unable to read sclk.\n", __func__);
+
+ return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+ if (msm_pm_use_qtimer)
+ return sched_clock() - time;
+
+ if (time != 0) {
+ int64_t end_time = msm_timer_get_sclk_time(NULL);
+ if (end_time != 0) {
+ time = end_time - time;
+ if (time < 0)
+ time += period;
+ } else
+ time = 0;
+ }
+
+ return time;
+}
+
/******************************************************************************
* External Idle/Suspend Functions
*****************************************************************************/
@@ -926,9 +742,7 @@
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
{
int64_t time;
-#ifdef CONFIG_MSM_IDLE_STATS
int exit_stat;
-#endif
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: mode %d\n",
@@ -939,23 +753,17 @@
switch (sleep_mode) {
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
msm_pm_swfi();
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
break;
case MSM_PM_SLEEP_MODE_RETENTION:
msm_pm_retention();
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_RETENTION;
-#endif
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
msm_pm_power_collapse_standalone(true);
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
@@ -987,10 +795,7 @@
notify_rpm, collapsed);
}
msm_pm_timer_exit_idle(timer_halted);
-
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-#endif
break;
}
@@ -1000,9 +805,7 @@
}
time = ktime_to_ns(ktime_get()) - time;
-#ifdef CONFIG_MSM_IDLE_STATS
msm_pm_add_stat(exit_stat, time);
-#endif
do_div(time, 1000);
return (int) time;
@@ -1057,7 +860,7 @@
msm_pm_retention();
} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
per_cpu(msm_pm_last_slp_mode, cpu)
- = MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
+ = MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT;
msm_pm_swfi();
} else
per_cpu(msm_pm_last_slp_mode, cpu) = MSM_PM_SLEEP_MODE_NR;
@@ -1097,11 +900,8 @@
{
bool allow[MSM_PM_SLEEP_MODE_NR];
int i;
-
-#ifdef CONFIG_MSM_IDLE_STATS
int64_t period = 0;
- int64_t time = msm_timer_get_sclk_time(&period);
-#endif
+ int64_t time = msm_pm_timer_enter_suspend(&period);
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s\n", __func__);
@@ -1163,19 +963,8 @@
pr_err("%s: cannot find the lowest power limit\n",
__func__);
}
-
-#ifdef CONFIG_MSM_IDLE_STATS
- if (time != 0) {
- int64_t end_time = msm_timer_get_sclk_time(NULL);
- if (end_time != 0) {
- time = end_time - time;
- if (time < 0)
- time += period;
- } else
- time = 0;
- }
+ time = msm_pm_timer_exit_suspend(time, period);
msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
-#endif /* CONFIG_MSM_IDLE_STATS */
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: standalone power collapse\n", __func__);
@@ -1217,10 +1006,14 @@
pgd_t *pc_pgd;
pmd_t *pmd;
unsigned long pmdval;
-#ifdef CONFIG_MSM_IDLE_STATS
- unsigned int cpu;
- struct proc_dir_entry *d_entry;
-#endif
+ enum msm_pm_time_stats_id enable_stats[] = {
+ MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_RETENTION,
+ MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+ MSM_PM_STAT_SUSPEND,
+ };
+
/* Page table for cores to come back up safely. */
pc_pgd = pgd_alloc(&init_mm);
if (!pc_pgd)
@@ -1257,49 +1050,9 @@
clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
virt_to_phys(&msm_pm_pc_pgd));
-#ifdef CONFIG_MSM_IDLE_STATS
- for_each_possible_cpu(cpu) {
- struct msm_pm_time_stats *stats =
- per_cpu(msm_pm_stats, cpu).stats;
-
- stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
- stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
- stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_RETENTION].name = "retention";
- stats[MSM_PM_STAT_RETENTION].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
- "idle-standalone-power-collapse";
- stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
- first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
- "idle-power-collapse";
- stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_SUSPEND].name = "suspend";
- stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
- CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
- }
-
- d_entry = create_proc_entry("msm_pm_stats",
- S_IRUGO | S_IWUSR | S_IWGRP, NULL);
- if (d_entry) {
- d_entry->read_proc = msm_pm_read_proc;
- d_entry->write_proc = msm_pm_write_proc;
- d_entry->data = NULL;
- }
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
msm_pm_mode_sysfs_add();
+ msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
msm_spm_allow_x_cpu_set_vdd(false);
suspend_set_ops(&msm_pm_ops);
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
new file mode 100644
index 0000000..936820a
--- /dev/null
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -0,0 +1,305 @@
+/* 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/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/proc_fs.h>
+
+#include "pm.h"
+
+struct msm_pm_time_stats {
+ const char *name;
+ int64_t first_bucket_time;
+ int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int count;
+ int64_t total_time;
+ bool enabled;
+};
+
+struct msm_pm_cpu_time_stats {
+ struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
+};
+
+static DEFINE_SPINLOCK(msm_pm_stats_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(
+ struct msm_pm_cpu_time_stats, msm_pm_stats);
+
+/*
+ * Add the given time data to the statistics collection.
+ */
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+ unsigned long flags;
+ struct msm_pm_time_stats *stats;
+ int64_t bt;
+ int i;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ stats = __get_cpu_var(msm_pm_stats).stats;
+
+ if (!stats[id].enabled)
+ goto add_bail;
+
+ stats[id].total_time += t;
+ stats[id].count++;
+
+ bt = t;
+ do_div(bt, stats[id].first_bucket_time);
+
+ if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+ (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+ i = DIV_ROUND_UP(fls((uint32_t)bt),
+ CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+ else
+ i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+ if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
+ i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+ stats[id].bucket[i]++;
+
+ if (t < stats[id].min_time[i] || !stats[id].max_time[i])
+ stats[id].min_time[i] = t;
+ if (t > stats[id].max_time[i])
+ stats[id].max_time[i] = t;
+
+add_bail:
+ spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+}
+
+/*
+ * Helper function of snprintf where buf is auto-incremented, size is auto-
+ * decremented, and there is no return value.
+ *
+ * NOTE: buf and size must be l-values (e.g. variables)
+ */
+#define SNPRINTF(buf, size, format, ...) \
+ do { \
+ if (size > 0) { \
+ int ret; \
+ ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+ if (ret > size) { \
+ buf += size; \
+ size = 0; \
+ } else { \
+ buf += ret; \
+ size -= ret; \
+ } \
+ } \
+ } while (0)
+
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_read_proc
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ unsigned int cpu = off / MSM_PM_STAT_COUNT;
+ int id = off % MSM_PM_STAT_COUNT;
+ char *p = page;
+
+ if (count < 1024) {
+ *start = (char *) 0;
+ *eof = 0;
+ return 0;
+ }
+
+ if (cpu < num_possible_cpus()) {
+ unsigned long flags;
+ struct msm_pm_time_stats *stats;
+ int i;
+ int64_t bucket_time;
+ int64_t s;
+ uint32_t ns;
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ stats = per_cpu(msm_pm_stats, cpu).stats;
+
+ /* Skip the disabled ones */
+ if (!stats[id].enabled) {
+ *p = '\0';
+ p++;
+ goto again;
+ }
+
+ s = stats[id].total_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ SNPRINTF(p, count,
+ "[cpu %u] %s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ cpu, stats[id].name,
+ stats[id].count,
+ s, ns);
+
+ bucket_time = stats[id].first_bucket_time;
+ for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
+ s = bucket_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ SNPRINTF(p, count,
+ " <%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats[id].bucket[i],
+ stats[id].min_time[i],
+ stats[id].max_time[i]);
+
+ bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+ }
+
+ SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, stats[id].bucket[i],
+ stats[id].min_time[i],
+ stats[id].max_time[i]);
+
+again:
+ *start = (char *) 1;
+ *eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
+
+ spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+ }
+
+ return p - page;
+}
+#undef SNPRINTF
+
+#define MSM_PM_STATS_RESET "reset"
+
+/*
+ * Reset the power management statistics values.
+ */
+static int msm_pm_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char buf[sizeof(MSM_PM_STATS_RESET)];
+ int ret;
+ unsigned long flags;
+ unsigned int cpu;
+
+ if (count < sizeof(MSM_PM_STATS_RESET)) {
+ ret = -EINVAL;
+ goto write_proc_failed;
+ }
+
+ if (copy_from_user(buf, buffer, sizeof(MSM_PM_STATS_RESET))) {
+ ret = -EFAULT;
+ goto write_proc_failed;
+ }
+
+ if (memcmp(buf, MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET))) {
+ ret = -EINVAL;
+ goto write_proc_failed;
+ }
+
+ spin_lock_irqsave(&msm_pm_stats_lock, flags);
+ for_each_possible_cpu(cpu) {
+ struct msm_pm_time_stats *stats;
+ int i;
+
+ stats = per_cpu(msm_pm_stats, cpu).stats;
+ for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
+ memset(stats[i].bucket,
+ 0, sizeof(stats[i].bucket));
+ memset(stats[i].min_time,
+ 0, sizeof(stats[i].min_time));
+ memset(stats[i].max_time,
+ 0, sizeof(stats[i].max_time));
+ stats[i].count = 0;
+ stats[i].total_time = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
+ return count;
+
+write_proc_failed:
+ return ret;
+}
+#undef MSM_PM_STATS_RESET
+
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size)
+{
+ unsigned int cpu;
+ struct proc_dir_entry *d_entry;
+ int i = 0;
+
+ for_each_possible_cpu(cpu) {
+ struct msm_pm_time_stats *stats =
+ per_cpu(msm_pm_stats, cpu).stats;
+
+ stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
+ stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
+ stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
+ stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_RETENTION].name = "retention";
+ stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
+ "idle-standalone-power-collapse";
+ stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
+ first_bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
+ "idle-failed-standalone-power-collapse";
+ stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
+ first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
+ "idle-power-collapse";
+ stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
+ "idle-failed-power-collapse";
+ stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
+ first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_SUSPEND].name = "suspend";
+ stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
+ CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
+ stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
+ stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
+ for (i = 0; i < size; i++)
+ stats[enable_stats[i]].enabled = true;
+
+ }
+
+ d_entry = create_proc_entry("msm_pm_stats",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL);
+ if (d_entry) {
+ d_entry->read_proc = msm_pm_read_proc;
+ d_entry->write_proc = msm_pm_write_proc;
+ d_entry->data = NULL;
+ }
+}
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
deleted file mode 100644
index d684a5a..0000000
--- a/arch/arm/mach-msm/pm.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/* arch/arm/mach-msm/pm.c
- *
- * MSM Power Management Routines
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, 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/clk.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
-#include <linux/suspend.h>
-#include <linux/reboot.h>
-#include <linux/uaccess.h>
-#include <mach/msm_iomap.h>
-#include <mach/system.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_HAS_WAKELOCK
-#include <linux/wakelock.h>
-#endif
-
-#include "smd_private.h"
-#include "smd_rpcrouter.h"
-#include "acpuclock.h"
-#include "clock.h"
-#include "proc_comm.h"
-#include "idle.h"
-#include "irq.h"
-#include "gpio.h"
-#include "timer.h"
-#include "pm.h"
-#include "pm-boot.h"
-
-enum {
- MSM_PM_DEBUG_SUSPEND = 1U << 0,
- MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
- MSM_PM_DEBUG_STATE = 1U << 2,
- MSM_PM_DEBUG_CLOCK = 1U << 3,
- MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
- MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
- MSM_PM_DEBUG_IDLE = 1U << 6,
-};
-static int msm_pm_debug_mask;
-module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
- msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
-module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
-module_param_named(idle_sleep_mode, msm_pm_idle_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
-module_param_named(idle_sleep_min_time, msm_pm_idle_sleep_min_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static int msm_pm_idle_spin_time = CONFIG_MSM7X00A_IDLE_SPIN_TIME;
-module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define A11S_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
-#define A11S_PWRDOWN (MSM_CSR_BASE + 0x440)
-#define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108)
-#define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508)
-
-enum {
- SLEEP_LIMIT_NONE = 0,
- SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2
-};
-
-static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
-struct smsm_interrupt_info_ext {
- uint32_t aArm_en_mask;
- uint32_t aArm_interrupts_pending;
- uint32_t aArm_wakeup_reason;
- uint32_t aArm_rpc_prog;
- uint32_t aArm_rpc_proc;
- char aArm_smd_port_name[20];
- uint32_t aArm_gpio_info;
-};
-static struct msm_pm_smem_addr_t {
- uint32_t *sleep_delay;
- uint32_t *limit_sleep;
- struct smsm_interrupt_info *int_info;
- struct smsm_interrupt_info_ext *int_info_ext;
-} msm_pm_sma;
-
-static uint32_t msm_pm_max_sleep_time;
-static struct msm_pm_platform_data *msm_pm_modes;
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
- MSM_PM_STAT_REQUESTED_IDLE,
- MSM_PM_STAT_IDLE_SPIN,
- MSM_PM_STAT_IDLE_WFI,
- MSM_PM_STAT_IDLE_SLEEP,
- MSM_PM_STAT_IDLE_FAILED_SLEEP,
- MSM_PM_STAT_IDLE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
- MSM_PM_STAT_SUSPEND,
- MSM_PM_STAT_FAILED_SUSPEND,
- MSM_PM_STAT_NOT_IDLE,
- MSM_PM_STAT_COUNT
-};
-
-static struct msm_pm_time_stats {
- const char *name;
- int64_t first_bucket_time;
- int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int count;
- int64_t total_time;
-} msm_pm_stats[MSM_PM_STAT_COUNT] = {
- [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
- [MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
- [MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
- [MSM_PM_STAT_IDLE_WFI].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
- [MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
- [MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse",
- [MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
- "idle-failed-power-collapse",
- [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_SUSPEND].name = "suspend",
- [MSM_PM_STAT_SUSPEND].first_bucket_time =
- CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend",
- [MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-
- [MSM_PM_STAT_NOT_IDLE].name = "not-idle",
- [MSM_PM_STAT_NOT_IDLE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
-};
-
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
- int i;
- int64_t bt;
- msm_pm_stats[id].total_time += t;
- msm_pm_stats[id].count++;
- bt = t;
- do_div(bt, msm_pm_stats[id].first_bucket_time);
- if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
- (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
- i = DIV_ROUND_UP(fls((uint32_t)bt),
- CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
- else
- i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
- msm_pm_stats[id].bucket[i]++;
- if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
- msm_pm_stats[id].min_time[i] = t;
- if (t > msm_pm_stats[id].max_time[i])
- msm_pm_stats[id].max_time[i] = t;
-}
-
-static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-#endif
-
-static int
-msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear,
- uint32_t wait_state_any_set, uint32_t wait_state_any_clear)
-{
- int i;
- uint32_t state;
-
- for (i = 0; i < 2000000; i++) {
- state = smsm_get_state(SMSM_MODEM_STATE);
- if (((state & wait_state_all_set) == wait_state_all_set) &&
- ((~state & wait_state_all_clear) == wait_state_all_clear) &&
- (wait_state_any_set == 0 || (state & wait_state_any_set) ||
- wait_state_any_clear == 0 || (state & wait_state_any_clear)))
- return 0;
- }
- printk(KERN_ERR "msm_pm_wait_state(%x, %x, %x, %x) failed %x\n",
- wait_state_all_set, wait_state_all_clear,
- wait_state_any_set, wait_state_any_clear, state);
- return -ETIMEDOUT;
-}
-
-/*
- * Respond to timing out waiting for Modem
- *
- * NOTE: The function never returns.
- */
-static void msm_pm_timeout(void)
-{
-#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
- printk(KERN_EMERG "%s(): resetting chip\n", __func__);
- msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
-#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
- printk(KERN_EMERG "%s(): resetting modem\n", __func__);
- msm_proc_comm_reset_modem_now();
-#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
- printk(KERN_EMERG "%s(): halting\n", __func__);
-#endif
- for (;;)
- ;
-}
-
-static int msm_sleep(int sleep_mode, uint32_t sleep_delay,
- uint32_t sleep_limit, int from_idle)
-{
- int collapsed;
- uint32_t enter_state;
- uint32_t enter_wait_set = 0;
- uint32_t enter_wait_clear = 0;
- uint32_t exit_state;
- uint32_t exit_wait_clear = 0;
- uint32_t exit_wait_set = 0;
- unsigned long pm_saved_acpu_clk_rate = 0;
- int ret;
- int rv = -EINTR;
-
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
- printk(KERN_INFO "msm_sleep(): "
- "mode %d delay %u limit %u idle %d\n",
- sleep_mode, sleep_delay, sleep_limit, from_idle);
-
- switch (sleep_mode) {
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- enter_state = SMSM_PWRC;
- enter_wait_set = SMSM_RSA;
- exit_state = SMSM_WFPI;
- exit_wait_clear = SMSM_RSA;
- break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
- enter_state = SMSM_PWRC_SUSPEND;
- enter_wait_set = SMSM_RSA;
- exit_state = SMSM_WFPI;
- exit_wait_clear = SMSM_RSA;
- break;
- case MSM_PM_SLEEP_MODE_APPS_SLEEP:
- enter_state = SMSM_SLEEP;
- exit_state = SMSM_SLEEPEXIT;
- exit_wait_set = SMSM_SLEEPEXIT;
- break;
- default:
- enter_state = 0;
- exit_state = 0;
- }
-
- if (enter_state && !(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RUN)) {
- if ((MSM_PM_DEBUG_POWER_COLLAPSE | MSM_PM_DEBUG_SUSPEND) &
- msm_pm_debug_mask)
- printk(KERN_INFO "msm_sleep(): modem not ready\n");
- rv = -EBUSY;
- goto check_failed;
- }
-
- memset(msm_pm_sma.int_info, 0, sizeof(*msm_pm_sma.int_info));
- msm_irq_enter_sleep1(!!enter_state, from_idle,
- &msm_pm_sma.int_info->aArm_en_mask);
- msm_gpio_enter_sleep(from_idle);
-
- if (enter_state) {
- if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP)
- sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */
-
- *msm_pm_sma.sleep_delay = sleep_delay;
- *msm_pm_sma.limit_sleep = sleep_limit;
- ret = smsm_change_state(SMSM_APPS_STATE, SMSM_RUN, enter_state);
- if (ret) {
- printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state);
- enter_state = 0;
- exit_state = 0;
- }
- ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0);
- if (ret) {
- printk(KERN_EMERG "msm_sleep(): power collapse entry "
- "timed out waiting for Modem's response\n");
- msm_pm_timeout();
- }
- }
- if (msm_irq_enter_sleep2(!!enter_state, from_idle))
- goto enter_failed;
-
- if (enter_state) {
- __raw_writel(0x1f, A11S_CLK_SLEEP_EN);
- __raw_writel(1, A11S_PWRDOWN);
-
- __raw_writel(0, A11S_STANDBY_CTL);
- __raw_writel(0, A11RAMBACKBIAS);
-
- if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
- printk(KERN_INFO "msm_sleep(): enter "
- "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
- "smsm_get_state %x\n",
- __raw_readl(A11S_CLK_SLEEP_EN),
- __raw_readl(A11S_PWRDOWN),
- smsm_get_state(SMSM_MODEM_STATE));
- }
-
- if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
- pm_saved_acpu_clk_rate = acpuclk_power_collapse();
- if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
- printk(KERN_INFO "msm_sleep(): %ld enter power collapse"
- "\n", pm_saved_acpu_clk_rate);
- if (pm_saved_acpu_clk_rate == 0)
- goto ramp_down_failed;
- }
- if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) {
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
- smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
- *msm_pm_sma.limit_sleep,
- msm_pm_sma.int_info->aArm_en_mask,
- msm_pm_sma.int_info->aArm_wakeup_reason,
- msm_pm_sma.int_info->aArm_interrupts_pending);
- msm_pm_boot_config_before_pc(smp_processor_id(),
- virt_to_phys(msm_pm_collapse_exit));
- collapsed = msm_pm_collapse();
- msm_pm_boot_config_after_pc(smp_processor_id());
- if (collapsed) {
- cpu_init();
- local_fiq_enable();
- rv = 0;
- }
- if (msm_pm_debug_mask & MSM_PM_DEBUG_POWER_COLLAPSE)
- printk(KERN_INFO "msm_pm_collapse(): returned %d\n",
- collapsed);
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
- smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
- *msm_pm_sma.limit_sleep,
- msm_pm_sma.int_info->aArm_en_mask,
- msm_pm_sma.int_info->aArm_wakeup_reason,
- msm_pm_sma.int_info->aArm_interrupts_pending);
- } else {
- msm_arch_idle();
- rv = 0;
- }
-
- if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
- if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
- printk(KERN_INFO "msm_sleep(): exit power collapse %ld"
- "\n", pm_saved_acpu_clk_rate);
- if (acpuclk_set_rate(smp_processor_id(),
- pm_saved_acpu_clk_rate, SETRATE_PC) < 0)
- printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
- "failed\n", pm_saved_acpu_clk_rate);
- }
- if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
- printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, "
- "A11S_PWRDOWN %x, smsm_get_state %x\n",
- __raw_readl(A11S_CLK_SLEEP_EN),
- __raw_readl(A11S_PWRDOWN),
- smsm_get_state(SMSM_MODEM_STATE));
-ramp_down_failed:
- msm_irq_exit_sleep1(msm_pm_sma.int_info->aArm_en_mask,
- msm_pm_sma.int_info->aArm_wakeup_reason,
- msm_pm_sma.int_info->aArm_interrupts_pending);
-enter_failed:
- if (enter_state) {
- __raw_writel(0x00, A11S_CLK_SLEEP_EN);
- __raw_writel(0, A11S_PWRDOWN);
- smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state);
- if (msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0)) {
- printk(KERN_EMERG "msm_sleep(): power collapse exit "
- "timed out waiting for Modem's response\n");
- msm_pm_timeout();
- }
- if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
- printk(KERN_INFO "msm_sleep(): sleep exit "
- "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
- "smsm_get_state %x\n",
- __raw_readl(A11S_CLK_SLEEP_EN),
- __raw_readl(A11S_PWRDOWN),
- smsm_get_state(SMSM_MODEM_STATE));
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
- smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
- *msm_pm_sma.limit_sleep,
- msm_pm_sma.int_info->aArm_en_mask,
- msm_pm_sma.int_info->aArm_wakeup_reason,
- msm_pm_sma.int_info->aArm_interrupts_pending);
- }
- msm_irq_exit_sleep2(msm_pm_sma.int_info->aArm_en_mask,
- msm_pm_sma.int_info->aArm_wakeup_reason,
- msm_pm_sma.int_info->aArm_interrupts_pending);
- if (enter_state) {
- smsm_change_state(SMSM_APPS_STATE, exit_state, SMSM_RUN);
- if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
- printk(KERN_INFO "msm_sleep(): sleep exit "
- "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
- "smsm_get_state %x\n",
- __raw_readl(A11S_CLK_SLEEP_EN),
- __raw_readl(A11S_PWRDOWN),
- smsm_get_state(SMSM_MODEM_STATE));
- }
- msm_irq_exit_sleep3(msm_pm_sma.int_info->aArm_en_mask,
- msm_pm_sma.int_info->aArm_wakeup_reason,
- msm_pm_sma.int_info->aArm_interrupts_pending);
- msm_gpio_exit_sleep();
- smd_sleep_exit();
-
-check_failed:
- return rv;
-}
-
-void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
-{
- int64_t max_sleep_time_bs = max_sleep_time_ns;
-
- /* Convert from ns -> BS units */
- do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768);
-
- if (max_sleep_time_bs > 0x6DDD000)
- msm_pm_max_sleep_time = (uint32_t) 0x6DDD000;
- else
- msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs;
-
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
- printk(KERN_INFO "%s: Requested %lldns (%lldbs), Giving %ubs\n",
- __func__, max_sleep_time_ns,
- max_sleep_time_bs,
- msm_pm_max_sleep_time);
-}
-EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-
-void arch_idle(void)
-{
- int ret;
- int spin;
- int64_t sleep_time;
- int low_power = 0;
- struct msm_pm_platform_data *mode;
-#ifdef CONFIG_MSM_IDLE_STATS
- int64_t t1;
- static int64_t t2;
- int exit_stat;
-#endif
- int latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
- uint32_t sleep_limit = SLEEP_LIMIT_NONE;
- int allow_sleep =
- msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT &&
-#ifdef CONFIG_HAS_WAKELOCK
- !has_wake_lock(WAKE_LOCK_IDLE) &&
-#endif
- msm_irq_idle_sleep_allowed();
-
- if (!atomic_read(&msm_pm_init_done))
- return;
-
- sleep_time = msm_timer_enter_idle();
-
-#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_REQUESTED_IDLE, sleep_time);
-#endif
-
- mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE];
- if (mode->latency >= latency_qos)
- sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
-
- mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN];
- if (mode->latency >= latency_qos)
- allow_sleep = false;
-
- mode = &msm_pm_modes[
- MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT];
- if (mode->latency >= latency_qos) {
- /* no time even for SWFI */
- while (!msm_irq_pending())
- udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
- exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
- goto abort_idle;
- }
-
- if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE)
- printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n",
- sleep_time, allow_sleep);
- spin = msm_pm_idle_spin_time >> 10;
- while (spin-- > 0) {
- if (msm_irq_pending()) {
-#ifdef CONFIG_MSM_IDLE_STATS
- exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
- goto abort_idle;
- }
- udelay(1);
- }
- if (sleep_time < msm_pm_idle_sleep_min_time || !allow_sleep) {
- unsigned long saved_rate;
- saved_rate = acpuclk_wait_for_irq();
- if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
- printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n",
- saved_rate);
- if (saved_rate) {
- msm_arch_idle();
-#ifdef CONFIG_MSM_IDLE_STATS
- exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
- } else {
- while (!msm_irq_pending())
- udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
- exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
- }
- if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
- printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n",
- saved_rate);
- if (saved_rate
- && acpuclk_set_rate(smp_processor_id(),
- saved_rate, SETRATE_SWFI) < 0)
- printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
- "failed\n", saved_rate);
- } else {
- low_power = 1;
- do_div(sleep_time, NSEC_PER_SEC / 32768);
- if (sleep_time > 0x6DDD000) {
- printk("sleep_time too big %lld\n", sleep_time);
- sleep_time = 0x6DDD000;
- }
- ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time,
- sleep_limit, 1);
-#ifdef CONFIG_MSM_IDLE_STATS
- switch (msm_pm_idle_sleep_mode) {
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- if (ret)
- exit_stat =
- MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
- else {
- exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
- msm_pm_sleep_limit = sleep_limit;
- }
- break;
- case MSM_PM_SLEEP_MODE_APPS_SLEEP:
- if (ret)
- exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
- else
- exit_stat = MSM_PM_STAT_IDLE_SLEEP;
- break;
- default:
- exit_stat = MSM_PM_STAT_IDLE_WFI;
- }
-#endif
- }
-abort_idle:
- 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);
-#endif
-}
-
-static int msm_pm_enter(suspend_state_t state)
-{
- uint32_t sleep_limit = SLEEP_LIMIT_NONE;
- int ret;
-#ifdef CONFIG_MSM_IDLE_STATS
- int64_t period = 0;
- int64_t time = 0;
-
- time = msm_timer_get_sclk_time(&period);
-#endif
-
- clock_debug_print_enabled();
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
- if (msm_pm_sleep_time_override > 0) {
- int64_t ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
- msm_pm_set_max_sleep_time(ns);
- msm_pm_sleep_time_override = 0;
- }
-#endif
-
- ret = msm_sleep(msm_pm_sleep_mode,
- msm_pm_max_sleep_time, sleep_limit, 0);
-
-#ifdef CONFIG_MSM_IDLE_STATS
- if (msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND ||
- msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
- enum msm_pm_time_stats_id id;
- int64_t end_time;
-
- if (ret)
- id = MSM_PM_STAT_FAILED_SUSPEND;
- else {
- id = MSM_PM_STAT_SUSPEND;
- msm_pm_sleep_limit = sleep_limit;
- }
-
- if (time != 0) {
- end_time = msm_timer_get_sclk_time(NULL);
- if (end_time != 0) {
- time = end_time - time;
- if (time < 0)
- time += period;
- } else
- time = 0;
- }
-
- msm_pm_add_stat(id, time);
- }
-#endif
-
- return 0;
-}
-
-static struct platform_suspend_ops msm_pm_ops = {
- .enter = msm_pm_enter,
- .valid = suspend_valid_only_mem,
-};
-
-static uint32_t restart_reason = 0x776655AA;
-
-static void msm_pm_power_off(void)
-{
- msm_rpcrouter_close();
- msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
- for (;;) ;
-}
-
-static void msm_pm_restart(char str, const char *cmd)
-{
- msm_rpcrouter_close();
- msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
-
- for (;;) ;
-}
-
-static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd)
-{
- if((code == SYS_RESTART) && _cmd) {
- char *cmd = _cmd;
- if (!strcmp(cmd, "bootloader")) {
- restart_reason = 0x77665500;
- } else if (!strcmp(cmd, "recovery")) {
- restart_reason = 0x77665502;
- } else if (!strcmp(cmd, "eraseflash")) {
- restart_reason = 0x776655EF;
- } else if (!strncmp(cmd, "oem-", 4)) {
- unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
- restart_reason = 0x6f656d00 | code;
- } else {
- restart_reason = 0x77665501;
- }
- }
- return NOTIFY_DONE;
-}
-
-static struct notifier_block msm_reboot_notifier = {
- .notifier_call = msm_reboot_call,
-};
-
-#ifdef CONFIG_MSM_IDLE_STATS
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
- do { \
- if (size > 0) { \
- int ret; \
- ret = snprintf(buf, size, format, ## __VA_ARGS__); \
- if (ret > size) { \
- buf += size; \
- size = 0; \
- } else { \
- buf += ret; \
- size -= ret; \
- } \
- } \
- } while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc(
- char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int i;
- char *p = page;
-
- if (count < 1024) {
- *start = (char *) 0;
- *eof = 0;
- return 0;
- }
-
- if (!off) {
- SNPRINTF(p, count, "Last power collapse voted ");
- if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE)
- SNPRINTF(p, count, "for TCXO shutdown\n\n");
- else
- SNPRINTF(p, count, "against TCXO shutdown\n\n");
-
- *start = (char *) 1;
- *eof = 0;
- } else if (--off < ARRAY_SIZE(msm_pm_stats)) {
- int64_t bucket_time;
- int64_t s;
- uint32_t ns;
-
- s = msm_pm_stats[off].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- "%s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- msm_pm_stats[off].name,
- msm_pm_stats[off].count,
- s, ns);
-
- bucket_time = msm_pm_stats[off].first_bucket_time;
- for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
- s = bucket_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, msm_pm_stats[off].bucket[i],
- msm_pm_stats[off].min_time[i],
- msm_pm_stats[off].max_time[i]);
-
- bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- }
-
- SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, msm_pm_stats[off].bucket[i],
- msm_pm_stats[off].min_time[i],
- msm_pm_stats[off].max_time[i]);
-
- *start = (char *) 1;
- *eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats));
- }
-
- return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char buf[sizeof(MSM_PM_STATS_RESET)];
- int ret;
- unsigned long flags;
- int i;
-
- if (count < strlen(MSM_PM_STATS_RESET)) {
- ret = -EINVAL;
- goto write_proc_failed;
- }
-
- if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
- ret = -EFAULT;
- goto write_proc_failed;
- }
-
- if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
- ret = -EINVAL;
- goto write_proc_failed;
- }
-
- local_irq_save(flags);
- for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
- memset(msm_pm_stats[i].bucket,
- 0, sizeof(msm_pm_stats[i].bucket));
- memset(msm_pm_stats[i].min_time,
- 0, sizeof(msm_pm_stats[i].min_time));
- memset(msm_pm_stats[i].max_time,
- 0, sizeof(msm_pm_stats[i].max_time));
- msm_pm_stats[i].count = 0;
- msm_pm_stats[i].total_time = 0;
- }
-
- msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
- local_irq_restore(flags);
-
- return count;
-
-write_proc_failed:
- return ret;
-}
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-static int __init msm_pm_init(void)
-{
-#ifdef CONFIG_MSM_IDLE_STATS
- struct proc_dir_entry *d_entry;
-#endif
- int ret;
-
- pm_power_off = msm_pm_power_off;
- arm_pm_restart = msm_pm_restart;
- msm_pm_max_sleep_time = 0;
-
- register_reboot_notifier(&msm_reboot_notifier);
-
- msm_pm_sma.sleep_delay = smem_alloc(SMEM_SMSM_SLEEP_DELAY,
- sizeof(*msm_pm_sma.sleep_delay));
- if (msm_pm_sma.sleep_delay == NULL) {
- printk(KERN_ERR "msm_pm_init: failed get SLEEP_DELAY\n");
- return -ENODEV;
- }
-
- msm_pm_sma.limit_sleep = smem_alloc(SMEM_SMSM_LIMIT_SLEEP,
- sizeof(*msm_pm_sma.limit_sleep));
- if (msm_pm_sma.limit_sleep == NULL) {
- printk(KERN_ERR "msm_pm_init: failed get LIMIT_SLEEP\n");
- return -ENODEV;
- }
-
- msm_pm_sma.int_info_ext = smem_alloc(SMEM_SMSM_INT_INFO,
- sizeof(*msm_pm_sma.int_info_ext));
-
- if (msm_pm_sma.int_info_ext)
- msm_pm_sma.int_info = (struct smsm_interrupt_info *)
- msm_pm_sma.int_info_ext;
- else
- msm_pm_sma.int_info = smem_alloc(SMEM_SMSM_INT_INFO,
- sizeof(*msm_pm_sma.int_info));
-
- if (msm_pm_sma.int_info == NULL) {
- printk(KERN_ERR "msm_pm_init: failed get INT_INFO\n");
- return -ENODEV;
- }
-
- ret = msm_timer_init_time_sync(msm_pm_timeout);
- if (ret)
- return ret;
-
- BUG_ON(msm_pm_modes == NULL);
-
- atomic_set(&msm_pm_init_done, 1);
- suspend_set_ops(&msm_pm_ops);
-
-#ifdef CONFIG_MSM_IDLE_STATS
- d_entry = create_proc_entry("msm_pm_stats",
- S_IRUGO | S_IWUSR | S_IWGRP, NULL);
- if (d_entry) {
- d_entry->read_proc = msm_pm_read_proc;
- d_entry->write_proc = msm_pm_write_proc;
- d_entry->data = NULL;
- }
-#endif
-
- return 0;
-}
-
-void __init msm_pm_set_platform_data(
- struct msm_pm_platform_data *data, int count)
-{
- BUG_ON(MSM_PM_SLEEP_MODE_NR != count);
- msm_pm_modes = data;
-}
-
-late_initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 09494a0..ce0d747 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -84,6 +84,8 @@
void __init msm_pm_init_sleep_status_data(
struct msm_pm_sleep_status_data *sleep_data);
+
+
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
int msm_pm_wait_cpu_shutdown(unsigned int cpu);
@@ -99,4 +101,29 @@
#else
static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
#endif
+
+enum msm_pm_time_stats_id {
+ MSM_PM_STAT_REQUESTED_IDLE = 0,
+ MSM_PM_STAT_IDLE_SPIN,
+ MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_RETENTION,
+ MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+ MSM_PM_STAT_SUSPEND,
+ MSM_PM_STAT_FAILED_SUSPEND,
+ MSM_PM_STAT_NOT_IDLE,
+ MSM_PM_STAT_COUNT
+};
+
+#ifdef CONFIG_MSM_IDLE_STATS
+void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats, int size);
+void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t);
+#else
+static inline void msm_pm_add_stats(enum msm_pm_time_stats_id *enable_stats,
+ int size) {}
+static inline void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) {}
+#endif
+
#endif /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index f4bfe23..426d6e6 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -23,10 +23,8 @@
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/pm_qos_params.h>
-#include <linux/proc_fs.h>
#include <linux/suspend.h>
#include <linux/reboot.h>
-#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/tick.h>
#include <linux/memory.h>
@@ -65,7 +63,7 @@
#include "spm.h"
#include "sirc.h"
#include "pm-boot.h"
-#define MSM_CORE1_RESET 0xA8600590
+#include "devices-msm7x2xa.h"
/******************************************************************************
* Debug Definitions
@@ -425,6 +423,7 @@
SLEEP_LIMIT_MASK = 0x03,
};
+static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
enum {
SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
@@ -455,30 +454,21 @@
static void msm_pm_config_hw_before_power_down(void)
{
if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
- __raw_writel(1, APPS_PWRDOWN);
- mb();
__raw_writel(4, APPS_SECOP);
- mb();
} else if (cpu_is_msm7x27()) {
__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
- mb();
- __raw_writel(1, APPS_PWRDOWN);
- mb();
} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
cpu_is_msm7x25ab()) {
__raw_writel(0x7, APPS_CLK_SLEEP_EN);
- mb();
- __raw_writel(1, APPS_PWRDOWN);
- mb();
- } else {
+ } else if (cpu_is_qsd8x50()) {
__raw_writel(0x1f, APPS_CLK_SLEEP_EN);
mb();
- __raw_writel(1, APPS_PWRDOWN);
- mb();
__raw_writel(0, APPS_STANDBY_CTL);
- mb();
}
+ mb();
+ __raw_writel(1, APPS_PWRDOWN);
+ mb();
}
/*
@@ -490,7 +480,7 @@
void __iomem *base_ptr;
unsigned int value = 0;
- base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+ base_ptr = core1_reset_base();
if (!base_ptr)
return;
@@ -545,7 +535,6 @@
mb();
__raw_writel(0x0, base_ptr);
mb();
- iounmap(base_ptr);
}
/*
@@ -560,13 +549,11 @@
__raw_writel(0, APPS_PWRDOWN);
mb();
msm_spm_reinit();
- } else {
+ } else if (cpu_is_msm8625()) {
__raw_writel(0, APPS_PWRDOWN);
mb();
- __raw_writel(0, APPS_CLK_SLEEP_EN);
- mb();
- if (cpu_is_msm8625() && power_collapsed) {
+ if (power_collapsed) {
/*
* enable the SCU while coming out of power
* collapse.
@@ -577,6 +564,11 @@
*/
configure_top_csr();
}
+ } else {
+ __raw_writel(0, APPS_PWRDOWN);
+ mb();
+ __raw_writel(0, APPS_CLK_SLEEP_EN);
+ mb();
}
}
@@ -772,238 +764,6 @@
/******************************************************************************
- * CONFIG_MSM_IDLE_STATS
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_IDLE_STATS
-enum msm_pm_time_stats_id {
- MSM_PM_STAT_REQUESTED_IDLE,
- MSM_PM_STAT_IDLE_SPIN,
- MSM_PM_STAT_IDLE_WFI,
- MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
- MSM_PM_STAT_SUSPEND,
- MSM_PM_STAT_FAILED_SUSPEND,
- MSM_PM_STAT_NOT_IDLE,
- MSM_PM_STAT_COUNT
-};
-
-struct msm_pm_time_stats {
- const char *name;
- int64_t first_bucket_time;
- int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
- int count;
- int64_t total_time;
-};
-
-struct msm_pm_cpu_time_stats {
- struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(
- struct msm_pm_cpu_time_stats, msm_pm_stats);
-
-static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
-
-static DEFINE_SPINLOCK(msm_pm_stats_lock);
-
-/*
- * Add the given time data to the statistics collection.
- */
-static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
-{
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int i;
- int64_t bt;
-
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = __get_cpu_var(msm_pm_stats).stats;
-
- stats[id].total_time += t;
- stats[id].count++;
-
- bt = t;
- do_div(bt, stats[id].first_bucket_time);
-
- if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
- (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
- i = DIV_ROUND_UP(fls((uint32_t)bt),
- CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
- else
- i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
- if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
- i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
-
- stats[id].bucket[i]++;
-
- if (t < stats[id].min_time[i] || !stats[id].max_time[i])
- stats[id].min_time[i] = t;
- if (t > stats[id].max_time[i])
- stats[id].max_time[i] = t;
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-}
-
-/*
- * Helper function of snprintf where buf is auto-incremented, size is auto-
- * decremented, and there is no return value.
- *
- * NOTE: buf and size must be l-values (e.g. variables)
- */
-#define SNPRINTF(buf, size, format, ...) \
- do { \
- if (size > 0) { \
- int ret; \
- ret = snprintf(buf, size, format, ## __VA_ARGS__); \
- if (ret > size) { \
- buf += size; \
- size = 0; \
- } else { \
- buf += ret; \
- size -= ret; \
- } \
- } \
- } while (0)
-
-/*
- * Write out the power management statistics.
- */
-static int msm_pm_read_proc
- (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- unsigned int cpu = off / MSM_PM_STAT_COUNT;
- int id = off % MSM_PM_STAT_COUNT;
- char *p = page;
-
- if (count < 1024) {
- *start = (char *) 0;
- *eof = 0;
- return 0;
- }
-
- if (!off) {
- SNPRINTF(p, count, "Last power collapse voted ");
- if ((msm_pm_sleep_limit & SLEEP_LIMIT_MASK) ==
- SLEEP_LIMIT_NONE)
- SNPRINTF(p, count, "for TCXO shutdown\n\n");
- else
- SNPRINTF(p, count, "against TCXO shutdown\n\n");
- }
-
- if (cpu < num_possible_cpus()) {
- unsigned long flags;
- struct msm_pm_time_stats *stats;
- int i;
- int64_t bucket_time;
- int64_t s;
- uint32_t ns;
-
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- stats = per_cpu(msm_pm_stats, cpu).stats;
-
- s = stats[id].total_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- "[cpu %u] %s:\n"
- " count: %7d\n"
- " total_time: %lld.%09u\n",
- cpu, stats[id].name,
- stats[id].count,
- s, ns);
-
- bucket_time = stats[id].first_bucket_time;
- for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
- s = bucket_time;
- ns = do_div(s, NSEC_PER_SEC);
- SNPRINTF(p, count,
- " <%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
- }
-
- SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
- s, ns, stats[id].bucket[i],
- stats[id].min_time[i],
- stats[id].max_time[i]);
-
- *start = (char *) 1;
- *eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
-
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
- }
-
- return p - page;
-}
-#undef SNPRINTF
-
-#define MSM_PM_STATS_RESET "reset"
-
-/*
- * Reset the power management statistics values.
- */
-static int msm_pm_write_proc(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char buf[sizeof(MSM_PM_STATS_RESET)];
- int ret;
- unsigned long flags;
- unsigned int cpu;
-
- if (count < strlen(MSM_PM_STATS_RESET)) {
- ret = -EINVAL;
- goto write_proc_failed;
- }
-
- if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
- ret = -EFAULT;
- goto write_proc_failed;
- }
-
- if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
- ret = -EINVAL;
- goto write_proc_failed;
- }
-
- spin_lock_irqsave(&msm_pm_stats_lock, flags);
- for_each_possible_cpu(cpu) {
- struct msm_pm_time_stats *stats;
- int i;
-
- stats = per_cpu(msm_pm_stats, cpu).stats;
- for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
- memset(stats[i].bucket,
- 0, sizeof(stats[i].bucket));
- memset(stats[i].min_time,
- 0, sizeof(stats[i].min_time));
- memset(stats[i].max_time,
- 0, sizeof(stats[i].max_time));
- stats[i].count = 0;
- stats[i].total_time = 0;
- }
- }
- msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
- spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
-
- return count;
-
-write_proc_failed:
- return ret;
-}
-
-#undef MSM_PM_STATS_RESET
-#endif /* CONFIG_MSM_IDLE_STATS */
-
-
-/******************************************************************************
* Shared Memory Bits
*****************************************************************************/
@@ -1194,7 +954,10 @@
#endif
#ifdef CONFIG_CACHE_L2X0
- l2cc_suspend();
+ if (!cpu_is_msm8625())
+ l2cc_suspend();
+ else
+ apps_power_collapse = 1;
#endif
collapsed = msm_pm_collapse();
@@ -1221,7 +984,10 @@
}
#ifdef CONFIG_CACHE_L2X0
- l2cc_resume();
+ if (!cpu_is_msm8625())
+ l2cc_resume();
+ else
+ apps_power_collapse = 0;
#endif
msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1508,6 +1274,30 @@
return 0;
}
+static int64_t msm_pm_timer_enter_suspend(int64_t *period)
+{
+ int time = 0;
+
+ time = msm_timer_get_sclk_time(period);
+ if (!time)
+ pr_err("%s: Unable to read sclk.\n", __func__);
+ return time;
+}
+
+static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
+{
+
+ if (time != 0) {
+ int64_t end_time = msm_timer_get_sclk_time(NULL);
+ if (end_time != 0) {
+ time = end_time - time;
+ if (time < 0)
+ time += period;
+ } else
+ time = 0;
+ }
+ return time;
+}
/******************************************************************************
* External Idle/Suspend Functions
@@ -1526,28 +1316,22 @@
int ret;
int i;
unsigned int cpu;
-
-#ifdef CONFIG_MSM_IDLE_STATS
int64_t t1;
static DEFINE_PER_CPU(int64_t, t2);
int exit_stat;
- #endif
if (!atomic_read(&msm_pm_init_done))
return;
cpu = smp_processor_id();
-
latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
/* 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 - __get_cpu_var(t2));
msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
for (i = 0; i < ARRAY_SIZE(allow); i++)
allow[i] = true;
@@ -1628,46 +1412,34 @@
low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
msm_timer_exit_idle(low_power);
-#ifdef CONFIG_MSM_IDLE_STATS
if (ret)
exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
else {
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
msm_pm_sleep_limit = sleep_limit;
}
-#endif
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
ret = msm_pm_power_collapse_standalone(true);
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = ret ?
MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif
} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
ret = msm_pm_swfi(true);
if (ret)
while (!msm_pm_irq_extns->irq_pending())
udelay(1);
-#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);
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif
} else {
while (!msm_pm_irq_extns->irq_pending())
udelay(1);
-#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif
}
-#ifdef CONFIG_MSM_IDLE_STATS
__get_cpu_var(t2) = ktime_to_ns(ktime_get());
msm_pm_add_stat(exit_stat, __get_cpu_var(t2) - t1);
-#endif
}
/*
@@ -1688,10 +1460,8 @@
uint32_t sleep_limit = SLEEP_LIMIT_NONE;
int ret = -EPERM;
int i;
-#ifdef CONFIG_MSM_IDLE_STATS
int64_t period = 0;
int64_t time = 0;
-#endif
/* Must executed by CORE0 */
if (smp_processor_id()) {
@@ -1699,9 +1469,7 @@
goto suspend_exit;
}
-#ifdef CONFIG_MSM_IDLE_STATS
- time = msm_timer_get_sclk_time(&period);
-#endif
+ time = msm_pm_timer_enter_suspend(&period);
MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
"%s(): sleep limit %u\n", __func__, sleep_limit);
@@ -1718,10 +1486,7 @@
if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
-#ifdef CONFIG_MSM_IDLE_STATS
enum msm_pm_time_stats_id id;
- int64_t end_time;
-#endif
clock_debug_print_enabled();
@@ -1751,7 +1516,6 @@
ret = msm_pm_power_collapse(
false, msm_pm_max_sleep_time, sleep_limit);
-#ifdef CONFIG_MSM_IDLE_STATS
if (ret)
id = MSM_PM_STAT_FAILED_SUSPEND;
else {
@@ -1759,18 +1523,8 @@
msm_pm_sleep_limit = sleep_limit;
}
- if (time != 0) {
- end_time = msm_timer_get_sclk_time(NULL);
- if (end_time != 0) {
- time = end_time - time;
- if (time < 0)
- time += period;
- } else
- time = 0;
- }
-
+ time = msm_pm_timer_exit_suspend(time, period);
msm_pm_add_stat(id, time);
-#endif
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
ret = msm_pm_power_collapse_standalone(false);
} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
@@ -1880,12 +1634,21 @@
*/
static int __init msm_pm_init(void)
{
-#ifdef CONFIG_MSM_IDLE_STATS
- struct proc_dir_entry *d_entry;
- unsigned int cpu;
-#endif
int ret;
int val;
+ enum msm_pm_time_stats_id enable_stats[] = {
+ MSM_PM_STAT_REQUESTED_IDLE,
+ MSM_PM_STAT_IDLE_SPIN,
+ MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+ MSM_PM_STAT_SUSPEND,
+ MSM_PM_STAT_FAILED_SUSPEND,
+ MSM_PM_STAT_NOT_IDLE,
+ };
+
#ifdef CONFIG_CPU_V7
pgd_t *pc_pgd;
pmd_t *pmd;
@@ -1963,6 +1726,8 @@
*/
val = 0x00030002;
__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+
+ l2x0_base_addr = MSM_L2CC_BASE;
}
#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
@@ -1979,70 +1744,9 @@
suspend_set_ops(&msm_pm_ops);
msm_pm_mode_sysfs_add();
-#ifdef CONFIG_MSM_IDLE_STATS
- for_each_possible_cpu(cpu) {
- struct msm_pm_time_stats *stats =
- per_cpu(msm_pm_stats, cpu).stats;
-
- stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
- stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
- stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
- stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
- "idle-standalone-power-collapse";
- stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
- first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
- "idle-failed-standalone-power-collapse";
- stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
- first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
- "idle-power-collapse";
- stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
- "idle-failed-power-collapse";
- stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
- first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_SUSPEND].name = "suspend";
- stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
- CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
- stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
- stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
- }
+ msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
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) {
- d_entry->read_proc = msm_pm_read_proc;
- d_entry->write_proc = msm_pm_write_proc;
- d_entry->data = NULL;
- }
-#endif
-
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
index dc41bf4..fae2401 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mvs.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
@@ -276,7 +276,7 @@
struct audio_mvs_dl_reply {
struct rpc_reply_hdr reply_hdr;
- uint32_t voc_pkt[MVS_MAX_VOC_PKT_SIZE/4];
+ uint32_t voc_pkt[Q5V2_MVS_MAX_VOC_PKT_SIZE/4];
uint32_t valid_frame_info_ptr;
uint32_t frame_mode;
@@ -288,7 +288,7 @@
struct audio_mvs_buf_node {
struct list_head list;
- struct msm_audio_mvs_frame frame;
+ struct q5v2_msm_audio_mvs_frame frame;
};
/* Each buffer is 20 ms, queue holds 200 ms of data. */
@@ -933,10 +933,15 @@
pr_debug("%s: UL AMR frame_type %d\n",
__func__, be32_to_cpu(*args));
- } else if ((frame_mode == MVS_FRAME_MODE_PCM_UL) ||
- (frame_mode == MVS_FRAME_MODE_VOC_TX)) {
- /* PCM and EVRC don't have frame_type */
+ } else if (frame_mode == MVS_FRAME_MODE_PCM_UL) {
+ /* PCM don't have frame_type */
buf_node->frame.frame_type = 0;
+ } else if (frame_mode == MVS_FRAME_MODE_VOC_TX) {
+ /* Extracting EVRC current buffer frame rate*/
+ buf_node->frame.frame_type = be32_to_cpu(*args);
+
+ pr_debug("%s: UL EVRC frame_type %d\n",
+ __func__, be32_to_cpu(*args));
} else if (frame_mode == MVS_FRAME_MODE_G711_UL) {
/* Extract G711 frame type. */
buf_node->frame.frame_type = be32_to_cpu(*args);
@@ -1065,7 +1070,7 @@
cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
} else if (frame_mode == MVS_FRAME_MODE_VOC_RX) {
dl_reply.cdc_param.gnr_arg.param1 =
- cpu_to_be32(audio->rate_type);
+ cpu_to_be32(buf_node->frame.frame_type);
dl_reply.cdc_param.gnr_arg.param2 = 0;
dl_reply.cdc_param.\
gnr_arg.valid_pkt_status_ptr =
@@ -1427,7 +1432,7 @@
if ((audio->state == AUDIO_MVS_STARTED) &&
(!list_empty(&audio->out_queue))) {
- if (count >= sizeof(struct msm_audio_mvs_frame)) {
+ if (count >= sizeof(struct q5v2_msm_audio_mvs_frame)) {
buf_node = list_first_entry(&audio->out_queue,
struct audio_mvs_buf_node,
list);
@@ -1435,7 +1440,8 @@
rc = copy_to_user(buf,
&buf_node->frame,
- sizeof(struct msm_audio_mvs_frame));
+ sizeof(struct q5v2_msm_audio_mvs_frame)
+ );
if (rc == 0) {
rc = buf_node->frame.len +
@@ -1453,7 +1459,7 @@
} else {
pr_err("%s: Read count %d < sizeof(frame) %d",
__func__, count,
- sizeof(struct msm_audio_mvs_frame));
+ sizeof(struct q5v2_msm_audio_mvs_frame));
rc = -ENOMEM;
}
@@ -1491,7 +1497,7 @@
mutex_lock(&audio->in_lock);
if (audio->state == AUDIO_MVS_STARTED) {
- if (count <= sizeof(struct msm_audio_mvs_frame)) {
+ if (count <= sizeof(struct q5v2_msm_audio_mvs_frame)) {
if (!list_empty(&audio->free_in_queue)) {
buf_node =
list_first_entry(&audio->free_in_queue,
@@ -1511,7 +1517,7 @@
} else {
pr_err("%s: Write count %d < sizeof(frame) %d",
__func__, count,
- sizeof(struct msm_audio_mvs_frame));
+ sizeof(struct q5v2_msm_audio_mvs_frame));
rc = -ENOMEM;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
index 1d8195e..1fa0876 100644
--- a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
+++ b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
@@ -27,7 +27,6 @@
#include "../proc_comm.h"
#include <mach/debug_mm.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp6v2/dsp_debug.h>
static wait_queue_head_t dsp_wait;
@@ -72,8 +71,7 @@
{
char cmd[32];
void __iomem *ptr;
- unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
- struct msm_mapped_buffer *mem_buffer;
+ void *mem_buffer;
if (count >= sizeof(cmd))
return -EINVAL;
@@ -96,21 +94,19 @@
}
}
/* assert DSP NMI */
- mem_buffer = msm_subsystem_map_buffer(DSP_NMI_ADDR, 0x16, flags,
- NULL, 0);
+ mem_buffer = ioremap(DSP_NMI_ADDR, 0x16);
if (IS_ERR((void *)mem_buffer)) {
pr_err("%s:map_buffer failed, error = %ld\n", __func__,
PTR_ERR((void *)mem_buffer));
return -ENOMEM;
}
- ptr = mem_buffer->vaddr;
+ ptr = mem_buffer;
if (!ptr) {
pr_err("Unable to map DSP NMI\n");
return -EFAULT;
}
writel(0x1, (void *)ptr);
- if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
- pr_err("%s:unmap buffer failed\n", __func__);
+ iounmap(mem_buffer);
} else if (!strcmp(cmd, "boom")) {
q6audio_dsp_not_responding();
} else if (!strcmp(cmd, "continue-crash")) {
@@ -135,8 +131,7 @@
size_t mapsize = PAGE_SIZE;
unsigned addr;
void __iomem *ptr;
- unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
- struct msm_mapped_buffer *mem_buffer;
+ void *mem_buffer;
if ((dsp_ram_base == 0) || (dsp_ram_size == 0)) {
pr_err("[%s:%s] Memory Invalid or not initialized, Base = 0x%x,"
@@ -158,29 +153,26 @@
mapsize *= 2;
while (count >= PAGE_SIZE) {
- mem_buffer = msm_subsystem_map_buffer(addr, mapsize, flags,
- NULL, 0);
+ mem_buffer = ioremap(addr, mapsize);
if (IS_ERR((void *)mem_buffer)) {
pr_err("%s:map_buffer failed, error = %ld\n",
__func__, PTR_ERR((void *)mem_buffer));
return -ENOMEM;
}
- ptr = mem_buffer->vaddr;
+ ptr = mem_buffer;
if (!ptr) {
pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
__func__, addr);
return -EFAULT;
}
if (copy_to_user(buf, ptr, PAGE_SIZE)) {
- if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
- pr_err("%s: unmap buffer failed\n", __func__);
+ iounmap(mem_buffer);
pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
__func__, buf);
return -EFAULT;
}
copy_ok_count += PAGE_SIZE;
- if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
- pr_err("%s: unmap buffer failed\n", __func__);
+ iounmap(mem_buffer);
addr += PAGE_SIZE;
buf += PAGE_SIZE;
actual += PAGE_SIZE;
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index b14c968..221ffca 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.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
@@ -21,6 +21,10 @@
#define SCM_FLAG_WARMBOOT_CPU2 0x10
#define SCM_FLAG_WARMBOOT_CPU3 0x40
+#ifdef CONFIG_MSM_SCM
int scm_set_boot_addr(void *addr, int flags);
+#else
+static inline int scm_set_boot_addr(void *addr, int flags) { return 0; }
+#endif
#endif
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d811f71..b047cf4 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -218,7 +218,6 @@
/* 8064 IDs */
[109] = MSM_CPU_8064,
- [130] = MSM_CPU_8064,
/* 8930 IDs */
[116] = MSM_CPU_8930,
@@ -247,14 +246,17 @@
[128] = MSM_CPU_8625,
[129] = MSM_CPU_8625,
- /* 9625 IDs */
- [130] = MSM_CPU_9625,
+ /* 8064 MPQ ID */
+ [130] = MSM_CPU_8064,
/* 7x25AB IDs */
[131] = MSM_CPU_7X25AB,
[132] = MSM_CPU_7X25AB,
[133] = MSM_CPU_7X25AB,
+ /* 9625 IDs */
+ [134] = MSM_CPU_9625,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -625,7 +627,7 @@
strlcpy(dummy_socinfo.build_id, "copper - ",
sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_msm9625()) {
- dummy_socinfo.id = 130;
+ dummy_socinfo.id = 134;
strlcpy(dummy_socinfo.build_id, "msm9625 - ",
sizeof(dummy_socinfo.build_id));
} else if (machine_is_msm8625_rumi3())
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 34640c3..7b7549a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -194,6 +194,7 @@
return -ENOMEM;
}
}
+ driver->data_ready[i] = 0x0;
driver->data_ready[i] |= MSG_MASKS_TYPE;
driver->data_ready[i] |= EVENT_MASKS_TYPE;
driver->data_ready[i] |= LOG_MASKS_TYPE;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index a7a4a2a..4ac2643 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1139,8 +1139,17 @@
}
}
#if defined(CONFIG_DIAG_OVER_USB)
+ /* Check for the command/respond msg for the maximum packet length */
+ if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
+ (*(uint16_t *)(buf+2) == 0x0055)) {
+ for (i = 0; i < 4; i++)
+ *(driver->apps_rsp_buf+i) = *(buf+i);
+ *(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
+ ENCODE_RSP_AND_SEND(7);
+ return 0;
+ }
/* Check for Apps Only & get event mask request */
- if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+ else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
driver->apps_rsp_buf[0] = 0x81;
driver->apps_rsp_buf[1] = 0x0;
*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 111bc49..c203fc5 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -2101,32 +2101,33 @@
uint32_t authsize = q_req->authsize;
uint32_t totallen_in, totallen_out, out_len;
uint32_t pad_len_in, pad_len_out;
- uint32_t pad_mac_len_out, pad_ptx_len_out;
int rc = 0;
int ce_block_size;
ce_block_size = pce_dev->ce_dm.ce_block_size;
if (q_req->dir == QCE_ENCRYPT) {
+ uint32_t pad_mac_len_out;
+
q_req->cryptlen = areq->cryptlen;
totallen_in = q_req->cryptlen + areq->assoclen;
- totallen_out = q_req->cryptlen + authsize + areq->assoclen;
- out_len = areq->cryptlen + authsize;
pad_len_in = ALIGN(totallen_in, ce_block_size) - totallen_in;
- pad_mac_len_out = ALIGN(authsize, ce_block_size) -
- authsize;
- pad_ptx_len_out = ALIGN(q_req->cryptlen, ce_block_size) -
- q_req->cryptlen;
- pad_len_out = pad_ptx_len_out + pad_mac_len_out;
- totallen_out += pad_len_out;
+
+ out_len = areq->cryptlen + authsize;
+ totallen_out = q_req->cryptlen + authsize + areq->assoclen;
+ pad_mac_len_out = ALIGN(authsize, ce_block_size) - authsize;
+ totallen_out += pad_mac_len_out;
+ pad_len_out = ALIGN(totallen_out, ce_block_size) -
+ totallen_out + pad_mac_len_out;
+
} else {
q_req->cryptlen = areq->cryptlen - authsize;
totallen_in = areq->cryptlen + areq->assoclen;
- totallen_out = q_req->cryptlen + areq->assoclen;
- out_len = areq->cryptlen - authsize;
- pad_len_in = ALIGN(areq->cryptlen, ce_block_size) -
- areq->cryptlen;
- pad_len_out = pad_len_in + authsize;
- totallen_out += pad_len_out;
+ pad_len_in = ALIGN(totallen_in, ce_block_size) - totallen_in;
+
+ out_len = q_req->cryptlen;
+ totallen_out = totallen_in;
+ pad_len_out = ALIGN(totallen_out, ce_block_size) - totallen_out;
+ pad_len_out += authsize;
}
_chain_buffer_in_init(pce_dev);
@@ -2605,4 +2606,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.16");
+MODULE_VERSION("2.17");
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index bd7729b..bbb13f3 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -996,19 +996,41 @@
{
struct ion_client *client = s->private;
struct rb_node *n;
+ struct rb_node *n2;
- seq_printf(s, "%16.16s: %16.16s : %16.16s : %16.16s\n", "heap_name",
- "size_in_bytes", "handle refcount", "buffer");
+ seq_printf(s, "%16.16s: %16.16s : %16.16s : %12.12s : %12.12s : %s\n",
+ "heap_name", "size_in_bytes", "handle refcount",
+ "buffer", "physical", "[domain,partition] - virt");
+
mutex_lock(&client->lock);
for (n = rb_first(&client->handles); n; n = rb_next(n)) {
struct ion_handle *handle = rb_entry(n, struct ion_handle,
node);
+ enum ion_heap_type type = handle->buffer->heap->type;
- seq_printf(s, "%16.16s: %16x : %16d : %16p\n",
+ seq_printf(s, "%16.16s: %16x : %16d : %12p",
handle->buffer->heap->name,
handle->buffer->size,
atomic_read(&handle->ref.refcount),
handle->buffer);
+
+ if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
+ type == ION_HEAP_TYPE_CARVEOUT ||
+ type == ION_HEAP_TYPE_CP)
+ seq_printf(s, " : %12lx", handle->buffer->priv_phys);
+ else
+ seq_printf(s, " : %12s", "N/A");
+
+ for (n2 = rb_first(&handle->buffer->iommu_maps); n2;
+ n2 = rb_next(n2)) {
+ struct ion_iommu_map *imap =
+ rb_entry(n2, struct ion_iommu_map, node);
+ seq_printf(s, " : [%d,%d] - %8lx",
+ imap->domain_info[DI_DOMAIN_NUM],
+ imap->domain_info[DI_PARTITION_NUM],
+ imap->iova_addr);
+ }
+ seq_printf(s, "\n");
}
seq_printf(s, "%16.16s %d\n", "client refcount:",
@@ -1063,7 +1085,13 @@
struct rb_node *parent = NULL;
struct ion_client *entry;
pid_t pid;
- unsigned int name_len = strnlen(name, 64);
+ unsigned int name_len;
+
+ if (!name) {
+ pr_err("%s: Name cannot be null\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+ name_len = strnlen(name, 64);
get_task_struct(current->group_leader);
task_lock(current->group_leader);
@@ -1493,21 +1521,28 @@
mutex_unlock(&client->lock);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
+ if (data.fd < 0)
+ return data.fd;
break;
}
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
+ int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
data.handle = ion_import_fd(client, data.fd);
- if (IS_ERR(data.handle))
+ if (IS_ERR(data.handle)) {
+ ret = PTR_ERR(data.handle);
data.handle = NULL;
+ }
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
+ if (ret < 0)
+ return ret;
break;
}
case ION_IOC_CUSTOM:
@@ -1561,6 +1596,8 @@
if (!data.handle)
ion_free(client, handle);
+ if (ret < 0)
+ return ret;
break;
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 7f57fe6..052b778 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -243,7 +243,8 @@
cp_heap->total_size -
cp_heap->allocated_bytes, size);
- if (cp_heap->reusable && !cp_heap->allocated_bytes) {
+ if (cp_heap->reusable && !cp_heap->allocated_bytes &&
+ cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
if (fmem_set_state(FMEM_T_STATE) != 0)
pr_err("%s: unable to transition heap to T-state\n",
__func__);
@@ -293,7 +294,8 @@
mutex_lock(&cp_heap->lock);
cp_heap->allocated_bytes -= size;
- if (cp_heap->reusable && !cp_heap->allocated_bytes) {
+ if (cp_heap->reusable && !cp_heap->allocated_bytes &&
+ cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
if (fmem_set_state(FMEM_T_STATE) != 0)
pr_err("%s: unable to transition heap to T-state\n",
__func__);
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 15c0ec5..c8bfce3 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -213,6 +213,45 @@
}
}
+static int is_heap_overlapping(const struct ion_platform_heap *heap1,
+ const struct ion_platform_heap *heap2)
+{
+ unsigned long heap1_base = heap1->base;
+ unsigned long heap2_base = heap2->base;
+ unsigned long heap1_end = heap1->base + heap1->size - 1;
+ unsigned long heap2_end = heap2->base + heap2->size - 1;
+
+ if (heap1_base == heap2_base)
+ return 1;
+ if (heap1_base < heap2_base && heap1_end >= heap2_base)
+ return 1;
+ if (heap2_base < heap1_base && heap2_end >= heap1_base)
+ return 1;
+ return 0;
+}
+
+static void check_for_heap_overlap(const struct ion_platform_heap heap_list[],
+ unsigned long nheaps)
+{
+ unsigned long i;
+ unsigned long j;
+
+ for (i = 0; i < nheaps; ++i) {
+ const struct ion_platform_heap *heap1 = &heap_list[i];
+ if (!heap1->base)
+ continue;
+ for (j = i + 1; j < nheaps; ++j) {
+ const struct ion_platform_heap *heap2 = &heap_list[j];
+ if (!heap2->base)
+ continue;
+ if (is_heap_overlapping(heap1, heap2)) {
+ panic("Memory in heap %s overlaps with heap %s\n",
+ heap1->name, heap2->name);
+ }
+ }
+ }
+}
+
static int msm_ion_probe(struct platform_device *pdev)
{
struct ion_platform_data *pdata = pdev->dev.platform_data;
@@ -258,6 +297,8 @@
ion_device_add_heap(idev, heaps[i]);
}
+
+ check_for_heap_overlap(pdata->heaps, num_heaps);
platform_set_drvdata(pdev, idev);
return 0;
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index bfbf411..1432ccf 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -158,7 +158,7 @@
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_256K },
/* A3XX doesn't use the pix_shader_start */
- { ADRENO_REV_A320, 3, 2, 0, 0,
+ { ADRENO_REV_A320, 3, 2, 0, ANY_ID,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_512K },
@@ -276,7 +276,7 @@
/* set page table base */
*cmds++ = cp_type0_packet(MH_MMU_PT_BASE, 1);
- *cmds++ = kgsl_pt_get_base_addr(
+ *cmds++ = kgsl_mmu_pt_get_base_addr(
device->mmu.hwpagetable);
sizedwords += 4;
}
@@ -362,10 +362,22 @@
*/
if (cpu_is_apq8064()) {
+ unsigned int version = socinfo_get_version();
+
/* A320 */
majorid = 2;
minorid = 0;
- patchid = 0;
+
+ /*
+ * V1.1 has some GPU work arounds that we need to communicate
+ * up to user space via the patchid
+ */
+
+ if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+ (SOCINFO_VERSION_MINOR(version) == 1))
+ patchid = 1;
+ else
+ patchid = 0;
} else if (cpu_is_msm8930()) {
/* A305 */
majorid = 0;
@@ -1129,16 +1141,12 @@
static unsigned int _get_context_id(struct kgsl_context *k_ctxt)
{
unsigned int context_id = KGSL_MEMSTORE_GLOBAL;
-
if (k_ctxt != NULL) {
struct adreno_context *a_ctxt = k_ctxt->devctxt;
- /*
- * if the context was not created with per context timestamp
- * support, we must use the global timestamp since issueibcmds
- * will be returning that one.
- */
- if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
- context_id = a_ctxt->id;
+ if (k_ctxt->id == KGSL_CONTEXT_INVALID || a_ctxt == NULL)
+ context_id = KGSL_CONTEXT_INVALID;
+ else if (a_ctxt->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ context_id = k_ctxt->id;
}
return context_id;
@@ -1149,11 +1157,22 @@
{
int status;
unsigned int ref_ts, enableflag;
- unsigned int context_id = _get_context_id(context);
+ unsigned int context_id;
+
+ mutex_lock(&device->mutex);
+ context_id = _get_context_id(context);
+ /*
+ * If the context ID is invalid, we are in a race with
+ * the context being destroyed by userspace so bail.
+ */
+ if (context_id == KGSL_CONTEXT_INVALID) {
+ KGSL_DRV_WARN(device, "context was detached");
+ status = -EINVAL;
+ goto unlock;
+ }
status = kgsl_check_timestamp(device, context, timestamp);
if (!status) {
- mutex_lock(&device->mutex);
kgsl_sharedmem_readl(&device->memstore, &enableflag,
KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
mb();
@@ -1187,8 +1206,9 @@
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
&cmds[0], 2);
}
- mutex_unlock(&device->mutex);
}
+unlock:
+ mutex_unlock(&device->mutex);
return status;
}
@@ -1247,6 +1267,15 @@
msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
msecs_part = (msecs - msecs_first + 3) / 4;
for (retries = 0; retries < 5; retries++) {
+ /*
+ * If the context ID is invalid, we are in a race with
+ * the context being destroyed by userspace so bail.
+ */
+ if (context_id == KGSL_CONTEXT_INVALID) {
+ KGSL_DRV_WARN(device, "context was detached");
+ status = -EINVAL;
+ goto done;
+ }
if (kgsl_check_timestamp(device, context, timestamp)) {
/* if the timestamp happens while we're not
* waiting, there's a chance that an interrupt
@@ -1308,6 +1337,14 @@
unsigned int timestamp = 0;
unsigned int context_id = _get_context_id(context);
+ /*
+ * If the context ID is invalid, we are in a race with
+ * the context being destroyed by userspace so bail.
+ */
+ if (context_id == KGSL_CONTEXT_INVALID) {
+ KGSL_DRV_WARN(device, "context was detached");
+ return timestamp;
+ }
switch (type) {
case KGSL_TIMESTAMP_QUEUED: {
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index adf2772..cf09f52 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -363,28 +363,54 @@
return NULL;
}
+ kref_init(&context->refcount);
context->id = id;
context->dev_priv = dev_priv;
return context;
}
-static void
-kgsl_destroy_context(struct kgsl_device_private *dev_priv,
- struct kgsl_context *context)
+/**
+ * kgsl_context_detach - Release the "master" context reference
+ * @context - The context that will be detached
+ *
+ * This is called when a context becomes unusable, because userspace
+ * has requested for it to be destroyed. The context itself may
+ * exist a bit longer until its reference count goes to zero.
+ * Other code referencing the context can detect that it has been
+ * detached because the context id will be set to KGSL_CONTEXT_INVALID.
+ */
+void
+kgsl_context_detach(struct kgsl_context *context)
{
int id;
-
+ struct kgsl_device *device;
if (context == NULL)
return;
-
- /* Fire a bug if the devctxt hasn't been freed */
- BUG_ON(context->devctxt);
-
+ device = context->dev_priv->device;
id = context->id;
- kfree(context);
- idr_remove(&dev_priv->device->context_idr, id);
+ if (device->ftbl->drawctxt_destroy)
+ device->ftbl->drawctxt_destroy(device, context);
+ /*device specific drawctxt_destroy MUST clean up devctxt */
+ BUG_ON(context->devctxt);
+ /*
+ * Cancel events after the device-specific context is
+ * destroyed, to avoid possibly freeing memory while
+ * it is still in use by the GPU.
+ */
+ kgsl_cancel_events_ctxt(device, context);
+ idr_remove(&device->context_idr, id);
+ context->id = KGSL_CONTEXT_INVALID;
+ kgsl_context_put(context);
+}
+
+void
+kgsl_context_destroy(struct kref *kref)
+{
+ struct kgsl_context *context = container_of(kref, struct kgsl_context,
+ refcount);
+ kfree(context);
}
void kgsl_timestamp_expired(struct work_struct *work)
@@ -758,23 +784,23 @@
mutex_lock(&device->mutex);
kgsl_check_suspended(device);
- /* clean up any to-be-freed entries that belong to this
- * process and this device
- */
- kgsl_cancel_events(device, dev_priv);
-
while (1) {
context = idr_get_next(&device->context_idr, &next);
if (context == NULL)
break;
- if (context->dev_priv == dev_priv) {
- device->ftbl->drawctxt_destroy(device, context);
- kgsl_destroy_context(dev_priv, context);
- }
+ if (context->dev_priv == dev_priv)
+ kgsl_context_detach(context);
next = next + 1;
}
+ /*
+ * Clean up any to-be-freed entries that belong to this
+ * process and this device. This is done after the context
+ * are destroyed to avoid possibly freeing memory while
+ * it is still in use by the GPU.
+ */
+ kgsl_cancel_events(device, dev_priv);
device->open_count--;
if (device->open_count == 0) {
@@ -1034,6 +1060,7 @@
{
struct kgsl_device_waittimestamp_ctxtid *param = data;
struct kgsl_context *context;
+ int result;
context = kgsl_find_context(dev_priv, param->context_id);
if (context == NULL) {
@@ -1041,9 +1068,16 @@
param->context_id);
return -EINVAL;
}
-
- return _device_waittimestamp(dev_priv, context,
+ /*
+ * A reference count is needed here, because waittimestamp may
+ * block with the device mutex unlocked and userspace could
+ * request for the context to be destroyed during that time.
+ */
+ kgsl_context_get(context);
+ result = _device_waittimestamp(dev_priv, context,
param->timestamp, param->timeout);
+ kgsl_context_put(context);
+ return result;
}
static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
@@ -1261,7 +1295,7 @@
param->drawctxt_id = context->id;
done:
if (result && context)
- kgsl_destroy_context(dev_priv, context);
+ kgsl_context_detach(context);
return result;
}
@@ -1280,14 +1314,7 @@
goto done;
}
- kgsl_cancel_events_ctxt(dev_priv->device, context);
-
- if (dev_priv->device->ftbl->drawctxt_destroy)
- dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
- context);
-
- kgsl_destroy_context(dev_priv, context);
-
+ kgsl_context_detach(context);
done:
return result;
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0964458..5b6522a 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -220,6 +220,7 @@
.last_expired_ctxt_id = KGSL_CONTEXT_INVALID
struct kgsl_context {
+ struct kref refcount;
uint32_t id;
/* Pointer to the owning device instance */
@@ -380,4 +381,32 @@
return pdev->dev.platform_data;
}
+/**
+ * kgsl_context_get - Get context reference count
+ * @context
+ *
+ * Asynchronous code that holds a pointer to a context
+ * must hold a reference count on it. The kgsl device
+ * mutex must be held while the context reference count
+ * is changed.
+ */
+static inline void
+kgsl_context_get(struct kgsl_context *context)
+{
+ kref_get(&context->refcount);
+}
+
+void kgsl_context_destroy(struct kref *kref);
+
+/**
+ * kgsl_context_put - Release context reference count
+ * @context
+ *
+ */
+static inline void
+kgsl_context_put(struct kgsl_context *context)
+{
+ kref_put(&context->refcount, kgsl_context_destroy);
+}
+
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index a477439..ab47f40 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -708,6 +708,13 @@
return ptbase;
}
+static unsigned int
+kgsl_gpummu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
+ return gpummu_pt->base.gpuaddr;
+}
+
struct kgsl_mmu_ops gpummu_ops = {
.mmu_init = kgsl_gpummu_init,
.mmu_close = kgsl_gpummu_close,
@@ -720,6 +727,8 @@
.mmu_enable_clk = NULL,
.mmu_disable_clk = NULL,
.mmu_get_hwpagetable_asid = NULL,
+ .mmu_get_pt_lsb = NULL,
+ .mmu_get_reg_map_desc = NULL,
};
struct kgsl_mmu_pt_ops gpummu_pt_ops = {
@@ -728,4 +737,5 @@
.mmu_create_pagetable = kgsl_gpummu_create_pagetable,
.mmu_destroy_pagetable = kgsl_gpummu_destroy_pagetable,
.mmu_pt_equal = kgsl_gpummu_pt_equal,
+ .mmu_pt_get_base_addr = kgsl_gpummu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_gpummu.h b/drivers/gpu/msm/kgsl_gpummu.h
index c61a8b2..caa5df1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.h
+++ b/drivers/gpu/msm/kgsl_gpummu.h
@@ -75,9 +75,4 @@
void *kgsl_gpummu_ptpool_init(int entries);
void kgsl_gpummu_ptpool_destroy(void *ptpool);
-static inline unsigned int kgsl_pt_get_base_addr(struct kgsl_pagetable *pt)
-{
- struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
- return gpummu_pt->base.gpuaddr;
-}
#endif /* __KGSL_GPUMMU_H */
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 1598e16..fdd4aa5 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -23,6 +23,8 @@
#include "kgsl_mmu.h"
#include "kgsl_sharedmem.h"
#include "kgsl_iommu.h"
+#include "adreno_pm4types.h"
+#include "adreno.h"
/*
* kgsl_iommu_disable_clk - Disable iommu clocks
@@ -160,7 +162,7 @@
sizeof(struct kgsl_iommu_pt));
return NULL;
}
- iommu_pt->domain = iommu_domain_alloc(0);
+ iommu_pt->domain = iommu_domain_alloc(MSM_IOMMU_DOMAIN_PT_CACHEABLE);
if (!iommu_pt->domain) {
KGSL_CORE_ERR("Failed to create iommu domain\n");
kfree(iommu_pt);
@@ -402,19 +404,66 @@
return ret;
}
+/*
+ * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * IOMMU ttbr0 register is programmed with
+ * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
+ *
+ * Return - actual pagetable address that the ttbr0 register is programmed
+ * with
+ */
+static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
+ return iommu_get_pt_base_addr(iommu_pt->domain);
+}
+
+/*
+ * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
+ * @mmu - Pointer to mmu structure
+ * @hostptr - Pointer to the IOMMU register map. This is used to match
+ * the iommu device whose lsb value is to be returned
+ * @ctx_id - The context bank whose lsb valus is to be returned
+ * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
+ * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
+ * are only programmed once in the beginning when a domain is attached
+ * does not change.
+ */
+static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
+ unsigned int unit_id,
+ enum kgsl_iommu_context_id ctx_id)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i, j;
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++)
+ if (unit_id == i &&
+ ctx_id == iommu_unit->dev[j].ctx_id)
+ return iommu_unit->dev[j].pt_lsb;
+ }
+ return 0;
+}
+
static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable)
{
if (mmu->flags & KGSL_FLAGS_STARTED) {
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
/* page table not current, then setup mmu to use new
* specified page table
*/
if (mmu->hwpagetable != pagetable) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
- kgsl_detach_pagetable_iommu_domain(mmu);
+ unsigned int flags = 0;
mmu->hwpagetable = pagetable;
- if (mmu->hwpagetable)
- kgsl_attach_pagetable_iommu_domain(mmu);
+ /* force tlb flush if asid is reused */
+ if (iommu->asid_reuse &&
+ (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
+ flags |= KGSL_MMUFLAGS_TLBFLUSH;
+ flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
+ mmu->device->id);
+ kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
}
}
}
@@ -452,6 +501,12 @@
if (status)
goto done;
+ /* A nop is required in an indirect buffer when switching
+ * pagetables in-stream */
+ kgsl_sharedmem_writel(&mmu->setstate_memory,
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET,
+ cp_nop_packet(1));
+
dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
__func__);
done:
@@ -523,6 +578,7 @@
{
int status;
struct kgsl_iommu *iommu = mmu->priv;
+ int i, j;
if (mmu->flags & KGSL_FLAGS_STARTED)
return 0;
@@ -532,23 +588,62 @@
if (status)
return -ENOMEM;
}
- kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
+ /* We use the GPU MMU to control access to IOMMU registers on a225,
+ * hence we still keep the MMU active on a225 */
+ if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
+ struct kgsl_mh *mh = &(mmu->device->mh);
+ kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
+ kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
+ mh->mpu_base +
+ iommu->iommu_units[0].reg_map.gpuaddr - PAGE_SIZE);
+ } else {
+ kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
+ }
mmu->hwpagetable = mmu->defaultpagetable;
status = kgsl_attach_pagetable_iommu_domain(mmu);
- if (!status) {
- mmu->flags |= KGSL_FLAGS_STARTED;
- } else {
- kgsl_detach_pagetable_iommu_domain(mmu);
+ if (status) {
mmu->hwpagetable = NULL;
+ goto done;
}
status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
- iommu->asid = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
- (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
- KGSL_IOMMU_CONTEXTIDR);
- kgsl_iommu_disable_clk(mmu);
+ if (status) {
+ KGSL_CORE_ERR("clk enable failed\n");
+ goto done;
+ }
+ status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
+ if (status) {
+ KGSL_CORE_ERR("clk enable failed\n");
+ goto done;
+ }
+ /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
+ * that value should not change when we change pagetables, so while
+ * changing pagetables we can use this lsb value of the pagetable w/o
+ * having to read it again
+ */
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++)
+ iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
+ KGSL_IOMMU_GET_IOMMU_REG(
+ iommu_unit->reg_map.hostptr,
+ iommu_unit->dev[j].ctx_id,
+ TTBR0));
+ }
+ iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[0].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER,
+ CONTEXTIDR);
+ kgsl_iommu_disable_clk(mmu);
+ mmu->flags |= KGSL_FLAGS_STARTED;
+
+done:
+ if (status) {
+ kgsl_iommu_disable_clk(mmu);
+ kgsl_detach_pagetable_iommu_domain(mmu);
+ }
return status;
}
@@ -623,6 +718,7 @@
*/
if (mmu->flags & KGSL_FLAGS_STARTED) {
+ kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
/* detach iommu attachment */
kgsl_detach_pagetable_iommu_domain(mmu);
mmu->hwpagetable = NULL;
@@ -708,18 +804,127 @@
KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
}
+/*
+ * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
+ * of the primary context bank
+ * @mmu - Pointer to mmu structure
+ * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
+ * flushed or both
+ *
+ * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
+ * do both by doing direct register writes to the IOMMu registers through the
+ * cpu
+ * Return - void
+ */
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+ uint32_t flags)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int temp;
+ int i;
+ unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
+ mmu->hwpagetable);
+ unsigned int pt_val;
+
+ if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
+ KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+ return;
+ }
+ /* Mask off the lsb of the pt base address since lsb will not change */
+ pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
+ if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+ kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ for (i = 0; i < iommu->unit_count; i++) {
+ /* get the lsb value which should not change when
+ * changing ttbr0 */
+ pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
+ KGSL_IOMMU_CONTEXT_USER);
+ pt_val += pt_base;
+
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+
+ mb();
+ temp = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, TTBR0);
+ /* Set asid */
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
+ kgsl_iommu_get_hwpagetable_asid(mmu));
+ mb();
+ temp = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
+ }
+ }
+ /* Flush tlb */
+ if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+ for (i = 0; i < iommu->unit_count; i++) {
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
+ kgsl_iommu_get_hwpagetable_asid(mmu));
+ mb();
+ }
+ }
+ /* Disable smmu clock */
+ kgsl_iommu_disable_clk(mmu);
+}
+
+/*
+ * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
+ * the address of memory descriptors which map the IOMMU registers
+ * @mmu - Pointer to mmu structure
+ * @reg_map_desc - Out parameter in which the address of the array containing
+ * pointers to register map descriptors is returned. The caller is supposed
+ * to free this array
+ *
+ * Return - The number of iommu units which is also the number of register
+ * mapped descriptor arrays which the out parameter will have
+ */
+static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
+ void **reg_map_desc)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ void **reg_desc_ptr;
+ int i;
+
+ /*
+ * Alocate array of pointers that will hold address of the register map
+ * descriptors
+ */
+ reg_desc_ptr = kmalloc(iommu->unit_count *
+ sizeof(struct kgsl_memdesc *), GFP_KERNEL);
+ if (!reg_desc_ptr) {
+ KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
+ iommu->unit_count * sizeof(struct kgsl_memdesc *));
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < iommu->unit_count; i++)
+ reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
+
+ *reg_map_desc = reg_desc_ptr;
+ return i;
+}
+
struct kgsl_mmu_ops iommu_ops = {
.mmu_init = kgsl_iommu_init,
.mmu_close = kgsl_iommu_close,
.mmu_start = kgsl_iommu_start,
.mmu_stop = kgsl_iommu_stop,
.mmu_setstate = kgsl_iommu_setstate,
- .mmu_device_setstate = NULL,
+ .mmu_device_setstate = kgsl_iommu_default_setstate,
.mmu_pagefault = NULL,
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk = kgsl_iommu_disable_clk,
.mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
+ .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
+ .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
};
struct kgsl_mmu_pt_ops iommu_pt_ops = {
@@ -728,4 +933,5 @@
.mmu_create_pagetable = kgsl_iommu_create_pagetable,
.mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
.mmu_pt_equal = kgsl_iommu_pt_equal,
+ .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index db2fed0..d4de656 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -39,6 +39,25 @@
/* Max number of iommu contexts per IOMMU unit */
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
+/* Macros to read/write IOMMU registers */
+#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val) \
+ writel_relaxed(val, base_addr + \
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ KGSL_IOMMU_##REG)
+
+#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG) \
+ readl_relaxed(base_addr + \
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ KGSL_IOMMU_##REG)
+
+/* Gets the lsb value of pagetable */
+#define KGSL_IOMMMU_PT_LSB(pt_val) \
+ (pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK << \
+ KGSL_IOMMU_TTBR0_PA_SHIFT))
+
+/* offset at which a nop command is placed in setstate_memory */
+#define KGSL_IOMMU_SETSTATE_NOP_OFFSET 1024
+
/*
* struct kgsl_iommu_device - Structure holding data about iommu contexts
* @dev: Device pointer to iommu context
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 5fdc182..663ba0f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -453,10 +453,11 @@
*/
if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
(KGSL_MMU_GLOBAL_PT == name)) {
- pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
+ pagetable->kgsl_pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT,
+ -1);
if (pagetable->kgsl_pool == NULL) {
KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
- PAGE_SHIFT);
+ KGSL_MMU_ALIGN_SHIFT);
goto err_alloc;
}
if (gen_pool_add(pagetable->kgsl_pool,
@@ -467,9 +468,10 @@
}
}
- pagetable->pool = gen_pool_create(PAGE_SHIFT, -1);
+ pagetable->pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT, -1);
if (pagetable->pool == NULL) {
- KGSL_CORE_ERR("gen_pool_create(%d) failed\n", PAGE_SHIFT);
+ KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
+ KGSL_MMU_ALIGN_SHIFT);
goto err_kgsl_pool;
}
@@ -521,11 +523,8 @@
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return (void *)(-1);
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
- if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
- name = KGSL_MMU_GLOBAL_PT;
-#else
- name = KGSL_MMU_GLOBAL_PT;
+#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+ name = KGSL_MMU_GLOBAL_PT;
#endif
pt = kgsl_get_pagetable(name);
@@ -546,7 +545,8 @@
struct kgsl_device *device = mmu->device;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return;
- else if (device->ftbl->setstate)
+ else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
+ kgsl_mmu_type))
device->ftbl->setstate(device, flags);
else if (mmu->mmu_ops->mmu_device_setstate)
mmu->mmu_ops->mmu_device_setstate(mmu, flags);
@@ -580,12 +580,22 @@
*/
}
+static inline struct gen_pool *
+_get_pool(struct kgsl_pagetable *pagetable, unsigned int flags)
+{
+ if (pagetable->kgsl_pool &&
+ (KGSL_MEMFLAGS_GLOBAL & flags))
+ return pagetable->kgsl_pool;
+ return pagetable->pool;
+}
+
int
kgsl_mmu_map(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc,
unsigned int protflags)
{
int ret;
+ struct gen_pool *pool;
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
if (memdesc->sglen == 1) {
@@ -606,20 +616,14 @@
}
/* 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);
+ pool = _get_pool(pagetable, memdesc->priv);
+ memdesc->gpuaddr = gen_pool_alloc(pool, memdesc->size);
if (memdesc->gpuaddr == 0) {
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"));
+ (pool == pagetable->kgsl_pool) ?
+ "kgsl_pool" : "general_pool");
KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
pagetable->name, pagetable->stats.mapped,
pagetable->stats.entries);
@@ -650,7 +654,7 @@
err_free_gpuaddr:
spin_unlock(&pagetable->lock);
- gen_pool_free(pagetable->pool, memdesc->gpuaddr, memdesc->size);
+ gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
memdesc->gpuaddr = 0;
return ret;
}
@@ -660,6 +664,7 @@
kgsl_mmu_unmap(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc)
{
+ struct gen_pool *pool;
if (memdesc->size == 0 || memdesc->gpuaddr == 0)
return 0;
@@ -678,15 +683,8 @@
spin_unlock(&pagetable->lock);
- 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);
+ pool = _get_pool(pagetable, memdesc->priv);
+ gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
/*
* Don't clear the gpuaddr on global mappings because they
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 24eaba4..2db327b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -135,6 +135,11 @@
int (*mmu_enable_clk)
(struct kgsl_mmu *mmu, int ctx_id);
int (*mmu_get_hwpagetable_asid)(struct kgsl_mmu *mmu);
+ int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
+ unsigned int unit_id,
+ enum kgsl_iommu_context_id ctx_id);
+ int (*mmu_get_reg_map_desc)(struct kgsl_mmu *mmu,
+ void **reg_map_desc);
};
struct kgsl_mmu_pt_ops {
@@ -148,6 +153,8 @@
void (*mmu_destroy_pagetable) (void *pt);
int (*mmu_pt_equal) (struct kgsl_pagetable *pt,
unsigned int pt_base);
+ unsigned int (*mmu_pt_get_base_addr)
+ (struct kgsl_pagetable *pt);
};
struct kgsl_mmu {
@@ -237,4 +244,54 @@
return pt->pt_ops->mmu_pt_equal(pt, pt_base);
}
+static inline unsigned int kgsl_mmu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+ return 0;
+ else
+ return pt->pt_ops->mmu_pt_get_base_addr(pt);
+}
+
+static inline int kgsl_mmu_get_reg_map_desc(struct kgsl_mmu *mmu,
+ void **reg_map_desc)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_map_desc)
+ return mmu->mmu_ops->mmu_get_reg_map_desc(mmu, reg_map_desc);
+ else
+ return 0;
+}
+
+static inline int kgsl_mmu_get_pt_lsb(struct kgsl_mmu *mmu,
+ unsigned int unit_id,
+ enum kgsl_iommu_context_id ctx_id)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_lsb)
+ return mmu->mmu_ops->mmu_get_pt_lsb(mmu, unit_id, ctx_id);
+ else
+ return 0;
+}
+
+static inline int kgsl_mmu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_hwpagetable_asid)
+ return mmu->mmu_ops->mmu_get_hwpagetable_asid(mmu);
+ else
+ return 0;
+}
+
+static inline int kgsl_mmu_enable_clk(struct kgsl_mmu *mmu,
+ int ctx_id)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_enable_clk)
+ return mmu->mmu_ops->mmu_enable_clk(mmu, ctx_id);
+ else
+ return 0;
+}
+
+static inline void kgsl_mmu_disable_clk(struct kgsl_mmu *mmu)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_disable_clk)
+ mmu->mmu_ops->mmu_disable_clk(mmu);
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3238d33..701160c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -777,7 +777,7 @@
input_report_abs(input_dev, ABS_MT_POSITION_Y,
finger[id].y);
input_report_abs(input_dev, ABS_MT_PRESSURE,
- finger[id].area);
+ finger[id].pressure);
} else {
finger[id].status = 0;
}
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index fa42c2c..ece7b0f 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -57,6 +57,7 @@
#define WLED_OVP_VAL_BIT_SHFT 0x04
#define WLED_BOOST_LIMIT_MASK 0xE0
#define WLED_BOOST_LIMIT_BIT_SHFT 0x05
+#define WLED_BOOST_OFF 0x00
#define WLED_EN_MASK 0x01
#define WLED_CP_SELECT_MAX 0x03
#define WLED_CP_SELECT_MASK 0x03
@@ -155,6 +156,7 @@
struct led_classdev cdev;
int id;
u8 reg;
+ u8 wled_mod_ctrl_val;
struct device *dev;
struct work_struct work;
struct mutex lock;
@@ -237,6 +239,24 @@
if (value > WLED_MAX_LEVEL)
value = WLED_MAX_LEVEL;
+ if (value == 0) {
+ rc = pm8xxx_writeb(led->dev->parent, WLED_MOD_CTRL_REG,
+ WLED_BOOST_OFF);
+ if (rc) {
+ dev_err(led->dev->parent, "can't write wled ctrl config"
+ " register rc=%d\n", rc);
+ return rc;
+ }
+ } else {
+ rc = pm8xxx_writeb(led->dev->parent, WLED_MOD_CTRL_REG,
+ led->wled_mod_ctrl_val);
+ if (rc) {
+ dev_err(led->dev->parent, "can't write wled ctrl config"
+ " register rc=%d\n", rc);
+ return rc;
+ }
+ }
+
duty = (WLED_MAX_DUTY_CYCLE * value) / WLED_MAX_LEVEL;
num_wled_strings = led->wled_cfg->num_strings;
@@ -629,6 +649,7 @@
" register rc=%d\n", rc);
return rc;
}
+ led->wled_mod_ctrl_val = val;
/* dump wled registers */
wled_dump_regs(led);
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 5508c3d..c07bdc4 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -24,6 +24,17 @@
LIRC daemon handles protocol decoding for IR reception and
encoding for IR transmitting (aka "blasting").
+config USER_RC_INPUT
+ tristate "User Space Input device wrapper for Remote Control"
+ depends on RC_CORE
+
+ ---help---
+ Say Y if you want to report remote control input events
+ from userspace.
+
+ To compile this driver as a module, choose M here: the module will
+ be called user-rc-input.
+
source "drivers/media/rc/keymaps/Kconfig"
config IR_NEC_DECODER
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 523fcd0..b9c1e21 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -11,6 +11,7 @@
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
+obj-$(CONFIG_USER_RC_INPUT) += user-rc-input.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/rc/user-rc-input.c b/drivers/media/rc/user-rc-input.c
new file mode 100644
index 0000000..f1a9334
--- /dev/null
+++ b/drivers/media/rc/user-rc-input.c
@@ -0,0 +1,251 @@
+/* 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/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <media/rc-core.h>
+#include <media/user-rc-input.h>
+
+#define MAX_RC_DEVICES 1
+#define USER_RC_INPUT_DEV_NAME "user-rc-input"
+#define USER_RC_INPUT_DRV_NAME "rc-user-input"
+
+struct user_rc_input_dev {
+ struct cdev rc_input_cdev;
+ struct class *rc_input_class;
+ struct device *rc_input_dev;
+ struct rc_dev *rcdev;
+ dev_t rc_input_base_dev;
+ struct device *dev;
+ int in_use;
+};
+
+static int user_rc_input_open(struct inode *inode, struct file *file)
+{
+ struct cdev *input_cdev = inode->i_cdev;
+ struct user_rc_input_dev *input_dev =
+ container_of(input_cdev, struct user_rc_input_dev, rc_input_cdev);
+
+ if (input_dev->in_use) {
+ dev_err(input_dev->dev,
+ "Device is already open..only one instance is allowed\n");
+ return -EBUSY;
+ }
+ input_dev->in_use++;
+ file->private_data = input_dev;
+
+ return 0;
+}
+
+static int user_rc_input_release(struct inode *inode, struct file *file)
+{
+ struct user_rc_input_dev *input_dev = file->private_data;
+
+ input_dev->in_use--;
+
+ return 0;
+}
+
+static ssize_t user_rc_input_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ struct user_rc_input_dev *input_dev = file->private_data;
+ __u8 *buf;
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf) {
+ dev_err(input_dev->dev,
+ "kmalloc failed...Insufficient memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ dev_err(input_dev->dev, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ switch (buf[0]) {
+ case USER_CONTROL_PRESSED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " pressed 0x%x\n", buf[1]);
+ rc_keydown(input_dev->rcdev, buf[1], 0);
+ break;
+ case USER_CONTROL_REPEATED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " repeated 0x%x\n", buf[1]);
+ rc_repeat(input_dev->rcdev);
+ break;
+ case USER_CONTROL_RELEASED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " released 0x%x\n", buf[1]);
+ rc_keyup(input_dev->rcdev);
+ break;
+ }
+
+out_free:
+ kfree(buf);
+out:
+ return ret;
+}
+
+const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = user_rc_input_open,
+ .write = user_rc_input_write,
+ .release = user_rc_input_release,
+};
+
+static int __devinit user_rc_input_probe(struct platform_device *pdev)
+{
+ struct user_rc_input_dev *user_rc_dev;
+ struct rc_dev *rcdev;
+ int retval;
+
+ user_rc_dev = kzalloc(sizeof(struct user_rc_input_dev), GFP_KERNEL);
+ if (!user_rc_dev)
+ return -ENOMEM;
+
+ user_rc_dev->rc_input_class = class_create(THIS_MODULE,
+ "user-rc-input-loopback");
+
+ if (IS_ERR(user_rc_dev->rc_input_class)) {
+ retval = PTR_ERR(user_rc_dev->rc_input_class);
+ goto err;
+ }
+
+ retval = alloc_chrdev_region(&user_rc_dev->rc_input_base_dev, 0,
+ MAX_RC_DEVICES, USER_RC_INPUT_DEV_NAME);
+
+ if (retval) {
+ dev_err(&pdev->dev,
+ "alloc_chrdev_region failed\n");
+ goto alloc_chrdev_err;
+ }
+
+ dev_info(&pdev->dev, "User space report key event input "
+ "loopback driver registered, "
+ "major %d\n", MAJOR(user_rc_dev->rc_input_base_dev));
+
+ cdev_init(&user_rc_dev->rc_input_cdev, &fops);
+ retval = cdev_add(&user_rc_dev->rc_input_cdev,
+ user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+ if (retval) {
+ dev_err(&pdev->dev, "cdev_add failed\n");
+ goto cdev_add_err;
+ }
+ user_rc_dev->rc_input_dev =
+ device_create(user_rc_dev->rc_input_class,
+ NULL,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev),
+ 0), NULL, "user-rc-input-dev%d", 0);
+
+ if (IS_ERR(user_rc_dev->rc_input_dev)) {
+ retval = PTR_ERR(user_rc_dev->rc_input_dev);
+ dev_err(&pdev->dev, "device_create failed\n");
+ goto device_create_err;
+ }
+
+ rcdev = rc_allocate_device();
+ if (!rcdev) {
+ dev_err(&pdev->dev, "failed to allocate rc device");
+ retval = -ENOMEM;
+ goto err_allocate_device;
+ }
+
+ rcdev->driver_type = RC_DRIVER_SCANCODE;
+ rcdev->allowed_protos = RC_TYPE_OTHER;
+ rcdev->input_name = USER_RC_INPUT_DEV_NAME;
+ rcdev->input_id.bustype = BUS_HOST;
+ rcdev->driver_name = USER_RC_INPUT_DRV_NAME;
+ rcdev->map_name = RC_MAP_UE_RF4CE;
+
+ retval = rc_register_device(rcdev);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "failed to register rc device\n");
+ goto rc_register_err;
+ }
+ user_rc_dev->rcdev = rcdev;
+ user_rc_dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, user_rc_dev);
+ user_rc_dev->in_use = 0;
+
+ return 0;
+
+rc_register_err:
+ rc_free_device(rcdev);
+err_allocate_device:
+ device_destroy(user_rc_dev->rc_input_class,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+cdev_add_err:
+ unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+device_create_err:
+ cdev_del(&user_rc_dev->rc_input_cdev);
+alloc_chrdev_err:
+ class_destroy(user_rc_dev->rc_input_class);
+err:
+ kfree(user_rc_dev);
+ return retval;
+}
+
+static int __devexit user_rc_input_remove(struct platform_device *pdev)
+{
+ struct user_rc_input_dev *user_rc_dev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ rc_free_device(user_rc_dev->rcdev);
+ device_destroy(user_rc_dev->rc_input_class,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+ unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+ cdev_del(&user_rc_dev->rc_input_cdev);
+ class_destroy(user_rc_dev->rc_input_class);
+ kfree(user_rc_dev);
+
+ return 0;
+}
+
+static struct platform_driver user_rc_input_driver = {
+ .probe = user_rc_input_probe,
+ .remove = __devexit_p(user_rc_input_remove),
+ .driver = {
+ .name = USER_RC_INPUT_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init user_rc_input_init(void)
+{
+ return platform_driver_register(&user_rc_input_driver);
+}
+module_init(user_rc_input_init);
+
+static void __exit user_rc_input_exit(void)
+{
+ platform_driver_unregister(&user_rc_input_driver);
+}
+module_exit(user_rc_input_exit);
+
+MODULE_DESCRIPTION("User RC Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 5aaef24..7d53e11 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1090,3 +1090,5 @@
endif # V4L_MEM2MEM_DRIVERS
+
+source "drivers/media/video/msm_vidc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 65a2348..444d3d4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -189,6 +189,7 @@
obj-$(CONFIG_MSM_CAMERA) += msm/
obj-$(CONFIG_ARCH_OMAP) += omap/
+obj-$(CONFIG_MSM_VIDC) += msm_vidc/
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index fbc3a37..b602c37 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -271,3 +271,9 @@
overlay driver. This allows video rendering
apps to render overlaid video using Video4Linux2
APIs, by using /dev/videoX device
+
+config OV7692
+ bool "Sensor OV7692 (VGA YUV)"
+ depends on MSM_CAMERA
+ ---help---
+ Omni Vision VGA YUV Sensor
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index ebfed6c..b60f99f 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -13,6 +13,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
+ obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index e4d8368..85470b7 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -253,6 +253,8 @@
target_step_pos = dest_step_pos;
target_lens_pos =
a_ctrl->step_position_table[target_step_pos];
+ if (curr_lens_pos == target_lens_pos)
+ return rc;
rc = a_ctrl->func_tbl->
actuator_write_focus(
a_ctrl,
@@ -273,6 +275,8 @@
target_step_pos = step_boundary;
target_lens_pos =
a_ctrl->step_position_table[target_step_pos];
+ if (curr_lens_pos == target_lens_pos)
+ return rc;
rc = a_ctrl->func_tbl->
actuator_write_focus(
a_ctrl,
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index 6a5a647..e8be393 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -289,6 +289,8 @@
return rc;
}
}
+ if (csic_dev->hw_version == CSIC_7X)
+ msm_camio_vfe_blk_reset_3();
#if DBG_CSIC
enable_irq(csic_dev->irq->start);
@@ -433,12 +435,28 @@
goto csic_no_resource;
}
disable_irq(new_csic_dev->irq->start);
- iounmap(new_csic_dev->base);
- new_csic_dev->base = NULL;
new_csic_dev->pdev = pdev;
+
+ rc = msm_cam_clk_enable(&new_csic_dev->pdev->dev, &csic_7x_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;
+ return rc;
+ }
+
+ msm_camera_io_w(MIPI_PWR_CNTL_DIS, new_csic_dev->base + MIPI_PWR_CNTL);
+
+ rc = msm_cam_clk_enable(&new_csic_dev->pdev->dev, &csic_7x_clk_info[2],
+ new_csic_dev->csic_clk, 1, 0);
+
+ iounmap(new_csic_dev->base);
+ new_csic_dev->base = NULL;
msm_cam_register_subdev_node(
&new_csic_dev->subdev, CSIC_DEV, pdev->id);
+
return 0;
csic_no_resource:
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index a86e5c4..0d17e13 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -307,13 +307,13 @@
#endif
rc = gpio_request(external->led_en, "sc628a");
if (!rc) {
- gpio_direction_output(external->led_en, 1);
+ gpio_direction_output(external->led_en, 0);
} else {
goto err1;
}
rc = gpio_request(external->led_flash_en, "sc628a");
if (!rc) {
- gpio_direction_output(external->led_flash_en, 1);
+ gpio_direction_output(external->led_flash_en, 0);
break;
}
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 45761d5..946b985 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -85,27 +85,18 @@
clk_set_rate(clk, rate);
}
-void msm_camio_vfe_blk_reset_2(int vfe_apps_reset)
+void msm_camio_vfe_blk_reset_2(void)
{
uint32_t val;
- if (apps_reset && !vfe_apps_reset)
- return;
-
/* do apps reset */
val = readl_relaxed(appbase + 0x00000210);
- if (apps_reset)
- val |= 0x10A0001;
- else
- val |= 0x1;
+ val |= 0x1;
writel_relaxed(val, appbase + 0x00000210);
usleep_range(10000, 11000);
val = readl_relaxed(appbase + 0x00000210);
- if (apps_reset)
- val &= ~(0x10A0001);
- else
- val &= ~0x1;
+ val &= ~0x1;
writel_relaxed(val, appbase + 0x00000210);
usleep_range(10000, 11000);
@@ -122,6 +113,26 @@
usleep_range(10000, 11000);
}
+void msm_camio_vfe_blk_reset_3(void)
+{
+ uint32_t val;
+
+ if (!apps_reset)
+ return;
+
+ /* do apps reset */
+ val = readl_relaxed(appbase + 0x00000210);
+ val |= 0x10A0000;
+ writel_relaxed(val, appbase + 0x00000210);
+ usleep_range(10000, 11000);
+
+ val = readl_relaxed(appbase + 0x00000210);
+ val &= ~(0x10A0000);
+ writel_relaxed(val, appbase + 0x00000210);
+ usleep_range(10000, 11000);
+ mb();
+}
+
void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
{
switch (perf_setting) {
diff --git a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
index a1270ea..9dc097b 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
@@ -156,6 +156,11 @@
return;
}
+void msm_camio_vfe_blk_reset_3(void)
+{
+ return;
+}
+
static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
{
switch (perf_setting) {
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index fa9aace..034cbc5 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -45,6 +45,10 @@
module_param(msm_camera_v4l2_nr, uint, 0644);
MODULE_PARM_DESC(msm_camera_v4l2_nr, "videoX start number, -1 is autodetect");
+static long msm_server_send_v4l2_evt(void *evt);
+static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
+ unsigned int notification, void *arg);
+
static void msm_queue_init(struct msm_device_queue *queue, const char *name)
{
D("%s\n", __func__);
@@ -178,10 +182,16 @@
return -EINVAL;
}
+ D("%s qid %d evtid %d %d\n", __func__, command->queue_idx,
+ command->evt_id,
+ g_server_dev.server_queue[command->queue_idx].evt_id);
g_server_dev.server_queue[command->queue_idx].ctrl = command;
if (command->evt_id !=
g_server_dev.server_queue[command->queue_idx].evt_id) {
- pr_err("Invalid event id from userspace\n");
+ pr_err("%s Invalid event id from userspace cmd id %d %d qid %d\n",
+ __func__, command->evt_id,
+ g_server_dev.server_queue[command->queue_idx].evt_id,
+ command->queue_idx);
return -EINVAL;
}
@@ -241,6 +251,8 @@
mutex_lock(&server_dev->server_queue_lock);
if (++server_dev->server_evt_id == 0)
server_dev->server_evt_id++;
+ D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+ server_dev->server_evt_id);
server_dev->server_queue[out->queue_idx].evt_id =
server_dev->server_evt_id;
@@ -286,7 +298,8 @@
ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
value = out->value;
- if (ctrlcmd->length > 0)
+ if (ctrlcmd->length > 0 && value != NULL &&
+ ctrlcmd->length <= out->length)
memcpy(value, ctrlcmd->value, ctrlcmd->length);
memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
@@ -316,7 +329,7 @@
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
- D("%s\n", __func__);
+ D("%s qid %d\n", __func__, pcam->server_queue_idx);
ctrlcmd.type = MSM_V4L2_OPEN;
ctrlcmd.timeout_ms = 10000;
ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -336,7 +349,7 @@
{
int rc = 0;
struct msm_ctrl_cmd ctrlcmd;
- D("%s\n", __func__);
+ D("%s qid %d\n", __func__, pcam->server_queue_idx);
ctrlcmd.type = MSM_V4L2_CLOSE;
ctrlcmd.timeout_ms = 10000;
ctrlcmd.length = strnlen(g_server_dev.config_info.config_dev_name[0],
@@ -1431,7 +1444,7 @@
sub->type++;
D("sub->type while = 0x%x\n", sub->type);
} while (sub->type !=
- V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MAX);
+ V4L2_EVENT_PRIVATE_START + MSM_SVR_RESP_MAX);
} else {
D("sub->type not V4L2_EVENT_ALL = 0x%x\n", sub->type);
rc = v4l2_event_subscribe(fh, sub);
@@ -1554,6 +1567,150 @@
msm_mctl_free(pcam);
return rc;
}
+
+int msm_server_open_client(int *p_qidx)
+{
+ int rc = 0;
+ int server_q_idx = 0;
+ struct msm_cam_server_queue *queue = NULL;
+
+ mutex_lock(&g_server_dev.server_lock);
+ server_q_idx = msm_find_free_queue();
+ if (server_q_idx < 0) {
+ mutex_unlock(&g_server_dev.server_lock);
+ return server_q_idx;
+ }
+
+ *p_qidx = server_q_idx;
+ queue = &g_server_dev.server_queue[server_q_idx];
+ queue->ctrl = NULL;
+ queue->ctrl_data = kzalloc(sizeof(uint8_t) *
+ max_control_command_size, GFP_KERNEL);
+ msm_queue_init(&queue->ctrl_q, "control");
+ msm_queue_init(&queue->eventData_q, "eventdata");
+ queue->queue_active = 1;
+ mutex_unlock(&g_server_dev.server_lock);
+ return rc;
+}
+
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out,
+ int ctrl_id)
+{
+ int rc = 0;
+ void *value;
+ struct msm_queue_cmd *rcmd;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_ctrl_cmd *ctrlcmd;
+ struct msm_cam_server_dev *server_dev = &g_server_dev;
+ struct msm_device_queue *queue =
+ &server_dev->server_queue[out->queue_idx].ctrl_q;
+
+ struct v4l2_event v4l2_evt;
+ struct msm_isp_event_ctrl *isp_event;
+ isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+ if (!isp_event) {
+ pr_err("%s Insufficient memory. return", __func__);
+ return -ENOMEM;
+ }
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!event_qcmd) {
+ pr_err("%s Insufficient memory. return", __func__);
+ kfree(isp_event);
+ return -ENOMEM;
+ }
+
+ D("%s\n", __func__);
+ mutex_lock(&server_dev->server_queue_lock);
+ if (++server_dev->server_evt_id == 0)
+ server_dev->server_evt_id++;
+
+ D("%s qid %d evtid %d\n", __func__, out->queue_idx,
+ server_dev->server_evt_id);
+ server_dev->server_queue[out->queue_idx].evt_id =
+ server_dev->server_evt_id;
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+ v4l2_evt.u.data[0] = out->queue_idx;
+ /* setup event object to transfer the command; */
+ isp_event->resptype = MSM_CAM_RESP_V4L2;
+ isp_event->isp_data.ctrl = *out;
+ isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = isp_event;
+
+ msm_enqueue(&server_dev->server_queue[out->queue_idx].eventData_q,
+ &event_qcmd->list_eventdata);
+
+ /* now send command to config thread in userspace,
+ * and wait for results */
+ v4l2_event_queue(server_dev->server_command_queue.pvdev,
+ &v4l2_evt);
+ D("%s v4l2_event_queue: type = 0x%x\n", __func__, v4l2_evt.type);
+ mutex_unlock(&server_dev->server_queue_lock);
+
+ /* wait for config return status */
+ D("Waiting for config status\n");
+ rc = wait_event_interruptible_timeout(queue->wait,
+ !list_empty_careful(&queue->list),
+ msecs_to_jiffies(out->timeout_ms));
+ D("Waiting is over for config status\n");
+ if (list_empty_careful(&queue->list)) {
+ if (!rc)
+ rc = -ETIMEDOUT;
+ if (rc < 0) {
+ kfree(isp_event);
+ pr_err("%s: wait_event error %d\n", __func__, rc);
+ return rc;
+ }
+ }
+
+ rcmd = msm_dequeue(queue, list_control);
+ BUG_ON(!rcmd);
+ D("%s Finished servicing ioctl\n", __func__);
+
+ ctrlcmd = (struct msm_ctrl_cmd *)(rcmd->command);
+ value = out->value;
+ if (ctrlcmd->length > 0)
+ memcpy(value, ctrlcmd->value, ctrlcmd->length);
+
+ memcpy(out, ctrlcmd, sizeof(struct msm_ctrl_cmd));
+ out->value = value;
+
+ kfree(ctrlcmd);
+ server_dev->server_queue[out->queue_idx].ctrl = NULL;
+
+ free_qcmd(rcmd);
+ kfree(isp_event);
+ D("%s: rc %d\n", __func__, rc);
+ /* rc is the time elapsed. */
+ if (rc >= 0) {
+ /* TODO: Refactor msm_ctrl_cmd::status field */
+ if (out->status == 0)
+ rc = -1;
+ else if (out->status == 1 || out->status == 4)
+ rc = 0;
+ else
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_server_close_client(int idx)
+{
+ int rc = 0;
+ struct msm_cam_server_queue *queue = NULL;
+ mutex_lock(&g_server_dev.server_lock);
+ queue = &g_server_dev.server_queue[idx];
+ queue->queue_active = 0;
+ kfree(queue->ctrl);
+ queue->ctrl = NULL;
+ kfree(queue->ctrl_data);
+ queue->ctrl_data = NULL;
+ msm_queue_drain(&queue->ctrl_q, list_control);
+ msm_drain_eventq(&queue->eventData_q);
+ mutex_unlock(&g_server_dev.server_lock);
+ return rc;
+}
/* v4l2_file_operations */
static int msm_open(struct file *f)
{
@@ -1609,7 +1766,10 @@
pcam_inst->my_index,
pcam->vnode_id, pcam->use_count);
pcam->use_count++;
+ D("%s use_count %d\n", __func__, pcam->use_count);
if (pcam->use_count == 1) {
+ struct msm_cam_server_queue *queue;
+ int ges_evt = MSM_V4L2_GES_CAM_OPEN;
pcam->server_queue_idx = server_q_idx;
queue = &g_server_dev.server_queue[server_q_idx];
queue->ctrl = NULL;
@@ -1619,6 +1779,10 @@
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
+ pr_err("%s send gesture evt\n", __func__);
+ msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+ NOTIFY_GESTURE_CAM_EVT, &ges_evt);
+
rc = msm_cam_server_open_session(&g_server_dev, pcam);
if (rc < 0) {
pr_err("%s: cam_server_open_session failed %d\n",
@@ -1712,6 +1876,74 @@
}
mutex_unlock(&pcam->vid_lock);
kfree(pcam_inst);
+ pr_err("%s: error end", __func__);
+ return rc;
+}
+
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam)
+{
+ int rc = 0;
+ struct msm_cam_media_controller *pmctl = NULL;
+
+ pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ D("%s: invalid handle\n", __func__);
+ return -ENODEV;
+ }
+
+ if (pmctl->mctl_release) {
+ rc = pmctl->mctl_release(pmctl);
+ if (rc < 0)
+ pr_err("mctl_release fails %d\n", rc);
+ }
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ kref_put(&pmctl->refcount, msm_release_ion_client);
+#endif
+
+ rc = msm_cam_server_close_session(&g_server_dev, pcam);
+ if (rc < 0)
+ pr_err("msm_cam_server_close_session fails %d\n", rc);
+
+ return rc;
+}
+
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+ int *p_active)
+{
+ int rc = 0;
+ struct msm_cam_media_controller *pmctl = NULL;
+ D("%s: %p", __func__, g_server_dev.pcam_active);
+ *p_active = 0;
+ if (g_server_dev.pcam_active) {
+ D("%s: Active camera present return", __func__);
+ return 0;
+ }
+ rc = msm_cam_server_open_session(&g_server_dev, pcam);
+ if (rc < 0) {
+ pr_err("%s: cam_server_open_session failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ /* Should be set to sensor ops if any but right now its OK!! */
+ if (!pmctl->mctl_open) {
+ D("%s: media contoller is not inited\n",
+ __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+
+ D("%s: call mctl_open\n", __func__);
+ rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
+
+ if (rc < 0) {
+ pr_err("%s: HW open failed rc = 0x%x\n", __func__, rc);
+ return rc;
+ }
+ pmctl->pcam_ptr = pcam;
+ *p_active = 1;
return rc;
}
@@ -1838,6 +2070,7 @@
f->private_data = NULL;
if (pcam->use_count == 0) {
+ int ges_evt = MSM_V4L2_GES_CAM_CLOSE;
if (g_server_dev.use_count > 0) {
rc = msm_send_close_server(pcam);
if (rc < 0)
@@ -1865,6 +2098,9 @@
if (g_server_dev.use_count == 0)
mutex_unlock(&g_server_dev.server_lock);
+
+ msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+ NOTIFY_GESTURE_CAM_EVT, &ges_evt);
}
mutex_unlock(&pcam->vid_lock);
return rc;
@@ -2079,6 +2315,11 @@
rc = 0;
break;
}
+
+ case MSM_CAM_IOCTL_SEND_EVENT:
+ rc = msm_server_send_v4l2_evt(arg);
+ break;
+
default:
pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
break;
@@ -2118,6 +2359,7 @@
static int msm_close_server(struct file *fp)
{
+ struct v4l2_event_subscription sub;
D("%s\n", __func__);
mutex_lock(&g_server_dev.server_lock);
if (g_server_dev.use_count > 0)
@@ -2134,10 +2376,36 @@
v4l2_event_queue(
g_server_dev.pcam_active->pvdev, &v4l2_ev);
}
+ sub.type = V4L2_EVENT_ALL;
+ msm_server_v4l2_unsubscribe_event(
+ &g_server_dev.server_command_queue.eventHandle, &sub);
}
return 0;
}
+static long msm_server_send_v4l2_evt(void *evt)
+{
+ struct v4l2_event *v4l2_ev = (struct v4l2_event *)evt;
+ int rc = 0;
+
+ if (NULL == evt) {
+ pr_err("%s: evt is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ D("%s: evt type 0x%x\n", __func__, v4l2_ev->type);
+ if ((v4l2_ev->type >= MSM_GES_APP_EVT_MIN) &&
+ (v4l2_ev->type < MSM_GES_APP_EVT_MAX)) {
+ msm_cam_server_subdev_notify(g_server_dev.gesture_device,
+ NOTIFY_GESTURE_EVT, v4l2_ev);
+ } else {
+ pr_err("%s: Invalid evt %d\n", __func__, v4l2_ev->type);
+ rc = -EINVAL;
+ }
+ D("%s: end\n", __func__);
+
+ return rc;
+}
static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
unsigned int cmd, unsigned long evt)
@@ -2630,6 +2898,14 @@
rc = v4l2_subdev_call(g_server_dev.csic_device[csid_core],
core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
break;
+ case NOTIFY_GESTURE_EVT:
+ rc = v4l2_subdev_call(g_server_dev.gesture_device,
+ core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
+ break;
+ case NOTIFY_GESTURE_CAM_EVT:
+ rc = v4l2_subdev_call(g_server_dev.gesture_device,
+ core, ioctl, VIDIOC_MSM_GESTURE_CAM_EVT, arg);
+ break;
default:
break;
}
@@ -2669,6 +2945,8 @@
if (index >= MAX_NUM_AXI_DEV)
return -EINVAL;
g_server_dev.axi_device[index] = sd;
+ } else if (sdev_type == GESTURE_DEV) {
+ g_server_dev.gesture_device = sd;
}
err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 04e224c..6798cbb 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -32,6 +32,7 @@
#include <mach/camera.h>
#include <media/msm_isp.h>
#include <linux/ion.h>
+#include <media/msm_gestures.h>
#define MSM_V4L2_DIMENSION_SIZE 96
#define MAX_DEV_NAME_LEN 50
@@ -69,6 +70,7 @@
SENSOR_DEV,
ACTUATOR_DEV,
EEPROM_DEV,
+ GESTURE_DEV,
};
/* msm queue management APIs*/
@@ -150,6 +152,8 @@
NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
NOTIFY_VFE_IRQ,
NOTIFY_AXI_IRQ,
+ NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
+ NOTIFY_GESTURE_CAM_EVT, /* arg = int */
NOTIFY_INVALID
};
@@ -330,6 +334,8 @@
struct msm_cam_v4l2_dev_inst *dev_inst[MSM_DEV_INST_MAX];
struct msm_cam_v4l2_dev_inst *dev_inst_map[MSM_MAX_IMG_MODE];
struct mutex dev_lock;
+ int active;
+ int use_count;
};
/* abstract camera device for each sensor successfully probed*/
@@ -384,7 +390,8 @@
struct msm_mem_map_info mem_map;
};
-#define MAX_NUM_ACTIVE_CAMERA 2
+/* 2 for camera, 1 for gesture */
+#define MAX_NUM_ACTIVE_CAMERA 3
struct msm_cam_server_queue {
uint32_t queue_active;
@@ -444,6 +451,7 @@
struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];
struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
+ struct v4l2_subdev *gesture_device;
};
/* camera server related functions */
@@ -566,6 +574,12 @@
uint32_t msm_camera_get_mctl_handle(void);
struct msm_cam_media_controller *msm_camera_get_mctl(uint32_t handle);
void msm_camera_free_mctl(uint32_t handle);
+int msm_server_open_client(int *p_qidx);
+int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
+int msm_server_close_client(int idx);
+int msm_cam_server_open_mctl_session(struct msm_cam_v4l2_device *pcam,
+ int *p_active);
+int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
new file mode 100644
index 0000000..654594d
--- /dev/null
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -0,0 +1,497 @@
+/* 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 <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include <media/msm_camera.h>
+#include <media/msm_gestures.h>
+#include <media/v4l2-ctrls.h>
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_gesture: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+struct msm_gesture_ctrl {
+ int queue_id;
+ atomic_t active;
+ struct v4l2_ctrl_handler ctrl_handler;
+ int num_ctrls;
+ struct v4l2_fh *p_eventHandle;
+ struct v4l2_subdev *sd;
+ struct msm_ges_evt event;
+ int camera_opened;
+};
+
+static struct msm_gesture_ctrl g_gesture_ctrl;
+
+int msm_gesture_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ D("%s\n", __func__);
+ if (sub->type == V4L2_EVENT_ALL)
+ sub->type = MSM_GES_APP_NOTIFY_EVENT;
+ return v4l2_event_subscribe(fh, sub);
+}
+
+static int msm_gesture_send_ctrl(struct msm_gesture_ctrl *p_gesture_ctrl,
+ int type, void *value, int length, uint32_t timeout)
+{
+ int rc = 0;
+ struct msm_ctrl_cmd ctrlcmd;
+ D("%s qid %d\n", __func__, p_gesture_ctrl->queue_id);
+ ctrlcmd.type = type;
+ ctrlcmd.timeout_ms = timeout;
+ ctrlcmd.length = length;
+ ctrlcmd.value = value;
+ ctrlcmd.vnode_id = 0;
+ ctrlcmd.queue_idx = p_gesture_ctrl->queue_id;
+ ctrlcmd.config_ident = 0;
+
+ rc = msm_server_send_ctrl(&ctrlcmd, MSM_GES_RESP_V4L2);
+ return rc;
+}
+
+static int msm_gesture_proc_ctrl_cmd(struct msm_gesture_ctrl *p_gesture_ctrl,
+ struct v4l2_control *ctrl)
+{
+ int rc = 0;
+ struct msm_ctrl_cmd *tmp_cmd = NULL;
+ uint8_t *ctrl_data = NULL;
+ void __user *uptr_cmd;
+ void __user *uptr_value;
+ uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
+ uint32_t value_len;
+
+ tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
+ uptr_cmd = (void __user *)ctrl->value;
+ uptr_value = (void __user *)tmp_cmd->value;
+ value_len = tmp_cmd->length;
+
+ D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+ __func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
+ (uint32_t)uptr_value, tmp_cmd->length);
+
+ ctrl_data = kzalloc(value_len + cmd_len, GFP_KERNEL);
+ if (ctrl_data == 0) {
+ pr_err("%s could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+ tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
+ if (copy_from_user((void *)ctrl_data, uptr_cmd,
+ cmd_len)) {
+ pr_err("%s: copy_from_user failed.\n", __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+ tmp_cmd->value = (void *)(ctrl_data + cmd_len);
+ if (uptr_value && tmp_cmd->length > 0) {
+ if (copy_from_user((void *)tmp_cmd->value, uptr_value,
+ value_len)) {
+ pr_err("%s: copy_from_user failed, size=%d\n",
+ __func__, value_len);
+ rc = -EINVAL;
+ goto end;
+ }
+ } else
+ tmp_cmd->value = NULL;
+
+ /* send command to config thread in usersspace, and get return value */
+ rc = msm_server_send_ctrl((struct msm_ctrl_cmd *)ctrl_data,
+ MSM_GES_RESP_V4L2);
+ D("%s: msm_server_control rc=%d\n", __func__, rc);
+ if (rc == 0) {
+ if (uptr_value && tmp_cmd->length > 0 &&
+ copy_to_user((void __user *)uptr_value,
+ (void *)(ctrl_data + cmd_len),
+ tmp_cmd->length)) {
+ pr_err("%s: copy_to_user failed, size=%d\n",
+ __func__, tmp_cmd->length);
+ rc = -EINVAL;
+ goto end;
+ }
+ tmp_cmd->value = uptr_value;
+ if (copy_to_user((void __user *)uptr_cmd,
+ (void *)tmp_cmd, cmd_len)) {
+ pr_err("%s: copy_to_user failed in cpy, size=%d\n",
+ __func__, cmd_len);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+end:
+ D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
+ __func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
+ tmp_cmd->length, tmp_cmd->status, rc);
+ kfree(ctrl_data);
+ return rc;
+}
+
+static int msm_gesture_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ int rc = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s ctrl->id %d\n", __func__, ctrl->id);
+ rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, ctrl);
+ if (rc != 0) {
+ pr_err("%s set ctrl failed %d\n", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_gesture_s_ctrl_ops(struct v4l2_ctrl *ctrl)
+{
+ int rc = 0;
+ struct v4l2_control control;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ control.id = ctrl->id;
+ control.value = ctrl->val;
+ D("%s ctrl->id 0x%x\n", __func__, ctrl->id);
+ rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+ if (rc != 0) {
+ pr_err("%s proc ctrl failed %d\n", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_gesture_s_ctrl_ext(struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls)
+{
+ int rc = 0;
+ struct v4l2_control control;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ if ((ctrls->count < 1) || (NULL == ctrls->controls)) {
+ pr_err("%s invalid ctrl failed\n", __func__);
+ return -EINVAL;
+ }
+ control.id = ctrls->controls->id;
+ control.value = ctrls->controls->value;
+ D("%s ctrl->id %d\n", __func__, control.id);
+ rc = msm_gesture_proc_ctrl_cmd(p_gesture_ctrl, &control);
+ if (rc != 0) {
+ pr_err("%s proc ctrl failed %d\n", __func__, rc);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_gesture_handle_event(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+ int rc = 0;
+ struct v4l2_event *evt = (struct v4l2_event *)arg;
+ struct msm_ges_evt *p_ges_evt = NULL;
+ D("%s: Received gesture evt 0x%x ", __func__, evt->type);
+ p_gesture_ctrl->event.evt_len = 0;
+ p_gesture_ctrl->event.evt_data = NULL;
+ if (0 != evt->u.data[0]) {
+ p_ges_evt = (struct msm_ges_evt *)evt->u.data;
+ D("%s: event data %p len %d", __func__,
+ p_ges_evt->evt_data,
+ p_ges_evt->evt_len);
+
+ if (p_ges_evt->evt_len > 0) {
+ p_gesture_ctrl->event.evt_data =
+ kzalloc(p_ges_evt->evt_len, GFP_KERNEL);
+
+ if (NULL == p_gesture_ctrl->event.evt_data) {
+ pr_err("%s: cannot allocate event", __func__);
+ rc = -ENOMEM;
+ } else {
+ if (copy_from_user(
+ (void *)p_gesture_ctrl->event.evt_data,
+ (void __user *)p_ges_evt->evt_data,
+ p_ges_evt->evt_len)) {
+ pr_err("%s: copy_from_user failed",
+ __func__);
+ rc = -EFAULT;
+ } else {
+ D("%s: copied the event", __func__);
+ p_gesture_ctrl->event.evt_len =
+ p_ges_evt->evt_len;
+ }
+ }
+ }
+ }
+
+ if (rc == 0) {
+ ktime_get_ts(&evt->timestamp);
+ v4l2_event_queue(&sd->devnode, evt);
+ }
+ D("%s: exit rc %d ", __func__, rc);
+ return rc;
+}
+
+static int msm_gesture_get_evt_payload(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl, void* arg)
+{
+ int rc = 0;
+ struct msm_ges_evt *p_ges_evt = (struct msm_ges_evt *)arg;
+ D("%s: enter ", __func__);
+ if (NULL != p_gesture_ctrl->event.evt_data) {
+ D("%s: event data %p len %d", __func__,
+ p_gesture_ctrl->event.evt_data,
+ p_gesture_ctrl->event.evt_len);
+
+ if (copy_to_user((void __user *)p_ges_evt->evt_data,
+ p_gesture_ctrl->event.evt_data,
+ p_gesture_ctrl->event.evt_len)) {
+ pr_err("%s: copy_to_user failed.\n", __func__);
+ rc = -EFAULT;
+ } else {
+ D("%s: copied the event", __func__);
+ p_ges_evt->evt_len = p_gesture_ctrl->event.evt_len;
+ }
+ }
+ D("%s: exit rc %d ", __func__, rc);
+ return rc;
+}
+
+static int msm_gesture_handle_cam_event(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl, int cam_evt)
+{
+ int rc = 0;
+ D("%s: cam_evt %d ", __func__, cam_evt);
+
+ if ((cam_evt != MSM_V4L2_GES_CAM_OPEN)
+ && (cam_evt != MSM_V4L2_GES_CAM_CLOSE)) {
+ pr_err("%s: error invalid event %d ", __func__, cam_evt);
+ return -EINVAL;
+ }
+
+ p_gesture_ctrl->camera_opened =
+ (cam_evt == MSM_V4L2_GES_CAM_OPEN);
+
+ if (atomic_read(&p_gesture_ctrl->active) == 0) {
+ D("%s gesture not active\n", __func__);
+ return 0;
+ }
+
+ rc = msm_gesture_send_ctrl(p_gesture_ctrl, cam_evt, NULL,
+ 0, 2000);
+ if (rc != 0) {
+ pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ }
+ D("%s exit rc %d\n", __func__, rc);
+ return rc;
+}
+
+long msm_gesture_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s\n", __func__);
+ switch (cmd) {
+ case MSM_GES_IOCTL_CTRL_COMMAND: {
+ struct v4l2_control *ctrl = (struct v4l2_control *)arg;
+ D("%s MSM_GES_IOCTL_CTRL_COMMAND arg %p size %d\n", __func__,
+ arg, sizeof(ctrl));
+ rc = msm_gesture_s_ctrl(sd, ctrl);
+ break;
+ }
+ case VIDIOC_MSM_GESTURE_EVT: {
+ rc = msm_gesture_handle_event(sd, p_gesture_ctrl, arg);
+ break;
+ }
+ case VIDIOC_MSM_GESTURE_CAM_EVT: {
+ int cam_evt = *((int *)arg);
+ rc = msm_gesture_handle_cam_event(sd, p_gesture_ctrl, cam_evt);
+ break;
+ }
+ case MSM_GES_GET_EVT_PAYLOAD: {
+ rc = msm_gesture_get_evt_payload(sd, p_gesture_ctrl, arg);
+ break;
+ }
+ default:
+ pr_err("%s: Invalid ioctl %d", __func__, cmd);
+ break;
+ }
+ D("%s exit rc %d\n", __func__, rc);
+ return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_gesture_ctrl_ops = {
+ .s_ctrl = msm_gesture_s_ctrl_ops,
+};
+
+static const struct v4l2_ctrl_config msm_gesture_ctrl_filter = {
+ .ops = &msm_gesture_ctrl_ops,
+ .id = MSM_GESTURE_CID_CTRL_CMD,
+ .name = "Gesture ctrl",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 0x7fffffff,
+ .step = 1,
+ .min = 0x80000000,
+};
+
+static int msm_gesture_init_ctrl(struct v4l2_subdev *sd,
+ struct msm_gesture_ctrl *p_gesture_ctrl)
+{
+ int rc = 0;
+ p_gesture_ctrl->num_ctrls = 1;
+ p_gesture_ctrl->ctrl_handler.error = 0;
+ v4l2_ctrl_handler_init(&p_gesture_ctrl->ctrl_handler,
+ p_gesture_ctrl->num_ctrls);
+ v4l2_ctrl_new_custom(&p_gesture_ctrl->ctrl_handler,
+ &msm_gesture_ctrl_filter, p_gesture_ctrl);
+ if (p_gesture_ctrl->ctrl_handler.error) {
+ int err = p_gesture_ctrl->ctrl_handler.error;
+ D("%s: error adding control %d", __func__, err);
+ p_gesture_ctrl->ctrl_handler.error = 0;
+ }
+ sd->ctrl_handler = &p_gesture_ctrl->ctrl_handler;
+ return rc;
+}
+
+static int msm_gesture_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0, rc_err = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s\n", __func__);
+ if (atomic_read(&p_gesture_ctrl->active) != 0) {
+ pr_err("%s already opened\n", __func__);
+ return -EINVAL;
+ }
+ memset(&p_gesture_ctrl->event, 0x0, sizeof(struct msm_ges_evt));
+ rc = msm_server_open_client(&p_gesture_ctrl->queue_id);
+ if (rc != 0) {
+ pr_err("%s open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = msm_gesture_init_ctrl(sd, p_gesture_ctrl);
+ if (rc != 0) {
+ pr_err("%s init ctrl failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_OPEN, NULL,
+ 0, 10000);
+ if (rc != 0) {
+ pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto err;
+ }
+
+ atomic_inc(&p_gesture_ctrl->active);
+
+ return rc;
+
+err:
+ rc_err = msm_server_close_client(p_gesture_ctrl->queue_id);
+ if (rc_err != 0)
+ pr_err("%s failed %d\n", __func__, rc);
+ return rc;
+}
+
+static int msm_gesture_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ D("%s\n", __func__);
+ if (atomic_read(&p_gesture_ctrl->active) == 0) {
+ pr_err("%s already closed\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_gesture_send_ctrl(p_gesture_ctrl, MSM_V4L2_GES_CLOSE, NULL,
+ 0, 10000);
+ if (rc != 0)
+ pr_err("%s gesture ctrl failed %d\n", __func__, rc);
+
+ rc = msm_server_close_client(p_gesture_ctrl->queue_id);
+ if (rc != 0)
+ pr_err("%s failed %d\n", __func__, rc);
+
+ v4l2_ctrl_handler_free(&p_gesture_ctrl->ctrl_handler);
+ kfree(p_gesture_ctrl->event.evt_data);
+
+ atomic_dec(&p_gesture_ctrl->active);
+ g_gesture_ctrl.queue_id = -1;
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_gesture_core_ops = {
+ .s_ctrl = msm_gesture_s_ctrl,
+ .s_ext_ctrls = msm_gesture_s_ctrl_ext,
+ .ioctl = msm_gesture_ioctl,
+ .subscribe_event = msm_gesture_subscribe_event,
+};
+
+static struct v4l2_subdev_video_ops msm_gesture_video_ops;
+
+static struct v4l2_subdev_ops msm_gesture_subdev_ops = {
+ .core = &msm_gesture_core_ops,
+ .video = &msm_gesture_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops msm_gesture_internal_ops = {
+ .open = msm_gesture_open,
+ .close = msm_gesture_close,
+};
+
+static int msm_gesture_node_register(void)
+{
+ struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
+ struct v4l2_subdev *gesture_subdev =
+ kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ D("%s\n", __func__);
+ if (!gesture_subdev) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ };
+
+ v4l2_subdev_init(gesture_subdev, &msm_gesture_subdev_ops);
+ gesture_subdev->internal_ops = &msm_gesture_internal_ops;
+ gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(gesture_subdev->name,
+ sizeof(gesture_subdev->name), "gesture");
+
+ media_entity_init(&gesture_subdev->entity, 0, NULL, 0);
+ gesture_subdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ gesture_subdev->entity.group_id = GESTURE_DEV;
+ gesture_subdev->entity.name = gesture_subdev->name;
+
+ /* events */
+ gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+ gesture_subdev->nevents = MAX_GES_EVENTS;
+
+ msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+
+ gesture_subdev->entity.revision = gesture_subdev->devnode.num;
+
+ atomic_set(&p_gesture_ctrl->active, 0);
+ p_gesture_ctrl->queue_id = -1;
+ p_gesture_ctrl->event.evt_data = NULL;
+ p_gesture_ctrl->event.evt_len = 0;
+ return 0;
+}
+
+static int __init msm_gesture_init_module(void)
+{
+ return msm_gesture_node_register();
+}
+
+module_init(msm_gesture_init_module);
+MODULE_DESCRIPTION("MSM Gesture driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e878063..e9eb68f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -923,7 +923,6 @@
struct msm_cam_v4l2_device *pcam = NULL;
struct msm_cam_v4l2_dev_inst *pcam_inst;
struct msm_cam_media_controller *pmctl;
- D("%s : E ", __func__);
if (f == NULL) {
pr_err("%s :: cannot open video driver data", __func__);
@@ -935,8 +934,8 @@
pr_err("%s NULL pointer passed in!\n", __func__);
return rc;
}
- pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ D("%s : E use_count %d", __func__, pcam->mctl_node.use_count);
mutex_lock(&pcam->mctl_node.dev_lock);
for (i = 0; i < MSM_DEV_INST_MAX; i++) {
if (pcam->mctl_node.dev_inst[i] == NULL)
@@ -960,6 +959,21 @@
D("%s pcam_inst %p my_index = %d\n", __func__,
pcam_inst, pcam_inst->my_index);
+ rc = msm_cam_server_open_mctl_session(pcam,
+ &pcam->mctl_node.active);
+ if (rc < 0) {
+ pr_err("%s: mctl session open failed %d", __func__, rc);
+ mutex_unlock(&pcam->mctl_node.dev_lock);
+ return rc;
+ }
+
+ pmctl = msm_camera_get_mctl(pcam->mctl_handle);
+ if (!pmctl) {
+ pr_err("%s mctl NULL!\n", __func__);
+ return rc;
+ }
+
+ D("%s active %d\n", __func__, pcam->mctl_node.active);
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->mctl_node.pvdev);
if (rc < 0) {
@@ -973,6 +987,7 @@
D("f->private_data = 0x%x, pcam = 0x%x\n",
(u32)f->private_data, (u32)pcam_inst);
+ pcam->mctl_node.use_count++;
mutex_unlock(&pcam->mctl_node.dev_lock);
D("%s : X ", __func__);
return rc;
@@ -1030,6 +1045,17 @@
pmctl = msm_camera_get_mctl(pcam->mctl_handle);
mutex_lock(&pcam->mctl_node.dev_lock);
+ D("%s : active %d ", __func__, pcam->mctl_node.active);
+ if (pcam->mctl_node.active == 1) {
+ rc = msm_cam_server_close_mctl_session(pcam);
+ if (rc < 0) {
+ pr_err("%s: mctl session close failed %d",
+ __func__, rc);
+ mutex_unlock(&pcam->mctl_node.dev_lock);
+ return rc;
+ }
+ pmctl = NULL;
+ }
pcam_inst->streamon = 0;
pcam->mctl_node.dev_inst_map[pcam_inst->image_mode] = NULL;
if (pcam_inst->vbqueue_initialized)
@@ -1040,10 +1066,14 @@
v4l2_fh_exit(&pcam_inst->eventHandle);
kfree(pcam_inst);
- kref_put(&pmctl->refcount, msm_release_ion_client);
+ if (NULL != pmctl) {
+ D("%s : release ion client", __func__);
+ kref_put(&pmctl->refcount, msm_release_ion_client);
+ }
f->private_data = NULL;
mutex_unlock(&pcam->mctl_node.dev_lock);
- D("%s : X ", __func__);
+ pcam->mctl_node.use_count--;
+ D("%s : use_count %d X ", __func__, pcam->mctl_node.use_count);
return rc;
}
@@ -1246,6 +1276,11 @@
pb->m.planes[i].data_offset;
pcam_inst->buf_offset[pb->index][i].addr_offset =
pb->m.planes[i].reserved[0];
+ pcam_inst->plane_info.plane[i].offset = 0;
+ D("%s, len %d user[%d] %p buf_len %d\n",
+ __func__, pb->length, i,
+ (void *)pb->m.planes[i].m.userptr,
+ pb->m.planes[i].length);
}
} else {
D("%s stored reserved info %d", __func__, pb->reserved);
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 5bc81a7..42d13a1 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -431,8 +431,8 @@
int pp_divert_type = 0, pp_type = 0;
msm_mctl_check_pp(p_mctl, image_mode, &pp_divert_type, &pp_type);
- D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x",
- __func__, pp_type, pp_divert_type, frame_id);
+ D("%s: pp_type=%d, pp_divert_type = %d, frame_id = 0x%x image_mode %d",
+ __func__, pp_type, pp_divert_type, frame_id, image_mode);
if (pp_type || pp_divert_type)
rc = msm_mctl_do_pp_divert(p_mctl,
image_mode, fbuf, frame_id, pp_type);
@@ -440,9 +440,26 @@
idx = msm_mctl_img_mode_to_inst_index(
p_mctl, image_mode, 0);
if (idx < 0) {
- pr_err("%s Invalid instance, dropping buffer\n",
- __func__);
- return idx;
+ /* check mctl node */
+ if ((image_mode >= 0) &&
+ p_mctl->pcam_ptr->mctl_node.
+ dev_inst_map[image_mode]) {
+ int index = p_mctl->pcam_ptr->mctl_node.
+ dev_inst_map[image_mode]->my_index;
+ pcam_inst = p_mctl->pcam_ptr->mctl_node.
+ dev_inst[index];
+ D("%s: Mctl node index %d inst %p",
+ __func__, index, pcam_inst);
+ rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
+ image_mode, fbuf,
+ &frame_id, 1);
+ D("%s mctl node buf done %d\n", __func__, 0);
+ return -EINVAL;
+ } else {
+ pr_err("%s Invalid instance, dropping buffer\n",
+ __func__);
+ return idx;
+ }
}
pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
@@ -573,6 +590,10 @@
plane_offset =
mem->offset.sp_off.cbcr_off;
+ D("%s: data off %d plane off %d",
+ __func__,
+ pcam_inst->buf_offset[buf_idx][i].
+ data_offset, plane_offset);
free_buf->ch_paddr[i] = (uint32_t)
videobuf2_to_pmem_contig(&buf->vidbuf, i) +
pcam_inst->buf_offset[buf_idx][i].data_offset +
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index becdd95..3e8d3be 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -3056,7 +3056,7 @@
ch2_paddr = vfe32_get_ch_addr(ping_pong,
vfe32_ctrl->outpath.out1.ch2);
- pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
__func__, ch0_paddr, ch1_paddr, ch2_paddr);
if (free_buf) {
/* Y channel */
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index dd567d1..0f71404 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -258,7 +258,8 @@
{VFE_CMD_DUMMY_9, VFE_MAX, VFE_MAX},
{VFE_CMD_STATS_AF_START, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
"VFE_CMD_STATS_AF_START", "VFE_STATS_AUTOFOCUS_CONFIG"},
- {VFE_CMD_STATS_AF_STOP, VFE_MAX, VFE_MAX},
+ {VFE_CMD_STATS_AF_STOP, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
+ "VFE_CMD_STATS_AF_STOP", "VFE_STATS_AUTOFOCUS_CONFIG"},
{VFE_CMD_STATS_AE_START, VFE_MAX, VFE_MAX},
{VFE_CMD_STATS_AE_STOP, VFE_MAX, VFE_MAX},
{VFE_CMD_STATS_AWB_START, VFE_MAX, VFE_MAX},
@@ -341,7 +342,6 @@
static uint32_t extlen;
struct mutex vfe_lock;
-static int apps_reset;
static uint8_t vfestopped;
static struct stop_event stopevent;
@@ -489,6 +489,8 @@
len = sizeof(fack);
msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
cmd_data, len);
+ kfree(data);
+ return;
}
}
y_phy = ((struct vfe_endframe *)data)->y_address;
@@ -557,6 +559,8 @@
len = sizeof(fack);
msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
cmd_data, len);
+ kfree(data);
+ return;
}
}
y_phy = ((struct vfe_endframe *)data)->y_address;
@@ -666,7 +670,9 @@
msgs_map[id].isp_id);
break;
default:
- vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+ if (MSG_TABLE_CMD_ACK != id)
+ vfe2x_send_isp_msg(vfe2x_ctrl,
+ msgs_map[id].isp_id);
break;
}
}
@@ -1216,8 +1222,7 @@
if (queue == QDSP_CMDQUEUE) {
switch (vfecmd.id) {
case VFE_CMD_RESET:
- msm_camio_vfe_blk_reset_2(apps_reset);
- apps_reset = 0;
+ msm_camio_vfe_blk_reset_2();
vfestopped = 0;
break;
case VFE_CMD_START:
@@ -1270,7 +1275,10 @@
if ((!list_empty(&vfe2x_ctrl->table_q)) ||
vfe2x_ctrl->tableack_pending) {
CDBG("update pending\n");
- vfe2x_ctrl->update_pending = 1;
+ vfe2x_ctrl->update_pending = 0;
+ vfe2x_send_isp_msg(vfe2x_ctrl,
+ msgs_map[MSG_UPDATE_ACK].
+ isp_id);
spin_unlock_irqrestore(
&vfe2x_ctrl->table_lock,
flags);
@@ -1588,29 +1596,30 @@
config_send:
CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+ spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
if (queue == QDSP_TABLEQUEUE &&
vfe2x_ctrl->tableack_pending) {
CDBG("store table cmd\n");
table_pending = kzalloc(sizeof(struct table_cmd), GFP_ATOMIC);
if (!table_pending) {
rc = -ENOMEM;
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
goto config_done;
}
table_pending->cmd = kzalloc(vfecmd.length + 4, GFP_ATOMIC);
if (!table_pending->cmd) {
kfree(table_pending);
rc = -ENOMEM;
+ spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
goto config_done;
}
memcpy(table_pending->cmd, cmd_data, vfecmd.length + 4);
table_pending->queue = queue;
table_pending->size = vfecmd.length + 4;
- spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
list_add_tail(&table_pending->list, &vfe2x_ctrl->table_q);
spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
} else {
if (queue == QDSP_TABLEQUEUE) {
- 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,
@@ -1621,7 +1630,6 @@
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);
@@ -1717,8 +1725,6 @@
CDBG("msm_cam_clk_enable: disable vfe_clk\n");
msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
- apps_reset = 1;
-
msm_adsp_disable(qcam_mod);
msm_adsp_disable(vfe_mod);
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 13dc446..ea36bf6 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -13,5 +13,5 @@
obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
-obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd_v4l2.o
+obj-$(CONFIG_OV7692) += ov7692_v4l2.o
obj-$(CONFIG_VX6953) += vx6953.o
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index d30d48b..48f1d5d 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -21,8 +21,6 @@
DEFINE_MUTEX(ov5647_mut);
-
-
static struct msm_camera_i2c_reg_conf ov5647_start_settings[] = {
{0x4202, 0x00}, /* streaming on */
};
@@ -159,6 +157,34 @@
{0x4004, 0x02},
};
+static struct msm_camera_i2c_reg_conf ov5647_zsl_settings[] = {
+ {0x3035, 0x21},
+ {0x3036, 0x2f},
+ {0x3821, 0x06},
+ {0x3820, 0x00},
+ {0x3612, 0x0b},
+ {0x3618, 0x04},
+ {0x380c, 0x0a},
+ {0x380d, 0x8c},
+ {0x380e, 0x07},
+ {0x380f, 0xb0},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3709, 0x12},
+ {0x3808, 0x0a},
+ {0x3809, 0x30},
+ {0x380a, 0x07},
+ {0x380b, 0xa0},
+ {0x3800, 0x00},
+ {0x3801, 0x04},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3b},
+ {0x3806, 0x07},
+ {0x3807, 0xa3},
+ {0x4004, 0x04},
+};
static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
{0x3035, 0x11},
@@ -313,6 +339,8 @@
ARRAY_SIZE(ov5647_video_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
{&ov5647_video_90fps_settings[0],
ARRAY_SIZE(ov5647_video_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov5647_zsl_settings[0],
+ ARRAY_SIZE(ov5647_zsl_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_camera_csi_params ov5647_csi_params = {
@@ -370,6 +398,15 @@
.op_pixel_clk = 159408000,
.binning_factor = 0x0,
},
+ { /* For ZSL */
+ .x_output = 0xA30, /*2608*/ /*for 5Mp*/
+ .y_output = 0x7A0, /*1952*/
+ .line_length_pclk = 0xA8C,
+ .frame_length_lines = 0x7B0,
+ .vt_pixel_clk = 79704000,
+ .op_pixel_clk = 159408000,
+ .binning_factor = 0x0,
+ },
};
@@ -381,10 +418,11 @@
};
static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
- &ov5647_csi_params,
- &ov5647_csi_params,
- &ov5647_csi_params,
- &ov5647_csi_params,
+ &ov5647_csi_params, /* Snapshot */
+ &ov5647_csi_params, /* Preview */
+ &ov5647_csi_params, /* 60fps */
+ &ov5647_csi_params, /* 90fps */
+ &ov5647_csi_params, /* ZSL */
};
static struct msm_sensor_id_info_t ov5647_id_info = {
@@ -711,6 +749,8 @@
}
+static int32_t vfe_clk = 266667000;
+
int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res)
{
@@ -762,6 +802,10 @@
0x4800, 0x4,
MSM_CAMERA_I2C_BYTE_DATA);
msleep(266);
+ if (res == MSM_SENSOR_RES_4)
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_PCLK_CHANGE,
+ &vfe_clk);
s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
msleep(50);
}
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
similarity index 87%
rename from drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
rename to drivers/media/video/msm/sensors/ov7692_v4l2.c
index 2324495..e7970d5 100644
--- a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -247,7 +247,43 @@
.video = &ov7692_subdev_video_ops,
};
+int32_t ov7692_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;
+ if (info->pmic_gpio_enable) {
+ info->sensor_lcd_gpio_onoff(1);
+ usleep_range(5000, 5100);
+ }
+
+ rc = msm_sensor_power_up(s_ctrl);
+ if (rc < 0) {
+ CDBG("%s: msm_sensor_power_up failed\n", __func__);
+ return rc;
+ }
+
+ return rc;
+}
+
+int32_t ov7692_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t rc = 0;
+ struct msm_camera_sensor_info *info = NULL;
+
+ rc = msm_sensor_power_down(s_ctrl);
+ if (rc < 0)
+ CDBG("%s: msm_sensor_power_down failed\n", __func__);
+
+ info = s_ctrl->sensordata;
+ if (info->pmic_gpio_enable) {
+ info->pmic_gpio_enable = 0;
+ info->sensor_lcd_gpio_onoff(0);
+ usleep_range(5000, 5100);
+ }
+ return rc;
+}
static struct msm_sensor_fn_t ov7692_func_tbl = {
.sensor_start_stream = msm_sensor_start_stream,
@@ -257,8 +293,8 @@
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
.sensor_config = msm_sensor_config,
- .sensor_power_up = msm_sensor_power_up,
- .sensor_power_down = msm_sensor_power_down,
+ .sensor_power_up = ov7692_sensor_power_up,
+ .sensor_power_down = ov7692_sensor_power_down,
};
static struct msm_sensor_reg_t ov7692_regs = {
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index b7ae0f4..c94fa13 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -191,7 +191,7 @@
}
vbuf->v4l2_buf.timestamp =
- ns_to_timeval(frame_data->time_stamp);
+ ns_to_timeval(frame_data->time_stamp * NSEC_PER_USEC);
WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
frame_data->data_len,
@@ -365,7 +365,15 @@
WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
goto err;
}
- b->count = buf_req.actual_count;
+
+ buf_req.actual_count = b->count = max(buf_req.min_count, b->count);
+ rc = vcd_set_buffer_requirements(client_ctx->vcd_handle,
+ VCD_BUFFER_OUTPUT, &buf_req);
+ if (rc) {
+ WFD_MSG_ERR("Failed to set out buf reqs rc = %d", rc);
+ goto err;
+ }
+
err:
return rc;
}
@@ -1051,6 +1059,7 @@
struct v4l2_fract *frate = arg;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_frame_rate vcd_frame_rate;
+ struct vcd_property_vop_timing_constant_delta vcd_delta;
int rc;
vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
vcd_property_hdr.sz =
@@ -1060,8 +1069,25 @@
vcd_frame_rate.fps_numerator = frate->denominator;
rc = vcd_set_property(client_ctx->vcd_handle,
&vcd_property_hdr, &vcd_frame_rate);
- if (rc)
+ if (rc) {
WFD_MSG_ERR("Failed to set frame rate, rc = %d\n", rc);
+ goto set_framerate_fail;
+ }
+
+ vcd_property_hdr.prop_id = VCD_I_VOP_TIMING_CONSTANT_DELTA;
+ vcd_property_hdr.sz = sizeof(vcd_delta);
+
+ vcd_delta.constant_delta = (frate->numerator * USEC_PER_SEC) /
+ frate->denominator;
+ rc = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_delta);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to set frame delta, rc = %d", rc);
+ goto set_framerate_fail;
+ }
+
+set_framerate_fail:
return rc;
}
@@ -1827,12 +1853,16 @@
struct venc_buf_info *venc_buf = arg;
struct mem_region *mregion = venc_buf->mregion;
struct vcd_frame_data vcd_input_buffer = {0};
+ int64_t ts = 0;
+
+ ts = venc_buf->timestamp;
+ do_div(ts, NSEC_PER_USEC);
vcd_input_buffer.virtual = mregion->kvaddr;
vcd_input_buffer.frm_clnt_data = (u32)mregion;
vcd_input_buffer.ip_frm_tag = (u32)mregion;
vcd_input_buffer.data_len = mregion->size;
- vcd_input_buffer.time_stamp = venc_buf->timestamp;
+ vcd_input_buffer.time_stamp = ts;
vcd_input_buffer.offset = 0;
rc = vcd_encode_frame(client_ctx->vcd_handle,
diff --git a/drivers/media/video/msm_vidc/Kconfig b/drivers/media/video/msm_vidc/Kconfig
new file mode 100644
index 0000000..0b5a5fe
--- /dev/null
+++ b/drivers/media/video/msm_vidc/Kconfig
@@ -0,0 +1,8 @@
+#
+# VIDEO CORE
+#
+
+menuconfig MSM_VIDC
+ bool "Qualcomm MSM Video Core Driver"
+ depends on ARCH_MSMCOPPER && VIDEO_V4L2
+ default y
diff --git a/drivers/media/video/msm_vidc/Makefile b/drivers/media/video/msm_vidc/Makefile
new file mode 100644
index 0000000..12c61c9
--- /dev/null
+++ b/drivers/media/video/msm_vidc/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_MSM_VIDC) := msm_v4l2_vidc.o \
+ msm_vidc_common.o \
+ msm_vidc.o \
+ msm_vdec.o \
+ msm_venc.o \
+ msm_smem.o \
+ vidc_hal.o \
+ vidc_hal_interrupt_handler.o \
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
new file mode 100644
index 0000000..25b5c5c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -0,0 +1,244 @@
+/* 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 "msm_smem.h"
+
+struct smem_client {
+ int mem_type;
+ void *clnt;
+};
+
+static int ion_user_to_kernel(struct smem_client *client,
+ int fd, u32 offset, struct msm_smem *mem)
+{
+ struct ion_handle *hndl;
+ unsigned long ionflag;
+ size_t len;
+ int rc = 0;
+ hndl = ion_import_fd(client->clnt, fd);
+ if (IS_ERR_OR_NULL(hndl)) {
+ pr_err("Failed to get handle: %p, %d, %d, %p\n",
+ client, fd, offset, hndl);
+ rc = -ENOMEM;
+ goto fail_import_fd;
+ }
+ rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
+ if (rc) {
+ pr_err("Failed to get ion flags: %d", rc);
+ goto fail_map;
+ }
+ rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
+ if (rc) {
+ pr_err("Failed to get physical address\n");
+ goto fail_map;
+ }
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
+ if (!mem->kvaddr) {
+ pr_err("Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+
+ mem->kvaddr += offset;
+ mem->paddr += offset;
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ mem->device_addr = mem->paddr;
+ mem->size = len;
+ return rc;
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_import_fd:
+ return rc;
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size,
+ u32 align, u32 flags, struct msm_smem *mem)
+{
+ struct ion_handle *hndl;
+ size_t len;
+ int rc = 0;
+ flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+ hndl = ion_alloc(client->clnt, size, align, flags);
+ if (IS_ERR_OR_NULL(hndl)) {
+ pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
+ client, size, align, flags);
+ rc = -ENOMEM;
+ goto fail_shared_mem_alloc;
+ }
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
+ pr_err("Failed to get physical address\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ mem->device_addr = mem->paddr;
+ mem->size = size;
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+ if (!mem->kvaddr) {
+ pr_err("Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ return rc;
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+ return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+ ion_unmap_kernel(client->clnt, mem->smem_priv);
+ ion_free(client->clnt, mem->smem_priv);
+}
+
+static void *ion_new_client(void)
+{
+ struct ion_client *client = NULL;
+ client = msm_ion_client_create(-1, "video_client");
+ if (!client)
+ pr_err("Failed to create smem client\n");
+ return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+ ion_client_destroy(client->clnt);
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
+{
+ struct smem_client *client = clt;
+ int rc = 0;
+ struct msm_smem *mem;
+ if (fd < 0) {
+ pr_err("Invalid fd: %d\n", fd);
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ pr_err("Failed to allocte shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = ion_user_to_kernel(clt, fd, offset, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void *msm_smem_new_client(enum smem_type mtype)
+{
+ struct smem_client *client = NULL;
+ void *clnt = NULL;
+ switch (mtype) {
+ case SMEM_ION:
+ clnt = ion_new_client();
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ if (clnt) {
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client) {
+ client->mem_type = mtype;
+ client->clnt = clnt;
+ }
+ } else {
+ pr_err("Failed to create new client: mtype = %d\n", mtype);
+ }
+ return client;
+};
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
+{
+ struct smem_client *client;
+ int rc = 0;
+ struct msm_smem *mem;
+
+ client = clt;
+ if (!client) {
+ pr_err("Invalid client passed\n");
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ pr_err("Failed to allocate shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = alloc_ion_mem(client, size, align, flags, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+ struct smem_client *client = clt;
+ if (!client || !mem) {
+ pr_err("Invalid client/handle passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ free_ion_mem(client, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+ struct smem_client *client = clt;
+ if (!client) {
+ pr_err("Invalid client passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ ion_delete_client(client);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ kfree(client);
+}
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
new file mode 100644
index 0000000..84d12cc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -0,0 +1,38 @@
+/* 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_SMEM_H_
+#define _MSM_SMEM_H_
+
+#include <linux/types.h>
+#include <linux/ion.h>
+
+enum smem_type {
+ SMEM_ION,
+};
+
+struct msm_smem {
+ int mem_type;
+ size_t size;
+ void *kvaddr;
+ unsigned long paddr;
+ unsigned long device_addr;
+ /*Device address and others to follow*/
+ void *smem_priv;
+};
+
+void *msm_smem_new_client(enum smem_type mtype);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset);
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
new file mode 100644
index 0000000..550fbde
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -0,0 +1,611 @@
+/* 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/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_drv *vidc_driver;
+
+struct buffer_info {
+ struct list_head list;
+ int type;
+ int fd;
+ int buff_off;
+ int size;
+ u32 uvaddr;
+ struct msm_smem *handle;
+};
+
+struct msm_v4l2_vid_inst {
+ struct msm_vidc_inst vidc_inst;
+ void *mem_client;
+ struct list_head registered_bufs;
+};
+
+static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+ return container_of(filp->private_data,
+ struct msm_vidc_inst, event_handler);
+}
+
+static inline struct msm_v4l2_vid_inst *get_v4l2_inst(struct file *filp,
+ void *fh)
+{
+ struct msm_vidc_inst *vidc_inst;
+ vidc_inst = container_of(filp->private_data,
+ struct msm_vidc_inst, event_handler);
+ return container_of((void *)vidc_inst,
+ struct msm_v4l2_vid_inst, vidc_inst);
+}
+
+static int msm_vidc_v4l2_setup_event_queue(void *inst,
+ struct video_device *pvdev)
+{
+ int rc = 0;
+ struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+ spin_lock_init(&pvdev->fh_lock);
+ INIT_LIST_HEAD(&pvdev->fh_list);
+ rc = v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+ if (rc < 0)
+ return rc;
+ if (&vidc_inst->event_handler.events == NULL) {
+ rc = v4l2_event_init(&vidc_inst->event_handler);
+ if (rc < 0)
+ return rc;
+ }
+ rc = v4l2_event_alloc(&vidc_inst->event_handler, 32);
+ if (rc < 0)
+ return rc;
+ v4l2_fh_add(&vidc_inst->event_handler);
+ return rc;
+}
+
+struct buffer_info *get_registered_buf(struct list_head *list,
+ int fd, u32 buff_off, u32 size)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ if (!list || fd < 0) {
+ pr_err("%s Invalid input\n", __func__);
+ goto err_invalid_input;
+ }
+ if (!list_empty(list)) {
+ list_for_each_entry(temp, list, list) {
+ if (temp && temp->fd == fd &&
+ (CONTAINS(temp->buff_off, temp->size, buff_off)
+ || CONTAINS(buff_off, size, temp->buff_off)
+ || OVERLAPS(buff_off, size,
+ temp->buff_off, temp->size))) {
+ pr_err("This memory region is already mapped\n");
+ ret = temp;
+ break;
+ }
+ }
+ }
+err_invalid_input:
+ return ret;
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+ int rc = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct msm_video_device *vid_dev =
+ container_of(vdev, struct msm_video_device, vdev);
+ struct msm_vidc_core *core = video_drvdata(filp);
+ struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
+ GFP_KERNEL);
+ if (!v4l2_inst) {
+ pr_err("Failed to allocate memory for this instance\n");
+ rc = -ENOMEM;
+ goto fail_nomem;
+ }
+ v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
+ if (!v4l2_inst->mem_client) {
+ pr_err("Failed to create memory client\n");
+ rc = -ENOMEM;
+ goto fail_mem_client;
+ }
+ rc = msm_vidc_open(&v4l2_inst->vidc_inst, core->id, vid_dev->type);
+ if (rc) {
+ pr_err("Failed to create video instance, core: %d, type = %d\n",
+ core->id, vid_dev->type);
+ rc = -ENOMEM;
+ goto fail_open;
+ }
+ INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
+ rc = msm_vidc_v4l2_setup_event_queue(&v4l2_inst->vidc_inst, vdev);
+ clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
+ filp->private_data = &(v4l2_inst->vidc_inst.event_handler);
+ return rc;
+fail_open:
+ msm_smem_delete_client(v4l2_inst->mem_client);
+fail_mem_client:
+ kfree(v4l2_inst);
+fail_nomem:
+ return rc;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+ int rc;
+ struct list_head *ptr, *next;
+ struct buffer_info *binfo;
+ struct msm_vidc_inst *vidc_inst;
+ struct msm_v4l2_vid_inst *v4l2_inst;
+ vidc_inst = get_vidc_inst(filp, NULL);
+ v4l2_inst = get_v4l2_inst(filp, NULL);
+ rc = msm_vidc_close(vidc_inst);
+ list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+ binfo = list_entry(ptr, struct buffer_info, list);
+ list_del(&binfo->list);
+ msm_smem_free(v4l2_inst->mem_client, binfo->handle);
+ kfree(binfo);
+ }
+ msm_smem_delete_client(v4l2_inst->mem_client);
+ kfree(v4l2_inst);
+ return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
+ return msm_vidc_querycap((void *)vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_enum_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_g_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_s_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_g_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ struct msm_v4l2_vid_inst *v4l2_inst;
+ struct list_head *ptr, *next;
+ int rc;
+ struct buffer_info *bi;
+ struct v4l2_buffer buffer_info;
+ v4l2_inst = get_v4l2_inst(file, NULL);
+ if (b->count == 0) {
+ list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buffer_info.type = bi->type;
+ buffer_info.m.planes[0].reserved[0] =
+ bi->fd;
+ buffer_info.m.planes[0].reserved[1] =
+ bi->buff_off;
+ buffer_info.m.planes[0].length = bi->size;
+ buffer_info.m.planes[0].m.userptr =
+ bi->uvaddr;
+ buffer_info.length = 1;
+ pr_err("Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+ &buffer_info);
+ list_del(&bi->list);
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle);
+ kfree(bi);
+ }
+ }
+ }
+ return msm_vidc_reqbufs((void *)vidc_inst, b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_smem *handle;
+ struct buffer_info *binfo;
+ struct msm_vidc_inst *vidc_inst;
+ struct msm_v4l2_vid_inst *v4l2_inst;
+ int i, rc = 0;
+ vidc_inst = get_vidc_inst(file, fh);
+ v4l2_inst = get_v4l2_inst(file, fh);
+ if (!v4l2_inst->mem_client) {
+ pr_err("Failed to get memory client\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ for (i = 0; i < b->length; ++i) {
+ binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ if (binfo) {
+ pr_err("This memory region has already been prepared\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1]);
+ if (!handle) {
+ pr_err("Failed to get device buffer address\n");
+ kfree(binfo);
+ goto exit;
+ }
+ binfo->type = b->type;
+ binfo->fd = b->m.planes[i].reserved[0];
+ binfo->buff_off = b->m.planes[i].reserved[1];
+ binfo->size = b->m.planes[i].length;
+ binfo->uvaddr = b->m.planes[i].m.userptr;
+ binfo->handle = handle;
+ pr_debug("Registering buffer: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
+ b->m.planes[i].m.userptr = handle->device_addr;
+ }
+ rc = msm_vidc_prepare_buf(&v4l2_inst->vidc_inst, b);
+exit:
+ return rc;
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *vidc_inst;
+ struct msm_v4l2_vid_inst *v4l2_inst;
+ struct buffer_info *binfo;
+ int rc = 0;
+ int i;
+ vidc_inst = get_vidc_inst(file, fh);
+ v4l2_inst = get_v4l2_inst(file, fh);
+ for (i = 0; i < b->length; ++i) {
+ binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ if (!binfo) {
+ pr_err("This buffer is not registered: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ rc = -EINVAL;
+ goto err_invalid_buff;
+ }
+ b->m.planes[i].m.userptr = binfo->handle->device_addr;
+ pr_debug("Queueing device address = %ld\n",
+ binfo->handle->device_addr);
+ }
+ rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
+err_invalid_buff:
+ return rc;
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_dqbuf((void *)vidc_inst, b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_streamon((void *)vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_streamoff((void *)vidc_inst, i);
+}
+
+static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int rc = 0;
+ if (sub->type == V4L2_EVENT_ALL)
+ sub->type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ rc = v4l2_event_subscribe(fh, sub);
+ return rc;
+}
+
+static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int rc = 0;
+ rc = v4l2_event_unsubscribe(fh, sub);
+ return rc;
+}
+
+static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+ struct v4l2_decoder_cmd *dec)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
+}
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+ .vidioc_querycap = msm_v4l2_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+ .vidioc_reqbufs = msm_v4l2_reqbufs,
+ .vidioc_prepare_buf = msm_v4l2_prepare_buf,
+ .vidioc_qbuf = msm_v4l2_qbuf,
+ .vidioc_dqbuf = msm_v4l2_dqbuf,
+ .vidioc_streamon = msm_v4l2_streamon,
+ .vidioc_streamoff = msm_v4l2_streamoff,
+ .vidioc_s_ctrl = msm_v4l2_s_ctrl,
+ .vidioc_g_ctrl = msm_v4l2_g_ctrl,
+ .vidioc_subscribe_event = msm_v4l2_subscribe_event,
+ .vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
+ .vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+ struct poll_table_struct *pt)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
+ return msm_vidc_poll((void *)vidc_inst, filp, pt);
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_v4l2_open,
+ .release = msm_v4l2_close,
+ .ioctl = video_ioctl2,
+ .poll = msm_v4l2_poll,
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+ struct msm_vidc_core *core)
+{
+ struct resource *res;
+ int i = 0;
+ if (!core)
+ return -EINVAL;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("Failed to get IORESOURCE_MEM\n");
+ return -ENODEV;
+ }
+ core->register_base = res->start;
+ core->register_size = resource_size(res);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("Failed to get IORESOURCE_IRQ\n");
+ return -ENODEV;
+ }
+ core->irq = res->start;
+ INIT_LIST_HEAD(&core->instances);
+ mutex_init(&core->sync_lock);
+ spin_lock_init(&core->lock);
+ core->base_addr = 0x34f00000;
+ core->state = VIDC_CORE_UNINIT;
+ for (i = SYS_MSG_INDEX(SYS_MSG_START);
+ i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+ init_completion(&core->completions[i]);
+ }
+ return 0;
+}
+
+static int __devinit msm_vidc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+ unsigned long flags;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core || !vidc_driver) {
+ pr_err("Failed to allocate memory for device core\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ rc = msm_vidc_initialize_core(pdev, core);
+ if (rc) {
+ pr_err("Failed to init core\n");
+ goto err_v4l2_register;
+ }
+ rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+ if (rc) {
+ pr_err("Failed to register v4l2 device\n");
+ goto err_v4l2_register;
+ }
+ core->vdev[MSM_VIDC_DECODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+ rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+ VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER);
+ if (rc) {
+ pr_err("Failed to register video decoder device");
+ goto err_dec_register;
+ }
+ video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+
+ core->vdev[MSM_VIDC_ENCODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+ rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+ VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER + 1);
+ if (rc) {
+ pr_err("Failed to register video encoder device");
+ goto err_enc_register;
+ }
+ video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+ core->device = vidc_hal_add_device(core->id, core->base_addr,
+ core->register_base, core->register_size, core->irq,
+ &handle_cmd_response);
+ if (!core->device) {
+ pr_err("Failed to create interrupt handler");
+ goto err_cores_exceeded;
+ }
+
+ spin_lock_irqsave(&vidc_driver->lock, flags);
+ if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) {
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ pr_err("Maximum cores already exist, core_no = %d\n",
+ vidc_driver->num_cores);
+ goto err_cores_exceeded;
+ }
+
+ core->id = vidc_driver->num_cores++;
+ list_add_tail(&core->list, &vidc_driver->cores);
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+ core->debugfs_root = debugfs_create_dir(debugfs_name,
+ vidc_driver->debugfs_root);
+ pdev->dev.platform_data = core;
+ return rc;
+
+err_cores_exceeded:
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+ v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+ kfree(core);
+err_no_mem:
+ return rc;
+}
+
+static int __devexit msm_vidc_remove(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = pdev->dev.platform_data;
+ vidc_hal_delete_device(core->device);
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+ v4l2_device_unregister(&core->v4l2_dev);
+ kfree(core);
+ return rc;
+}
+static const struct of_device_id msm_vidc_dt_match[] = {
+ {.compatible = "qcom,msm-vidc"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+ .probe = msm_vidc_probe,
+ .remove = msm_vidc_remove,
+ .driver = {
+ .name = "msm_vidc",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_vidc_dt_match,
+ },
+};
+
+static int __init msm_vidc_init(void)
+{
+ int rc = 0;
+ vidc_driver = kzalloc(sizeof(*vidc_driver),
+ GFP_KERNEL);
+ if (!vidc_driver) {
+ pr_err("Failed to allocate memroy for msm_vidc_drv\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&vidc_driver->cores);
+ spin_lock_init(&vidc_driver->lock);
+ vidc_driver->debugfs_root = debugfs_create_dir("msm_vidc", NULL);
+ if (!vidc_driver->debugfs_root)
+ pr_err("Failed to create debugfs for msm_vidc\n");
+
+ rc = platform_driver_register(&msm_vidc_driver);
+ if (rc) {
+ pr_err("Failed to register platform driver\n");
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+ platform_driver_unregister(&msm_vidc_driver);
+ debugfs_remove_recursive(vidc_driver->debugfs_root);
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
new file mode 100644
index 0000000..3c279c9
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -0,0 +1,927 @@
+/* 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 "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MAX_PLANES 1
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 6
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+ "DIVX Format 4",
+ "DIVX Format 5",
+ "DIVX Format 6",
+ NULL
+};
+static const char *mpeg_video_stream_format[] = {
+ "NAL Format Start Codes",
+ "NAL Format One NAL Per Buffer",
+ "NAL Format One Byte Length",
+ "NAL Format Two Byte Length",
+ "NAL Format Four Byte Length",
+ NULL
+};
+static const char *const mpeg_video_output_order[] = {
+ "Display Order",
+ "Decode Order",
+ NULL
+};
+static const struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+ .name = "NAL Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+ ),
+ .qmenu = mpeg_video_stream_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+ .name = "Output Order",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+ ),
+ .qmenu = mpeg_video_output_order,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
+ .name = "Picture Type Decoding",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 15,
+ .default_value = 15,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+ .name = "Keep Aspect Ratio",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+ .name = "Deblocker Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+ .name = "Divx Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+ ),
+ .qmenu = mpeg_video_vidc_divx_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+ .name = "MB Error Map Reporting",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+ .name = "control",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static u32 get_frame_size_nv12(int plane,
+ u32 height, u32 width)
+{
+ int stride = (width + 31) & (~31);
+ return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane,
+ u32 height, u32 width)
+{
+ return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane,
+ u32 height, u32 width)
+{
+ return 0x500000;
+}
+
+static const struct msm_vidc_format vdec_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg2",
+ .description = "Mpeg2 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = CAPTURE_PORT,
+ },
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamon\n");
+ rc = vb2_streamon(q, i);
+ if (rc)
+ pr_err("streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ unsigned long flags;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct extradata_buf *ebuf;
+
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->internalbufs)) {
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
+ if (!list_empty(&inst->extradatabufs)) {
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ ebuf = list_entry(ptr, struct extradata_buf,
+ list);
+ ebuf->device_addr = 0;
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ }
+
+ pr_debug("Calling streamoff\n");
+ rc = vb2_streamoff(q, i);
+ if (rc)
+ pr_err("streamoff failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ struct extradata_buf *binfo;
+ for (i = 0; i < b->length; i++) {
+ pr_err("device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Failed to allocate shared mem\n");
+ return -ENOMEM;
+ }
+ binfo->device_addr = b->m.planes[i].m.userptr;
+ rc = msm_comm_allocate_extradata_buffers(inst, binfo);
+ if (rc) {
+ pr_err("msm_comm_allocate_extradata_buffers failed");
+ break;
+ }
+ buffer_info.extradata_size = binfo->handle->size;
+ buffer_info.extradata_addr = binfo->handle->device_addr;
+ rc = vidc_hal_session_set_buffers((void *)inst->session,
+ &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_vdec_release_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ struct extradata_buf *addr;
+ for (i = 0; i < b->length; i++) {
+ pr_err("Release device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ if (!list_empty(&inst->extradatabufs)) {
+ list_for_each_entry(addr, &inst->
+ extradatabufs, list) {
+ if (addr->device_addr ==
+ buffer_info.
+ align_device_addr) {
+ buffer_info.extradata_addr =
+ addr->handle->
+ device_addr;
+ break;
+ }
+ }
+ }
+ rc = vidc_hal_session_release_buffers(
+ (void *)inst->session, &buffer_info);
+ if (rc)
+ pr_err("vidc_hal_session_release_buffers failed");
+ }
+ break;
+ }
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_qbuf(q, b);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_dqbuf(q, b, true);
+ if (rc)
+ pr_err("Failed to dqbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ rc = vb2_reqbufs(q, b);
+ if (rc)
+ pr_err("Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+
+ if (fmt) {
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ if (inst->in_reconfig == true) {
+ inst->height = inst->reconfig_height;
+ inst->width = inst->reconfig_width;
+ }
+ f->fmt.pix_mp.height = inst->height;
+ f->fmt.pix_mp.width = inst->width;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, inst->height, inst->width);
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ inst->width = f->fmt.pix_mp.width;
+ inst->height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (fmt && fmt->type != CAPTURE_PORT) {
+ pr_err("Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (fmt && fmt->type != OUTPUT_PORT) {
+ pr_err("Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ }
+
+ if (fmt) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ inst->fmts[fmt->type] = fmt;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ goto err_invalid_fmt;
+ }
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+err_invalid_fmt:
+ return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ pr_err("No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_frame_size frame_sz;
+ unsigned long flags;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ *num_planes = 1;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ pr_debug("Getting bufreqs on capture plane\n");
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->width;
+ frame_sz.height = inst->height;
+ pr_debug("width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set hal property for framesize\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+ *num_planes = 1;
+ spin_lock_irqsave(&inst->lock, flags);
+ *num_buffers = inst->buff_req.buffer[1].buffer_count_actual;
+ spin_unlock_irqrestore(&inst->lock, flags);
+ pr_debug("size = %d, alignment = %d\n",
+ inst->buff_req.buffer[1].buffer_size,
+ inst->buff_req.buffer[1].buffer_alignment);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+
+ break;
+ default:
+ pr_err("Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+ struct v4l2_control control;
+ struct hal_nal_stream_format_supported stream_format;
+ struct hal_enable_picture enable_picture;
+ struct hal_enable hal_property;
+ u32 control_idx = 0;
+ enum hal_property property_id = 0;
+ u32 property_val = 0;
+ void *pdata;
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ for (; control_idx < NUM_CTRLS; control_idx++) {
+ control.id = msm_vdec_ctrls[control_idx].id;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc) {
+ pr_err("Failed to get control value for ID=%d\n",
+ msm_vdec_ctrls[control_idx].id);
+ } else {
+ property_id = 0;
+ switch (control.id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ property_id =
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+ stream_format.nal_stream_format_supported =
+ (0x00000001 << control.value);
+ pdata = &stream_format;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+ property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
+ property_id =
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ enable_picture.picture_type = control.value;
+ pdata = &enable_picture;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+ property_id =
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+ property_id =
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+ property_id = HAL_PARAM_DIVX_FORMAT;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+ property_id =
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+ property_id =
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ default:
+ break;
+ }
+ if (property_id) {
+ pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ property_id,
+ msm_vdec_ctrls[control_idx].id,
+ control.value);
+ rc = vidc_hal_session_set_property((void *)
+ inst->session, property_id,
+ pdata);
+ }
+ if (rc)
+ pr_err("Failed to set hal property for framesize\n");
+ }
+ }
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto fail_start;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ pr_err("Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_vdec_start_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ inst->in_reconfig = false;
+ if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc)
+ pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+ .queue_setup = msm_vdec_queue_setup,
+ .start_streaming = msm_vdec_start_streaming,
+ .buf_queue = msm_vdec_buf_queue,
+ .stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+ return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ pr_err("Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
+ inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
+ inst->height = DEFAULT_HEIGHT;
+ inst->width = DEFAULT_WIDTH;
+ return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+ .s_ctrl = msm_vdec_op_s_ctrl,
+ .g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+ return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_s_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+ int idx = 0;
+ struct v4l2_ctrl_config ctrl_cfg;
+ int ret_val = 0;
+
+ ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+
+ if (ret_val) {
+ pr_err("CTRL ERR: Control handler init failed, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ for (; idx < NUM_CTRLS; idx++) {
+ if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
+ /*add private control*/
+ ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
+ ctrl_cfg.flags = 0;
+ ctrl_cfg.id = msm_vdec_ctrls[idx].id;
+ /*ctrl_cfg.is_private =
+ * msm_vdec_ctrls[idx].is_private;
+ * ctrl_cfg.is_volatile =
+ * msm_vdec_ctrls[idx].is_volatile;*/
+ ctrl_cfg.max = msm_vdec_ctrls[idx].maximum;
+ ctrl_cfg.min = msm_vdec_ctrls[idx].minimum;
+ ctrl_cfg.menu_skip_mask =
+ msm_vdec_ctrls[idx].menu_skip_mask;
+ ctrl_cfg.name = msm_vdec_ctrls[idx].name;
+ ctrl_cfg.ops = &msm_vdec_ctrl_ops;
+ ctrl_cfg.step = msm_vdec_ctrls[idx].step;
+ ctrl_cfg.type = msm_vdec_ctrls[idx].type;
+ ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
+
+ v4l2_ctrl_new_custom(&inst->ctrl_handler,
+ &ctrl_cfg, NULL);
+ } else {
+ if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].menu_skip_mask,
+ msm_vdec_ctrls[idx].default_value);
+ } else {
+ v4l2_ctrl_new_std(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].minimum,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].step,
+ msm_vdec_ctrls[idx].default_value);
+ }
+ }
+ }
+ ret_val = inst->ctrl_handler.error;
+ if (ret_val)
+ pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
new file mode 100644
index 0000000..1242fb4
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -0,0 +1,36 @@
+/* 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_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
new file mode 100644
index 0000000..5dfea04f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -0,0 +1,1252 @@
+/* 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 "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 8
+#define MIN_BIT_RATE 64
+#define MAX_BIT_RATE 8000
+#define DEFAULT_BIT_RATE 64
+#define BIT_RATE_STEP 1
+#define MIN_FRAME_RATE 1
+#define MAX_FRAME_RATE 120
+#define DEFAULT_FRAME_RATE 30
+#define MAX_SLICE_BYTE_SIZE 1024
+#define MIN_SLICE_BYTE_SIZE 1024
+#define MAX_SLICE_MB_SIZE 300
+#define I_FRAME_QP 26
+#define P_FRAME_QP 28
+#define B_FRAME_QP 30
+#define MAX_INTRA_REFRESH_MBS 300
+#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+
+static const char *const mpeg_video_rate_control[] = {
+ "No Rate Control",
+ "VBR VFR",
+ "VBR CFR",
+ "CBR VFR",
+ "CBR CFR",
+ NULL
+};
+
+static const char *const mpeg_video_rotation[] = {
+ "No Rotation",
+ "90 Degree Rotation",
+ "180 Degree Rotation",
+ "270 Degree Rotation",
+ NULL
+};
+
+static const char *const h264_video_entropy_cabac_model[] = {
+ "Model 0",
+ "Model 1",
+ "Model 2",
+ NULL
+};
+static const struct msm_vidc_ctrl msm_venc_ctrls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE,
+ .name = "Frame Rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_FRAME_RATE,
+ .maximum = MAX_FRAME_RATE,
+ .default_value = DEFAULT_FRAME_RATE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
+ .name = "IDR Period",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 10*MAX_FRAME_RATE,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
+ .name = "Intra Period for P frames",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 10*DEFAULT_FRAME_RATE,
+ .default_value = 2*DEFAULT_FRAME_RATE-1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
+ .name = "Intra Period for B frames",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = 10*DEFAULT_FRAME_RATE,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
+ .name = "Request I Frame",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
+ .name = "Rate Control",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)
+ ),
+ .qmenu = mpeg_video_rate_control,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ .name = "Bit Rate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_BIT_RATE,
+ .maximum = MAX_BIT_RATE,
+ .default_value = DEFAULT_BIT_RATE,
+ .step = BIT_RATE_STEP,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ .name = "Entropy Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+ (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+ .name = "CABAC Model",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
+ ),
+ .qmenu = h264_video_entropy_cabac_model,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .name = "H264 Profile",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
+ .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .name = "H264 Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+ .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+ .name = "Rotation",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
+ ),
+ .qmenu = mpeg_video_rotation,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ .name = "I Frame Quantization",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = I_FRAME_QP,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+ .name = "P Frame Quantization",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = P_FRAME_QP,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+ .name = "B Frame Quantization",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 51,
+ .default_value = B_FRAME_QP,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ .name = "Slice Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+ .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+ .name = "Slice Byte Size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = MIN_SLICE_BYTE_SIZE,
+ .maximum = MAX_SLICE_BYTE_SIZE,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ .name = "Slice MB Size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = MAX_SLICE_MB_SIZE,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
+ .name = "Intra Refresh Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+ .maximum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM,
+ .default_value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+ .step = 0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
+ (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
+ ),
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
+ .name = "Intra Refresh AIR MBS",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
+ .name = "Intra Refresh AIR REF",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
+ .name = "Intra Refresh CIR MBS",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ .name = "H.264 Loop Filter Alpha Offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ .name = "H.264 Loop Filter Beta Offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = -6,
+ .maximum = 6,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ .name = "H.264 Loop Filter Mode",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ .maximum = L_MODE,
+ .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ .step = 1,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
+ (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
+ (1 << L_MODE)
+ ),
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
+
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+ return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+}
+
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+ return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+ return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+}
+
+static struct hal_quantization
+ venc_quantization = {I_FRAME_QP, P_FRAME_QP, B_FRAME_QP};
+static struct hal_intra_period
+ venc_intra_period = {2*DEFAULT_FRAME_RATE-1 , 0};
+static struct hal_profile_level
+ venc_profile_level = {V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_0};
+static struct hal_h264_entropy_control
+ venc_h264_entropy_control = {V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0};
+static struct hal_multi_slice_control
+ venc_multi_slice_control = {V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE ,
+ 0};
+
+static const struct msm_vidc_format venc_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = OUTPUT_PORT,
+ },
+};
+
+static int msm_venc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_frame_size frame_sz;
+ unsigned long flags;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ *num_planes = 1;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->width;
+ frame_sz.height = inst->height;
+ pr_debug("width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set hal property for framesize\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+ *num_planes = 1;
+ spin_lock_irqsave(&inst->lock, flags);
+ *num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
+ spin_unlock_irqrestore(&inst->lock, flags);
+ pr_debug("size = %d, alignment = %d, count = %d\n",
+ inst->buff_req.buffer[0].buffer_size,
+ inst->buff_req.buffer[0].buffer_alignment,
+ inst->buff_req.buffer[0].buffer_count_actual);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+
+ break;
+ default:
+ pr_err("Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto fail_start;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ pr_err("Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_venc_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc)
+ pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+ .queue_setup = msm_venc_queue_setup,
+ .start_streaming = msm_venc_start_streaming,
+ .buf_queue = msm_venc_buf_queue,
+ .stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+ return &msm_venc_vb2q_ops;
+}
+
+static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+ int rc = 0;
+ struct v4l2_control control;
+ struct hal_frame_rate frame_rate;
+ struct hal_request_iframe request_iframe;
+ struct hal_bitrate bitrate;
+ struct hal_profile_level profile_level;
+ struct hal_h264_entropy_control h264_entropy_control;
+ struct hal_quantization quantization;
+ struct hal_intra_period intra_period;
+ struct hal_idr_period idr_period;
+ struct hal_operations operations;
+ struct hal_intra_refresh intra_refresh;
+ struct hal_multi_slice_control multi_slice_control;
+ struct hal_h264_db_control h264_db_control;
+ u32 control_idx = 0;
+ u32 property_id = 0;
+ u32 property_val = 0;
+ void *pdata;
+ struct msm_vidc_inst *inst = container_of(ctrl->handler,
+ struct msm_vidc_inst, ctrl_handler);
+
+ control.id = ctrl->id;
+ control.value = ctrl->val;
+
+ switch (control.id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE:
+ property_id =
+ HAL_CONFIG_FRAME_RATE;
+ frame_rate.frame_rate = control.value;
+ frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &frame_rate;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
+ property_id =
+ HAL_CONFIG_VENC_IDR_PERIOD;
+ idr_period.idr_period = control.value;
+ pdata = &idr_period;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+ property_id =
+ HAL_CONFIG_VENC_INTRA_PERIOD;
+ intra_period.pframes = control.value;
+ venc_intra_period.pframes = control.value;
+ intra_period.bframes = venc_intra_period.bframes;
+ pdata = &intra_period;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+ property_id =
+ HAL_CONFIG_VENC_INTRA_PERIOD;
+ intra_period.bframes = control.value;
+ venc_intra_period.bframes = control.value;
+ intra_period.pframes = venc_intra_period.pframes;
+ pdata = &intra_period;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
+ property_id =
+ HAL_CONFIG_VENC_REQUEST_IFRAME;
+ request_iframe.enable = control.value;
+ pdata = &request_iframe;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
+ property_id =
+ HAL_PARAM_VENC_RATE_CONTROL;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ property_id =
+ HAL_CONFIG_VENC_TARGET_BITRATE;
+ bitrate.bit_rate = control.value;
+ pdata = &bitrate;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ property_id =
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+ h264_entropy_control.entropy_mode = control.value;
+ venc_h264_entropy_control.entropy_mode = control.value;
+ h264_entropy_control.cabac_model =
+ venc_h264_entropy_control.cabac_model;
+ pdata = &h264_entropy_control;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+ property_id =
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+ h264_entropy_control.cabac_model = control.value;
+ venc_h264_entropy_control.cabac_model = control.value;
+ h264_entropy_control.entropy_mode =
+ venc_h264_entropy_control.entropy_mode;
+ pdata = &h264_entropy_control;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+
+ switch (control.value) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ control.value = HAL_H264_PROFILE_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ control.value = HAL_H264_PROFILE_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ control.value = HAL_H264_PROFILE_EXTENDED;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ control.value = HAL_H264_PROFILE_HIGH;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+ control.value = HAL_H264_PROFILE_HIGH10;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+ control.value = HAL_H264_PROFILE_HIGH422;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+ control.value = HAL_H264_PROFILE_HIGH444;
+ break;
+ default:
+ break;
+ }
+ profile_level.profile = control.value;
+ venc_profile_level.profile = control.value;
+ profile_level.level = venc_profile_level.level;
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+
+ switch (control.value) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ control.value = HAL_H264_LEVEL_1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ control.value = HAL_H264_LEVEL_1b;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ control.value = HAL_H264_LEVEL_11;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ control.value = HAL_H264_LEVEL_12;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ control.value = HAL_H264_LEVEL_13;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ control.value = HAL_H264_LEVEL_2;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ control.value = HAL_H264_LEVEL_21;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ control.value = HAL_H264_LEVEL_22;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ control.value = HAL_H264_LEVEL_3;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ control.value = HAL_H264_LEVEL_31;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ control.value = HAL_H264_LEVEL_32;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ control.value = HAL_H264_LEVEL_4;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ control.value = HAL_H264_LEVEL_41;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ control.value = HAL_H264_LEVEL_42;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ control.value = HAL_H264_LEVEL_3;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ control.value = HAL_H264_LEVEL_51;
+ break;
+ default:
+ break;
+ }
+ profile_level.level = control.value;
+ venc_profile_level.level = control.value;
+ profile_level.profile = venc_profile_level.profile;
+ pdata = &profile_level;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+ property_id =
+ HAL_CONFIG_VPE_OPERATIONS;
+ operations.rotate = control.value;
+ pdata = &operations;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ property_id =
+ HAL_PARAM_VENC_SESSION_QP;
+ quantization.qpi = control.value;
+ venc_quantization.qpi = control.value;
+ quantization.qpp = venc_quantization.qpp;
+ quantization.qpb = venc_quantization.qpb;
+ pdata = &quantization;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ property_id =
+ HAL_PARAM_VENC_SESSION_QP;
+ quantization.qpp = control.value;
+ venc_quantization.qpp = control.value;
+ quantization.qpi = venc_quantization.qpi;
+ quantization.qpb = venc_quantization.qpb;
+ pdata = &quantization;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ property_id =
+ HAL_PARAM_VENC_SESSION_QP;
+ quantization.qpb = control.value;
+ venc_quantization.qpb = control.value;
+ quantization.qpi = venc_quantization.qpi;
+ quantization.qpp = venc_quantization.qpp;
+ pdata = &quantization;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ property_id =
+ HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+ multi_slice_control.multi_slice = control.value;
+ venc_multi_slice_control.multi_slice = control.value;
+ multi_slice_control.slice_size =
+ venc_multi_slice_control.slice_size;
+ pdata = &multi_slice_control;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ property_id =
+ HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+ multi_slice_control.multi_slice =
+ venc_multi_slice_control.multi_slice;
+ multi_slice_control.slice_size = control.value;
+ venc_multi_slice_control.slice_size = control.value;
+ pdata = &multi_slice_control;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE:
+ property_id =
+ HAL_PARAM_VENC_INTRA_REFRESH;
+ intra_refresh.mode = control.value;
+ pdata = &intra_refresh;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS:
+ property_id =
+ HAL_PARAM_VENC_INTRA_REFRESH;
+ intra_refresh.air_mbs = control.value;
+ pdata = &intra_refresh;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF:
+ property_id =
+ HAL_PARAM_VENC_INTRA_REFRESH;
+ intra_refresh.air_ref = control.value;
+ pdata = &intra_refresh;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS:
+ property_id =
+ HAL_PARAM_VENC_INTRA_REFRESH;
+ intra_refresh.cir_mbs = control.value;
+ pdata = &intra_refresh;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ property_id =
+ HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.mode = control.value;
+ pdata = &h264_db_control;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ property_id =
+ HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slice_alpha_offset = control.value;
+ pdata = &h264_db_control;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ property_id =
+ HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ h264_db_control.slicebeta_offset = control.value;
+ pdata = &h264_db_control;
+ default:
+ break;
+ }
+ if (property_id) {
+ pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ property_id,
+ msm_venc_ctrls[control_idx].id,
+ control.value);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ property_id, pdata);
+ }
+ if (rc)
+ pr_err("Failed to set hal property for framesize\n");
+ return rc;
+}
+static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_venc_ctrl_ops = {
+
+ .s_ctrl = msm_venc_op_s_ctrl,
+ .g_volatile_ctrl = msm_venc_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_venc_get_ctrl_ops(void)
+{
+ return &msm_venc_ctrl_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ pr_err("Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[CAPTURE_PORT] = &venc_formats[1];
+ inst->fmts[OUTPUT_PORT] = &venc_formats[0];
+ inst->height = DEFAULT_HEIGHT;
+ inst->width = DEFAULT_WIDTH;
+ return rc;
+}
+
+int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_s_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_venc_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ pr_err("No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (fmt && fmt->type != CAPTURE_PORT) {
+ pr_err("Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->width = f->fmt.pix_mp.width;
+ inst->height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (fmt && fmt->type != OUTPUT_PORT) {
+ pr_err("Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (fmt) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ inst->fmts[fmt->type] = fmt;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ goto exit;
+ }
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+
+ if (fmt) {
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.height = inst->height;
+ f->fmt.pix_mp.width = inst->width;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, inst->height, inst->width);
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ rc = vb2_reqbufs(q, b);
+ if (rc)
+ pr_err("Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ for (i = 0; i < b->length; i++) {
+ pr_debug("device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ rc = vidc_hal_session_set_buffers((void *)inst->session,
+ &buffer_info);
+ if (rc)
+ pr_err("vidc_hal_session_set_buffers failed");
+ }
+ break;
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_qbuf(q, b);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_dqbuf(q, b, true);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamon\n");
+ rc = vb2_streamon(q, i);
+ if (rc)
+ pr_err("streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamoff\n");
+ rc = vb2_streamoff(q, i);
+ if (rc)
+ pr_err("streamoff failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
+{
+
+ int idx = 0;
+ struct v4l2_ctrl_config ctrl_cfg;
+ int ret_val = 0;
+ ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+ if (ret_val) {
+ pr_err("CTRL ERR: Control handler init failed, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ for (; idx < NUM_CTRLS; idx++) {
+ if (IS_PRIV_CTRL(msm_venc_ctrls[idx].id)) {
+ ctrl_cfg.def = msm_venc_ctrls[idx].default_value;
+ ctrl_cfg.flags = 0;
+ ctrl_cfg.id = msm_venc_ctrls[idx].id;
+ ctrl_cfg.max = msm_venc_ctrls[idx].maximum;
+ ctrl_cfg.min = msm_venc_ctrls[idx].minimum;
+ ctrl_cfg.menu_skip_mask =
+ msm_venc_ctrls[idx].menu_skip_mask;
+ ctrl_cfg.name = msm_venc_ctrls[idx].name;
+ ctrl_cfg.ops = &msm_venc_ctrl_ops;
+ ctrl_cfg.step = msm_venc_ctrls[idx].step;
+ ctrl_cfg.type = msm_venc_ctrls[idx].type;
+ ctrl_cfg.qmenu = msm_venc_ctrls[idx].qmenu;
+ v4l2_ctrl_new_custom(&inst->ctrl_handler,
+ &ctrl_cfg, NULL);
+ } else {
+ if (msm_venc_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+ &msm_venc_ctrl_ops,
+ msm_venc_ctrls[idx].id,
+ msm_venc_ctrls[idx].maximum,
+ msm_venc_ctrls[idx].menu_skip_mask,
+ msm_venc_ctrls[idx].default_value);
+ } else {
+ v4l2_ctrl_new_std(&inst->ctrl_handler,
+ &msm_venc_ctrl_ops,
+ msm_venc_ctrls[idx].id,
+ msm_venc_ctrls[idx].minimum,
+ msm_venc_ctrls[idx].maximum,
+ msm_venc_ctrls[idx].step,
+ msm_venc_ctrls[idx].default_value);
+ }
+ }
+ }
+ ret_val = inst->ctrl_handler.error;
+ if (ret_val)
+ pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+}
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
new file mode 100644
index 0000000..4a156dd
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -0,0 +1,35 @@
+/* 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_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
new file mode 100644
index 0000000..d589bf5
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -0,0 +1,350 @@
+/* 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 <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include "msm_smem.h"
+
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *wait)
+{
+ int rc = 0;
+ struct msm_vidc_inst *inst = instance;
+ struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
+ struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+ struct vb2_buffer *out_vb = NULL;
+ struct vb2_buffer *cap_vb = NULL;
+ unsigned long flags;
+ poll_wait(filp, &inst->event_handler.events->wait, wait);
+ if (v4l2_event_pending(&inst->event_handler))
+ return POLLPRI;
+ if (!outq->streaming && !capq->streaming) {
+ pr_err("Returning POLLERR from here: %d, %d\n",
+ outq->streaming, capq->streaming);
+ return POLLERR;
+ }
+ poll_wait(filp, &inst->event_handler.events->wait, wait);
+ if (v4l2_event_pending(&inst->event_handler))
+ return POLLPRI;
+ poll_wait(filp, &capq->done_wq, wait);
+ poll_wait(filp, &outq->done_wq, wait);
+ spin_lock_irqsave(&capq->done_lock, flags);
+ if (!list_empty(&capq->done_list))
+ cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+ done_entry);
+ if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+ || cap_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&capq->done_lock, flags);
+ spin_lock_irqsave(&outq->done_lock, flags);
+ if (!list_empty(&outq->done_list))
+ out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+ done_entry);
+ if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+ || out_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&outq->done_lock, flags);
+ return rc;
+}
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_querycap(instance, cap);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_querycap(instance, cap);
+ return -EINVAL;
+}
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_enum_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_enum_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_fmt(instance, f);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_g_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_ctrl(instance, control);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_ctrl(instance, control);
+ return -EINVAL;
+}
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_ctrl(instance, control);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_g_ctrl(instance, control);
+ return -EINVAL;
+}
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_reqbufs(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_reqbufs(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_prepare_buf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_prepare_buf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_release_buf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_dqbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_dqbuf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamon(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamon(instance, i);
+ return -EINVAL;
+}
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamoff(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamoff(instance, i);
+ return -EINVAL;
+}
+
+void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ return NULL;
+}
+
+void vidc_put_userptr(void *buf_priv)
+{
+}
+
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+ .get_userptr = vidc_get_userptr,
+ .put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+ enum v4l2_buf_type type, enum session_type sess)
+{
+ struct vb2_queue *q = NULL;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q = &inst->vb2_bufq[CAPTURE_PORT];
+ } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q = &inst->vb2_bufq[OUTPUT_PORT];
+ } else {
+ pr_err("buf_type = %d not recognised\n", type);
+ return -EINVAL;
+ }
+ q->type = type;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_flags = 0;
+ if (sess == MSM_VIDC_DECODER)
+ q->ops = msm_vdec_get_vb2q_ops();
+ else if (sess == MSM_VIDC_ENCODER)
+ q->ops = msm_venc_get_vb2q_ops();
+ q->mem_ops = &msm_vidc_vb2_mem_ops;
+ q->drv_priv = inst;
+ return vb2_queue_init(q);
+}
+
+int msm_vidc_open(void *vidc_inst, int core_id, int session_type)
+{
+ struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst;
+ struct msm_vidc_core *core = NULL;
+ unsigned long flags;
+ int rc = 0;
+ int i = 0;
+ if (core_id >= MSM_VIDC_CORES_MAX ||
+ session_type >= MSM_VIDC_MAX_DEVICES) {
+ pr_err("Invalid input, core_id = %d, session = %d\n",
+ core_id, session_type);
+ goto err_invalid_core;
+ }
+ core = get_vidc_core(core_id);
+ if (!core) {
+ pr_err("Failed to find core for core_id = %d\n", core_id);
+ goto err_invalid_core;
+ }
+
+ mutex_init(&inst->sync_lock);
+ spin_lock_init(&inst->lock);
+ inst->session_type = session_type;
+ INIT_LIST_HEAD(&inst->pendingq);
+ INIT_LIST_HEAD(&inst->internalbufs);
+ INIT_LIST_HEAD(&inst->extradatabufs);
+ inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+ inst->core = core;
+ for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+ i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+ init_completion(&inst->completions[i]);
+ }
+ inst->mem_client = msm_smem_new_client(SMEM_ION);
+ if (!inst->mem_client) {
+ pr_err("Failed to create memory client\n");
+ goto fail_mem_client;
+ }
+ if (session_type == MSM_VIDC_DECODER) {
+ msm_vdec_inst_init(inst);
+ msm_vdec_ctrl_init(inst);
+ } else if (session_type == MSM_VIDC_ENCODER) {
+ msm_venc_inst_init(inst);
+ msm_venc_ctrl_init(inst);
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ session_type);
+ if (rc) {
+ pr_err("Failed to initialize vb2 queue on capture port\n");
+ goto fail_init;
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ session_type);
+ if (rc) {
+ pr_err("Failed to initialize vb2 queue on capture port\n");
+ goto fail_init;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
+ if (rc) {
+ pr_err("Failed to move video instance to init state\n");
+ goto fail_init;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ list_add_tail(&inst->list, &core->instances);
+ spin_unlock_irqrestore(&core->lock, flags);
+ return rc;
+fail_init:
+ msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+ kfree(inst);
+ inst = NULL;
+err_invalid_core:
+ return rc;
+}
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+ unsigned long flags;
+ struct list_head *ptr, *next;
+ struct vb2_buf_entry *entry;
+ struct internal_buf *buf;
+
+ if (inst) {
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ entry = list_entry(ptr, struct vb2_buf_entry,
+ list);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ }
+ if (!list_empty(&inst->internalbufs)) {
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ msm_smem_delete_client(inst->mem_client);
+ }
+}
+
+int msm_vidc_close(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_inst *temp;
+ struct msm_vidc_core *core;
+ struct list_head *ptr, *next;
+ int rc = 0;
+ core = inst->core;
+ mutex_lock(&core->sync_lock);
+ list_for_each_safe(ptr, next, &core->instances) {
+ temp = list_entry(ptr, struct msm_vidc_inst, list);
+ if (temp == inst)
+ list_del(&inst->list);
+ }
+ mutex_unlock(&core->sync_lock);
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+ if (rc)
+ pr_err("Failed to move video instance to uninit state\n");
+ cleanup_instance(inst);
+ pr_debug("Closed the instance\n");
+ return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
new file mode 100644
index 0000000..8a51301
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -0,0 +1,1048 @@
+/* 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 "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define HW_RESPONSE_TIMEOUT 5000
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+ int __rc = (__p >= __d);\
+ __rc; \
+})
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+ struct msm_vidc_core *core;
+ int found = 0;
+ unsigned long flags;
+ if (core_id > MSM_VIDC_CORES_MAX) {
+ pr_err("Core id = %d is greater than max = %d\n",
+ core_id, MSM_VIDC_CORES_MAX);
+ return NULL;
+ }
+ spin_lock_irqsave(&vidc_driver->lock, flags);
+ list_for_each_entry(core, &vidc_driver->cores, list) {
+ if (core && core->id == core_id)
+ found = 1;
+ break;
+ }
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ if (found)
+ return core;
+ return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+ int i, k = 0;
+ if (!fmt || index < 0) {
+ pr_err("Invalid inputs, fmt = %p, index = %d\n",
+ fmt, index);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].type != fmt_type)
+ continue;
+ if (k == index)
+ break;
+ k++;
+ }
+ if (i == size) {
+ pr_err("Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+ int i;
+ if (!fmt) {
+ pr_err("Invalid inputs, fmt = %p\n", fmt);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].fourcc == fourcc)
+ break;
+ }
+ if (i == size) {
+ pr_err("Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+
+struct vb2_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return &inst->vb2_bufq[CAPTURE_PORT];
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return &inst->vb2_bufq[OUTPUT_PORT];
+ return NULL;
+}
+
+static void handle_sys_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_core *core;
+ struct vidc_hal_sys_init_done *sys_init_msg;
+ int index = SYS_MSG_INDEX(cmd);
+ if (!response) {
+ pr_err("Failed to get valid response for sys init\n");
+ return;
+ }
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ pr_err("Wrong device_id received\n");
+ return;
+ }
+ pr_debug("index = %d\n", index);
+ pr_debug("ptr = %p\n", &(core->completions[index]));
+ complete(&(core->completions[index]));
+ sys_init_msg = response->data;
+ if (!sys_init_msg) {
+ pr_err("sys_init_done message not proper\n");
+ return;
+ }
+}
+
+static inline void change_inst_state(struct msm_vidc_inst *inst,
+ enum instance_state state)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ pr_debug("Moved inst: %p from state: %d to state: %d\n",
+ inst, inst->state, state);
+ inst->state = state;
+ spin_unlock_irqrestore(&inst->lock, flags);
+}
+
+static int signal_session_msg_receipt(enum command_response cmd,
+ struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ pr_err("Invalid(%p) instance id\n", inst);
+ return -EINVAL;
+ }
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+ return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+ enum command_response cmd)
+{
+ int rc = 0;
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(cmd)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+ enum instance_state flipped_state,
+ enum instance_state desired_state,
+ enum command_response hal_cmd)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto err_same_state;
+ }
+ pr_debug("Waiting for hal_cmd: %d\n", hal_cmd);
+ rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+ if (!rc)
+ change_inst_state(inst, desired_state);
+err_same_state:
+ return rc;
+}
+
+static void handle_session_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct video_device *vdev;
+ struct v4l2_event dqevent;
+ struct msm_vidc_core *core;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ core = inst->core;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+ else
+ vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+ dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ dqevent.u.data[0] = (uint8_t)MSM_VIDC_OPEN_DONE;
+ v4l2_event_queue(vdev, &dqevent);
+ return;
+ } else {
+ pr_err("Failed to get valid response for session init\n");
+ }
+}
+
+static void handle_event_change(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct video_device *vdev;
+ struct v4l2_event dqevent;
+ struct msm_vidc_cb_event *event_notify;
+ struct msm_vidc_core *core;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ core = inst->core;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+ else
+ vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+ dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_EVENT_CHANGE;
+ event_notify = (struct msm_vidc_cb_event *) response->data;
+ inst->reconfig_height = event_notify->height;
+ inst->reconfig_width = event_notify->width;
+ inst->in_reconfig = true;
+ v4l2_event_queue(vdev, &dqevent);
+ return;
+ } else {
+ pr_err("Failed to get valid response for event_change\n");
+ }
+}
+
+static void handle_session_prop_info(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ unsigned long flags;
+ if (!response || !response->data) {
+ pr_err("Failed to get valid response for prop info\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ spin_lock_irqsave(&inst->lock, flags);
+ memcpy(&inst->buff_req, response->data,
+ sizeof(struct buffer_requirements));
+ spin_unlock_irqrestore(&inst->lock, flags);
+ signal_session_msg_receipt(cmd, inst);
+}
+
+static void handle_load_resource_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response)
+ inst = (struct msm_vidc_inst *)response->session_id;
+ else
+ pr_err("Failed to get valid response for load resource\n");
+}
+
+static void handle_start_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct video_device *vdev;
+ struct v4l2_event dqevent;
+ struct msm_vidc_core *core;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ core = inst->core;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+ else
+ vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+ dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ dqevent.u.data[0] = (uint8_t)MSM_VIDC_START_DONE;
+ v4l2_event_queue(vdev, &dqevent);
+ } else {
+ pr_err("Failed to get valid response for start\n");
+ }
+}
+
+static void handle_stop_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct video_device *vdev;
+ struct v4l2_event dqevent;
+ struct msm_vidc_core *core;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ core = inst->core;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+ else
+ vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+ dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ dqevent.u.data[0] = (uint8_t)MSM_VIDC_STOP_DONE;
+ v4l2_event_queue(vdev, &dqevent);
+ } else {
+ pr_err("Failed to get valid response for stop\n");
+ }
+}
+
+static void handle_release_res_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for release resource\n");
+ }
+}
+
+static void handle_session_flush(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct video_device *vdev;
+ struct v4l2_event dqevent;
+ struct msm_vidc_core *core;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ core = inst->core;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+ else
+ vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+ dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_FLUSH_DONE;
+ v4l2_event_queue(vdev, &dqevent);
+ } else {
+ pr_err("Failed to get valid response for flush\n");
+ }
+}
+
+
+static void handle_session_close(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct video_device *vdev;
+ struct v4l2_event dqevent;
+ struct msm_vidc_core *core;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ core = inst->core;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
+ else
+ vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
+ dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
+ dqevent.u.data[0] = (uint8_t)MSM_VIDC_CLOSE_DONE;
+ v4l2_event_queue(vdev, &dqevent);
+ } else {
+ pr_err("Failed to get valid response for session close\n");
+ }
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q,
+ u32 dev_addr)
+{
+ struct vb2_buffer *vb = NULL;
+ int found = 0;
+ if (!q) {
+ pr_err("Invalid parameter\n");
+ return NULL;
+ }
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->v4l2_planes[0].m.userptr == dev_addr) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("Failed to find the buffer in queued list: %d, %d\n",
+ dev_addr, q->type);
+ vb = NULL;
+ }
+ return vb;
+}
+
+static void handle_ebd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct vb2_buffer *vb;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ vb = response->clnt_data;
+ if (vb)
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
+static void handle_fbd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct vb2_buffer *vb;
+ struct vidc_hal_fbd *fill_buf_done;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+ vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+ (u32)fill_buf_done->packet_buffer1);
+ if (vb) {
+ vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ pr_debug("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+}
+
+void handle_cmd_response(enum command_response cmd, void *data)
+{
+ pr_debug("Command response = %d\n", cmd);
+ switch (cmd) {
+ case SYS_INIT_DONE:
+ handle_sys_init_done(cmd, data);
+ break;
+ case SESSION_INIT_DONE:
+ handle_session_init_done(cmd, data);
+ break;
+ case SESSION_PROPERTY_INFO:
+ handle_session_prop_info(cmd, data);
+ break;
+ case SESSION_LOAD_RESOURCE_DONE:
+ handle_load_resource_done(cmd, data);
+ break;
+ case SESSION_START_DONE:
+ handle_start_done(cmd, data);
+ break;
+ case SESSION_ETB_DONE:
+ handle_ebd(cmd, data);
+ break;
+ case SESSION_FTB_DONE:
+ handle_fbd(cmd, data);
+ break;
+ case SESSION_STOP_DONE:
+ handle_stop_done(cmd, data);
+ break;
+ case SESSION_RELEASE_RESOURCE_DONE:
+ handle_release_res_done(cmd, data);
+ break;
+ case SESSION_END_DONE:
+ handle_session_close(cmd, data);
+ break;
+ case VIDC_EVENT_CHANGE:
+ handle_event_change(cmd, data);
+ break;
+ case SESSION_FLUSH_DONE:
+ handle_session_flush(cmd, data);
+ break;
+ default:
+ pr_err("response unhandled\n");
+ break;
+ }
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ int rc = 0;
+ mutex_lock(&core->sync_lock);
+ if (core->state >= VIDC_CORE_INIT_DONE) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+ pr_debug("Waiting for SYS_INIT_DONE\n");
+ rc = wait_for_completion_timeout(
+ &core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ goto exit;
+ } else {
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INIT_DONE;
+ spin_unlock_irqrestore(&core->lock, flags);
+ }
+ pr_debug("SYS_INIT_DONE!!!\n");
+core_already_inited:
+ change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+ rc = 0;
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ mutex_lock(&core->sync_lock);
+ if (core->state >= VIDC_CORE_INIT) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+ init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
+ rc = vidc_hal_core_init(core->device);
+ if (rc) {
+ pr_err("Failed to init core, id = %d\n", core->id);
+ goto exit;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INIT;
+ spin_unlock_irqrestore(&core->lock, flags);
+core_already_inited:
+ change_inst_state(inst, MSM_VIDC_CORE_INIT);
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ mutex_lock(&core->sync_lock);
+ if (core->state == VIDC_CORE_UNINIT) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_uninited;
+ }
+ if (list_empty(&core->instances)) {
+ pr_debug("Calling vidc_hal_core_release\n");
+ rc = vidc_hal_core_release(core->device);
+ if (rc) {
+ pr_err("Failed to release core, id = %d\n", core->id);
+ goto exit;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_UNINIT;
+ spin_unlock_irqrestore(&core->lock, flags);
+ }
+core_already_uninited:
+ change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static enum hal_domain get_hal_domain(int session_type)
+{
+ enum hal_domain domain;
+ switch (session_type) {
+ case MSM_VIDC_ENCODER:
+ domain = HAL_VIDEO_DOMAIN_ENCODER;
+ break;
+ case MSM_VIDC_DECODER:
+ domain = HAL_VIDEO_DOMAIN_DECODER;
+ break;
+ default:
+ pr_err("Wrong domain\n");
+ domain = HAL_UNUSED_DOMAIN;
+ break;
+ }
+ return domain;
+}
+
+static enum hal_video_codec get_hal_codec_type(int fourcc)
+{
+ enum hal_video_codec codec;
+ pr_debug("codec in %s is 0x%x", __func__, fourcc);
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_H264_NO_SC:
+ codec = HAL_VIDEO_CODEC_H264;
+ break;
+ case V4L2_PIX_FMT_H263:
+ codec = HAL_VIDEO_CODEC_H263;
+ break;
+ case V4L2_PIX_FMT_MPEG1:
+ codec = HAL_VIDEO_CODEC_MPEG1;
+ break;
+ case V4L2_PIX_FMT_MPEG2:
+ codec = HAL_VIDEO_CODEC_MPEG2;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ codec = HAL_VIDEO_CODEC_MPEG4;
+ break;
+ case V4L2_PIX_FMT_VC1_ANNEX_G:
+ case V4L2_PIX_FMT_VC1_ANNEX_L:
+ codec = HAL_VIDEO_CODEC_VC1;
+ break;
+ /*HAL_VIDEO_CODEC_MVC
+ HAL_VIDEO_CODEC_DIVX_311
+ HAL_VIDEO_CODEC_DIVX
+ HAL_VIDEO_CODEC_SPARK
+ HAL_VIDEO_CODEC_VP6
+ HAL_VIDEO_CODEC_VP7
+ HAL_VIDEO_CODEC_VP8*/
+ default:
+ pr_err("Wrong codec: %d\n", fourcc);
+ codec = HAL_UNUSED_CODEC;
+ }
+ return codec;
+}
+
+static int msm_comm_session_init(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ int fourcc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ fourcc = inst->fmts[OUTPUT_PORT]->fourcc;
+ } else if (inst->session_type == MSM_VIDC_ENCODER) {
+ fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
+ } else {
+ pr_err("Invalid session\n");
+ return -EINVAL;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
+ inst->session = vidc_hal_session_init(inst->core->device, (u32) inst,
+ get_hal_domain(inst->session_type),
+ get_hal_codec_type(fourcc));
+ if (!inst->session) {
+ pr_err("Failed to call session init for: %d, %d, %d, %d\n",
+ (int)inst->core->device, (int)inst,
+ inst->session_type, fourcc);
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ rc = vidc_hal_session_load_res((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
+ rc = vidc_hal_session_start((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_START);
+exit:
+ return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send Stop to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
+ rc = vidc_hal_session_stop((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send stop\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+ return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send release res to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
+ rc = vidc_hal_session_release_res((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_comm_session_close(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send session close to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
+ rc = vidc_hal_session_end((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+ int rc = 0;
+ int flipped_state;
+ if (!inst) {
+ pr_err("Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ pr_debug("Trying to move inst: %p from: 0x%x to 0x%x\n",
+ inst, inst->state, state);
+ mutex_lock(&inst->sync_lock);
+ flipped_state = inst->state;
+ if (flipped_state < MSM_VIDC_STOP
+ && state > MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ } else if (flipped_state > MSM_VIDC_STOP
+ && state < MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP -
+ (flipped_state - MSM_VIDC_STOP + 1);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ }
+ pr_debug("flipped_state = 0x%x\n", flipped_state);
+ switch (flipped_state) {
+ case MSM_VIDC_CORE_UNINIT_DONE:
+ case MSM_VIDC_CORE_INIT:
+ rc = msm_comm_init_core(inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CORE_INIT_DONE:
+ rc = msm_comm_init_core_done(inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_OPEN:
+ rc = msm_comm_session_init(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_OPEN_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+ SESSION_INIT_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_LOAD_RESOURCES:
+ rc = msm_vidc_load_resources(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_LOAD_RESOURCES_DONE:
+ case MSM_VIDC_START:
+ rc = msm_vidc_start(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_START_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+ SESSION_START_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_STOP:
+ rc = msm_vidc_stop(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_STOP_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+ SESSION_STOP_DONE);
+ if (rc || state <= inst->state)
+ break;
+ pr_debug("Moving to Stop Done state\n");
+ case MSM_VIDC_RELEASE_RESOURCES:
+ rc = msm_vidc_release_res(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_RELEASE_RESOURCES_DONE:
+ rc = wait_for_state(inst, flipped_state,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ SESSION_RELEASE_RESOURCE_DONE);
+ if (rc || state <= inst->state)
+ break;
+ pr_debug("Moving to release resources done state\n");
+ case MSM_VIDC_CLOSE:
+ rc = msm_comm_session_close(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CLOSE_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+ SESSION_END_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CORE_UNINIT:
+ pr_debug("***************Sending core uninit\n");
+ rc = msm_vidc_deinit_core(inst);
+ if (rc || state == inst->state)
+ break;
+ default:
+ pr_err("State not recognized\n");
+ rc = -EINVAL;
+ break;
+ }
+ mutex_unlock(&inst->sync_lock);
+ if (rc)
+ pr_err("Failed to move from state: %d to %d\n",
+ inst->state, state);
+ return rc;
+}
+
+int msm_comm_qbuf(struct vb2_buffer *vb)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ struct msm_vidc_inst *inst;
+ unsigned long flags;
+ struct vb2_buf_entry *entry;
+ struct vidc_frame_data frame_data;
+ q = vb->vb2_queue;
+ inst = q->drv_priv;
+
+ if (!inst || !vb) {
+ pr_err("Invalid input: %p, %p\n", inst, vb);
+ return -EINVAL;
+ }
+ if (inst->state != MSM_VIDC_START_DONE) {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_err("Out of memory\n");
+ goto err_no_mem;
+ }
+ entry->vb = vb;
+ pr_debug("Queueing buffer in pendingq\n");
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&entry->list, &inst->pendingq);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ } else {
+ memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
+ frame_data.alloc_len = vb->v4l2_planes[0].length;
+ frame_data.filled_len = vb->v4l2_planes[0].bytesused;
+ frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
+ frame_data.clnt_data = (u32)vb;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ frame_data.buffer_type = HAL_BUFFER_INPUT;
+ if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
+ frame_data.flags = HAL_BUFFERFLAG_EOS;
+ pr_debug("Received EOS on output capability\n");
+ }
+ pr_debug("Sending etb to hal: Alloc: %d :filled: %d\n",
+ frame_data.alloc_len, frame_data.filled_len);
+ rc = vidc_hal_session_etb((void *) inst->session,
+ &frame_data);
+ pr_debug("Sent etb to HAL\n");
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct extradata_buf *addr;
+ frame_data.filled_len = 0;
+ frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_data.extradata_addr = 0;
+ if (!list_empty(&inst->extradatabufs)) {
+ list_for_each_entry(addr, &inst->extradatabufs,
+ list) {
+ if (addr->device_addr ==
+ frame_data.
+ device_addr) {
+ frame_data.extradata_addr =
+ addr->
+ handle->device_addr;
+ break;
+ }
+ }
+ }
+ pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
+ " extradata_addr: %d\n", frame_data.alloc_len,
+ frame_data.filled_len,
+ frame_data.extradata_addr);
+ rc = vidc_hal_session_ftb((void *) inst->session,
+ &frame_data);
+ } else {
+ pr_err("This capability is not supported: %d\n",
+ q->type);
+ rc = -EINVAL;
+ }
+ }
+ if (rc)
+ pr_err("Failed to queue buffer\n");
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ mutex_lock(&inst->sync_lock);
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
+ rc = vidc_hal_session_get_buf_req((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to get property\n");
+ goto exit;
+ }
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ goto exit;
+ }
+ rc = 0;
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+ int rc = 0;
+ struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
+ mutex_lock(&inst->sync_lock);
+ if (dec->cmd != V4L2_DEC_CMD_STOP)
+ return -EINVAL;
+ rc = vidc_hal_session_flush((void *)inst->session, HAL_FLUSH_OUTPUT);
+ if (rc) {
+ pr_err("Failed to get property\n");
+ goto exit;
+ }
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+ struct extradata_buf *binfo)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct msm_smem *handle;
+ pr_debug("Extradata: num = %d, size = %d, align = %d\n",
+ inst->buff_req.buffer[4].buffer_count_actual,
+ inst->buff_req.buffer[4].buffer_size,
+ inst->buff_req.buffer[4].buffer_alignment);
+ if (!inst->buff_req.buffer[4].buffer_size) {
+ pr_err("invalid size: %d",
+ inst->buff_req.buffer[4].buffer_size);
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ handle = msm_smem_alloc(inst->mem_client,
+ inst->buff_req.buffer[4].buffer_size,
+ inst->buff_req.buffer[4].buffer_alignment, 0);
+ if (!handle) {
+ pr_err("Failed to allocate Extradata memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo->handle = handle;
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->extradatabufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info;
+ unsigned long flags;
+ int i;
+ pr_debug("scratch: num = %d, size = %d\n",
+ inst->buff_req.buffer[6].buffer_count_actual,
+ inst->buff_req.buffer[6].buffer_size);
+ for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
+ i++) {
+ handle = msm_smem_alloc(inst->mem_client,
+ inst->buff_req.buffer[6].buffer_size, 1, 0);
+ if (!handle) {
+ pr_err("Failed to allocate scratch memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo->handle = handle;
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->internalbufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ buffer_info.buffer_size =
+ inst->buff_req.buffer[6].buffer_size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_set_buffers((void *) inst->session,
+ &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ break;
+ }
+ }
+err_no_mem:
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
new file mode 100644
index 0000000..45bfa7b
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -0,0 +1,38 @@
+/* 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_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+ struct list_head list;
+ struct vb2_buffer *vb;
+};
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct vb2_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+ struct extradata_buf *binfo);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct vb2_buffer *vb);
+#define IS_PRIV_CTRL(idx) (\
+ (V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
+ V4L2_CTRL_DRIVER_PRIV(idx))
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
new file mode 100644
index 0000000..2c7853b
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -0,0 +1,178 @@
+/* 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_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/msm_vidc.h>
+
+#include "vidc_hal_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+
+#define V4L2_EVENT_VIDC_BASE 10
+
+#define SYS_MSG_START VIDC_EVENT_CHANGE
+#define SYS_MSG_END SYS_DEBUG
+#define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
+#define SESSION_MSG_END SESSION_PROPERTY_INFO
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+enum vidc_ports {
+ OUTPUT_PORT,
+ CAPTURE_PORT,
+ MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+ VIDC_CORE_UNINIT = 0,
+ VIDC_CORE_INIT,
+ VIDC_CORE_INIT_DONE,
+};
+
+/*Donot change the enum values unless
+ * you know what you are doing*/
+enum instance_state {
+ MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+ MSM_VIDC_CORE_INIT,
+ MSM_VIDC_CORE_INIT_DONE,
+ MSM_VIDC_OPEN,
+ MSM_VIDC_OPEN_DONE,
+ MSM_VIDC_LOAD_RESOURCES,
+ MSM_VIDC_LOAD_RESOURCES_DONE,
+ MSM_VIDC_START,
+ MSM_VIDC_START_DONE,
+ MSM_VIDC_STOP,
+ MSM_VIDC_STOP_DONE,
+ MSM_VIDC_RELEASE_RESOURCES,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ MSM_VIDC_CLOSE,
+ MSM_VIDC_CLOSE_DONE,
+ MSM_VIDC_CORE_UNINIT,
+};
+
+enum vidc_resposes_id {
+ MSM_VIDC_DECODER_FLUSH_DONE = 0x11,
+ MSM_VIDC_DECODER_EVENT_CHANGE,
+};
+
+struct buf_info {
+ struct list_head list;
+ struct vb2_buffer *buf;
+};
+
+struct internal_buf {
+ struct list_head list;
+ struct msm_smem *handle;
+};
+
+struct extradata_buf {
+ struct list_head list;
+ struct msm_smem *handle;
+ u32 device_addr;
+};
+
+struct msm_vidc_format {
+ char name[64];
+ u8 description[32];
+ u32 fourcc;
+ int num_planes;
+ int type;
+ u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+ spinlock_t lock;
+ struct list_head cores;
+ int num_cores;
+ struct dentry *debugfs_root;
+};
+
+struct msm_video_device {
+ int type;
+ struct video_device vdev;
+};
+
+struct msm_vidc_core {
+ struct list_head list;
+ struct mutex sync_lock;
+ int id;
+ void *device;
+ struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+ struct v4l2_device v4l2_dev;
+ spinlock_t lock;
+ struct list_head instances;
+ struct dentry *debugfs_root;
+ u32 base_addr;
+ u32 register_base;
+ u32 register_size;
+ u32 irq;
+ enum vidc_core_state state;
+ struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+};
+
+struct msm_vidc_inst {
+ struct list_head list;
+ struct mutex sync_lock;
+ struct msm_vidc_core *core;
+ int session_type;
+ void *session;
+ u32 width;
+ u32 height;
+ int state;
+ const struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct vb2_queue vb2_bufq[MAX_PORT_NUM];
+ spinlock_t lock;
+ struct list_head pendingq;
+ struct list_head internalbufs;
+ struct list_head extradatabufs;
+ struct buffer_requirements buff_req;
+ void *mem_client;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+ struct v4l2_fh event_handler;
+ bool in_reconfig;
+ u32 reconfig_width;
+ u32 reconfig_height;
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl {
+ u32 id;
+ char name[64];
+ enum v4l2_ctrl_type type;
+ s32 minimum;
+ s32 maximum;
+ s32 default_value;
+ u32 step;
+ u32 menu_skip_mask;
+ const char * const *qmenu;
+};
+
+void handle_cmd_response(enum command_response cmd, void *data);
+#endif
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
new file mode 100644
index 0000000..f4c7878
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -0,0 +1,1925 @@
+/* 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 <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/memory.h>
+#include "vidc_hal.h"
+#include "vidc_hal_io.h"
+
+#define FIRMWARE_SIZE 0X00A00000
+#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
+
+/*Workaround for virtio */
+#define HFI_VIRTIO_FW_BIAS 0x34f00000
+
+struct hal_device_data hal_ctxt;
+
+static void hal_virtio_modify_cmd_packet(u8 *packet)
+{
+ struct hfi_cmd_sys_session_init_packet *sys_init;
+ struct hal_session *sess;
+ u8 i;
+
+ if (!packet) {
+ HAL_MSG_ERROR("Invalid Param: %s", __func__);
+ return;
+ }
+
+ sys_init = (struct hfi_cmd_sys_session_init_packet *)packet;
+ sess = (struct hal_session *) sys_init->session_id;
+ switch (sys_init->packet) {
+ case HFI_CMD_SESSION_EMPTY_BUFFER:
+ if (sess->is_decoder) {
+ struct hfi_cmd_session_empty_buffer_compressed_packet
+ *pkt = (struct
+ hfi_cmd_session_empty_buffer_compressed_packet
+ *) packet;
+ pkt->packet_buffer -= HFI_VIRTIO_FW_BIAS;
+ } else {
+ struct
+ hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ *pkt = (struct
+ hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ *) packet;
+ pkt->packet_buffer -= HFI_VIRTIO_FW_BIAS;
+ }
+ break;
+ case HFI_CMD_SESSION_FILL_BUFFER:
+ {
+ struct hfi_cmd_session_fill_buffer_packet *pkt =
+ (struct hfi_cmd_session_fill_buffer_packet *)packet;
+ pkt->packet_buffer -= HFI_VIRTIO_FW_BIAS;
+ break;
+ }
+ case HFI_CMD_SESSION_SET_BUFFERS:
+ {
+ struct hfi_cmd_session_set_buffers_packet *pkt =
+ (struct hfi_cmd_session_set_buffers_packet *)packet;
+ if ((pkt->buffer_type == HFI_BUFFER_OUTPUT) ||
+ (pkt->buffer_type == HFI_BUFFER_OUTPUT2)) {
+ struct hfi_buffer_info *buff;
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ buff->buffer_addr -= HFI_VIRTIO_FW_BIAS;
+ buff->extradata_addr -= HFI_VIRTIO_FW_BIAS;
+ } else {
+ for (i = 0; i < pkt->num_buffers; i++)
+ pkt->rg_buffer_info[i] -= HFI_VIRTIO_FW_BIAS;
+ }
+ break;
+ }
+ case HFI_CMD_SESSION_RELEASE_BUFFERS:
+ {
+ struct hfi_cmd_session_release_buffer_packet *pkt =
+ (struct hfi_cmd_session_release_buffer_packet *)packet;
+ if ((pkt->buffer_type == HAL_BUFFER_OUTPUT) ||
+ (pkt->buffer_type == HAL_BUFFER_OUTPUT2)) {
+ struct hfi_buffer_info *buff;
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ buff->buffer_addr -= HFI_VIRTIO_FW_BIAS;
+ buff->extradata_addr -= HFI_VIRTIO_FW_BIAS;
+ } else {
+ for (i = 0; i < pkt->num_buffers; i++)
+ pkt->rg_buffer_info[i] -= HFI_VIRTIO_FW_BIAS;
+ }
+ break;
+ }
+ case HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER:
+ {
+ struct hfi_cmd_session_parse_sequence_header_packet *pkt =
+ (struct hfi_cmd_session_parse_sequence_header_packet *)
+ packet;
+ pkt->packet_buffer -= HFI_VIRTIO_FW_BIAS;
+ break;
+ }
+ case HFI_CMD_SESSION_GET_SEQUENCE_HEADER:
+ {
+ struct hfi_cmd_session_get_sequence_header_packet *pkt =
+ (struct hfi_cmd_session_get_sequence_header_packet *)
+ packet;
+ pkt->packet_buffer -= HFI_VIRTIO_FW_BIAS;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static int write_queue(void *info, u8 *packet, u32 *rx_req_is_set)
+{
+ struct hfi_queue_header *queue;
+ u32 packet_size_in_words, new_write_idx;
+ struct vidc_iface_q_info *qinfo;
+ u32 empty_space, read_idx;
+ u32 *write_ptr;
+
+ if (!info || !packet || !rx_req_is_set) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ }
+
+ qinfo = (struct vidc_iface_q_info *) info;
+ HAL_MSG_LOW("In %s: ", __func__);
+ hal_virtio_modify_cmd_packet(packet);
+
+ queue = (struct hfi_queue_header *) qinfo->q_hdr;
+
+ if (!queue) {
+ HAL_MSG_ERROR("queue not present");
+ return -ENOENT;
+ }
+
+ packet_size_in_words = (*(u32 *)packet) >> 2;
+ HAL_MSG_LOW("Packet_size in words: %d", packet_size_in_words);
+
+ if (packet_size_in_words == 0) {
+ HAL_MSG_ERROR("Zero packet size");
+ return -ENODATA;
+ }
+
+ read_idx = queue->qhdr_read_idx;
+
+ empty_space = (queue->qhdr_write_idx >= read_idx) ?
+ (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
+ (read_idx - queue->qhdr_write_idx);
+ HAL_MSG_LOW("Empty_space: %d", empty_space);
+ if (empty_space <= packet_size_in_words) {
+ queue->qhdr_tx_req = 1;
+ HAL_MSG_ERROR("Insufficient size (%d) to write (%d)",
+ empty_space, packet_size_in_words);
+ return -ENOTEMPTY;
+ }
+
+ queue->qhdr_tx_req = 0;
+
+ new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+ write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+ (queue->qhdr_write_idx << 2));
+ HAL_MSG_LOW("Write Ptr: %d", (u32) write_ptr);
+ if (new_write_idx < queue->qhdr_q_size) {
+ memcpy(write_ptr, packet, packet_size_in_words << 2);
+ } else {
+ new_write_idx -= queue->qhdr_q_size;
+ memcpy(write_ptr, packet, (packet_size_in_words -
+ new_write_idx) << 2);
+ memcpy((void *)queue->qhdr_start_addr,
+ packet + ((packet_size_in_words - new_write_idx) << 2),
+ new_write_idx << 2);
+ }
+ queue->qhdr_write_idx = new_write_idx;
+ *rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
+ HAL_MSG_LOW("Out %s: ", __func__);
+ return 0;
+}
+
+static void hal_virtio_modify_msg_packet(u8 *packet)
+{
+ struct hfi_msg_sys_session_init_done_packet *sys_idle;
+ struct hal_session *sess;
+
+ if (!packet) {
+ HAL_MSG_ERROR("Invalid Param: %s", __func__);
+ return;
+ }
+
+ sys_idle = (struct hfi_msg_sys_session_init_done_packet *)packet;
+ sess = (struct hal_session *) sys_idle->session_id;
+
+ switch (sys_idle->packet_type) {
+ case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+ if (sess->is_decoder) {
+ struct
+ hfi_msg_session_fbd_uncompressed_plane0_packet
+ *pkt_uc = (struct
+ hfi_msg_session_fbd_uncompressed_plane0_packet
+ *) packet;
+ pkt_uc->packet_buffer += HFI_VIRTIO_FW_BIAS;
+ } else {
+ struct
+ hfi_msg_session_fill_buffer_done_compressed_packet
+ *pkt = (struct
+ hfi_msg_session_fill_buffer_done_compressed_packet
+ *) packet;
+ pkt->packet_buffer += HFI_VIRTIO_FW_BIAS;
+ }
+ break;
+ case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+ {
+ struct hfi_msg_session_empty_buffer_done_packet *pkt =
+ (struct hfi_msg_session_empty_buffer_done_packet *)packet;
+ pkt->packet_buffer += HFI_VIRTIO_FW_BIAS;
+ break;
+ }
+ case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+ {
+ struct
+ hfi_msg_session_get_sequence_header_done_packet
+ *pkt =
+ (struct hfi_msg_session_get_sequence_header_done_packet *)
+ packet;
+ pkt->sequence_header += HFI_VIRTIO_FW_BIAS;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static int read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set)
+{
+ struct hfi_queue_header *queue;
+ u32 packet_size_in_words, new_read_idx;
+ u32 *read_ptr;
+ struct vidc_iface_q_info *qinfo;
+
+ if (!info || !packet || !pb_tx_req_is_set) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ }
+
+ qinfo = (struct vidc_iface_q_info *) info;
+ HAL_MSG_LOW("In %s: ", __func__);
+ queue = (struct hfi_queue_header *) qinfo->q_hdr;
+
+ if (!queue) {
+ HAL_MSG_ERROR("Queue memory is not allocated\n");
+ return -ENOMEM;
+ }
+
+ if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+ queue->qhdr_rx_req = 1;
+ *pb_tx_req_is_set = 0;
+ return -EPERM;
+ }
+
+ read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+ (queue->qhdr_read_idx << 2));
+ packet_size_in_words = (*read_ptr) >> 2;
+ HAL_MSG_LOW("packet_size_in_words: %d", packet_size_in_words);
+ if (packet_size_in_words == 0) {
+ HAL_MSG_ERROR("Zero packet size");
+ return -ENODATA;
+ }
+
+ new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
+ HAL_MSG_LOW("Read Ptr: %d", (u32) new_read_idx);
+ if (new_read_idx < queue->qhdr_q_size) {
+ memcpy(packet, read_ptr,
+ packet_size_in_words << 2);
+ } else {
+ new_read_idx -= queue->qhdr_q_size;
+ memcpy(packet, read_ptr,
+ (packet_size_in_words - new_read_idx) << 2);
+ memcpy(packet + ((packet_size_in_words -
+ new_read_idx) << 2),
+ (u8 *)queue->qhdr_start_addr, new_read_idx << 2);
+ }
+
+ queue->qhdr_read_idx = new_read_idx;
+
+ if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+ queue->qhdr_rx_req = 0;
+ else
+ queue->qhdr_rx_req = 1;
+
+ *pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
+ hal_virtio_modify_msg_packet(packet);
+ HAL_MSG_LOW("Out %s: ", __func__);
+ return 0;
+}
+
+static int vidc_hal_alloc(void *mem, void *clnt, u32 size, u32 align, u32 flags)
+{
+ struct vidc_mem_addr *vmem;
+ struct msm_smem *alloc;
+
+ if (!mem || !clnt || !size) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ }
+ vmem = (struct vidc_mem_addr *)mem;
+ HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
+
+ alloc = msm_smem_alloc(clnt, size, align, flags);
+ HAL_MSG_LOW("Alloc done");
+ if (!alloc) {
+ HAL_MSG_HIGH("Alloc fail in %s", __func__);
+ return -ENOMEM;
+ } else {
+ HAL_MSG_MEDIUM("vidc_hal_alloc:ptr=%p,size=%d",
+ alloc->kvaddr, size);
+ vmem->mem_size = alloc->size;
+ vmem->mem_data = alloc;
+ vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
+ vmem->align_device_addr = (u8 *)alloc->device_addr;
+ }
+ return 0;
+}
+
+static void vidc_hal_free(struct smem_client *clnt, struct msm_smem *mem)
+{
+ msm_smem_free(clnt, mem);
+}
+
+static void write_register(u8 *base_addr, u32 reg, u32 value, u8 *vaddr)
+{
+ u32 hwiosymaddr = reg;
+
+ reg &= REG_ADDR_OFFSET_BITMASK;
+ if (reg == (u32)VIDC_CPU_CS_SCIACMDARG2) {
+ /* workaround to offset of FW bias */
+ struct hfi_queue_header *qhdr;
+ struct hfi_queue_table_header *qtbl_hdr =
+ (struct hfi_queue_table_header *)vaddr;
+
+ qhdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(qtbl_hdr, 0);
+ qhdr->qhdr_start_addr -= HFI_VIRTIO_FW_BIAS;
+
+ qhdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(qtbl_hdr, 1);
+ qhdr->qhdr_start_addr -= HFI_VIRTIO_FW_BIAS;
+
+ qhdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(qtbl_hdr, 2);
+ qhdr->qhdr_start_addr -= HFI_VIRTIO_FW_BIAS;
+ value -= HFI_VIRTIO_FW_BIAS;
+ }
+
+ hwiosymaddr = ((u32)base_addr + (hwiosymaddr));
+ HAL_MSG_LOW("Base addr: 0x%x, written to: 0x%x, Value: 0x%x...",
+ (u32)base_addr, hwiosymaddr, value);
+ writel_relaxed(value, hwiosymaddr);
+ wmb();
+}
+
+static int read_register(u8 *base_addr, u32 reg)
+{
+ int rc = readl_relaxed((u32)base_addr + reg);
+ rmb();
+ return rc;
+}
+
+static int vidc_hal_iface_cmdq_write(struct hal_device *device, void *pkt)
+{
+ u32 rx_req_is_set = 0;
+ struct vidc_iface_q_info *q_info;
+ int result = -EPERM;
+
+ if (!device || !pkt) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock(&device->write_lock);
+ q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+ if (!q_info) {
+ HAL_MSG_ERROR("cannot write to shared Q's");
+ goto err_q_write;
+ }
+
+ if (!write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
+ if (rx_req_is_set)
+ write_register(device->hal_data->register_base_addr,
+ VIDC_CPU_IC_SOFTINT,
+ 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
+ result = 0;
+ } else {
+ HAL_MSG_ERROR("vidc_hal_iface_cmdq_write:queue_full");
+ }
+err_q_write:
+ spin_unlock(&device->write_lock);
+ return result;
+}
+
+int vidc_hal_iface_msgq_read(struct hal_device *device, void *pkt)
+{
+ u32 tx_req_is_set = 0;
+ int rc = 0;
+ struct vidc_iface_q_info *q_info;
+
+ if (!pkt) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ }
+ spin_lock(&device->read_lock);
+ if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
+ q_array.align_virtual_addr == 0) {
+ HAL_MSG_ERROR("cannot read from shared MSG Q's");
+ rc = -ENODATA;
+ goto read_error;
+ }
+ q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+
+ if (!read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ if (tx_req_is_set)
+ write_register(device->hal_data->register_base_addr,
+ VIDC_CPU_IC_SOFTINT,
+ 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
+ rc = 0;
+ } else {
+ HAL_MSG_ERROR("vidc_hal_iface_msgq_read:queue_empty");
+ rc = -ENODATA;
+ }
+read_error:
+ spin_unlock(&device->read_lock);
+ return rc;
+}
+
+int vidc_hal_iface_dbgq_read(struct hal_device *device, void *pkt)
+{
+ u32 tx_req_is_set = 0;
+ int rc = 0;
+ struct vidc_iface_q_info *q_info;
+
+ if (!pkt) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ }
+ spin_lock(&device->read_lock);
+ if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
+ q_array.align_virtual_addr == 0) {
+ HAL_MSG_ERROR("cannot read from shared DBG Q's");
+ rc = -ENODATA;
+ goto dbg_error;
+ }
+ q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+ if (!read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ if (tx_req_is_set)
+ write_register(device->hal_data->register_base_addr,
+ VIDC_CPU_IC_SOFTINT,
+ 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
+ rc = 0;
+ } else {
+ HAL_MSG_MEDIUM("vidc_hal_iface_dbgq_read:queue_empty");
+ rc = -ENODATA;
+ }
+dbg_error:
+ spin_unlock(&device->read_lock);
+ return rc;
+}
+
+static void vidc_hal_set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
+{
+ q_hdr->qhdr_status = 0x1;
+ q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
+ q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE;
+ q_hdr->qhdr_pkt_size = 0;
+ q_hdr->qhdr_rx_wm = 0x1;
+ q_hdr->qhdr_tx_wm = 0x1;
+ q_hdr->qhdr_rx_req = 0x1;
+ q_hdr->qhdr_tx_req = 0x0;
+ q_hdr->qhdr_rx_irq_status = 0x0;
+ q_hdr->qhdr_tx_irq_status = 0x0;
+ q_hdr->qhdr_read_idx = 0x0;
+ q_hdr->qhdr_write_idx = 0x0;
+}
+
+static void vidc_hal_interface_queues_release(struct hal_device *device)
+{
+ int i;
+ for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+ vidc_hal_free(device->hal_client,
+ device->iface_queues[i].q_array.mem_data);
+ device->iface_queues[i].q_hdr = NULL;
+ device->iface_queues[i].q_array.mem_data = NULL;
+ device->iface_queues[i].q_array.align_virtual_addr = NULL;
+ device->iface_queues[i].q_array.align_device_addr = NULL;
+ }
+ vidc_hal_free(device->hal_client,
+ device->iface_q_table.mem_data);
+ device->iface_q_table.align_virtual_addr = NULL;
+ device->iface_q_table.align_device_addr = NULL;
+ msm_smem_delete_client(device->hal_client);
+ device->hal_client = NULL;
+}
+
+static int vidc_hal_interface_queues_init(struct hal_device *dev)
+{
+ struct hfi_queue_table_header *q_tbl_hdr;
+ struct hfi_queue_header *q_hdr;
+ u8 i;
+ int rc = 0;
+ struct vidc_iface_q_info *iface_q;
+
+ rc = vidc_hal_alloc((void *) &dev->iface_q_table,
+ dev->hal_client,
+ VIDC_IFACEQ_TABLE_SIZE, 1, 0);
+ if (rc) {
+ HAL_MSG_ERROR("%s:iface_q_table_alloc_fail", __func__);
+ return -ENOMEM;
+ }
+ q_tbl_hdr = (struct hfi_queue_table_header *)
+ dev->iface_q_table.align_virtual_addr;
+ q_tbl_hdr->qtbl_version = 0;
+ q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE;
+ q_tbl_hdr->qtbl_qhdr0_offset = sizeof(
+ struct hfi_queue_table_header);
+ q_tbl_hdr->qtbl_qhdr_size = sizeof(
+ struct hfi_queue_header);
+ q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ;
+ q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ;
+
+ for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+ iface_q = &dev->iface_queues[i];
+ rc = vidc_hal_alloc((void *) &iface_q->q_array,
+ dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
+ 1, 0);
+ if (rc) {
+ HAL_MSG_ERROR("%s:iface_q_table_alloc[%d]_fail",
+ __func__, i);
+ vidc_hal_interface_queues_release(dev);
+ return -ENOMEM;
+ } else {
+ iface_q->q_hdr =
+ VIDC_IFACEQ_GET_QHDR_START_ADDR(
+ dev->iface_q_table.align_virtual_addr, i);
+ vidc_hal_set_queue_hdr_defaults(iface_q->q_hdr);
+ }
+ }
+
+ iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+ q_hdr = iface_q->q_hdr;
+ q_hdr->qhdr_start_addr = (u32)
+ iface_q->q_array.align_device_addr;
+ q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
+
+ iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+ q_hdr = iface_q->q_hdr;
+ q_hdr->qhdr_start_addr = (u32)
+ iface_q->q_array.align_device_addr;
+ q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
+
+ iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+ q_hdr = iface_q->q_hdr;
+ q_hdr->qhdr_start_addr = (u32)
+ iface_q->q_array.align_device_addr;
+ q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
+ write_register(dev->hal_data->register_base_addr,
+ VIDC_CPU_CS_SCIACMDARG2,
+ (u32) dev->iface_q_table.align_device_addr,
+ dev->iface_q_table.align_virtual_addr);
+ write_register(dev->hal_data->register_base_addr,
+ VIDC_CPU_CS_SCIACMDARG1, 0x01,
+ dev->iface_q_table.align_virtual_addr);
+ return 0;
+}
+
+static int vidc_hal_core_start_cpu(struct hal_device *device)
+{
+ u32 ctrl_status = 0, count = 0, rc = 0;
+ write_register(device->hal_data->register_base_addr,
+ VIDC_WRAPPER_INTR_MASK, 0, 0);
+ write_register(device->hal_data->register_base_addr,
+ VIDC_CPU_CS_SCIACMDARG3, 1, 0);
+ while (!ctrl_status && count < 25) {
+ ctrl_status = read_register(
+ device->hal_data->register_base_addr,
+ VIDC_CPU_CS_SCIACMDARG0);
+ count++;
+ }
+ if (count >= 25)
+ rc = -ETIME;
+ return rc;
+}
+
+int vidc_hal_core_init(void *device)
+{
+ struct hfi_cmd_sys_init_packet pkt;
+ int rc = 0;
+ struct hal_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ HAL_MSG_ERROR("%s:invalid device", __func__);
+ return -ENODEV;
+ }
+ enable_irq(dev->hal_data->irq);
+ INIT_LIST_HEAD(&dev->sess_head);
+ spin_lock_init(&dev->read_lock);
+ spin_lock_init(&dev->write_lock);
+
+ if (!dev->hal_client) {
+ dev->hal_client = msm_smem_new_client(SMEM_ION);
+ if (dev->hal_client == NULL) {
+ HAL_MSG_ERROR("Failed to alloc ION_Client");
+ rc = -ENODEV;
+ goto err_no_mem;
+ }
+
+ HAL_MSG_ERROR("Device_Virt_Address : 0x%x,"
+ "Register_Virt_Addr: 0x%x",
+ (u32) dev->hal_data->device_base_addr,
+ (u32) dev->hal_data->register_base_addr);
+
+ rc = vidc_hal_interface_queues_init(dev);
+ if (rc) {
+ HAL_MSG_ERROR("failed to init queues");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ } else {
+ HAL_MSG_ERROR("hal_client exists");
+ rc = -EEXIST;
+ goto err_no_mem;
+ }
+ rc = vidc_hal_core_start_cpu(dev);
+ if (rc) {
+ HAL_MSG_ERROR("Failed to start core");
+ rc = -ENODEV;
+ goto err_no_dev;
+ }
+ pkt.size = sizeof(struct hfi_cmd_sys_init_packet);
+ pkt.packet = HFI_CMD_SYS_INIT;
+ if (vidc_hal_iface_cmdq_write(dev, &pkt)) {
+ rc = -ENOTEMPTY;
+ goto err_write_fail;
+ }
+ return rc;
+err_no_dev:
+err_write_fail:
+err_no_mem:
+ disable_irq_nosync(dev->hal_data->irq);
+ return rc;
+}
+
+int vidc_hal_core_release(void *device)
+{
+ struct hal_device *dev;
+ if (device) {
+ dev = device;
+ } else {
+ HAL_MSG_ERROR("%s:invalid device", __func__);
+ return -ENODEV;
+ }
+ write_register(dev->hal_data->register_base_addr,
+ VIDC_CPU_CS_SCIACMDARG3, 0, 0);
+ disable_irq_nosync(dev->hal_data->irq);
+ vidc_hal_interface_queues_release(dev);
+ HAL_MSG_INFO("\nHAL exited\n");
+ return 0;
+}
+
+int vidc_hal_core_pc_prep(void *device)
+{
+ struct hfi_cmd_sys_pc_prep_packet pkt;
+ int rc = 0;
+ struct hal_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ HAL_MSG_ERROR("%s:invalid device", __func__);
+ return -ENODEV;
+ }
+ pkt.size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
+ pkt.packet_type = HFI_CMD_SYS_PC_PREP;
+ if (vidc_hal_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+static void vidc_hal_core_clear_interrupt(struct hal_device *device)
+{
+ u32 intr_status = 0;
+
+ if (!device->callback)
+ return;
+
+ intr_status = read_register(
+ device->hal_data->register_base_addr,
+ VIDC_WRAPPER_INTR_STATUS);
+
+ if ((intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK) ||
+ (intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) {
+ device->intr_status |= intr_status;
+ HAL_MSG_ERROR("INTERRUPT for device: 0x%x: "
+ "times: %d interrupt_status: %d",
+ (u32) device, ++device->reg_count, intr_status);
+ } else {
+ HAL_MSG_ERROR("SPURIOUS_INTR for device: 0x%x: "
+ "times: %d interrupt_status: %d",
+ (u32) device, ++device->spur_count, intr_status);
+ }
+ write_register(device->hal_data->register_base_addr,
+ VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
+ write_register(device->hal_data->register_base_addr,
+ VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
+ HAL_MSG_ERROR("Cleared WRAPPER/A2H interrupt");
+}
+
+int vidc_hal_core_set_resource(void *device,
+ struct vidc_resource_hdr *resource_hdr, void *resource_value)
+{
+ struct hfi_cmd_sys_set_resource_packet *pkt;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ int rc = 0;
+ struct hal_device *dev;
+
+ if (!device || !resource_hdr || !resource_value) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ dev = device;
+ }
+
+ pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
+
+ pkt->size = sizeof(struct hfi_cmd_sys_set_resource_packet);
+ pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE;
+ pkt->resource_handle = resource_hdr->resource_handle;
+
+ switch (resource_hdr->resource_id) {
+ case VIDC_RESOURCE_OCMEM:
+ {
+ struct hfi_resource_ocmem_type *hfioc_mem =
+ (struct hfi_resource_ocmem_type *)
+ &pkt->rg_resource_data[0];
+ struct vidc_mem_addr *vidc_oc_mem =
+ (struct vidc_mem_addr *) resource_value;
+
+ pkt->resource_type = HFI_RESOURCE_OCMEM;
+ hfioc_mem->size = (u32) vidc_oc_mem->mem_size;
+ hfioc_mem->mem = (u8 *) vidc_oc_mem->align_device_addr;
+ pkt->size += sizeof(struct hfi_resource_ocmem_type);
+ if (vidc_hal_iface_cmdq_write(dev, pkt))
+ rc = -ENOTEMPTY;
+ break;
+ }
+ default:
+ HAL_MSG_INFO("In %s called for resource %d",
+ __func__, resource_hdr->resource_id);
+ break;
+ }
+ return rc;
+}
+
+int vidc_hal_core_release_resource(void *device,
+ struct vidc_resource_hdr *resource_hdr)
+{
+ struct hfi_cmd_sys_release_resource_packet pkt;
+ int rc = 0;
+ struct hal_device *dev;
+
+ if (!device || !resource_hdr) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ dev = device;
+ }
+
+ pkt.size = sizeof(struct hfi_cmd_sys_release_resource_packet);
+ pkt.packet_type = HFI_CMD_SYS_RELEASE_RESOURCE;
+ pkt.resource_type = resource_hdr->resource_id;
+ pkt.resource_handle = resource_hdr->resource_handle;
+
+ if (vidc_hal_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_core_ping(void *device)
+{
+ struct hfi_cmd_sys_ping_packet pkt;
+ int rc = 0;
+ struct hal_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ HAL_MSG_ERROR("%s:invalid device", __func__);
+ return -ENODEV;
+ }
+ pkt.size = sizeof(struct hfi_cmd_sys_ping_packet);
+ pkt.packet_type = HFI_CMD_SYS_PING;
+
+ if (vidc_hal_iface_cmdq_write(dev, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_set_property(void *sess,
+ enum hal_property ptype, void *pdata)
+{
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ struct hfi_cmd_session_set_property_packet *pkt =
+ (struct hfi_cmd_session_set_property_packet *) &packet;
+ struct hal_session *session;
+
+ if (!sess || !pdata) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
+ pkt->size = sizeof(struct hfi_cmd_session_set_property_packet)
+ - sizeof(u32);
+ pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
+ pkt->session_id = (u32) session;
+ pkt->num_properties = 1;
+
+ switch (ptype) {
+ case HAL_CONFIG_FRAME_RATE:
+ {
+ struct hfi_frame_rate *hfi_fps;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE;
+ hfi_fps = (struct hfi_frame_rate *) &pkt->rg_property_data[1];
+ memcpy(hfi_fps, (struct hfi_frame_rate *)
+ pdata, sizeof(struct hfi_frame_rate));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_frame_rate);
+ break;
+ }
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ {
+ struct hfi_uncompressed_format_select *hfi_buf_fmt;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
+ hfi_buf_fmt =
+ (struct hfi_uncompressed_format_select *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi_buf_fmt, (struct hfi_uncompressed_format_select *)
+ pdata, sizeof(struct hfi_uncompressed_format_select));
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_uncompressed_format_select);
+ break;
+ }
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
+ break;
+ case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
+ break;
+ case HAL_PARAM_FRAME_SIZE:
+ {
+ struct hfi_frame_size *hfi_rect;
+ pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE;
+ hfi_rect = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+ memcpy(hfi_rect, (struct hfi_frame_size *) pdata,
+ sizeof(struct hfi_frame_size));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
+ break;
+ }
+ case HAL_CONFIG_REALTIME:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_REALTIME;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_enable *) pdata,
+ sizeof(struct hfi_enable));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_BUFFER_COUNT_ACTUAL:
+ {
+ struct hfi_buffer_count_actual *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
+ hfi = (struct hfi_buffer_count_actual *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_buffer_count_actual *) pdata,
+ sizeof(struct hfi_buffer_count_actual));
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_buffer_count_actual);
+ break;
+ }
+ case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
+ pkt->rg_property_data[1] = (enum HFI_NAL_STREAM_FORMAT)pdata;
+ pkt->size += sizeof(u32) + sizeof(enum HFI_NAL_STREAM_FORMAT);
+ break;
+ }
+ case HAL_PARAM_VDEC_OUTPUT_ORDER:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER;
+ pkt->rg_property_data[1] = (enum HFI_OUTPUT_ORDER)pdata;
+ pkt->size += sizeof(u32) + sizeof(enum HFI_OUTPUT_ORDER);
+ break;
+ }
+ case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
+ {
+ struct hfi_enable_picture *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
+ hfi->picture_type = (u32) pdata;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable_picture);
+ break;
+ }
+ case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_enable *) pdata,
+ sizeof(struct hfi_enable));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_enable *) pdata,
+ sizeof(struct hfi_enable));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VDEC_MULTI_STREAM:
+ {
+ struct hfi_multi_stream *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
+ hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_multi_stream *)pdata,
+ sizeof(struct hfi_multi_stream));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_multi_stream);
+ break;
+ }
+ case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
+ {
+ struct hfi_display_picture_buffer_count *hfi_disp_buf;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT;
+ hfi_disp_buf = (struct hfi_display_picture_buffer_count *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi_disp_buf,
+ (struct hfi_display_picture_buffer_count *)pdata,
+ sizeof(struct hfi_display_picture_buffer_count));
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_display_picture_buffer_count);
+ break;
+ }
+ case HAL_PARAM_DIVX_FORMAT:
+ {
+ pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_DIVX_FORMAT;
+ pkt->rg_property_data[1] = (enum HFI_DIVX_FORMAT)pdata;
+ pkt->size += sizeof(u32) + sizeof(enum HFI_DIVX_FORMAT);
+ break;
+ }
+ case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_enable *) pdata,
+ sizeof(struct hfi_enable));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+ {
+ struct hfi_enable *enable;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ enable = (struct hfi_enable *) &pkt->rg_property_data[1];
+ memcpy(enable, (struct hfi_enable *) pdata,
+ sizeof(struct hfi_enable));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+ break;
+ }
+ case HAL_CONFIG_VENC_REQUEST_IFRAME:
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_REQUEST_IFRAME;
+ break;
+ case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
+ break;
+ case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
+ break;
+ case HAL_CONFIG_VENC_TARGET_BITRATE:
+ {
+ struct hfi_bitrate *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+ hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+ hfi->bit_rate = ((struct hfi_bitrate *)pdata)->bit_rate;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+ break;
+ }
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ {
+ struct hfi_profile_level *hfi_profile_level;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+ hfi_profile_level = (struct hfi_profile_level *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi_profile_level, (struct hfi_profile_level *) pdata,
+ sizeof(struct hfi_profile_level));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_profile_level);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+ {
+ struct hfi_h264_entropy_control *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL;
+ hfi = (struct hfi_h264_entropy_control *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_h264_entropy_control *) pdata,
+ sizeof(struct hfi_h264_entropy_control));
+ pkt->size += sizeof(u32) + sizeof(
+ struct hfi_h264_entropy_control);
+ break;
+ }
+ case HAL_PARAM_VENC_RATE_CONTROL:
+ {
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
+ pkt->rg_property_data[1] = (enum HFI_RATE_CONTROL)pdata;
+ pkt->size += sizeof(u32) + sizeof(enum HFI_RATE_CONTROL);
+ break;
+ }
+ case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
+ {
+ struct hfi_mpeg4_time_resolution *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+ hfi = (struct hfi_mpeg4_time_resolution *)
+ &pkt->rg_property_data[1];
+ hfi->time_increment_resolution =
+ ((struct hal_mpeg4_time_resolution *)pdata)->
+ time_increment_resolution;
+ pkt->size += sizeof(u32) + sizeof(
+ struct hfi_mpeg4_time_resolution);
+ break;
+ }
+ case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
+ {
+ struct hfi_mpeg4_header_extension *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION;
+ hfi = (struct hfi_mpeg4_header_extension *)
+ &pkt->rg_property_data[1];
+ hfi->header_extension = (u32) pdata;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_mpeg4_header_extension);
+ break;
+ }
+ case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
+ {
+ struct hfi_h264_db_control *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL;
+ hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_h264_db_control *) pdata,
+ sizeof(struct hfi_h264_db_control));
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_h264_db_control);
+ break;
+ }
+ case HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF:
+ {
+ struct hfi_temporal_spatial_tradeoff *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF;
+ hfi = (struct hfi_temporal_spatial_tradeoff *)
+ &pkt->rg_property_data[1];
+ hfi->ts_factor = ((struct hfi_temporal_spatial_tradeoff *)
+ pdata)->ts_factor;
+ pkt->size += sizeof(u32) +
+ sizeof(struct hfi_temporal_spatial_tradeoff);
+ break;
+ }
+ case HAL_PARAM_VENC_SESSION_QP:
+ {
+ struct hfi_quantization *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SESSION_QP;
+ hfi = (struct hfi_quantization *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_quantization *) pdata,
+ sizeof(struct hfi_quantization));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
+ break;
+ }
+ case HAL_CONFIG_VENC_INTRA_PERIOD:
+ {
+ struct hfi_intra_period *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD;
+ hfi = (struct hfi_intra_period *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_intra_period *) pdata,
+ sizeof(struct hfi_intra_period));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_intra_period);
+ break;
+ }
+ case HAL_CONFIG_VENC_IDR_PERIOD:
+ {
+ struct hfi_idr_period *hfi;
+ pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD;
+ hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1];
+ hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period;
+ pkt->size += sizeof(u32) + sizeof(struct hfi_idr_period);
+ break;
+ }
+ case HAL_CONFIG_VPE_OPERATIONS:
+ break;
+ case HAL_PARAM_VENC_INTRA_REFRESH:
+ {
+ struct hfi_intra_refresh *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
+ hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_intra_refresh *) pdata,
+ sizeof(struct hfi_intra_refresh));
+ pkt->size += sizeof(u32) + sizeof(struct hfi_intra_refresh);
+ break;
+ }
+ case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
+ {
+ struct hfi_multi_slice_control *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL;
+ hfi = (struct hfi_multi_slice_control *)
+ &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_multi_slice_control *) pdata,
+ sizeof(struct hfi_multi_slice_control));
+ pkt->size += sizeof(u32) + sizeof(struct
+ hfi_multi_slice_control);
+ break;
+ }
+ case HAL_CONFIG_VPE_DEINTERLACE:
+ break;
+ case HAL_SYS_DEBUG_CONFIG:
+ {
+ struct hfi_debug_config *hfi;
+ pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
+ hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
+ memcpy(hfi, (struct hfi_debug_config *) pdata,
+ sizeof(struct hfi_debug_config));
+ pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+ sizeof(struct hfi_debug_config);
+ break;
+ }
+ /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
+ case HAL_CONFIG_BUFFER_REQUIREMENTS:
+ case HAL_CONFIG_PRIORITY:
+ case HAL_CONFIG_BATCH_INFO:
+ case HAL_PARAM_METADATA_PASS_THROUGH:
+ case HAL_SYS_IDLE_INDICATOR:
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED:
+ case HAL_PARAM_CHROMA_SITE:
+ case HAL_PARAM_PROPERTIES_SUPPORTED:
+ case HAL_PARAM_PROFILE_LEVEL_SUPPORTED:
+ case HAL_PARAM_CAPABILITY_SUPPORTED:
+ case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ case HAL_PARAM_MULTI_VIEW_FORMAT:
+ case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ case HAL_PARAM_CODEC_SUPPORTED:
+ case HAL_PARAM_VDEC_MULTI_VIEW_SELECT:
+ case HAL_PARAM_VDEC_MB_QUANTIZATION:
+ case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
+ case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
+ case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+ case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
+
+ case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
+ case HAL_CONFIG_VDEC_MULTI_STREAM:
+ case HAL_PARAM_VENC_MULTI_SLICE_INFO:
+ case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
+ case HAL_PARAM_VENC_LOW_LATENCY:
+ default:
+ HAL_MSG_INFO("DEFAULT: Calling 0x%x", ptype);
+ break;
+ }
+ if (vidc_hal_iface_cmdq_write(session->device, pkt))
+ return -ENOTEMPTY;
+ return 0;
+}
+
+int vidc_hal_session_get_property(void *sess,
+ enum hal_property ptype, void *pdata)
+{
+ struct hal_session *session;
+
+ if (!sess || !pdata) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+ HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
+
+ switch (ptype) {
+ case HAL_CONFIG_FRAME_RATE:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
+ break;
+ case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
+ break;
+ case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
+ break;
+ case HAL_PARAM_FRAME_SIZE:
+ break;
+ case HAL_CONFIG_REALTIME:
+ break;
+ case HAL_PARAM_BUFFER_COUNT_ACTUAL:
+ break;
+ case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+ break;
+ case HAL_PARAM_VDEC_OUTPUT_ORDER:
+ break;
+ case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
+ break;
+ case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
+ break;
+ case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+ break;
+ case HAL_PARAM_VDEC_MULTI_STREAM:
+ break;
+ case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
+ break;
+ case HAL_PARAM_DIVX_FORMAT:
+ break;
+ case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
+ break;
+ case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+ break;
+ case HAL_CONFIG_VDEC_MB_ERROR_MAP:
+ break;
+ case HAL_CONFIG_VENC_REQUEST_IFRAME:
+ break;
+ case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
+ break;
+ case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
+ break;
+ case HAL_CONFIG_VENC_TARGET_BITRATE:
+ break;
+ case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+ break;
+ case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+ break;
+ case HAL_PARAM_VENC_RATE_CONTROL:
+ break;
+ case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
+ break;
+ case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
+ break;
+ case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
+ break;
+ case HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF:
+ break;
+ case HAL_PARAM_VENC_SESSION_QP:
+ break;
+ case HAL_CONFIG_VENC_INTRA_PERIOD:
+ break;
+ case HAL_CONFIG_VENC_IDR_PERIOD:
+ break;
+ case HAL_CONFIG_VPE_OPERATIONS:
+ break;
+ case HAL_PARAM_VENC_INTRA_REFRESH:
+ break;
+ case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
+ break;
+ case HAL_CONFIG_VPE_DEINTERLACE:
+ break;
+ case HAL_SYS_DEBUG_CONFIG:
+ break;
+ /*FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET*/
+ case HAL_CONFIG_BUFFER_REQUIREMENTS:
+ case HAL_CONFIG_PRIORITY:
+ case HAL_CONFIG_BATCH_INFO:
+ case HAL_PARAM_METADATA_PASS_THROUGH:
+ case HAL_SYS_IDLE_INDICATOR:
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+ case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED:
+ case HAL_PARAM_CHROMA_SITE:
+ case HAL_PARAM_PROPERTIES_SUPPORTED:
+ case HAL_PARAM_PROFILE_LEVEL_SUPPORTED:
+ case HAL_PARAM_CAPABILITY_SUPPORTED:
+ case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+ case HAL_PARAM_MULTI_VIEW_FORMAT:
+ case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+ case HAL_PARAM_CODEC_SUPPORTED:
+ case HAL_PARAM_VDEC_MULTI_VIEW_SELECT:
+ case HAL_PARAM_VDEC_MB_QUANTIZATION:
+ case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
+ case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
+ case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+ case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
+
+ case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
+ case HAL_CONFIG_VDEC_MULTI_STREAM:
+ case HAL_PARAM_VENC_MULTI_SLICE_INFO:
+ case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
+ case HAL_PARAM_VENC_LOW_LATENCY:
+ default:
+ HAL_MSG_INFO("DEFAULT: Calling 0x%x", ptype);
+ break;
+ }
+ return 0;
+}
+
+void *vidc_hal_session_init(void *device, u32 session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type)
+{
+ struct hfi_cmd_sys_session_init_packet pkt;
+ struct hal_session *new_session;
+ struct hal_device *dev;
+
+ if (device) {
+ dev = device;
+ } else {
+ HAL_MSG_ERROR("%s:invalid device", __func__);
+ return NULL;
+ }
+
+ new_session = (struct hal_session *)
+ kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+ new_session->session_id = (u32) session_id;
+ if (session_type == 1)
+ new_session->is_decoder = 0;
+ else if (session_type == 2)
+ new_session->is_decoder = 1;
+ new_session->device = dev;
+ list_add_tail(&new_session->list, &dev->sess_head);
+ pkt.size = sizeof(struct hfi_cmd_sys_session_init_packet);
+ pkt.packet = HFI_CMD_SYS_SESSION_INIT;
+ pkt.session_id = (u32) new_session;
+ pkt.session_domain = session_type;
+ pkt.session_codec = codec_type;
+ if (vidc_hal_iface_cmdq_write(dev, &pkt))
+ return NULL;
+ return (void *) new_session;
+}
+
+static int vidc_hal_send_session_cmd(void *session_id,
+ enum HFI_COMMAND pkt_type)
+{
+ struct vidc_hal_session_cmd_pkt pkt;
+ int rc = 0;
+ struct hal_session *session;
+
+ if (session_id) {
+ session = session_id;
+ } else {
+ HAL_MSG_ERROR("%s:invalid session", __func__);
+ return -ENODEV;
+ }
+
+ pkt.size = sizeof(struct vidc_hal_session_cmd_pkt);
+ pkt.packet_type = pkt_type;
+ pkt.session_id = (u32) session;
+
+ if (vidc_hal_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_end(void *session)
+{
+ return vidc_hal_send_session_cmd(session,
+ HFI_CMD_SYS_SESSION_END);
+}
+
+int vidc_hal_session_abort(void *session)
+{
+ return vidc_hal_send_session_cmd(session,
+ HFI_CMD_SYS_SESSION_ABORT);
+}
+
+int vidc_hal_session_set_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ struct hfi_cmd_session_set_buffers_packet *pkt;
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ int rc = 0;
+ u16 i;
+ struct hal_session *session;
+
+ if (!sess || !buffer_info) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INPUT)
+ return 0;
+
+ pkt = (struct hfi_cmd_session_set_buffers_packet *)packet;
+
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+ ((buffer_info->num_buffers - 1) * sizeof(u32));
+ pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS;
+ pkt->session_id = (u32) session;
+ pkt->buffer_mode = HFI_BUFFER_MODE_STATIC;
+ pkt->buffer_size = buffer_info->buffer_size;
+ pkt->min_buffer_size = buffer_info->buffer_size;
+ pkt->num_buffers = buffer_info->num_buffers;
+
+ if ((buffer_info->buffer_type == HAL_BUFFER_OUTPUT) ||
+ (buffer_info->buffer_type == HAL_BUFFER_OUTPUT2)) {
+ struct hfi_buffer_info *buff;
+ pkt->extradata_size = buffer_info->extradata_size;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+ sizeof(u32) + ((buffer_info->num_buffers) *
+ sizeof(struct hfi_buffer_info));
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ for (i = 0; i < pkt->num_buffers; i++) {
+ buff->buffer_addr =
+ buffer_info->align_device_addr;
+ buff->extradata_addr =
+ buffer_info->extradata_addr;
+ }
+ } else {
+ pkt->extradata_size = 0;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+ ((buffer_info->num_buffers - 1) * sizeof(u32));
+ for (i = 0; i < pkt->num_buffers; i++)
+ pkt->rg_buffer_info[i] =
+ buffer_info->align_device_addr;
+ }
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INTERNAL_SCRATCH)
+ pkt->buffer_type = HFI_BUFFER_INTERNAL_SCRATCH;
+ else if (buffer_info->buffer_type == HAL_BUFFER_INTERNAL_PERSIST)
+ pkt->buffer_type = HFI_BUFFER_INTERNAL_PERSIST;
+ else
+ pkt->buffer_type = (enum HFI_BUFFER) buffer_info->buffer_type;
+
+ if (vidc_hal_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_release_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info)
+{
+ struct hfi_cmd_session_release_buffer_packet *pkt;
+ u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+ int rc = 0;
+ u32 i;
+ struct hal_session *session;
+
+ if (!sess || !buffer_info) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ if (buffer_info->buffer_type == HAL_BUFFER_INPUT)
+ return 0;
+
+ pkt = (struct hfi_cmd_session_release_buffer_packet *) packet;
+ pkt->size = sizeof(struct hfi_cmd_session_release_buffer_packet) +
+ ((buffer_info->num_buffers - 1) * sizeof(u32));
+ pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
+ pkt->session_id = (u32) session;
+ pkt->buffer_type = (enum HFI_BUFFER) buffer_info->buffer_type;
+ pkt->buffer_size = buffer_info->buffer_size;
+ pkt->num_buffers = buffer_info->num_buffers;
+
+ if ((buffer_info->buffer_type == HAL_BUFFER_OUTPUT) ||
+ (buffer_info->buffer_type == HAL_BUFFER_OUTPUT2)) {
+ struct hfi_buffer_info *buff;
+ buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+ for (i = 0; i < pkt->num_buffers; i++) {
+ buff->buffer_addr =
+ buffer_info->align_device_addr;
+ buff->extradata_addr =
+ buffer_info->extradata_addr;
+ }
+ pkt->extradata_size = buffer_info->extradata_size;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+ sizeof(u32) + ((buffer_info->num_buffers) *
+ sizeof(struct hfi_buffer_info));
+ } else {
+ for (i = 0; i < pkt->num_buffers; i++)
+ pkt->rg_buffer_info[i] =
+ buffer_info->align_device_addr;
+ pkt->extradata_size = 0;
+ pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+ ((buffer_info->num_buffers - 1) * sizeof(u32));
+ }
+
+ if (vidc_hal_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_load_res(void *sess)
+{
+ return vidc_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_LOAD_RESOURCES);
+}
+
+int vidc_hal_session_release_res(void *sess)
+{
+ return vidc_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_RELEASE_RESOURCES);
+}
+
+int vidc_hal_session_start(void *sess)
+{
+ return vidc_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_START);
+}
+
+int vidc_hal_session_stop(void *sess)
+{
+ return vidc_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_STOP);
+}
+
+int vidc_hal_session_suspend(void *sess)
+{
+ return vidc_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_SUSPEND);
+}
+
+int vidc_hal_session_resume(void *sess)
+{
+ return vidc_hal_send_session_cmd(sess,
+ HFI_CMD_SESSION_RESUME);
+}
+
+int vidc_hal_session_etb(void *sess, struct vidc_frame_data *input_frame)
+{
+ int rc = 0;
+ struct hal_session *session;
+
+ if (!sess || !input_frame) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ if (session->is_decoder) {
+ struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
+ pkt.size = sizeof(
+ struct hfi_cmd_session_empty_buffer_compressed_packet);
+ pkt.packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+ pkt.session_id = (u32) session;
+ pkt.timestamp_hi = (int) (((u64)input_frame->timestamp) >> 32);
+ pkt.timestamp_lo = (int) input_frame->timestamp;
+ pkt.flags = input_frame->flags;
+ pkt.mark_target = input_frame->mark_target;
+ pkt.mark_data = input_frame->mark_data;
+ pkt.offset = input_frame->offset;
+ pkt.alloc_len = input_frame->alloc_len;
+ pkt.filled_len = input_frame->filled_len;
+ pkt.input_tag = input_frame->clnt_data;
+ pkt.packet_buffer = (u8 *) input_frame->device_addr;
+ HAL_MSG_ERROR("### Q DECODER INPUT BUFFER ###");
+ if (vidc_hal_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ } else {
+ struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+ pkt;
+ pkt.size = sizeof(struct
+ hfi_cmd_session_empty_buffer_uncompressed_plane0_packet);
+ pkt.packet = HFI_CMD_SESSION_EMPTY_BUFFER;
+ pkt.session_id = (u32) session;
+ pkt.view_id = 0;
+ pkt.timestamp_hi = (u32) (((u64)input_frame->timestamp) >> 32);
+ pkt.timestamp_lo = (u32) input_frame->timestamp;
+ pkt.flags = input_frame->flags;
+ pkt.mark_target = input_frame->mark_target;
+ pkt.mark_data = input_frame->mark_data;
+ pkt.offset = input_frame->offset;
+ pkt.alloc_len = input_frame->alloc_len;
+ pkt.filled_len = input_frame->filled_len;
+ pkt.input_tag = input_frame->clnt_data;
+ pkt.packet_buffer = (u8 *) input_frame->device_addr;
+ HAL_MSG_ERROR("### Q ENCODER INPUT BUFFER ###");
+ if (vidc_hal_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ }
+ return rc;
+}
+
+int vidc_hal_session_ftb(void *sess,
+ struct vidc_frame_data *output_frame)
+{
+ struct hfi_cmd_session_fill_buffer_packet pkt;
+ int rc = 0;
+ struct hal_session *session;
+
+ if (!sess || !output_frame) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ pkt.size = sizeof(struct hfi_cmd_session_fill_buffer_packet);
+ pkt.packet_type = HFI_CMD_SESSION_FILL_BUFFER;
+ pkt.session_id = (u32) session;
+ if (output_frame->buffer_type == HAL_BUFFER_OUTPUT)
+ pkt.stream_id = 0;
+ else if (output_frame->buffer_type == HAL_BUFFER_OUTPUT2)
+ pkt.stream_id = 1;
+ pkt.packet_buffer = (u8 *) output_frame->device_addr;
+ pkt.extra_data_buffer =
+ (u8 *) output_frame->extradata_addr;
+
+ HAL_MSG_INFO("### Q OUTPUT BUFFER ###");
+ if (vidc_hal_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_parse_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
+{
+ struct hfi_cmd_session_parse_sequence_header_packet *pkt;
+ int rc = 0;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hal_session *session;
+
+ if (!sess || !seq_hdr) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ pkt = (struct hfi_cmd_session_parse_sequence_header_packet *) packet;
+ pkt->size = sizeof(struct hfi_cmd_session_parse_sequence_header_packet);
+ pkt->packet_type = HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER;
+ pkt->session_id = (u32) session;
+ pkt->header_len = seq_hdr->seq_hdr_len;
+ pkt->packet_buffer = seq_hdr->seq_hdr;
+
+ if (vidc_hal_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_get_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr)
+{
+ struct hfi_cmd_session_get_sequence_header_packet *pkt;
+ int rc = 0;
+ u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+ struct hal_session *session;
+
+ if (!sess || !seq_hdr) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return -EINVAL;
+ } else {
+ session = sess;
+ }
+
+ pkt = (struct hfi_cmd_session_get_sequence_header_packet *) packet;
+ pkt->size = sizeof(struct hfi_cmd_session_get_sequence_header_packet);
+ pkt->packet_type = HFI_CMD_SESSION_GET_SEQUENCE_HEADER;
+ pkt->session_id = (u32) session;
+ pkt->buffer_len = seq_hdr->seq_hdr_len;
+ pkt->packet_buffer = seq_hdr->seq_hdr;
+
+ if (vidc_hal_iface_cmdq_write(session->device, pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_get_buf_req(void *sess)
+{
+ struct hfi_cmd_session_get_property_packet pkt;
+ int rc = 0;
+ struct hal_session *session;
+
+ if (sess) {
+ session = sess;
+ } else {
+ HAL_MSG_ERROR("%s:invalid session", __func__);
+ return -ENODEV;
+ }
+
+ pkt.size = sizeof(struct hfi_cmd_session_get_property_packet);
+ pkt.packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+ pkt.session_id = (u32) session;
+ pkt.num_properties = 1;
+ pkt.rg_property_data[0] = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
+ if (vidc_hal_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+int vidc_hal_session_flush(void *sess, enum hal_flush flush_mode)
+{
+ struct hfi_cmd_session_flush_packet pkt;
+ int rc = 0;
+ struct hal_session *session;
+
+ if (sess) {
+ session = sess;
+ } else {
+ HAL_MSG_ERROR("%s:invalid session", __func__);
+ return -ENODEV;
+ }
+
+ pkt.size = sizeof(struct hfi_cmd_session_flush_packet);
+ pkt.packet_type = HFI_CMD_SESSION_FLUSH;
+ pkt.session_id = (u32) session;
+ pkt.flush_type = flush_mode;
+
+ if (vidc_hal_iface_cmdq_write(session->device, &pkt))
+ rc = -ENOTEMPTY;
+ return rc;
+}
+
+static int vidc_hal_check_core_registered(
+ struct hal_device_data core, u32 fw_addr,
+ u32 reg_addr, u32 reg_size, u32 irq)
+{
+ struct hal_device *device;
+ struct list_head *curr, *next;
+
+ if (core.dev_count) {
+ list_for_each_safe(curr, next, &core.dev_head) {
+ device = list_entry(curr, struct hal_device, list);
+ if (device && device->hal_data->irq == irq &&
+ (CONTAINS((u32)device->hal_data->
+ device_base_addr,
+ FIRMWARE_SIZE, fw_addr) ||
+ CONTAINS(fw_addr, FIRMWARE_SIZE,
+ (u32)device->hal_data->
+ device_base_addr) ||
+ CONTAINS((u32)device->hal_data->
+ register_base_addr,
+ reg_size, reg_addr) ||
+ CONTAINS(reg_addr, reg_size,
+ (u32)device->hal_data->
+ register_base_addr) ||
+ OVERLAPS((u32)device->hal_data->
+ register_base_addr,
+ reg_size, reg_addr, reg_size) ||
+ OVERLAPS(reg_addr, reg_size,
+ (u32)device->hal_data->
+ register_base_addr, reg_size) ||
+ OVERLAPS((u32)device->hal_data->
+ device_base_addr,
+ FIRMWARE_SIZE, fw_addr,
+ FIRMWARE_SIZE) ||
+ OVERLAPS(fw_addr, FIRMWARE_SIZE,
+ (u32)device->hal_data->
+ device_base_addr,
+ FIRMWARE_SIZE))) {
+ return 0;
+ } else {
+ HAL_MSG_INFO("Device not registered");
+ return -EINVAL;
+ }
+ }
+ } else {
+ HAL_MSG_INFO("no device Registered");
+ }
+ return -EINVAL;
+}
+
+static void vidc_hal_core_work_handler(struct work_struct *work)
+{
+ struct hal_device *device = list_first_entry(
+ &hal_ctxt.dev_head, struct hal_device, list);
+
+ HAL_MSG_INFO(" GOT INTERRUPT %s() ", __func__);
+ if (!device->callback) {
+ HAL_MSG_ERROR("No callback function "
+ "to process interrupt: %p\n", device);
+ return;
+ }
+ vidc_hal_core_clear_interrupt(device);
+ vidc_hal_response_handler(device);
+ enable_irq(device->hal_data->irq);
+}
+static DECLARE_WORK(vidc_hal_work, vidc_hal_core_work_handler);
+
+static irqreturn_t vidc_hal_isr(int irq, void *dev)
+{
+ struct hal_device *device = dev;
+ HAL_MSG_MEDIUM("\n vidc_hal_isr() %d ", irq);
+ disable_irq_nosync(irq);
+ queue_work(device->vidc_workq, &vidc_hal_work);
+ HAL_MSG_MEDIUM("\n vidc_hal_isr() %d ", irq);
+ return IRQ_HANDLED;
+}
+
+void *vidc_hal_add_device(u32 device_id, u32 fw_base_addr, u32 reg_base,
+ u32 reg_size, u32 irq,
+ void (*callback) (enum command_response cmd, void *data))
+{
+ struct hal_device *hdevice = NULL;
+ struct hal_data *hal = NULL;
+ int rc = 0;
+
+ if (device_id || !fw_base_addr || !reg_base || !reg_size ||
+ !irq || !callback) {
+ HAL_MSG_ERROR("Invalid Paramters");
+ return NULL;
+ } else {
+ HAL_MSG_INFO("entered %s, device_id: %d", __func__, device_id);
+ }
+
+ if (vidc_hal_check_core_registered(hal_ctxt, fw_base_addr,
+ reg_base, reg_size, irq)) {
+ HAL_MSG_LOW("HAL_DATA will be assigned now");
+ hal = (struct hal_data *)
+ kzalloc(sizeof(struct hal_data), GFP_KERNEL);
+ if (!hal) {
+ HAL_MSG_ERROR("Failed to alloc");
+ return NULL;
+ }
+ hal->irq = irq;
+ hal->device_base_addr =
+ ioremap_nocache(fw_base_addr, FIRMWARE_SIZE);
+ if (!hal->device_base_addr) {
+ HAL_MSG_ERROR("could not map fw addr %d of size %d",
+ fw_base_addr, FIRMWARE_SIZE);
+ goto err_map;
+ }
+ hal->register_base_addr =
+ ioremap_nocache(reg_base, reg_size);
+ if (!hal->register_base_addr) {
+ HAL_MSG_ERROR("could not map reg addr %d of size %d",
+ reg_base, reg_size);
+ goto err_map;
+ }
+ INIT_LIST_HEAD(&hal_ctxt.dev_head);
+ } else {
+ HAL_MSG_ERROR("Core present/Already added");
+ return NULL;
+ }
+
+ hdevice = (struct hal_device *)
+ kzalloc(sizeof(struct hal_device), GFP_KERNEL);
+ if (!hdevice) {
+ HAL_MSG_ERROR("failed to allocate new device");
+ goto err_map;
+ }
+
+ INIT_LIST_HEAD(&hdevice->list);
+ list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+ hal_ctxt.dev_count++;
+ hdevice->device_id = device_id;
+ hdevice->hal_data = hal;
+ hdevice->callback = callback;
+
+ hdevice->vidc_workq = create_singlethread_workqueue(
+ "msm_vidc_workerq");
+ if (!hdevice->vidc_workq) {
+ HAL_MSG_ERROR("%s: create workq failed\n", __func__);
+ goto error_createq;
+ }
+
+ rc = request_irq(irq, vidc_hal_isr, IRQF_TRIGGER_HIGH,
+ "msm_vidc", hdevice);
+ if (unlikely(rc)) {
+ HAL_MSG_ERROR("%s() :request_irq failed\n", __func__);
+ goto error_irq_fail;
+ }
+ disable_irq_nosync(irq);
+ return (void *) hdevice;
+error_irq_fail:
+ destroy_workqueue(hdevice->vidc_workq);
+error_createq:
+ hal_ctxt.dev_count--;
+ list_del(&hal_ctxt.dev_head);
+err_map:
+ kfree(hal);
+ return NULL;
+}
+
+void vidc_hal_delete_device(void *device)
+{
+ struct hal_device *close, *dev;
+
+ if (device) {
+ dev = (struct hal_device *) device;
+ list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ if (close->hal_data->irq == dev->hal_data->irq) {
+ hal_ctxt.dev_count--;
+ free_irq(dev->hal_data->irq, NULL);
+ list_del(&close->list);
+ destroy_workqueue(close->vidc_workq);
+ kfree(close->hal_data);
+ kfree(close);
+ break;
+ }
+ }
+
+ }
+}
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
new file mode 100644
index 0000000..166ed0d
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -0,0 +1,1618 @@
+/* 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 __VIDC_HAL_H__
+#define __VIDC_HAL_H__
+
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#ifdef HAL_MSG_LOG
+#define HAL_MSG_LOW(x...) pr_debug(KERN_INFO x)
+#define HAL_MSG_MEDIUM(x...) pr_debug(KERN_INFO x)
+#define HAL_MSG_HIGH(x...) pr_debug(KERN_INFO x)
+#else
+#define HAL_MSG_LOW(x...)
+#define HAL_MSG_MEDIUM(x...)
+#define HAL_MSG_HIGH(x...)
+#endif
+
+#define HAL_MSG_ERROR(x...) pr_err(KERN_INFO x)
+#define HAL_MSG_FATAL(x...) pr_err(KERN_INFO x)
+#define HAL_MSG_INFO(x...) pr_info(KERN_INFO x)
+
+#define HFI_MASK_QHDR_TX_TYPE 0xFF000000
+#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000
+#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00
+#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000FF
+#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q 0x00
+#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q 0x01
+#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q 0x02
+#define HFI_MASK_QHDR_STATUS 0x000000FF
+
+#define VIDC_MAX_UNCOMPRESSED_FMT_PLANES 3
+
+#define VIDC_IFACEQ_NUMQ 3
+#define VIDC_IFACEQ_CMDQ_IDX 0
+#define VIDC_IFACEQ_MSGQ_IDX 1
+#define VIDC_IFACEQ_DBGQ_IDX 2
+
+#define VIDC_IFACEQ_MAX_PKT_SIZE 1024
+#define VIDC_IFACEQ_MED_PKT_SIZE 768
+#define VIDC_IFACEQ_MIN_PKT_SIZE 8
+#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE 100
+#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE 512
+#define VIDC_IFACEQ_MAX_BUF_COUNT 50
+#define VIDC_IFACE_MAX_PARALLEL_CLNTS 16
+#define VIDC_IFACEQ_DFLT_QHDR 0x01010000
+
+struct hfi_queue_table_header {
+ u32 qtbl_version;
+ u32 qtbl_size;
+ u32 qtbl_qhdr0_offset;
+ u32 qtbl_qhdr_size;
+ u32 qtbl_num_q;
+ u32 qtbl_num_active_q;
+};
+
+struct hfi_queue_header {
+ u32 qhdr_status;
+ u32 qhdr_start_addr;
+ u32 qhdr_type;
+ u32 qhdr_q_size;
+ u32 qhdr_pkt_size;
+ u32 qhdr_pkt_drop_cnt;
+ u32 qhdr_rx_wm;
+ u32 qhdr_tx_wm;
+ u32 qhdr_rx_req;
+ u32 qhdr_tx_req;
+ u32 qhdr_rx_irq_status;
+ u32 qhdr_tx_irq_status;
+ u32 qhdr_read_idx;
+ u32 qhdr_write_idx;
+};
+
+#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+ + sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
+
+#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \
+ VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
+
+#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \
+ (void *)((((u32)ptr) + sizeof(struct hfi_queue_table_header)) + \
+ (i * sizeof(struct hfi_queue_header)))
+
+enum vidc_hw_reg {
+ VIDC_HWREG_CTRL_STATUS = 0x1,
+ VIDC_HWREG_QTBL_INFO = 0x2,
+ VIDC_HWREG_QTBL_ADDR = 0x3,
+ VIDC_HWREG_CTRLR_RESET = 0x4,
+ VIDC_HWREG_IFACEQ_FWRXREQ = 0x5,
+ VIDC_HWREG_IFACEQ_FWTXREQ = 0x6,
+ VIDC_HWREG_VHI_SOFTINTEN = 0x7,
+ VIDC_HWREG_VHI_SOFTINTSTATUS = 0x8,
+ VIDC_HWREG_VHI_SOFTINTCLR = 0x9,
+ VIDC_HWREG_HVI_SOFTINTEN = 0xA,
+};
+
+enum HFI_EVENT {
+ HFI_EVENT_SYS_ERROR,
+ HFI_EVENT_SESSION_ERROR,
+ HFI_EVENT_SESSION_SEQUENCE_CHANGED,
+ HFI_EVENT_SESSION_PROPERTY_CHANGED,
+ HFI_UNUSED_EVENT = 0x10000000,
+};
+
+enum HFI_EVENT_DATA_SEQUENCE_CHANGED {
+ HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES,
+ HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES,
+ HFI_UNUSED_SEQCHG = 0x10000000,
+};
+
+#define HFI_BUFFERFLAG_EOS 0x00000001
+#define HFI_BUFFERFLAG_STARTTIME 0x00000002
+#define HFI_BUFFERFLAG_DECODEONLY 0x00000004
+#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008
+#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020
+#define HFI_BUFFERFLAG_EXTRADATA 0x00000040
+#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HFI_BUFFERFLAG_READONLY 0x00000200
+#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+
+enum HFI_ERROR {
+ HFI_ERR_NONE = 0,
+ HFI_ERR_SYS_UNKNOWN = 0x80000001,
+ HFI_ERR_SYS_FATAL = 0x80000002,
+ HFI_ERR_SYS_INVALID_PARAMETER = 0x80000003,
+ HFI_ERR_SYS_VERSION_MISMATCH = 0x80000004,
+ HFI_ERR_SYS_INSUFFICIENT_RESOURCES = 0x80000005,
+ HFI_ERR_SYS_MAX_SESSIONS_REACHED = 0x80000006,
+ HFI_ERR_SYS_UNSUPPORTED_CODEC = 0x80000007,
+ HFI_ERR_SYS_SESSION_IN_USE = 0x80000008,
+ HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE = 0x80000009,
+ HFI_ERR_SYS_UNSUPPORTED_DOMAIN = 0x8000000A,
+ HFI_ERR_SESSION_START_UNUSED = 0x80001000,
+ HFI_ERR_SESSION_UNKNOWN = 0x80001001,
+ HFI_ERR_SESSION_FATAL = 0x80001002,
+ HFI_ERR_SESSION_INVALID_PARAMETER = 0x80001003,
+ HFI_ERR_SESSION_BAD_POINTER = 0x80001004,
+ HFI_ERR_SESSION_INVALID_SESSION_ID = 0x80001005,
+ HFI_ERR_SESSION_INVALID_STREAM_ID = 0x80001006,
+ HFI_ERR_SESSION_INCORRECT_STATE_OPERATION = 0x80001007,
+ HFI_ERR_SESSION_UNSUPPORTED_PROPERTY = 0x80001008,
+ HFI_ERR_SESSION_UNSUPPORTED_SETTING = 0x80001009,
+ HFI_ERR_SESSION_INSUFFICIENT_RESOURCES = 0x8000100A,
+ HFI_ERR_SESSION_STREAM_CORRUPT = 0x8000100B,
+ HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED = 0x8000100C,
+ HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED = 0x8000100D,
+ HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING = 0x8000100E,
+ HFI_ERR_SESSION_SAME_STATE_OPERATION = 0x8000100F,
+ HFI_UNUSED_ERR = 0x10000000,
+};
+
+enum HFI_DOMAIN {
+ HFI_VIDEO_DOMAIN_VPE,
+ HFI_VIDEO_DOMAIN_ENCODER,
+ HFI_VIDEO_DOMAIN_DECODER,
+ HFI_UNUSED_DOMAIN = 0x10000000,
+};
+
+enum HFI_VIDEO_CODEC {
+ HFI_VIDEO_CODEC_UNKNOWN = 0x00000000,
+ HFI_VIDEO_CODEC_H264 = 0x00000002,
+ HFI_VIDEO_CODEC_H263 = 0x00000004,
+ HFI_VIDEO_CODEC_MPEG1 = 0x00000008,
+ HFI_VIDEO_CODEC_MPEG2 = 0x00000010,
+ HFI_VIDEO_CODEC_MPEG4 = 0x00000020,
+ HFI_VIDEO_CODEC_DIVX_311 = 0x00000040,
+ HFI_VIDEO_CODEC_DIVX = 0x00000080,
+ HFI_VIDEO_CODEC_VC1 = 0x00000100,
+ HFI_VIDEO_CODEC_SPARK = 0x00000200,
+ HFI_VIDEO_CODEC_VP6 = 0x00000400,
+ HFI_VIDEO_CODEC_VP7 = 0x00000800,
+ HFI_VIDEO_CODEC_VP8 = 0x00001000,
+ HFI_UNUSED_CODEC = 0x10000000,
+};
+
+enum HFI_H263_PROFILE {
+ HFI_H263_PROFILE_BASELINE = 0x00000001,
+ HFI_H263_PROFILE_H320CODING = 0x00000002,
+ HFI_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
+ HFI_H263_PROFILE_ISWV2 = 0x00000008,
+ HFI_H263_PROFILE_ISWV3 = 0x00000010,
+ HFI_H263_PROFILE_HIGHCOMPRESSION = 0x00000020,
+ HFI_H263_PROFILE_INTERNET = 0x00000040,
+ HFI_H263_PROFILE_INTERLACE = 0x00000080,
+ HFI_H263_PROFILE_HIGHLATENCY = 0x00000100,
+ HFI_UNUSED_H263_PROFILE = 0x10000000,
+};
+
+enum HFI_H263_LEVEL {
+ HFI_H263_LEVEL_10 = 0x00000001,
+ HFI_H263_LEVEL_20 = 0x00000002,
+ HFI_H263_LEVEL_30 = 0x00000004,
+ HFI_H263_LEVEL_40 = 0x00000008,
+ HFI_H263_LEVEL_45 = 0x00000010,
+ HFI_H263_LEVEL_50 = 0x00000020,
+ HFI_H263_LEVEL_60 = 0x00000040,
+ HFI_H263_LEVEL_70 = 0x00000080,
+ HFI_UNUSED_H263_LEVEL = 0x10000000,
+};
+
+enum HFI_MPEG2_PROFILE {
+ HFI_MPEG2_PROFILE_SIMPLE = 0x00000001,
+ HFI_MPEG2_PROFILE_MAIN = 0x00000002,
+ HFI_MPEG2_PROFILE_422 = 0x00000004,
+ HFI_MPEG2_PROFILE_SNR = 0x00000008,
+ HFI_MPEG2_PROFILE_SPATIAL = 0x00000010,
+ HFI_MPEG2_PROFILE_HIGH = 0x00000020,
+ HFI_UNUSED_MPEG2_PROFILE = 0x10000000,
+};
+
+enum HFI_MPEG2_LEVEL {
+ HFI_MPEG2_LEVEL_LL = 0x00000001,
+ HFI_MPEG2_LEVEL_ML = 0x00000002,
+ HFI_MPEG2_LEVEL_H14 = 0x00000004,
+ HFI_MPEG2_LEVEL_HL = 0x00000008,
+ HFI_UNUSED_MEPG2_LEVEL = 0x10000000,
+};
+
+enum HFI_MPEG4_PROFILE {
+ HFI_MPEG4_PROFILE_SIMPLE = 0x00000001,
+ HFI_MPEG4_PROFILE_SIMPLESCALABLE = 0x00000002,
+ HFI_MPEG4_PROFILE_CORE = 0x00000004,
+ HFI_MPEG4_PROFILE_MAIN = 0x00000008,
+ HFI_MPEG4_PROFILE_NBIT = 0x00000010,
+ HFI_MPEG4_PROFILE_SCALABLETEXTURE = 0x00000020,
+ HFI_MPEG4_PROFILE_SIMPLEFACE = 0x00000040,
+ HFI_MPEG4_PROFILE_SIMPLEFBA = 0x00000080,
+ HFI_MPEG4_PROFILE_BASICANIMATED = 0x00000100,
+ HFI_MPEG4_PROFILE_HYBRID = 0x00000200,
+ HFI_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
+ HFI_MPEG4_PROFILE_CORESCALABLE = 0x00000800,
+ HFI_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
+ HFI_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
+ HFI_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
+ HFI_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00008000,
+ HFI_UNUSED_MPEG4_PROFILE = 0x10000000,
+};
+
+enum HFI_MPEG4_LEVEL {
+ HFI_MPEG4_LEVEL_0 = 0x00000001,
+ HFI_MPEG4_LEVEL_0b = 0x00000002,
+ HFI_MPEG4_LEVEL_1 = 0x00000004,
+ HFI_MPEG4_LEVEL_2 = 0x00000008,
+ HFI_MPEG4_LEVEL_3 = 0x00000010,
+ HFI_MPEG4_LEVEL_4 = 0x00000020,
+ HFI_MPEG4_LEVEL_4a = 0x00000040,
+ HFI_MPEG4_LEVEL_5 = 0x00000080,
+ HFI_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
+ HFI_MPEG4_LEVEL_6 = 0x7F000001,
+ HFI_MPEG4_LEVEL_7 = 0x7F000002,
+ HFI_MPEG4_LEVEL_8 = 0x7F000003,
+ HFI_MPEG4_LEVEL_9 = 0x7F000004,
+ HFI_MPEG4_LEVEL_3b = 0x7F000005,
+ HFI_UNUSED_MPEG4_LEVEL = 0x10000000,
+};
+
+enum HFI_H264_PROFILE {
+ HFI_H264_PROFILE_BASELINE = 0x00000001,
+ HFI_H264_PROFILE_MAIN = 0x00000002,
+ HFI_H264_PROFILE_EXTENDED = 0x00000004,
+ HFI_H264_PROFILE_HIGH = 0x00000008,
+ HFI_H264_PROFILE_HIGH10 = 0x00000010,
+ HFI_H264_PROFILE_HIGH422 = 0x00000020,
+ HFI_H264_PROFILE_HIGH444 = 0x00000040,
+ HFI_H264_PROFILE_STEREO_HIGH = 0x00000080,
+ HFI_H264_PROFILE_MV_HIGH = 0x00000100,
+ HFI_UNUSED_H264_PROFILE = 0x10000000,
+};
+
+enum HFI_H264_LEVEL {
+ HFI_H264_LEVEL_1 = 0x00000001,
+ HFI_H264_LEVEL_1b = 0x00000002,
+ HFI_H264_LEVEL_11 = 0x00000004,
+ HFI_H264_LEVEL_12 = 0x00000008,
+ HFI_H264_LEVEL_13 = 0x00000010,
+ HFI_H264_LEVEL_2 = 0x00000020,
+ HFI_H264_LEVEL_21 = 0x00000040,
+ HFI_H264_LEVEL_22 = 0x00000080,
+ HFI_H264_LEVEL_3 = 0x00000100,
+ HFI_H264_LEVEL_31 = 0x00000200,
+ HFI_H264_LEVEL_32 = 0x00000400,
+ HFI_H264_LEVEL_4 = 0x00000800,
+ HFI_H264_LEVEL_41 = 0x00001000,
+ HFI_H264_LEVEL_42 = 0x00002000,
+ HFI_H264_LEVEL_5 = 0x00004000,
+ HFI_H264_LEVEL_51 = 0x00008000,
+ HFI_UNUSED_H264_LEVEL = 0x10000000,
+};
+
+enum HFI_VPX_PROFILE {
+ HFI_VPX_PROFILE_SIMPLE = 0x00000001,
+ HFI_VPX_PROFILE_ADVANCED = 0x00000002,
+ HFI_VPX_PROFILE_VERSION_0 = 0x00000004,
+ HFI_VPX_PROFILE_VERSION_1 = 0x00000008,
+ HFI_VPX_PROFILE_VERSION_2 = 0x00000010,
+ HFI_VPX_PROFILE_VERSION_3 = 0x00000020,
+ HFI_VPX_PROFILE_UNUSED = 0x10000000,
+};
+
+enum HFI_VC1_PROFILE {
+ HFI_VC1_PROFILE_SIMPLE = 0x00000001,
+ HFI_VC1_PROFILE_MAIN = 0x00000002,
+ HFI_VC1_PROFILE_ADVANCED = 0x00000004,
+ HFI_UNUSED_VC1_PROFILE = 0x10000000,
+};
+
+enum HFI_VC1_LEVEL {
+ HFI_VC1_LEVEL_LOW = 0x00000001,
+ HFI_VC1_LEVEL_MEDIUM = 0x00000002,
+ HFI_VC1_LEVEL_HIGH = 0x00000004,
+ HFI_VC1_LEVEL_0 = 0x00000008,
+ HFI_VC1_LEVEL_1 = 0x00000010,
+ HFI_VC1_LEVEL_2 = 0x00000020,
+ HFI_VC1_LEVEL_3 = 0x00000040,
+ HFI_VC1_LEVEL_4 = 0x00000080,
+ HFI_UNUSED_VC1_LEVEL = 0x10000000,
+};
+
+enum HFI_DIVX_FORMAT {
+ HFI_DIVX_FORMAT_4,
+ HFI_DIVX_FORMAT_5,
+ HFI_DIVX_FORMAT_6,
+ HFI_UNUSED_DIVX_FORMAT = 0x10000000,
+};
+
+enum HFI_DIVX_PROFILE {
+ HFI_DIVX_PROFILE_QMOBILE = 0x00000001,
+ HFI_DIVX_PROFILE_MOBILE = 0x00000002,
+ HFI_DIVX_PROFILE_MT = 0x00000004,
+ HFI_DIVX_PROFILE_HT = 0x00000008,
+ HFI_DIVX_PROFILE_HD = 0x00000010,
+ HFI_UNUSED_DIVX_PROFILE = 0x10000000,
+};
+
+enum HFI_BUFFER {
+ HFI_BUFFER_INPUT,
+ HFI_BUFFER_OUTPUT,
+ HFI_BUFFER_OUTPUT2,
+ HFI_BUFFER_EXTRADATA_INPUT,
+ HFI_BUFFER_EXTRADATA_OUTPUT,
+ HFI_BUFFER_EXTRADATA_OUTPUT2,
+ HFI_BUFFER_INTERNAL_SCRATCH = 0x7F000001,
+ HFI_BUFFER_INTERNAL_PERSIST = 0x7F000002,
+ HFI_UNUSED_BUFFER = 0x10000000,
+};
+
+enum HFI_BUFFER_MODE {
+ HFI_BUFFER_MODE_STATIC,
+ HFI_BUFFER_MODE_RING,
+ HFI_UNUSED_BUFFER_MODE = 0x10000000,
+};
+
+enum HFI_FLUSH {
+ HFI_FLUSH_INPUT,
+ HFI_FLUSH_OUTPUT,
+ HFI_FLUSH_OUTPUT2,
+ HFI_FLUSH_ALL,
+ HFI_UNUSED_FLUSH = 0x10000000,
+};
+
+enum HFI_EXTRADATA {
+ HFI_EXTRADATA_NONE = 0x00000000,
+ HFI_EXTRADATA_MB_QUANTIZATION = 0x00000001,
+ HFI_EXTRADATA_INTERLACE_VIDEO = 0x00000002,
+ HFI_EXTRADATA_VC1_FRAMEDISP = 0x00000003,
+ HFI_EXTRADATA_VC1_SEQDISP = 0x00000004,
+ HFI_EXTRADATA_TIMESTAMP = 0x00000005,
+ HFI_EXTRADATA_MULTISLICE_INFO = 0x7F100000,
+ HFI_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001,
+ HFI_EXTRADATA_INDEX = 0x7F100002,
+ HFI_EXTRADATA_METADATA_FILLER = 0x7FE00002,
+ HFI_UNUSED_EXTRADATA = 0x10000000,
+};
+
+enum HFI_EXTRADATA_INDEX_TYPE {
+ HFI_INDEX_EXTRADATA_INPUT_CROP = 0x0700000E,
+ HFI_INDEX_EXTRADATA_DIGITAL_ZOOM = 0x07000010,
+ HFI_INDEX_EXTRADATA_ASPECT_RATIO = 0x7F100003,
+};
+
+struct hfi_extradata_header {
+ u32 size;
+ u32 version;
+ u32 port_tndex;
+ enum HFI_EXTRADATA type;
+ u32 data_size;
+ u8 rg_data[1];
+};
+
+enum HFI_INTERLACE_FORMAT {
+ HFI_INTERLACE_FRAME_PROGRESSIVE = 0x01,
+ HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02,
+ HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+ HFI_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
+ HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+ HFI_UNUSED_INTERLACE = 0x10000000,
+};
+
+enum HFI_PROPERTY {
+ HFI_PROPERTY_SYS_UNUSED = 0x08000000,
+ HFI_PROPERTY_SYS_IDLE_INDICATOR,
+ HFI_PROPERTY_SYS_DEBUG_CONFIG,
+ HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO,
+ HFI_PROPERTY_PARAM_UNUSED = 0x04000000,
+ HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL,
+ HFI_PROPERTY_PARAM_FRAME_SIZE,
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED,
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
+ HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED,
+ HFI_PROPERTY_PARAM_CHROMA_SITE,
+ HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG,
+ HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT,
+ HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED,
+ HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED,
+ HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED,
+ HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT,
+ HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT,
+ HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED,
+ HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE,
+ HFI_PROPERTY_PARAM_CODEC_SUPPORTED,
+ HFI_PROPERTY_PARAM_DIVX_FORMAT,
+
+ HFI_PROPERTY_CONFIG_UNUSED = 0x02000000,
+ HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS,
+ HFI_PROPERTY_CONFIG_REALTIME,
+ HFI_PROPERTY_CONFIG_PRIORITY,
+ HFI_PROPERTY_CONFIG_BATCH_INFO,
+ HFI_PROPERTY_CONFIG_FRAME_RATE,
+
+ HFI_PROPERTY_PARAM_VDEC_UNUSED = 0x01000000,
+ HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+ HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
+ HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT,
+ HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE,
+ HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM,
+ HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER,
+ HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION,
+ HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB,
+ HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING,
+ HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+
+ HFI_PROPERTY_CONFIG_VDEC_UNUSED = 0x00800000,
+ HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+ HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+ HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP,
+
+ HFI_PROPERTY_PARAM_VENC_UNUSED = 0x00400000,
+ HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE,
+ HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL,
+ HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL,
+ HFI_PROPERTY_PARAM_VENC_RATE_CONTROL,
+ HFI_PROPERTY_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
+ HFI_PROPERTY_PARAM_VENC_SESSION_QP,
+ HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION,
+ HFI_PROPERTY_PARAM_VENC_MPEG4_DATA_PARTITIONING,
+ HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION,
+ HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER,
+ HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION,
+ HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO,
+ HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH,
+ HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL,
+
+ HFI_PROPERTY_CONFIG_VENC_UNUSED = 0x00200000,
+ HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE,
+ HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD,
+ HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD,
+ HFI_PROPERTY_CONFIG_VENC_REQUEST_IFRAME,
+ HFI_PROPERTY_CONFIG_VENC_TIMESTAMP_SCALE,
+ HFI_PROPERTY_PARAM_VENC_MPEG4_QPEL,
+ HFI_PROPERTY_PARAM_VENC_ADVANCED,
+
+ HFI_PROPERTY_PARAM_VPE_UNUSED = 0x00100000,
+
+ HFI_PROPERTY_CONFIG_VPE_UNUSED = 0x00080000,
+ HFI_PROPERTY_CONFIG_VPE_DEINTERLACE,
+ HFI_PROPERTY_CONFIG_VPE_OPERATIONS,
+ HFI_PROPERTY_UNUSED = 0x10000000,
+};
+
+struct hfi_batch_info {
+ u32 input_batch_count;
+ u32 output_batch_count;
+};
+
+struct hfi_bitrate {
+ u32 bit_rate;
+};
+
+struct hfi_buffer_count_actual {
+ enum HFI_BUFFER buffer;
+ u32 buffer_count_actual;
+};
+
+struct hfi_buffer_requirements {
+ enum HFI_BUFFER buffer;
+ u32 buffer_size;
+ u32 buffer_region_size;
+ u32 buffer_hold_count;
+ u32 buffer_count_min;
+ u32 buffer_count_actual;
+ u32 contiguous;
+ u32 buffer_alignment;
+};
+
+enum HFI_CAPABILITY {
+ HFI_CAPABILITY_FRAME_WIDTH,
+ HFI_CAPABILITY_FRAME_HEIGHT,
+ HFI_CAPABILITY_MBS_PER_FRAME,
+ HFI_CAPABILITY_MBS_PER_SECOND,
+ HFI_CAPABILITY_FRAMERATE,
+ HFI_CAPABILITY_SCALE_X,
+ HFI_CAPABILITY_SCALE_Y,
+ HFI_CAPABILITY_BITRATE,
+ HFI_UNUSED_CAPABILITY = 0x10000000,
+};
+
+struct hfi_capability_supported {
+ enum HFI_CAPABILITY eCapabilityType;
+ u32 min;
+ u32 max;
+ u32 step_size;
+};
+
+struct hfi_capability_supported_INFO {
+ u32 num_capabilities;
+ struct hfi_capability_supported rg_data[1];
+};
+
+enum HFI_CHROMA_SITE {
+ HFI_CHROMA_SITE_0,
+ HFI_CHROMA_SITE_1,
+ HFI_UNUSED_CHROMA = 0x10000000,
+};
+
+struct hfi_data_payload {
+ u32 size;
+ u8 rg_data[1];
+};
+
+struct hfi_seq_header_info {
+ u32 max_header_len;
+};
+
+struct hfi_enable_picture {
+ u32 picture_type;
+};
+
+struct hfi_display_picture_buffer_count {
+ int enable;
+ u32 count;
+};
+
+struct hfi_enable {
+ int enable;
+};
+
+enum HFI_H264_DB_MODE {
+ HFI_H264_DB_MODE_DISABLE,
+ HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
+ HFI_H264_DB_MODE_ALL_BOUNDARY,
+ HFI_UNUSED_H264_DB = 0x10000000,
+};
+
+struct hfi_h264_db_control {
+ enum HFI_H264_DB_MODE mode;
+ int slice_alpha_offset;
+ int slice_beta_offset;
+};
+
+enum HFI_H264_ENTROPY {
+ HFI_H264_ENTROPY_CAVLC,
+ HFI_H264_ENTROPY_CABAC,
+ HFI_UNUSED_ENTROPY = 0x10000000,
+};
+
+enum HFI_H264_CABAC_MODEL {
+ HFI_H264_CABAC_MODEL_0,
+ HFI_H264_CABAC_MODEL_1,
+ HFI_H264_CABAC_MODEL_2,
+ HFI_UNUSED_CABAC = 0x10000000,
+};
+
+struct hfi_h264_entropy_control {
+ enum HFI_H264_ENTROPY entropy_mode;
+ enum HFI_H264_CABAC_MODEL cabac_model;
+};
+
+struct hfi_extra_data_header_config {
+ u32 type;
+ enum HFI_BUFFER buffer_type;
+ u32 version;
+ u32 port_index;
+ u32 client_extradata_id;
+};
+
+struct hfi_frame_rate {
+ enum HFI_BUFFER buffer_type;
+ u32 frame_rate;
+};
+
+struct hfi_interlace_format_supported {
+ enum HFI_BUFFER buffer;
+ enum HFI_INTERLACE_FORMAT format;
+};
+
+enum hfi_intra_refresh_mode {
+ HFI_INTRA_REFRESH_NONE,
+ HFI_INTRA_REFRESH_CYCLIC,
+ HFI_INTRA_REFRESH_ADAPTIVE,
+ HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE,
+ HFI_INTRA_REFRESH_RANDOM,
+ HFI_UNUSED_INTRA = 0x10000000,
+};
+
+struct hfi_intra_refresh {
+ enum hfi_intra_refresh_mode mode;
+ u32 air_mbs;
+ u32 air_ref;
+ u32 cir_mbs;
+};
+
+struct hfi_idr_period {
+ u32 idr_period;
+};
+
+struct hfi_intra_period {
+ u32 pframes;
+ u32 bframes;
+};
+
+struct hfi_timestamp_scale {
+ u32 time_stamp_scale;
+};
+
+struct hfi_mb_error_map {
+ u32 error_map_size;
+ u8 rg_error_map[1];
+};
+
+struct hfi_metadata_pass_through {
+ int enable;
+ u32 size;
+};
+
+struct hfi_mpeg4_header_extension {
+ u32 header_extension;
+};
+
+struct hfi_mpeg4_time_resolution {
+ u32 time_increment_resolution;
+};
+
+enum HFI_MULTI_SLICE {
+ HFI_MULTI_SLICE_OFF,
+ HFI_MULTI_SLICE_BY_MB_COUNT,
+ HFI_MULTI_SLICE_BY_BYTE_COUNT,
+ HFI_MULTI_SLICE_GOB,
+ HFI_UNUSED_SLICE = 0x10000000,
+};
+
+struct hfi_multi_slice_control {
+ enum HFI_MULTI_SLICE multi_slice;
+ u32 slice_size;
+};
+
+struct hfi_multi_stream {
+ enum HFI_BUFFER buffer;
+ u32 enable;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_multi_view_format {
+ u32 views;
+ u32 rg_view_order[1];
+};
+
+struct hfi_multi_view_select {
+ u32 view_index;
+};
+
+enum HFI_NAL_STREAM_FORMAT {
+ HFI_NAL_FORMAT_STARTCODES = 0x00000001,
+ HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002,
+ HFI_NAL_FORMAT_ONE_BYTE_LENGTH = 0x00000004,
+ HFI_NAL_FORMAT_TWO_BYTE_LENGTH = 0x00000008,
+ HFI_NAL_FORMAT_FOUR_BYTE_LENGTH = 0x00000010,
+ HFI_UNUSED_NAL = 0x10000000,
+};
+
+struct hfi_nal_stream_format_supported {
+ u32 nal_stream_format_supported;
+};
+
+enum HFI_PICTURE {
+ HFI_PICTURE_I = 0x01,
+ HFI_PICTURE_P = 0x02,
+ HFI_PICTURE_B = 0x04,
+ HFI_PICTURE_IDR = 0x7F001000,
+ HFI_UNUSED_PICT = 0x10000000,
+};
+
+enum HFI_PRIORITY {
+ HFI_PRIORITY_LOW = 10,
+ HFI_PRIOIRTY_MEDIUM = 20,
+ HFI_PRIORITY_HIGH = 30,
+ HFI_UNUSED_PRIORITY = 0x10000000,
+};
+
+struct hfi_profile_level {
+ u32 profile;
+ u32 level;
+};
+
+struct hfi_profile_level_supported {
+ u32 profile_count;
+ struct hfi_profile_level rg_profile_level[1];
+};
+
+enum HFI_ROTATE {
+ HFI_ROTATE_NONE,
+ HFI_ROTATE_90,
+ HFI_ROTATE_180,
+ HFI_ROTATE_270,
+ HFI_UNUSED_ROTATE = 0x10000000,
+};
+
+enum HFI_FLIP {
+ HFI_FLIP_NONE,
+ HFI_FLIP_HORIZONTAL,
+ HFI_FLIP_VERTICAL,
+ HFI_UNUSED_FLIP = 0x10000000,
+};
+
+struct hfi_operations {
+ enum HFI_ROTATE rotate;
+ enum HFI_FLIP flip;
+};
+
+enum HFI_OUTPUT_ORDER {
+ HFI_OUTPUT_ORDER_DISPLAY,
+ HFI_OUTPUT_ORDER_DECODE,
+ HFI_UNUSED_OUTPUT = 0x10000000,
+};
+
+struct hfi_quantization {
+ u32 qp_i;
+ u32 qp_p;
+ u32 qp_b;
+};
+
+enum HFI_RATE_CONTROL {
+ HFI_RATE_CONTROL_OFF,
+ HFI_RATE_CONTROL_VBR_VFR,
+ HFI_RATE_CONTROL_VBR_CFR,
+ HFI_RATE_CONTROL_CBR_VFR,
+ HFI_RATE_CONTROL_CBR_CFR,
+ HFI_UNUSED_RC = 0x10000000,
+};
+
+struct hfi_slice_delivery_mode {
+ int enable;
+};
+
+struct hfi_temporal_spatial_tradeoff {
+ u32 ts_factor;
+};
+
+struct hfi_frame_size {
+ enum HFI_BUFFER buffer;
+ u32 width;
+ u32 height;
+};
+
+enum HFI_UNCOMPRESSED_FORMAT {
+ HFI_COLOR_FORMAT_MONOCHROME,
+ HFI_COLOR_FORMAT_NV12,
+ HFI_COLOR_FORMAT_NV21,
+ HFI_COLOR_FORMAT_NV12_4x4TILE,
+ HFI_COLOR_FORMAT_NV21_4x4TILE,
+ HFI_COLOR_FORMAT_YUYV,
+ HFI_COLOR_FORMAT_YVYU,
+ HFI_COLOR_FORMAT_UYVY,
+ HFI_COLOR_FORMAT_VYUY,
+ HFI_COLOR_FORMAT_RGB565,
+ HFI_COLOR_FORMAT_BGR565,
+ HFI_COLOR_FORMAT_RGB888,
+ HFI_COLOR_FORMAT_BGR888,
+ HFI_UNUSED_COLOR = 0x10000000,
+};
+
+struct hfi_uncompressed_format_select {
+ enum HFI_BUFFER buffer;
+ enum HFI_UNCOMPRESSED_FORMAT format;
+};
+
+struct hfi_uncompressed_format_supported {
+ enum HFI_BUFFER buffer;
+ u32 format_entries;
+ u32 rg_format_info[1];
+};
+
+struct hfi_uncompressed_plane_actual {
+ int actual_stride;
+ u32 actual_plane_buffer_height;
+};
+
+struct hfi_uncompressed_plane_actual_info {
+ enum HFI_BUFFER buffer;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hfi_uncompressed_plane_constraints {
+ u32 stride_multiples;
+ u32 max_stride;
+ u32 min_plane_buffer_height_multiple;
+ u32 buffer_alignment;
+};
+
+struct hfi_uncompressed_plane_info {
+ enum HFI_UNCOMPRESSED_FORMAT format;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hfi_uncompressed_plane_actual_constraints_info {
+ enum HFI_BUFFER buffer;
+ u32 num_planes;
+ struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hfi_codec_supported {
+ u32 decoder_codec_supported;
+ u32 encoder_codec_supported;
+};
+
+enum HFI_DEBUG_MSG {
+ HFI_DEBUG_MSG_LOW = 0x00000001,
+ HFI_DEBUG_MSG_MEDIUM = 0x00000002,
+ HFI_DEBUG_MSG_HIGH = 0x00000004,
+ HFI_DEBUG_MSG_ERROR = 0x00000008,
+ HFI_DEBUG_MSG_FATAL = 0x00000010,
+ HFI_UNUSED_DEBUG_MSG = 0x10000000,
+};
+
+struct hfi_debug_config {
+ u32 debug_config;
+};
+
+struct hfi_properties_supported {
+ u32 num_properties;
+ u32 rg_properties[1];
+};
+
+enum HFI_RESOURCE {
+ HFI_RESOURCE_OCMEM = 0x00000001,
+ HFI_UNUSED_RESOURCE = 0x10000000,
+};
+
+struct hfi_resource_ocmem_type {
+ u32 size;
+ u8 *mem;
+};
+
+struct hfi_resource_ocmem_requirement {
+ enum HFI_DOMAIN session_domain;
+ u32 width;
+ u32 height;
+ u32 size;
+};
+
+struct hfi_resource_ocmem_requirement_info {
+ u32 num_entries;
+ struct hfi_resource_ocmem_requirement rg_requirements[1];
+};
+
+struct hfi_venc_config_advanced {
+ u8 pipe2d;
+ u8 hw_mode;
+ u8 low_delay_enforce;
+ int h264_constrain_intra_pred;
+ int h264_transform_8x8_flag;
+ int mpeg4_qpel_enable;
+ int multi_refP_en;
+ int qmatrix_en;
+ u8 vpp_info_packet_mode;
+ u8 ref_tile_mode;
+ u8 bitstream_flush_mode;
+ u32 ds_display_frame_width;
+ u32 ds_display_frame_height;
+ u32 perf_tune_param_ptr;
+};
+
+enum HFI_COMMAND {
+ HFI_CMD_SYS_UNUSED = 0x01000000,
+ HFI_CMD_SYS_INIT,
+ HFI_CMD_SYS_SESSION_INIT,
+ HFI_CMD_SYS_SESSION_END,
+ HFI_CMD_SYS_SESSION_ABORT,
+ HFI_CMD_SYS_SET_RESOURCE,
+ HFI_CMD_SYS_RELEASE_RESOURCE,
+ HFI_CMD_SYS_PING,
+ HFI_CMD_SYS_PC_PREP,
+ HFI_CMD_SYS_SET_PROPERTY,
+ HFI_CMD_SYS_GET_PROPERTY,
+
+ HFI_CMD_SESSION_UNUSED = 0x02000000,
+ HFI_CMD_SESSION_LOAD_RESOURCES,
+ HFI_CMD_SESSION_START,
+ HFI_CMD_SESSION_STOP,
+ HFI_CMD_SESSION_EMPTY_BUFFER,
+ HFI_CMD_SESSION_FILL_BUFFER,
+ HFI_CMD_SESSION_FLUSH,
+ HFI_CMD_SESSION_SUSPEND,
+ HFI_CMD_SESSION_RESUME,
+ HFI_CMD_SESSION_SET_PROPERTY,
+ HFI_CMD_SESSION_GET_PROPERTY,
+ HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER,
+ HFI_CMD_SESSION_GET_SEQUENCE_HEADER,
+ HFI_CMD_SESSION_SET_BUFFERS,
+ HFI_CMD_SESSION_RELEASE_BUFFERS,
+ HFI_CMD_SESSION_RELEASE_RESOURCES,
+
+ HFI_CMD_UNUSED = 0x10000000,
+};
+
+enum HFI_MESSAGE {
+ HFI_MSG_SYS_UNUSED = 0x01000000,
+ HFI_MSG_SYS_IDLE,
+ HFI_MSG_SYS_PC_PREP_DONE,
+ HFI_MSG_SYS_RELEASE_RESOURCE,
+ HFI_MSG_SYS_PING_ACK,
+ HFI_MSG_SYS_DEBUG,
+ HFI_MSG_SYS_INIT_DONE,
+ HFI_MSG_SYS_PROPERTY_INFO,
+ HFI_MSG_SESSION_UNUSED = 0x02000000,
+ HFI_MSG_EVENT_NOTIFY,
+ HFI_MSG_SYS_SESSION_INIT_DONE,
+ HFI_MSG_SYS_SESSION_END_DONE,
+ HFI_MSG_SYS_SESSION_ABORT_DONE,
+ HFI_MSG_SESSION_LOAD_RESOURCES_DONE,
+ HFI_MSG_SESSION_START_DONE,
+ HFI_MSG_SESSION_STOP_DONE,
+ HFI_MSG_SESSION_SUSPEND_DONE,
+ HFI_MSG_SESSION_RESUME_DONE,
+ HFI_MSG_SESSION_EMPTY_BUFFER_DONE,
+ HFI_MSG_SESSION_FILL_BUFFER_DONE,
+ HFI_MSG_SESSION_FLUSH_DONE,
+ HFI_MSG_SESSION_PROPERTY_INFO,
+ HFI_MSG_SESSION_RELEASE_RESOURCES_DONE,
+ HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE,
+ HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE,
+ HFI_MSG_UNUSED = 0x10000000,
+};
+
+struct vidc_hal_msg_pkt_hdr {
+ u32 size;
+ enum HFI_MESSAGE packet;
+};
+
+struct vidc_hal_session_cmd_pkt {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+enum HFI_STATUS {
+ HFI_FAIL = 0,
+ HFI_SUCCESS,
+ HFI_UNUSED_STATUS = 0x10000000,
+};
+
+struct hfi_cmd_sys_init_packet {
+ u32 size;
+ enum HFI_COMMAND packet;
+};
+
+struct hfi_cmd_sys_session_init_packet {
+ u32 size;
+ enum HFI_COMMAND packet;
+ u32 session_id;
+ enum HFI_DOMAIN session_domain;
+ enum HFI_VIDEO_CODEC session_codec;
+};
+
+struct hfi_cmd_sys_session_end_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_session_abort_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_sys_pc_prep_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+};
+
+struct hfi_cmd_sys_set_resource_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 resource_handle;
+ enum HFI_RESOURCE resource_type;
+ u32 rg_resource_data[1];
+};
+
+struct hfi_cmd_sys_release_resource_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ enum HFI_RESOURCE resource_type;
+ u32 resource_handle;
+};
+
+struct hfi_cmd_sys_ping_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 client_data;
+};
+
+struct hfi_cmd_sys_set_property_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_get_property_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 num_properties;
+ enum HFI_PROPERTY rg_property_data[1];
+};
+
+struct hfi_cmd_session_load_resources_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_start_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_stop_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_empty_buffer_compressed_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 input_tag;
+ u8 *packet_buffer;
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
+ u32 size;
+ enum HFI_COMMAND packet;
+ u32 session_id;
+ u32 view_id;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u32 input_tag;
+ u8 *packet_buffer;
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer2;
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer3;
+};
+
+struct hfi_cmd_session_fill_buffer_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ u32 stream_id;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+};
+
+struct hfi_cmd_session_flush_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ enum HFI_FLUSH flush_type;
+};
+
+struct hfi_cmd_session_suspend_packet {
+ u32 size;
+ enum HFI_COMMAND packet;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_resume_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_set_property_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_cmd_session_get_property_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ u32 num_properties;
+ enum HFI_PROPERTY rg_property_data[1];
+};
+
+struct hfi_buffer_info {
+ u32 buffer_addr;
+ u32 extradata_addr;
+};
+
+struct hfi_cmd_session_set_buffers_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ enum HFI_BUFFER buffer_type;
+ enum HFI_BUFFER_MODE buffer_mode;
+ u32 buffer_size;
+ u32 extradata_size;
+ u32 min_buffer_size;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_release_buffer_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ enum HFI_BUFFER buffer_type;
+ u32 buffer_size;
+ u32 extradata_size;
+ u32 num_buffers;
+ u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_release_resources_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+};
+
+struct hfi_cmd_session_parse_sequence_header_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ u32 header_len;
+ u8 *packet_buffer;
+};
+
+struct hfi_cmd_session_get_sequence_header_packet {
+ u32 size;
+ enum HFI_COMMAND packet_type;
+ u32 session_id;
+ u32 buffer_len;
+ u8 *packet_buffer;
+};
+
+struct hfi_msg_event_notify_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_EVENT event_id;
+ u32 event_data1;
+ u32 event_data2;
+ u32 rg_ext_event_data[1];
+};
+
+struct hfi_msg_sys_init_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ enum HFI_ERROR error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_session_init_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_session_end_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_sys_session_abort_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_sys_idle_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+};
+
+struct hfi_msg_sys_pc_prep_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_sys_release_resource_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 resource_handle;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_sys_ping_ack_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 client_data;
+};
+
+struct hfi_msg_sys_debug_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ enum HFI_DEBUG_MSG msg_type;
+ u32 msg_size;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u8 rg_msg_data[1];
+};
+
+struct hfi_msg_sys_property_info_packet {
+ u32 nsize;
+ enum HFI_MESSAGE packet_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_load_resources_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_session_start_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_session_stop_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_session_suspend_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_session_resume_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_msg_session_empty_buffer_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+ u32 offset;
+ u32 filled_len;
+ u32 input_tag;
+ u8 *packet_buffer;
+};
+
+struct hfi_msg_session_fill_buffer_done_compressed_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ enum HFI_ERROR error_type;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 input_tag;
+ enum HFI_PICTURE picture_type;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+};
+
+struct hfi_msg_session_fbd_uncompressed_plane0_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ u32 stream_id;
+ u32 view_id;
+ enum HFI_ERROR error_type;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 oofset;
+ u32 frame_width;
+ u32 frame_height;
+ u32 start_xCoord;
+ u32 start_yCoord;
+ u32 input_tag;
+ u32 input_tag1;
+ enum HFI_PICTURE picture_type;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer;
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
+ u32 flags;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 offset;
+ u8 *packet_buffer;
+};
+
+struct hfi_msg_session_flush_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+ enum HFI_FLUSH flush_type;
+};
+
+struct hfi_msg_session_parse_sequence_header_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_get_sequence_header_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+ u32 header_len;
+ u8 *sequence_header;
+};
+
+struct hfi_msg_session_property_info_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ u32 num_properties;
+ u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_release_resources_done_packet {
+ u32 size;
+ enum HFI_MESSAGE packet_type;
+ u32 session_id;
+ enum HFI_ERROR error_type;
+};
+
+struct hfi_extradata_mb_quantization_payload {
+ u8 rg_mb_qp[1];
+};
+
+struct hfi_extradata_vc1_pswnd {
+ u32 ps_wnd_h_offset;
+ u32 ps_wndv_offset;
+ u32 ps_wnd_width;
+ u32 ps_wnd_height;
+};
+
+struct hfi_extradata_vc1_framedisp_payload {
+ u32 res_pic;
+ u32 ref;
+ u32 range_map_present;
+ u32 range_map_y;
+ u32 range_map_uv;
+ u32 num_pan_scan_wnds;
+ struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
+};
+
+struct hfi_extradata_vc1_seqdisp_payload {
+ u32 prog_seg_frm;
+ u32 uv_sampling_fmt;
+ u32 color_fmt_flag;
+ u32 color_primaries;
+ u32 transfer_char;
+ u32 mat_coeff;
+ u32 aspect_ratio;
+ u32 aspect_horiz;
+ u32 aspect_vert;
+};
+
+struct hfi_extradata_timestamp_payload {
+ u32 timestamp_low;
+ u32 timestamp_high;
+};
+
+struct hfi_extradata_interlace_video_payload {
+ enum HFI_INTERLACE_FORMAT format;
+};
+
+enum HFI_S3D_FP_LAYOUT {
+ HFI_S3D_FP_LAYOUT_NONE,
+ HFI_S3D_FP_LAYOUT_INTRLV_CHECKERBOARD,
+ HFI_S3D_FP_LAYOUT_INTRLV_COLUMN,
+ HFI_S3D_FP_LAYOUT_INTRLV_ROW,
+ HFI_S3D_FP_LAYOUT_SIDEBYSIDE,
+ HFI_S3D_FP_LAYOUT_TOPBOTTOM,
+ HFI_S3D_FP_LAYOUT_UNUSED = 0x10000000,
+};
+
+enum HFI_S3D_FP_VIEW_ORDER {
+ HFI_S3D_FP_LEFTVIEW_FIRST,
+ HFI_S3D_FP_RIGHTVIEW_FIRST,
+ HFI_S3D_FP_UNKNOWN,
+ HFI_S3D_FP_VIEWORDER_UNUSED = 0x10000000,
+};
+
+enum HFI_S3D_FP_FLIP {
+ HFI_S3D_FP_FLIP_NONE,
+ HFI_S3D_FP_FLIP_LEFT_HORIZ,
+ HFI_S3D_FP_FLIP_LEFT_VERT,
+ HFI_S3D_FP_FLIP_RIGHT_HORIZ,
+ HFI_S3D_FP_FLIP_RIGHT_VERT,
+ HFI_S3D_FP_FLIP_UNUSED = 0x10000000,
+};
+
+struct hfi_extradata_s3d_frame_packing_payload {
+ enum HFI_S3D_FP_LAYOUT eLayout;
+ enum HFI_S3D_FP_VIEW_ORDER eOrder;
+ enum HFI_S3D_FP_FLIP eFlip;
+ int bQuinCunx;
+ u32 nLeftViewLumaSiteX;
+ u32 nLeftViewLumaSiteY;
+ u32 nRightViewLumaSiteX;
+ u32 nRightViewLumaSiteY;
+};
+
+struct hfi_extradata_num_concealed_mb_payload {
+ u32 num_mb_concealed;
+};
+
+struct hfi_extradata_sliceinfo {
+ u32 offset_in_stream;
+ u32 slice_length;
+};
+
+struct hfi_extradata_multislice_info_payload {
+ u32 num_slices;
+ struct hfi_extradata_sliceinfo rg_slice_info[1];
+};
+
+struct hfi_index_extradata_input_crop_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+};
+
+struct hfi_index_extradata_digital_zoom_payload {
+ u32 size;
+ u32 version;
+ u32 port_index;
+ int width;
+ int height;
+};
+
+struct vidc_mem_addr {
+ u8 *align_device_addr;
+ u8 *align_virtual_addr;
+ u32 mem_size;
+ struct msm_smem *mem_data;
+};
+
+struct vidc_iface_q_info {
+ void *q_hdr;
+ struct vidc_mem_addr q_array;
+};
+
+/* Internal data used in vidc_hal not exposed to msm_vidc*/
+
+struct hal_data {
+ u32 irq;
+ u8 *device_base_addr;
+ u8 *register_base_addr;
+};
+
+struct hal_device {
+ struct list_head list;
+ struct list_head sess_head;
+ u32 intr_status;
+ u32 device_id;
+ spinlock_t read_lock;
+ spinlock_t write_lock;
+ void (*callback) (u32 response, void *callback);
+ struct vidc_mem_addr iface_q_table;
+ struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ];
+ struct smem_client *hal_client;
+ struct hal_data *hal_data;
+ struct workqueue_struct *vidc_workq;
+ int spur_count;
+ int reg_count;
+};
+
+struct hal_session {
+ struct list_head list;
+ u32 session_id;
+ u32 is_decoder;
+ struct hal_device *device;
+};
+
+struct hal_device_data {
+ struct list_head dev_head;
+ int dev_count;
+};
+
+extern struct hal_device_data hal_ctxt;
+
+int vidc_hal_iface_msgq_read(struct hal_device *device, void *pkt);
+int vidc_hal_iface_dbgq_read(struct hal_device *device, void *pkt);
+
+/* Interrupt Processing:*/
+void vidc_hal_response_handler(struct hal_device *device);
+
+#endif /*__VIDC_HAL_H__ */
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
new file mode 100644
index 0000000..036091b
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -0,0 +1,975 @@
+/* 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 __VIDC_HAL_API_H__
+#define __VIDC_HAL_API_H__
+
+#include <linux/types.h>
+
+#define CONTAINS(__a, __sz, __t) ({\
+ int __rc = __t >= __a && \
+ __t < __a + __sz; \
+ __rc; \
+})
+
+#define OVERLAPS(__t, __tsz, __a, __asz) ({\
+ int __rc = __t <= __a && \
+ __t + __tsz >= __a + __asz; \
+ __rc; \
+})
+
+#define HAL_BUFFERFLAG_EOS 0x00000001
+#define HAL_BUFFERFLAG_STARTTIME 0x00000002
+#define HAL_BUFFERFLAG_DECODEONLY 0x00000004
+#define HAL_BUFFERFLAG_DATACORRUPT 0x00000008
+#define HAL_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define HAL_BUFFERFLAG_SYNCFRAME 0x00000020
+#define HAL_BUFFERFLAG_EXTRADATA 0x00000040
+#define HAL_BUFFERFLAG_CODECCONFIG 0x00000080
+#define HAL_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HAL_BUFFERFLAG_READONLY 0x00000200
+#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
+
+enum vidc_status {
+ VIDC_ERR_NONE = 0x0,
+ VIDC_ERR_FAIL = 0x80000000,
+ VIDC_ERR_ALLOC_FAIL,
+ VIDC_ERR_ILLEGAL_OP,
+ VIDC_ERR_BAD_PARAM,
+ VIDC_ERR_BAD_HANDLE,
+ VIDC_ERR_NOT_SUPPORTED,
+ VIDC_ERR_BAD_STATE,
+ VIDC_ERR_MAX_CLIENT,
+ VIDC_ERR_IFRAME_EXPECTED,
+ VIDC_ERR_HW_FATAL,
+ VIDC_ERR_BITSTREAM_ERR,
+ VIDC_ERR_INDEX_NOMORE,
+ VIDC_ERR_SEQHDR_PARSE_FAIL,
+ VIDC_ERR_INSUFFICIENT_BUFFER,
+ VIDC_ERR_BAD_POWER_STATE,
+ VIDC_ERR_NO_VALID_SESSION,
+ VIDC_ERR_TIMEOUT,
+ VIDC_ERR_CMDQFULL,
+ VIDC_ERR_CLIENT_PRESENT = 0x90000001,
+ VIDC_ERR_CLIENT_FATAL,
+ VIDC_ERR_CMD_QUEUE_FULL,
+ VIDC_ERR_UNUSED = 0x10000000
+};
+
+enum hal_property {
+ HAL_CONFIG_FRAME_RATE = 0x04000001,
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
+ HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
+ HAL_PARAM_EXTRA_DATA_HEADER_CONFIG,
+ HAL_PARAM_FRAME_SIZE,
+ HAL_CONFIG_REALTIME,
+ HAL_PARAM_BUFFER_COUNT_ACTUAL,
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+ HAL_PARAM_VDEC_OUTPUT_ORDER,
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE,
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+ HAL_PARAM_VDEC_MULTI_STREAM,
+ HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
+ HAL_PARAM_DIVX_FORMAT,
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+ HAL_CONFIG_VDEC_MB_ERROR_MAP,
+ HAL_CONFIG_VENC_REQUEST_IFRAME,
+ HAL_PARAM_VENC_MPEG4_SHORT_HEADER,
+ HAL_PARAM_VENC_MPEG4_AC_PREDICTION,
+ HAL_CONFIG_VENC_TARGET_BITRATE,
+ HAL_PARAM_PROFILE_LEVEL_CURRENT,
+ HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+ HAL_PARAM_VENC_RATE_CONTROL,
+ HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION,
+ HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION,
+ HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
+ HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
+ HAL_PARAM_VENC_SESSION_QP,
+ HAL_CONFIG_VENC_INTRA_PERIOD,
+ HAL_CONFIG_VENC_IDR_PERIOD,
+ HAL_CONFIG_VPE_OPERATIONS,
+ HAL_PARAM_VENC_INTRA_REFRESH,
+ HAL_PARAM_VENC_MULTI_SLICE_CONTROL,
+ HAL_CONFIG_VPE_DEINTERLACE,
+ HAL_SYS_DEBUG_CONFIG,
+ HAL_CONFIG_BUFFER_REQUIREMENTS,
+ HAL_CONFIG_PRIORITY,
+ HAL_CONFIG_BATCH_INFO,
+ HAL_PARAM_METADATA_PASS_THROUGH,
+ HAL_SYS_IDLE_INDICATOR,
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED,
+ HAL_PARAM_INTERLACE_FORMAT_SUPPORTED,
+ HAL_PARAM_CHROMA_SITE,
+ HAL_PARAM_PROPERTIES_SUPPORTED,
+ HAL_PARAM_PROFILE_LEVEL_SUPPORTED,
+ HAL_PARAM_CAPABILITY_SUPPORTED,
+ HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED,
+ HAL_PARAM_MULTI_VIEW_FORMAT,
+ HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE,
+ HAL_PARAM_CODEC_SUPPORTED,
+ HAL_PARAM_VDEC_MULTI_VIEW_SELECT,
+ HAL_PARAM_VDEC_MB_QUANTIZATION,
+ HAL_PARAM_VDEC_NUM_CONCEALED_MB,
+ HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING,
+ HAL_PARAM_VENC_SLICE_DELIVERY_MODE,
+ HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING,
+ HAL_CONFIG_BUFFER_COUNT_ACTUAL,
+ HAL_CONFIG_VDEC_MULTI_STREAM,
+ HAL_PARAM_VENC_MULTI_SLICE_INFO,
+ HAL_CONFIG_VENC_TIMESTAMP_SCALE,
+ HAL_PARAM_VENC_LOW_LATENCY,
+};
+
+enum hal_domain {
+ HAL_VIDEO_DOMAIN_VPE,
+ HAL_VIDEO_DOMAIN_ENCODER,
+ HAL_VIDEO_DOMAIN_DECODER,
+ HAL_UNUSED_DOMAIN = 0x10000000,
+};
+
+enum hal_video_codec {
+ HAL_VIDEO_CODEC_UNKNOWN = 0x00000000,
+ HAL_VIDEO_CODEC_MVC = 0x00000001,
+ HAL_VIDEO_CODEC_H264 = 0x00000002,
+ HAL_VIDEO_CODEC_H263 = 0x00000004,
+ HAL_VIDEO_CODEC_MPEG1 = 0x00000008,
+ HAL_VIDEO_CODEC_MPEG2 = 0x00000010,
+ HAL_VIDEO_CODEC_MPEG4 = 0x00000020,
+ HAL_VIDEO_CODEC_DIVX_311 = 0x00000040,
+ HAL_VIDEO_CODEC_DIVX = 0x00000080,
+ HAL_VIDEO_CODEC_VC1 = 0x00000100,
+ HAL_VIDEO_CODEC_SPARK = 0x00000200,
+ HAL_VIDEO_CODEC_VP6 = 0x00000400,
+ HAL_VIDEO_CODEC_VP7 = 0x00000800,
+ HAL_VIDEO_CODEC_VP8 = 0x00001000,
+ HAL_UNUSED_CODEC = 0x10000000,
+};
+
+enum hal_h263_profile {
+ HAL_H263_PROFILE_BASELINE = 0x00000001,
+ HAL_H263_PROFILE_H320CODING = 0x00000002,
+ HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
+ HAL_H263_PROFILE_ISWV2 = 0x00000008,
+ HAL_H263_PROFILE_ISWV3 = 0x00000010,
+ HAL_H263_PROFILE_HIGHCOMPRESSION = 0x00000020,
+ HAL_H263_PROFILE_INTERNET = 0x00000040,
+ HAL_H263_PROFILE_INTERLACE = 0x00000080,
+ HAL_H263_PROFILE_HIGHLATENCY = 0x00000100,
+ HAL_UNUSED_H263_PROFILE = 0x10000000,
+};
+
+enum hal_h263_level {
+ HAL_H263_LEVEL_10 = 0x00000001,
+ HAL_H263_LEVEL_20 = 0x00000002,
+ HAL_H263_LEVEL_30 = 0x00000004,
+ HAL_H263_LEVEL_40 = 0x00000008,
+ HAL_H263_LEVEL_45 = 0x00000010,
+ HAL_H263_LEVEL_50 = 0x00000020,
+ HAL_H263_LEVEL_60 = 0x00000040,
+ HAL_H263_LEVEL_70 = 0x00000080,
+ HAL_UNUSED_H263_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg2_profile {
+ HAL_MPEG2_PROFILE_SIMPLE = 0x00000001,
+ HAL_MPEG2_PROFILE_MAIN = 0x00000002,
+ HAL_MPEG2_PROFILE_422 = 0x00000004,
+ HAL_MPEG2_PROFILE_SNR = 0x00000008,
+ HAL_MPEG2_PROFILE_SPATIAL = 0x00000010,
+ HAL_MPEG2_PROFILE_HIGH = 0x00000020,
+ HAL_UNUSED_MPEG2_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg2_level {
+ HAL_MPEG2_LEVEL_LL = 0x00000001,
+ HAL_MPEG2_LEVEL_ML = 0x00000002,
+ HAL_MPEG2_LEVEL_H14 = 0x00000004,
+ HAL_MPEG2_LEVEL_HL = 0x00000008,
+ HAL_UNUSED_MEPG2_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg4_profile {
+ HAL_MPEG4_PROFILE_SIMPLE = 0x00000001,
+ HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00000002,
+ HAL_MPEG4_PROFILE_CORE = 0x00000004,
+ HAL_MPEG4_PROFILE_MAIN = 0x00000008,
+ HAL_MPEG4_PROFILE_NBIT = 0x00000010,
+ HAL_MPEG4_PROFILE_SCALABLETEXTURE = 0x00000020,
+ HAL_MPEG4_PROFILE_SIMPLEFACE = 0x00000040,
+ HAL_MPEG4_PROFILE_SIMPLEFBA = 0x00000080,
+ HAL_MPEG4_PROFILE_BASICANIMATED = 0x00000100,
+ HAL_MPEG4_PROFILE_HYBRID = 0x00000200,
+ HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
+ HAL_MPEG4_PROFILE_CORESCALABLE = 0x00000800,
+ HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
+ HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
+ HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
+ HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00008000,
+ HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg4_level {
+ HAL_MPEG4_LEVEL_0 = 0x00000001,
+ HAL_MPEG4_LEVEL_0b = 0x00000002,
+ HAL_MPEG4_LEVEL_1 = 0x00000004,
+ HAL_MPEG4_LEVEL_2 = 0x00000008,
+ HAL_MPEG4_LEVEL_3 = 0x00000010,
+ HAL_MPEG4_LEVEL_4 = 0x00000020,
+ HAL_MPEG4_LEVEL_4a = 0x00000040,
+ HAL_MPEG4_LEVEL_5 = 0x00000080,
+ HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
+ HAL_MPEG4_LEVEL_6 = 0x7F000001,
+ HAL_MPEG4_LEVEL_7 = 0x7F000002,
+ HAL_MPEG4_LEVEL_8 = 0x7F000003,
+ HAL_MPEG4_LEVEL_9 = 0x7F000004,
+ HAL_MPEG4_LEVEL_3b = 0x7F000005,
+ HAL_UNUSED_MPEG4_LEVEL = 0x10000000,
+};
+
+enum hal_h264_profile {
+ HAL_H264_PROFILE_BASELINE = 0x00000001,
+ HAL_H264_PROFILE_MAIN = 0x00000002,
+ HAL_H264_PROFILE_EXTENDED = 0x00000004,
+ HAL_H264_PROFILE_HIGH = 0x00000008,
+ HAL_H264_PROFILE_HIGH10 = 0x00000010,
+ HAL_H264_PROFILE_HIGH422 = 0x00000020,
+ HAL_H264_PROFILE_HIGH444 = 0x00000040,
+ HAL_UNUSED_H264_PROFILE = 0x10000000,
+};
+
+enum hal_h264_level {
+ HAL_H264_LEVEL_1 = 0x00000001,
+ HAL_H264_LEVEL_1b = 0x00000002,
+ HAL_H264_LEVEL_11 = 0x00000004,
+ HAL_H264_LEVEL_12 = 0x00000008,
+ HAL_H264_LEVEL_13 = 0x00000010,
+ HAL_H264_LEVEL_2 = 0x00000020,
+ HAL_H264_LEVEL_21 = 0x00000040,
+ HAL_H264_LEVEL_22 = 0x00000080,
+ HAL_H264_LEVEL_3 = 0x00000100,
+ HAL_H264_LEVEL_31 = 0x00000200,
+ HAL_H264_LEVEL_32 = 0x00000400,
+ HAL_H264_LEVEL_4 = 0x00000800,
+ HAL_H264_LEVEL_41 = 0x00001000,
+ HAL_H264_LEVEL_42 = 0x00002000,
+ HAL_H264_LEVEL_5 = 0x00004000,
+ HAL_H264_LEVEL_51 = 0x00008000,
+ HAL_UNUSED_H264_LEVEL = 0x10000000,
+};
+
+enum hal_vpx_profile {
+ HAL_VPX_PROFILE_SIMPLE = 0x00000001,
+ HAL_VPX_PROFILE_ADVANCED = 0x00000002,
+ HAL_VPX_PROFILE_VERSION_0 = 0x00000004,
+ HAL_VPX_PROFILE_VERSION_1 = 0x00000008,
+ HAL_VPX_PROFILE_VERSION_2 = 0x00000010,
+ HAL_VPX_PROFILE_VERSION_3 = 0x00000020,
+ HAL_VPX_PROFILE_UNUSED = 0x10000000,
+};
+
+enum hal_vc1_profile {
+ HAL_VC1_PROFILE_SIMPLE = 0x00000001,
+ HAL_VC1_PROFILE_MAIN = 0x00000002,
+ HAL_VC1_PROFILE_ADVANCED = 0x00000004,
+ HAL_UNUSED_VC1_PROFILE = 0x10000000,
+};
+
+enum hal_vc1_level {
+ HAL_VC1_LEVEL_LOW = 0x00000001,
+ HAL_VC1_LEVEL_MEDIUM = 0x00000002,
+ HAL_VC1_LEVEL_HIGH = 0x00000004,
+ HAL_VC1_LEVEL_0 = 0x00000008,
+ HAL_VC1_LEVEL_1 = 0x00000010,
+ HAL_VC1_LEVEL_2 = 0x00000020,
+ HAL_VC1_LEVEL_3 = 0x00000040,
+ HAL_VC1_LEVEL_4 = 0x00000080,
+ HAL_UNUSED_VC1_LEVEL = 0x10000000,
+};
+
+enum hal_divx_format {
+ HAL_DIVX_FORMAT_4,
+ HAL_DIVX_FORMAT_5,
+ HAL_DIVX_FORMAT_6,
+ HAL_UNUSED_DIVX_FORMAT = 0x10000000,
+};
+
+enum hal_divx_profile {
+ HAL_DIVX_PROFILE_QMOBILE = 0x00000001,
+ HAL_DIVX_PROFILE_MOBILE = 0x00000002,
+ HAL_DIVX_PROFILE_MT = 0x00000004,
+ HAL_DIVX_PROFILE_HT = 0x00000008,
+ HAL_DIVX_PROFILE_HD = 0x00000010,
+ HAL_UNUSED_DIVX_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_profile {
+ HAL_MVC_PROFILE_STEREO_HIGH = 0x00000001,
+ HAL_MVC_PROFILE_MV_HIGH = 0x00000002,
+ HAL_UNUSED_MVC_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_level {
+ HAL_MVC_LEVEL_1 = 0x00000001,
+ HAL_MVC_LEVEL_1b = 0x00000002,
+ HAL_MVC_LEVEL_11 = 0x00000004,
+ HAL_MVC_LEVEL_12 = 0x00000008,
+ HAL_MVC_LEVEL_13 = 0x00000010,
+ HAL_MVC_LEVEL_2 = 0x00000020,
+ HAL_MVC_LEVEL_21 = 0x00000040,
+ HAL_MVC_LEVEL_22 = 0x00000080,
+ HAL_MVC_LEVEL_3 = 0x00000100,
+ HAL_MVC_LEVEL_31 = 0x00000200,
+ HAL_MVC_LEVEL_32 = 0x00000400,
+ HAL_MVC_LEVEL_4 = 0x00000800,
+ HAL_MVC_LEVEL_41 = 0x00001000,
+ HAL_MVC_LEVEL_42 = 0x00002000,
+ HAL_MVC_LEVEL_5 = 0x00004000,
+ HAL_MVC_LEVEL_51 = 0x00008000,
+ HAL_UNUSED_MVC_LEVEL = 0x10000000,
+};
+
+enum hal_buffer {
+ HAL_BUFFER_INPUT,
+ HAL_BUFFER_OUTPUT,
+ HAL_BUFFER_OUTPUT2,
+ HAL_BUFFER_EXTRADATA_INPUT,
+ HAL_BUFFER_EXTRADATA_OUTPUT,
+ HAL_BUFFER_EXTRADATA_OUTPUT2,
+ HAL_BUFFER_INTERNAL_SCRATCH,
+ HAL_BUFFER_INTERNAL_PERSIST,
+ HAL_UNUSED_BUFFER = 0x10000000,
+};
+
+struct hal_frame_rate {
+ enum hal_buffer buffer_type;
+ u32 frame_rate;
+};
+
+enum hal_uncompressed_format {
+ HAL_COLOR_FORMAT_MONOCHROME,
+ HAL_COLOR_FORMAT_NV12,
+ HAL_COLOR_FORMAT_NV21,
+ HAL_COLOR_FORMAT_NV12_4x4TILE,
+ HAL_COLOR_FORMAT_NV21_4x4TILE,
+ HAL_COLOR_FORMAT_YUYV,
+ HAL_COLOR_FORMAT_YVYU,
+ HAL_COLOR_FORMAT_UYVY,
+ HAL_COLOR_FORMAT_VYUY,
+ HAL_COLOR_FORMAT_RGB565,
+ HAL_COLOR_FORMAT_BGR565,
+ HAL_COLOR_FORMAT_RGB888,
+ HAL_COLOR_FORMAT_BGR888,
+ HAL_UNUSED_COLOR = 0x10000000,
+};
+
+struct hal_uncompressed_format_select {
+ enum hal_buffer buffer_type;
+ enum hal_uncompressed_format format;
+};
+
+struct hal_uncompressed_plane_actual {
+ int actual_stride;
+ u32 actual_plane_buffer_height;
+};
+
+struct hal_uncompressed_plane_actual_info {
+ enum hal_buffer buffer_type;
+ u32 num_planes;
+ struct hal_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hal_uncompressed_plane_constraints {
+ u32 stride_multiples;
+ u32 max_stride;
+ u32 min_plane_buffer_height_multiple;
+ u32 buffer_alignment;
+};
+
+struct hal_uncompressed_plane_actual_constraints_info {
+ enum hal_buffer buffer_type;
+ u32 num_planes;
+ struct hal_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hal_extra_data_header_config {
+ u32 type;
+ enum hal_buffer buffer_type;
+ u32 version;
+ u32 port_index;
+ u32 client_extradata_id;
+};
+
+struct hal_frame_size {
+ enum hal_buffer buffer_type;
+ u32 width;
+ u32 height;
+};
+
+struct hal_enable {
+ u32 enable;
+};
+
+struct hal_buffer_count_actual {
+ enum hal_buffer buffer_type;
+ u32 buffer_count_actual;
+};
+
+enum hal_nal_stream_format {
+ HAL_NAL_FORMAT_STARTCODES = 0x00000001,
+ HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002,
+ HAL_NAL_FORMAT_ONE_BYTE_LENGTH = 0x00000004,
+ HAL_NAL_FORMAT_TWO_BYTE_LENGTH = 0x00000008,
+ HAL_NAL_FORMAT_FOUR_BYTE_LENGTH = 0x00000010,
+};
+
+enum hal_output_order {
+ HAL_OUTPUT_ORDER_DISPLAY,
+ HAL_OUTPUT_ORDER_DECODE,
+ HAL_UNUSED_OUTPUT = 0x10000000,
+};
+
+enum hal_picture {
+ HAL_PICTURE_I = 0x01,
+ HAL_PICTURE_P = 0x02,
+ HAL_PICTURE_B = 0x04,
+ HAL_PICTURE_IDR = 0x7F001000,
+ HAL_FRAME_NOTCODED = 0x7F002000,
+ HAL_FRAME_YUV = 0x7F004000,
+ HAL_UNUSED_PICT = 0x10000000,
+};
+
+struct hal_enable_picture {
+ u32 picture_type;
+};
+
+struct hal_multi_stream {
+ enum hal_buffer buffer_type;
+ u32 enable;
+ u32 width;
+ u32 height;
+};
+
+struct hal_display_picture_buffer_count {
+ u32 enable;
+ u32 count;
+};
+
+struct hal_mb_error_map {
+ u32 error_map_size;
+ u8 rg_error_map[1];
+};
+
+struct hal_request_iframe {
+ u32 enable;
+};
+
+struct hal_bitrate {
+ u32 bit_rate;
+};
+
+struct hal_profile_level {
+ u32 profile;
+ u32 level;
+};
+/*
+struct hal_profile_level_range {
+ u32 profile;
+ u32 min_level;
+ u32 max_level;
+}
+
+struct hal_profile_level_supported {
+ u32 profile_count;
+ struct hal_profile_level_range profile_level[1];
+};
+*/
+enum hal_h264_entropy {
+ HAL_H264_ENTROPY_CAVLC,
+ HAL_H264_ENTROPY_CABAC,
+ HAL_UNUSED_ENTROPY = 0x10000000,
+};
+
+enum hal_h264_cabac_model {
+ HAL_H264_CABAC_MODEL_0,
+ HAL_H264_CABAC_MODEL_1,
+ HAL_H264_CABAC_MODEL_2,
+ HAL_UNUSED_CABAC = 0x10000000,
+};
+
+struct hal_h264_entropy_control {
+ enum hal_h264_entropy entropy_mode;
+ enum hal_h264_cabac_model cabac_model;
+};
+
+enum hal_rate_control {
+ HAL_RATE_CONTROL_OFF,
+ HAL_RATE_CONTROL_VBR_VFR,
+ HAL_RATE_CONTROL_VBR_CFR,
+ HAL_RATE_CONTROL_CBR_VFR,
+ HAL_RATE_CONTROL_CBR_CFR,
+ HAL_UNUSED_RC = 0x10000000,
+};
+
+struct hal_mpeg4_time_resolution {
+ u32 time_increment_resolution;
+};
+
+struct hal_mpeg4_header_extension {
+ u32 header_extension;
+};
+
+enum hal_h264_db_mode {
+ HAL_H264_DB_MODE_DISABLE,
+ HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
+ HAL_H264_DB_MODE_ALL_BOUNDARY,
+ HAL_UNUSED_H264_DB = 0x10000000,
+};
+
+struct hal_h264_db_control {
+ enum hal_h264_db_mode mode;
+ int slice_alpha_offset;
+ int slicebeta_offset;
+};
+
+struct hal_temporal_spatial_tradeoff {
+ u32 ts_factor;
+};
+
+struct hal_quantization {
+ u32 qpi;
+ u32 qpp;
+ u32 qpb;
+};
+
+struct hal_intra_period {
+ u32 pframes;
+ u32 bframes;
+};
+
+struct hal_idr_period {
+ u32 idr_period;
+};
+
+enum hal_rotate {
+ HAL_ROTATE_NONE,
+ HAL_ROTATE_90,
+ HAL_ROTATE_180,
+ HAL_ROTATE_270,
+ HAL_UNUSED_ROTATE = 0x10000000,
+};
+
+enum hal_flip {
+ HAL_FLIP_NONE,
+ HAL_FLIP_HORIZONTAL,
+ HAL_FLIP_VERTICAL,
+ HAL_UNUSED_FLIP = 0x10000000,
+};
+
+struct hal_operations {
+ enum hal_rotate rotate;
+ enum hal_flip flip;
+};
+
+enum hal_intra_refresh_mode {
+ HAL_INTRA_REFRESH_NONE,
+ HAL_INTRA_REFRESH_CYCLIC,
+ HAL_INTRA_REFRESH_ADAPTIVE,
+ HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE,
+ HAL_INTRA_REFRESH_RANDOM,
+ HAL_UNUSED_INTRA = 0x10000000,
+};
+
+struct hal_intra_refresh {
+ enum hal_intra_refresh_mode mode;
+ u32 air_mbs;
+ u32 air_ref;
+ u32 cir_mbs;
+};
+
+enum hal_multi_slice {
+ HAL_MULTI_SLICE_OFF,
+ HAL_MULTI_SLICE_BY_MB_COUNT,
+ HAL_MULTI_SLICE_BY_BYTE_COUNT,
+ HAL_MULTI_SLICE_GOB,
+ HAL_UNUSED_SLICE = 0x10000000,
+};
+
+struct hal_multi_slice_control {
+ enum hal_multi_slice multi_slice;
+ u32 slice_size;
+};
+
+struct hal_debug_config {
+ u32 debug_config;
+};
+
+struct hal_buffer_requirements {
+ enum hal_buffer buffer_type;
+ u32 buffer_size;
+ u32 buffer_region_size;
+ u32 buffer_hold_count;
+ u32 buffer_count_min;
+ u32 buffer_count_actual;
+ u32 contiguous;
+ u32 buffer_alignment;
+};
+
+enum hal_priority {/* Priority increases with number */
+ HAL_PRIORITY_LOW = 10,
+ HAL_PRIOIRTY_MEDIUM = 20,
+ HAL_PRIORITY_HIGH = 30,
+ HAL_UNUSED_PRIORITY = 0x10000000,
+};
+
+struct hal_batch_info {
+ u32 input_batch_count;
+ u32 output_batch_count;
+};
+
+struct hal_metadata_pass_through {
+ u32 enable;
+ u32 size;
+};
+
+struct hal_uncompressed_format_supported {
+ enum hal_buffer buffer_type;
+ u32 format_entries;
+ u32 rg_format_info[1];
+};
+
+enum hal_interlace_format {
+ HAL_INTERLACE_FRAME_PROGRESSIVE = 0x01,
+ HAL_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02,
+ HAL_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+ HAL_INTERLACE_FRAME_TOPFIELDFIRST = 0x08,
+ HAL_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10,
+ HAL_UNUSED_INTERLACE = 0x10000000,
+};
+
+struct hal_interlace_format_supported {
+ enum hal_buffer buffer_type;
+ enum hal_interlace_format format;
+};
+
+enum hal_chroma_site {
+ HAL_CHROMA_SITE_0,
+ HAL_CHROMA_SITE_1,
+ HAL_UNUSED_CHROMA = 0x10000000,
+};
+
+struct hal_properties_supported {
+ u32 num_properties;
+ u32 rg_properties[1];
+};
+
+enum hal_capability {
+ HAL_CAPABILITY_FRAME_WIDTH,
+ HAL_CAPABILITY_FRAME_HEIGHT,
+ HAL_CAPABILITY_MBS_PER_FRAME,
+ HAL_CAPABILITY_MBS_PER_SECOND,
+ HAL_CAPABILITY_FRAMERATE,
+ HAL_CAPABILITY_SCALE_X,
+ HAL_CAPABILITY_SCALE_Y,
+ HAL_CAPABILITY_BITRATE,
+ HAL_UNUSED_CAPABILITY = 0x10000000,
+};
+
+struct hal_capability_supported {
+ enum hal_capability capability_type;
+ u32 min;
+ u32 max;
+ u32 step_size;
+};
+
+struct hal_capability_supported_info {
+ u32 num_capabilities;
+ struct hal_capability_supported rg_data[1];
+};
+
+struct hal_nal_stream_format_supported {
+ u32 nal_stream_format_supported;
+};
+
+struct hal_multi_view_format {
+ u32 views;
+ u32 rg_view_order[1];
+};
+
+struct hal_seq_header_info {
+ u32 nax_header_len;
+};
+
+struct hal_codec_supported {
+ u32 decoder_codec_supported;
+ u32 encoder_codec_supported;
+};
+
+struct hal_multi_view_select {
+ u32 view_index;
+};
+
+struct hal_timestamp_scale {
+ u32 time_stamp_scale;
+};
+
+enum vidc_resource_id {
+ VIDC_RESOURCE_OCMEM = 0x00000001,
+ VIDC_UNUSED_RESORUCE = 0x10000000,
+};
+
+struct vidc_resource_hdr {
+ enum vidc_resource_id resource_id;
+ u32 resource_handle;
+ u32 size;
+};
+
+struct vidc_buffer_addr_info {
+ enum hal_buffer buffer_type;
+ u32 buffer_size;
+ u32 num_buffers;
+ u32 align_device_addr;
+ u32 extradata_size;
+ u32 extradata_addr;
+};
+
+struct vidc_frame_plane_config {
+ u32 left;
+ u32 top;
+ u32 width;
+ u32 height;
+ u32 stride;
+ u32 scan_lines;
+};
+
+struct vidc_uncompressed_frame_config {
+ struct vidc_frame_plane_config luma_plane;
+ struct vidc_frame_plane_config chroma_plane;
+};
+
+struct vidc_frame_data {
+ enum hal_buffer buffer_type;
+ u32 device_addr;
+ u32 extradata_addr;
+ int64_t timestamp;
+ u32 flags;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ u32 mark_target;
+ u32 mark_data;
+ u32 clnt_data;
+};
+
+struct vidc_seq_hdr {
+ u8 *seq_hdr;
+ u32 seq_hdr_len;
+};
+
+enum hal_flush {
+ HAL_FLUSH_INPUT,
+ HAL_FLUSH_OUTPUT,
+ HAL_FLUSH_OUTPUT2,
+ HAL_FLUSH_ALL,
+ HAL_UNUSED_FLUSH = 0x10000000,
+};
+
+/* HAL Response */
+
+enum command_response {
+/* SYSTEM COMMANDS_DONE*/
+ VIDC_EVENT_CHANGE,
+ SYS_INIT_DONE,
+ SET_RESOURCE_DONE,
+ RELEASE_RESOURCE_DONE,
+ PING_ACK_DONE,
+ PC_PREP_DONE,
+ SYS_IDLE,
+ SYS_DEBUG,
+/* SESSION COMMANDS_DONE */
+ SESSION_LOAD_RESOURCE_DONE,
+ SESSION_INIT_DONE,
+ SESSION_END_DONE,
+ SESSION_ABORT_DONE,
+ SESSION_START_DONE,
+ SESSION_STOP_DONE,
+ SESSION_ETB_DONE,
+ SESSION_FTB_DONE,
+ SESSION_FLUSH_DONE,
+ SESSION_SUSPEND_DONE,
+ SESSION_RESUME_DONE,
+ SESSION_SET_PROP_DONE,
+ SESSION_GET_PROP_DONE,
+ SESSION_PARSE_SEQ_HDR_DONE,
+ SESSION_GET_SEQ_HDR_DONE,
+ SESSION_RELEASE_BUFFER_DONE,
+ SESSION_RELEASE_RESOURCE_DONE,
+ SESSION_PROPERTY_INFO,
+ RESPONSE_UNUSED = 0x10000000,
+};
+
+/* Command Callback structure */
+
+struct msm_vidc_cb_cmd_done {
+ u32 device_id;
+ u32 session_id;
+ u32 status;
+ u32 size;
+ void *data;
+};
+
+struct msm_vidc_cb_event {
+ u32 device_id;
+ u32 session_id;
+ u32 status;
+ u32 height;
+ u32 width;
+};
+
+/* Data callback structure */
+
+struct vidc_hal_ebd {
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 offset;
+ u32 alloc_len;
+ u32 filled_len;
+ enum hal_picture picture_type;
+ u8 *packet_buffer;
+ u8 *extra_data_buffer;
+};
+
+struct vidc_hal_fbd {
+ u32 stream_id;
+ u32 view_id;
+ u32 timestamp_hi;
+ u32 timestamp_lo;
+ u32 flags1;
+ u32 mark_target;
+ u32 mark_data;
+ u32 stats;
+ u32 alloc_len1;
+ u32 filled_len1;
+ u32 offset1;
+ u32 frame_width;
+ u32 frame_height;
+ u32 start_xCoord;
+ u32 start_yCoord;
+ u32 input_tag;
+ u32 input_tag1;
+ enum hal_picture picture_type;
+ u8 *packet_buffer1;
+ u8 *extra_data_buffer;
+ u32 flags2;
+ u32 alloc_len2;
+ u32 filled_len2;
+ u32 offset2;
+ u8 *packet_buffer2;
+ u32 flags3;
+ u32 alloc_len3;
+ u32 filled_len3;
+ u32 offset3;
+ u8 *packet_buffer3;
+ enum hal_buffer buffer_type;
+};
+
+struct msm_vidc_cb_data_done {
+ u32 device_id;
+ u32 session_id;
+ u32 status;
+ u32 size;
+ void *clnt_data;
+ union {
+ struct vidc_hal_ebd input_done;
+ struct vidc_hal_fbd output_done;
+ };
+};
+
+struct vidc_hal_sys_init_done {
+ u32 enc_codec_supported;
+ u32 dec_codec_supported;
+};
+
+struct vidc_hal_session_init_done {
+ struct hal_capability_supported width;
+ struct hal_capability_supported height;
+ struct hal_capability_supported mbs_per_frame;
+ struct hal_capability_supported mbs_per_sec;
+ struct hal_capability_supported frame_rate;
+ struct hal_capability_supported scale_x;
+ struct hal_capability_supported scale_y;
+ struct hal_capability_supported bitrate;
+ struct hal_uncompressed_format_supported uncomp_format;
+ struct hal_interlace_format_supported HAL_format;
+ struct hal_nal_stream_format_supported nal_stream_format;
+/* struct hal_profile_level_supported profile_level;
+ // allocate and released memory for above. */
+ struct hal_intra_refresh intra_refresh;
+ struct hal_seq_header_info seq_hdr_info;
+};
+
+struct buffer_requirements {
+ struct hal_buffer_requirements buffer[8];
+};
+
+/* VIDC_HAL CORE API's */
+int vidc_hal_core_init(void *device);
+int vidc_hal_core_release(void *device);
+int vidc_hal_core_pc_prep(void *device);
+int vidc_hal_core_set_resource(void *device,
+ struct vidc_resource_hdr *resource_hdr, void *resource_value);
+int vidc_hal_core_release_resource(void *device,
+ struct vidc_resource_hdr *resource_hdr);
+int vidc_hal_core_ping(void *device);
+
+/* VIDC_HAL SESSION API's */
+void *vidc_hal_session_init(void *device, u32 session_id,
+ enum hal_domain session_type, enum hal_video_codec codec_type);
+int vidc_hal_session_end(void *session);
+int vidc_hal_session_abort(void *session);
+int vidc_hal_session_set_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info);
+int vidc_hal_session_release_buffers(void *sess,
+ struct vidc_buffer_addr_info *buffer_info);
+int vidc_hal_session_load_res(void *sess);
+int vidc_hal_session_release_res(void *sess);
+int vidc_hal_session_start(void *sess);
+int vidc_hal_session_stop(void *sess);
+int vidc_hal_session_suspend(void *sess);
+int vidc_hal_session_resume(void *sess);
+int vidc_hal_session_etb(void *sess,
+ struct vidc_frame_data *input_frame);
+int vidc_hal_session_ftb(void *sess,
+ struct vidc_frame_data *output_frame);
+int vidc_hal_session_parse_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr);
+int vidc_hal_session_get_seq_hdr(void *sess,
+ struct vidc_seq_hdr *seq_hdr);
+int vidc_hal_session_get_buf_req(void *sess);
+int vidc_hal_session_flush(void *sess, enum hal_flush flush_mode);
+int vidc_hal_session_set_property(void *sess, enum hal_property ptype,
+ void *pdata);
+int vidc_hal_session_get_property(void *sess, enum hal_property ptype,
+ void *pdata);
+void *vidc_hal_add_device(u32 device_id, u32 base_addr,
+ u32 reg_base, u32 reg_size, u32 irq,
+ void (*callback) (enum command_response cmd, void *data));
+void vidc_hal_delete_device(void *device);
+
+#endif /*__VIDC_HAL_API_H__ */
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
new file mode 100644
index 0000000..cb44d3a
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -0,0 +1,781 @@
+/* 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 <linux/list.h>
+#include "vidc_hal.h"
+
+static enum vidc_status vidc_map_hal_err_status(enum HFI_ERROR hfi_err)
+{
+ enum vidc_status vidc_err;
+ switch (hfi_err) {
+ case HFI_ERR_NONE:
+ case HFI_ERR_SESSION_SAME_STATE_OPERATION:
+ vidc_err = VIDC_ERR_NONE;
+ break;
+ case HFI_ERR_SYS_FATAL:
+ vidc_err = VIDC_ERR_HW_FATAL;
+ break;
+ case HFI_ERR_SYS_VERSION_MISMATCH:
+ case HFI_ERR_SYS_INVALID_PARAMETER:
+ case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE:
+ case HFI_ERR_SESSION_INVALID_PARAMETER:
+ case HFI_ERR_SESSION_INVALID_SESSION_ID:
+ case HFI_ERR_SESSION_INVALID_STREAM_ID:
+ vidc_err = VIDC_ERR_BAD_PARAM;
+ break;
+ case HFI_ERR_SYS_INSUFFICIENT_RESOURCES:
+ case HFI_ERR_SYS_UNSUPPORTED_DOMAIN:
+ case HFI_ERR_SYS_UNSUPPORTED_CODEC:
+ case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY:
+ case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+ case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES:
+ vidc_err = VIDC_ERR_NOT_SUPPORTED;
+ break;
+ case HFI_ERR_SYS_MAX_SESSIONS_REACHED:
+ vidc_err = VIDC_ERR_MAX_CLIENT;
+ break;
+ case HFI_ERR_SYS_SESSION_IN_USE:
+ vidc_err = VIDC_ERR_CLIENT_PRESENT;
+ break;
+ case HFI_ERR_SESSION_FATAL:
+ vidc_err = VIDC_ERR_CLIENT_FATAL;
+ break;
+ case HFI_ERR_SESSION_BAD_POINTER:
+ vidc_err = VIDC_ERR_BAD_PARAM;
+ break;
+ case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION:
+ vidc_err = VIDC_ERR_BAD_STATE;
+ break;
+ case HFI_ERR_SESSION_STREAM_CORRUPT:
+ case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED:
+ vidc_err = VIDC_ERR_BITSTREAM_ERR;
+ break;
+ case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED:
+ vidc_err = VIDC_ERR_IFRAME_EXPECTED;
+ break;
+ case HFI_ERR_SYS_UNKNOWN:
+ case HFI_ERR_SESSION_UNKNOWN:
+ case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING:
+ default:
+ vidc_err = VIDC_ERR_FAIL;
+ break;
+ }
+ return vidc_err;
+}
+
+void hal_process_sess_evt_seq_changed(struct hal_device *device,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct msm_vidc_cb_event event_notify;
+ int num_properties_changed;
+ struct hfi_frame_size frame_sz;
+ u8 *data_ptr;
+ enum HFI_PROPERTY prop_id;
+ HAL_MSG_LOW("RECEIVED:EVENT_NOTIFY");
+ if (sizeof(struct hfi_msg_event_notify_packet)
+ > pkt->size) {
+ HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ memset(&event_notify, 0, sizeof(struct
+ msm_vidc_cb_event));
+
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+ session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.size = sizeof(struct msm_vidc_cb_event);
+ num_properties_changed = pkt->event_data2;
+ if (num_properties_changed) {
+ data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
+ do {
+ prop_id = (enum HFI_PROPERTY) *((u32 *)data_ptr);
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_FRAME_SIZE:
+ frame_sz.buffer =
+ (enum HFI_BUFFER)
+ *((((u32 *)data_ptr)+1));
+ frame_sz.width =
+ event_notify.width =
+ *((((u32 *)data_ptr)+2));
+ frame_sz.height =
+ event_notify.height =
+ *((((u32 *)data_ptr)+3));
+ data_ptr += 4;
+ break;
+ default:
+ break;
+ }
+ num_properties_changed--;
+ } while (num_properties_changed > 0);
+ }
+ cmd_done.data = &event_notify;
+ device->callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
+static void hal_process_event_notify(struct hal_device *device,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ HAL_MSG_LOW("RECVD:EVENT_NOTIFY");
+
+ if (!device || !pkt ||
+ pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return;
+ }
+
+ switch (pkt->event_id) {
+ case HFI_EVENT_SYS_ERROR:
+ HAL_MSG_INFO("HFI_EVENT_SYS_ERROR");
+ break;
+ case HFI_EVENT_SESSION_ERROR:
+ HAL_MSG_INFO("HFI_EVENT_SESSION_ERROR");
+ break;
+ case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
+ HAL_MSG_INFO("HFI_EVENT_SESSION_SEQUENCE_CHANGED");
+ hal_process_sess_evt_seq_changed(device, pkt);
+ break;
+ case HFI_EVENT_SESSION_PROPERTY_CHANGED:
+ HAL_MSG_INFO("HFI_EVENT_SESSION_PROPERTY_CHANGED");
+ break;
+ default:
+ HAL_MSG_INFO("hal_process_event_notify:unkown_event_id");
+ break;
+ }
+}
+
+static void hal_process_sys_init_done(struct hal_device *device,
+ struct hfi_msg_sys_init_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct vidc_hal_sys_init_done sys_init_done;
+ u32 rem_bytes, bytes_read = 0, num_properties;
+ u8 *data_ptr;
+ enum HFI_PROPERTY prop_id;
+ enum vidc_status status = VIDC_ERR_NONE;
+
+ HAL_MSG_LOW("RECEIVED:SYS_INIT_DONE");
+ if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) {
+ HAL_MSG_ERROR("hal_process_sys_init_done:bad_pkt_size: %d",
+ pkt->size);
+ return;
+ }
+
+ status = vidc_map_hal_err_status((u32)pkt->error_type);
+
+ if (!status) {
+ if (pkt->num_properties == 0) {
+ HAL_MSG_ERROR("hal_process_sys_init_done:"
+ "no_properties");
+ status = VIDC_ERR_FAIL;
+ goto err_no_prop;
+ }
+
+ rem_bytes = pkt->size - sizeof(struct
+ hfi_msg_sys_init_done_packet) + sizeof(u32);
+
+ if (rem_bytes == 0) {
+ HAL_MSG_ERROR("hal_process_sys_init_done:"
+ "missing_prop_info");
+ status = VIDC_ERR_FAIL;
+ goto err_no_prop;
+ }
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ memset(&sys_init_done, 0, sizeof(struct
+ vidc_hal_sys_init_done));
+
+ data_ptr = (u8 *) &pkt->rg_property_data[0];
+ num_properties = pkt->num_properties;
+
+ while ((num_properties != 0) && (rem_bytes >= sizeof(u32))) {
+ prop_id = (enum HFI_PROPERTY) *((u32 *)data_ptr);
+ data_ptr = data_ptr + 4;
+
+ switch (prop_id) {
+ case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
+ {
+ struct hfi_codec_supported *prop =
+ (struct hfi_codec_supported *) data_ptr;
+ if (rem_bytes < sizeof(struct
+ hfi_codec_supported)) {
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ sys_init_done.dec_codec_supported =
+ prop->decoder_codec_supported;
+ sys_init_done.enc_codec_supported =
+ prop->encoder_codec_supported;
+ break;
+ }
+ default:
+ HAL_MSG_ERROR("hal_process_sys_init_done:"
+ "bad_prop_id");
+ status = VIDC_ERR_BAD_PARAM;
+ break;
+ }
+ if (!status) {
+ rem_bytes -= bytes_read;
+ data_ptr += bytes_read;
+ num_properties--;
+ }
+ }
+ }
+err_no_prop:
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id = 0;
+ cmd_done.status = (u32) status;
+ cmd_done.size = sizeof(struct vidc_hal_sys_init_done);
+ cmd_done.data = (void *) &sys_init_done;
+ device->callback(SYS_INIT_DONE, &cmd_done);
+}
+
+enum vidc_status vidc_hal_process_sess_init_done_prop_read(
+ struct hfi_msg_sys_session_init_done_packet *pkt,
+ struct msm_vidc_cb_cmd_done *cmddone)
+{
+ return VIDC_ERR_NONE;
+}
+
+static void hal_process_sess_get_prop_buf_req(
+ struct hfi_msg_session_property_info_packet *prop,
+ struct buffer_requirements *buffreq)
+{
+ struct hfi_buffer_requirements *hfi_buf_req;
+ u32 req_bytes;
+ enum vidc_status rc = VIDC_ERR_NONE;
+
+ HAL_MSG_LOW("Entered %s", __func__);
+ req_bytes = prop->size - sizeof(
+ struct hfi_msg_session_property_info_packet);
+
+ if (req_bytes == 0 || (req_bytes % sizeof(
+ struct hfi_buffer_requirements))) {
+ HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:bad_pkt_size:"
+ " %d", req_bytes);
+ return;
+ }
+
+ hfi_buf_req = (struct hfi_buffer_requirements *)
+ &prop->rg_property_data[1];
+
+ while (req_bytes != 0) {
+ if ((hfi_buf_req->buffer_count_min > hfi_buf_req->
+ buffer_count_actual)
+ || (hfi_buf_req->buffer_alignment == 0)
+ || (hfi_buf_req->buffer_size == 0)) {
+ HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:"
+ "bad_buf_req");
+ rc = VIDC_ERR_FAIL;
+ }
+ HAL_MSG_LOW("got buffer requirements for: %d",
+ hfi_buf_req->buffer);
+ switch (hfi_buf_req->buffer) {
+ case HFI_BUFFER_INPUT:
+ memcpy(&buffreq->buffer[0], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[0].buffer_type = HAL_BUFFER_INPUT;
+ break;
+ case HFI_BUFFER_OUTPUT:
+ memcpy(&buffreq->buffer[1], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[1].buffer_type = HAL_BUFFER_OUTPUT;
+ break;
+ case HFI_BUFFER_OUTPUT2:
+ memcpy(&buffreq->buffer[2], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[2].buffer_type = HAL_BUFFER_OUTPUT2;
+ break;
+ case HFI_BUFFER_EXTRADATA_INPUT:
+ memcpy(&buffreq->buffer[3], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[3].buffer_type =
+ HAL_BUFFER_EXTRADATA_INPUT;
+ break;
+ case HFI_BUFFER_EXTRADATA_OUTPUT:
+ memcpy(&buffreq->buffer[4], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[4].buffer_type =
+ HAL_BUFFER_EXTRADATA_OUTPUT;
+ break;
+ case HFI_BUFFER_EXTRADATA_OUTPUT2:
+ memcpy(&buffreq->buffer[5], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[5].buffer_type =
+ HAL_BUFFER_EXTRADATA_OUTPUT2;
+ break;
+ case HFI_BUFFER_INTERNAL_SCRATCH:
+ memcpy(&buffreq->buffer[6], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[6].buffer_type =
+ HAL_BUFFER_INTERNAL_SCRATCH;
+ break;
+ case HFI_BUFFER_INTERNAL_PERSIST:
+ memcpy(&buffreq->buffer[7], hfi_buf_req,
+ sizeof(struct hfi_buffer_requirements));
+ buffreq->buffer[7].buffer_type =
+ HAL_BUFFER_INTERNAL_PERSIST;
+ break;
+ default:
+ HAL_MSG_ERROR("hal_process_sess_get_prop_buf_req:"
+ "bad_buffer_type: %d", hfi_buf_req->buffer);
+ break;
+ }
+ req_bytes -= sizeof(struct hfi_buffer_requirements);
+ hfi_buf_req++;
+ }
+}
+
+static void hal_process_session_prop_info(struct hal_device *device,
+ struct hfi_msg_session_property_info_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct buffer_requirements buff_req;
+
+ HAL_MSG_INFO("Received SESSION_PROPERTY_INFO");
+
+ if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
+ HAL_MSG_ERROR("hal_process_session_prop_info:bad_pkt_size");
+ return;
+ }
+
+ if (pkt->num_properties == 0) {
+ HAL_MSG_ERROR("hal_process_session_prop_info:no_properties");
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ memset(&buff_req, 0, sizeof(struct buffer_requirements));
+
+ switch (pkt->rg_property_data[0]) {
+ case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+ hal_process_sess_get_prop_buf_req(pkt, &buff_req);
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.data = &buff_req;
+ cmd_done.size = sizeof(struct buffer_requirements);
+ device->callback(SESSION_PROPERTY_INFO, &cmd_done);
+ break;
+ default:
+ HAL_MSG_ERROR("hal_process_session_prop_info:"
+ "unknown_prop_id: %d",
+ pkt->rg_property_data[0]);
+ break;
+ }
+}
+
+static void hal_process_session_init_done(struct hal_device *device,
+ struct hfi_msg_sys_session_init_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct vidc_hal_session_init_done session_init_done;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_INIT_DONE");
+ if (sizeof(struct hfi_msg_sys_session_init_done_packet)
+ > pkt->size) {
+ HAL_MSG_ERROR("hal_process_session_init_done:bad_pkt_size");
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ memset(&session_init_done, 0, sizeof(struct
+ vidc_hal_session_init_done));
+
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = &session_init_done;
+ if (!cmd_done.status) {
+ cmd_done.status = vidc_hal_process_sess_init_done_prop_read(
+ pkt, &cmd_done);
+ }
+ cmd_done.size = sizeof(struct vidc_hal_session_init_done);
+ device->callback(SESSION_INIT_DONE, &cmd_done);
+}
+
+static void hal_process_session_load_res_done(struct hal_device *device,
+ struct hfi_msg_session_load_resources_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ HAL_MSG_LOW("RECEIVED:SESSION_LOAD_RESOURCES_DONE");
+
+ if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
+ pkt->size) {
+ HAL_MSG_ERROR("hal_process_session_load_res_done:"
+ " bad packet size: %d", pkt->size);
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ device->callback(SESSION_LOAD_RESOURCE_DONE, &cmd_done);
+}
+
+static void hal_process_session_flush_done(struct hal_device *device,
+ struct hfi_msg_session_flush_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_FLUSH_DONE");
+
+ if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
+ HAL_MSG_ERROR("hal_process_session_flush_done: "
+ "bad packet size: %d", pkt->size);
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = (void *) pkt->flush_type;
+ cmd_done.size = sizeof(u32);
+ device->callback(SESSION_FLUSH_DONE, &cmd_done);
+}
+
+static void hal_process_session_etb_done(struct hal_device *device,
+ struct hfi_msg_session_empty_buffer_done_packet *pkt)
+{
+ struct msm_vidc_cb_data_done data_done;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_ETB_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
+ HAL_MSG_ERROR("hal_process_session_etb_done:bad_pkt_size");
+ return;
+ }
+
+ memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
+
+ data_done.device_id = device->device_id;
+ data_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ data_done.status = vidc_map_hal_err_status((u32) pkt->error_type);
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.clnt_data = (void *)pkt->input_tag;
+ data_done.input_done.offset = pkt->offset;
+ data_done.input_done.filled_len = pkt->filled_len;
+ data_done.input_done.packet_buffer = pkt->packet_buffer;
+ device->callback(SESSION_ETB_DONE, &data_done);
+}
+
+static void hal_process_session_ftb_done(struct hal_device *device,
+ void *msg_hdr)
+{
+ struct msm_vidc_cb_data_done data_done;
+ struct hfi_msg_session_fill_buffer_done_compressed_packet *pack =
+ (struct hfi_msg_session_fill_buffer_done_compressed_packet *) msg_hdr;
+ u32 is_decoder = ((struct hal_session *)pack->session_id)->is_decoder;
+ struct hal_session *session;
+
+ if (!msg_hdr) {
+ HAL_MSG_ERROR("Invalid Params in %s", __func__);
+ return;
+ }
+
+ session = (struct hal_session *)
+ ((struct hal_session *) pack->session_id)->session_id;
+ HAL_MSG_ERROR("RECEIVED:SESSION_FTB_DONE");
+
+ memset(&data_done, 0, sizeof(struct msm_vidc_cb_data_done));
+
+ if (is_decoder == 0) {
+ struct hfi_msg_session_fill_buffer_done_compressed_packet *pkt =
+ (struct hfi_msg_session_fill_buffer_done_compressed_packet *)
+ msg_hdr;
+ if (sizeof(struct
+ hfi_msg_session_fill_buffer_done_compressed_packet)
+ != pkt->size) {
+ HAL_MSG_ERROR("hal_process_session_ftb_done:"
+ "bad_pkt_size");
+ return;
+ }
+
+ data_done.device_id = device->device_id;
+ data_done.session_id = (u32) session;
+ data_done.status = vidc_map_hal_err_status((u32)
+ pkt->error_type);
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.clnt_data = (void *) pkt->input_tag;
+
+ data_done.output_done.timestamp_hi = pkt->timestamp_hi;
+ data_done.output_done.timestamp_lo = pkt->timestamp_lo;
+ data_done.output_done.flags1 = pkt->flags;
+ data_done.output_done.mark_target = pkt->mark_target;
+ data_done.output_done.mark_data = pkt->mark_data;
+ data_done.output_done.stats = pkt->stats;
+ data_done.output_done.offset1 = pkt->offset;
+ data_done.output_done.alloc_len1 = pkt->alloc_len;
+ data_done.output_done.filled_len1 = pkt->filled_len;
+ data_done.output_done.picture_type = pkt->picture_type;
+ data_done.output_done.packet_buffer1 = pkt->packet_buffer;
+ data_done.output_done.extra_data_buffer =
+ pkt->extra_data_buffer;
+ } else if (is_decoder == 1) {
+ struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
+ (struct hfi_msg_session_fbd_uncompressed_plane0_packet *)
+ msg_hdr;
+ if (sizeof(struct
+ hfi_msg_session_fbd_uncompressed_plane0_packet)
+ > pkt->size) {
+ HAL_MSG_ERROR("hal_process_session_ftb_done:"
+ "bad_pkt_size");
+ return;
+ }
+
+ data_done.device_id = device->device_id;
+ data_done.session_id = (u32) session;
+ data_done.status = vidc_map_hal_err_status((u32)
+ pkt->error_type);
+ data_done.size = sizeof(struct msm_vidc_cb_data_done);
+ data_done.clnt_data = (void *)pkt->input_tag;
+
+ data_done.output_done.stream_id = pkt->stream_id;
+ data_done.output_done.view_id = pkt->view_id;
+ data_done.output_done.timestamp_hi = pkt->timestamp_hi;
+ data_done.output_done.timestamp_lo = pkt->timestamp_lo;
+ data_done.output_done.flags1 = pkt->flags;
+ data_done.output_done.mark_target = pkt->mark_target;
+ data_done.output_done.mark_data = pkt->mark_data;
+ data_done.output_done.stats = pkt->stats;
+ data_done.output_done.alloc_len1 = pkt->alloc_len;
+ data_done.output_done.filled_len1 = pkt->filled_len;
+ data_done.output_done.offset1 = pkt->oofset;
+ data_done.output_done.frame_width = pkt->frame_width;
+ data_done.output_done.frame_height = pkt->frame_height;
+ data_done.output_done.start_xCoord = pkt->start_xCoord;
+ data_done.output_done.start_yCoord = pkt->start_yCoord;
+ data_done.output_done.input_tag1 = pkt->input_tag1;
+ data_done.output_done.picture_type = pkt->picture_type;
+ data_done.output_done.packet_buffer1 = pkt->packet_buffer;
+ data_done.output_done.extra_data_buffer =
+ pkt->extra_data_buffer;
+
+ if (pkt->stream_id == 0)
+ data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+ else if (pkt->stream_id == 1)
+ data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2;
+ }
+ device->callback(SESSION_FTB_DONE, &data_done);
+}
+
+static void hal_process_session_start_done(struct hal_device *device,
+ struct hfi_msg_session_start_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_START_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_start_done_packet)) {
+ HAL_MSG_ERROR("hal_process_session_start_done:"
+ "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ device->callback(SESSION_START_DONE, &cmd_done);
+}
+
+static void hal_process_session_stop_done(struct hal_device *device,
+ struct hfi_msg_session_stop_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_STOP_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_stop_done_packet)) {
+ HAL_MSG_ERROR("hal_process_session_stop_done:"
+ "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ device->callback(SESSION_STOP_DONE, &cmd_done);
+}
+
+static void hal_process_session_rel_res_done(struct hal_device *device,
+ struct hfi_msg_session_release_resources_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_RELEASE_RESOURCES_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_session_release_resources_done_packet)) {
+ HAL_MSG_ERROR("hal_process_session_rel_res_done:"
+ "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ device->callback(SESSION_RELEASE_RESOURCE_DONE, &cmd_done);
+}
+
+static void hal_process_session_end_done(struct hal_device *device,
+ struct hfi_msg_sys_session_end_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct list_head *curr, *next;
+ struct hal_session *sess_close;
+
+ HAL_MSG_LOW("RECEIVED:SESSION_END_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_sys_session_end_done_packet)) {
+ HAL_MSG_ERROR("hal_process_session_end_done: "
+ "bad packet/packet size: %d", pkt->size);
+ return;
+ }
+
+ list_for_each_safe(curr, next, &device->sess_head) {
+ sess_close = list_entry(curr, struct hal_session, list);
+ HAL_MSG_MEDIUM("deleted the session: 0x%x",
+ sess_close->session_id);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ }
+
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device->device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = vidc_map_hal_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+ device->callback(SESSION_END_DONE, &cmd_done);
+}
+
+static void hal_process_msg_packet(struct hal_device *device,
+ struct vidc_hal_msg_pkt_hdr *msg_hdr)
+{
+ if (!device || !msg_hdr || msg_hdr->size <
+ VIDC_IFACEQ_MIN_PKT_SIZE) {
+ HAL_MSG_ERROR("hal_process_msg_packet:bad"
+ "packet/packet size: %d", msg_hdr->size);
+ return;
+ }
+
+ HAL_MSG_INFO("Received: 0x%x in %s", msg_hdr->packet, __func__);
+
+ switch (msg_hdr->packet) {
+ case HFI_MSG_EVENT_NOTIFY:
+ hal_process_event_notify(device,
+ (struct hfi_msg_event_notify_packet *) msg_hdr);
+ break;
+ case HFI_MSG_SYS_INIT_DONE:
+ hal_process_sys_init_done(device,
+ (struct hfi_msg_sys_init_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SYS_SESSION_INIT_DONE:
+ hal_process_session_init_done(device,
+ (struct hfi_msg_sys_session_init_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SYS_SESSION_END_DONE:
+ hal_process_session_end_done(device,
+ (struct hfi_msg_sys_session_end_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
+ hal_process_session_load_res_done(device,
+ (struct hfi_msg_session_load_resources_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_START_DONE:
+ hal_process_session_start_done(device,
+ (struct hfi_msg_session_start_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_STOP_DONE:
+ hal_process_session_stop_done(device,
+ (struct hfi_msg_session_stop_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+ hal_process_session_etb_done(device,
+ (struct hfi_msg_session_empty_buffer_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+ hal_process_session_ftb_done(device, msg_hdr);
+ break;
+ case HFI_MSG_SESSION_FLUSH_DONE:
+ hal_process_session_flush_done(device,
+ (struct hfi_msg_session_flush_done_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_PROPERTY_INFO:
+ hal_process_session_prop_info(device,
+ (struct hfi_msg_session_property_info_packet *)
+ msg_hdr);
+ break;
+ case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
+ hal_process_session_rel_res_done(device,
+ (struct hfi_msg_session_release_resources_done_packet *)
+ msg_hdr);
+ break;
+ default:
+ HAL_MSG_ERROR("UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
+ break;
+ }
+}
+
+void vidc_hal_response_handler(struct hal_device *device)
+{
+ u8 packet[VIDC_IFACEQ_MED_PKT_SIZE];
+
+ HAL_MSG_INFO("############vidc_hal_response_handler\n");
+ if (device) {
+ while (!vidc_hal_iface_msgq_read(device, packet)) {
+ hal_process_msg_packet(device,
+ (struct vidc_hal_msg_pkt_hdr *) packet);
+ }
+ } else {
+ HAL_MSG_ERROR("SPURIOUS_INTERRUPT");
+ }
+}
diff --git a/drivers/media/video/msm_vidc/vidc_hal_io.h b/drivers/media/video/msm_vidc/vidc_hal_io.h
new file mode 100644
index 0000000..05a4c60
--- /dev/null
+++ b/drivers/media/video/msm_vidc/vidc_hal_io.h
@@ -0,0 +1,103 @@
+/* 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 __VIDCHALIO_H__
+#define __VIDCHALIO_H__
+
+#include <linux/io.h>
+
+#define VIDC_VBIF_BASE_OFFS 0x00080000
+#define VIDC_VBIF_VERSION (VIDC_VBIF_BASE_OFFS + 0x00)
+#define VIDC_VBIF_ADDR_TRANS_EN (VIDC_VBIF_BASE_OFFS + 0x10)
+#define VIDC_VBIF_AT_OLD_BASE (VIDC_VBIF_BASE_OFFS + 0x14)
+#define VIDC_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0x18)
+#define VIDC_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0x20)
+#define VIDC_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0x28)
+
+#define VIDC_CPU_BASE_OFFS 0x000C0000
+#define VIDC_CPU_CS_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x00012000)
+#define VIDC_CPU_IC_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x0001F000)
+
+#define VIDC_CPU_CS_REMAP_OFFS (VIDC_CPU_CS_BASE_OFFS + 0x00)
+#define VIDC_CPU_CS_TIMER_CONTROL (VIDC_CPU_CS_BASE_OFFS + 0x04)
+#define VIDC_CPU_CS_A2HSOFTINTEN (VIDC_CPU_CS_BASE_OFFS + 0x10)
+#define VIDC_CPU_CS_A2HSOFTINTENCLR (VIDC_CPU_CS_BASE_OFFS + 0x14)
+#define VIDC_CPU_CS_A2HSOFTINT (VIDC_CPU_CS_BASE_OFFS + 0x18)
+#define VIDC_CPU_CS_A2HSOFTINTCLR (VIDC_CPU_CS_BASE_OFFS + 0x1C)
+#define VIDC_CPU_CS_SCIACMD (VIDC_CPU_CS_BASE_OFFS + 0x48)
+
+/* HFI_CTRL_STATUS */
+#define VIDC_CPU_CS_SCIACMDARG0 (VIDC_CPU_CS_BASE_OFFS + 0x4C)
+#define VIDC_CPU_CS_SCIACMDARG0_BMSK 0xff
+#define VIDC_CPU_CS_SCIACMDARG0_SHFT 0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK 0xfe
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT 0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK 0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT 0x0
+
+/* HFI_QTBL_INFO */
+#define VIDC_CPU_CS_SCIACMDARG1 (VIDC_CPU_CS_BASE_OFFS + 0x50)
+
+/* HFI_QTBL_ADDR */
+#define VIDC_CPU_CS_SCIACMDARG2 (VIDC_CPU_CS_BASE_OFFS + 0x54)
+
+/* HFI_VERSION_INFO */
+#define VIDC_CPU_CS_SCIACMDARG3 (VIDC_CPU_CS_BASE_OFFS + 0x58)
+#define VIDC_CPU_IC_IRQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x00)
+#define VIDC_CPU_IC_FIQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x04)
+#define VIDC_CPU_IC_RAWINTR (VIDC_CPU_IC_BASE_OFFS + 0x08)
+#define VIDC_CPU_IC_INTSELECT (VIDC_CPU_IC_BASE_OFFS + 0x0C)
+#define VIDC_CPU_IC_INTENABLE (VIDC_CPU_IC_BASE_OFFS + 0x10)
+#define VIDC_CPU_IC_INTENACLEAR (VIDC_CPU_IC_BASE_OFFS + 0x14)
+#define VIDC_CPU_IC_SOFTINT (VIDC_CPU_IC_BASE_OFFS + 0x18)
+#define VIDC_CPU_IC_SOFTINT_H2A_BMSK 0x8000
+#define VIDC_CPU_IC_SOFTINT_H2A_SHFT 0xF
+#define VIDC_CPU_IC_SOFTINTCLEAR (VIDC_CPU_IC_BASE_OFFS + 0x1C)
+
+/*---------------------------------------------------------------------------
+ * MODULE: vidc_wrapper
+ *--------------------------------------------------------------------------*/
+#define VIDC_WRAPPER_BASE_OFFS 0x000E0000
+
+#define VIDC_WRAPPER_HW_VERSION (VIDC_WRAPPER_BASE_OFFS + 0x00)
+#define VIDC_WRAPPER_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x04)
+
+#define VIDC_WRAPPER_INTR_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x0C)
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK 0x10
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT 0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK 0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT 0x2
+
+#define VIDC_WRAPPER_INTR_MASK (VIDC_WRAPPER_BASE_OFFS + 0x10)
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK 0x10
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT 0x4
+#define VIDC_WRAPPER_INTR_MASK_A2H_BMSK 0x4
+#define VIDC_WRAPPER_INTR_MASK_A2H_SHFT 0x2
+
+#define VIDC_WRAPPER_INTR_CLEAR (VIDC_WRAPPER_BASE_OFFS + 0x14)
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK 0x10
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT 0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK 0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT 0x2
+
+#define VIDC_WRAPPER_VBIF_XIN_SW_RESET (VIDC_WRAPPER_BASE_OFFS + 0x18)
+#define VIDC_WRAPPER_VBIF_XIN_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x1C)
+#define VIDC_WRAPPER_CPU_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x2000)
+#define VIDC_WRAPPER_VBIF_XIN_CPU_SW_RESET \
+ (VIDC_WRAPPER_BASE_OFFS + 0x2004)
+#define VIDC_WRAPPER_AXI_HALT (VIDC_WRAPPER_BASE_OFFS + 0x2008)
+#define VIDC_WRAPPER_AXI_HALT_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x200C)
+#define VIDC_WRAPPER_CPU_CGC_DIS (VIDC_WRAPPER_BASE_OFFS + 0x2010)
+
+#endif
+
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index deb35cc..737b726 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -958,6 +958,8 @@
case VIDIOC_G_ENC_INDEX:
case VIDIOC_ENCODER_CMD:
case VIDIOC_TRY_ENCODER_CMD:
+ case VIDIOC_DECODER_CMD:
+ case VIDIOC_TRY_DECODER_CMD:
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_DBG_G_CHIP_IDENT:
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 2412f08..f915a94 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -216,6 +216,69 @@
"75 useconds",
NULL,
};
+ static const char *const h264_video_entropy_mode[] = {
+ "CAVLC",
+ "CABAC",
+ NULL
+ };
+ static const char *const mpeg_video_slice_mode[] = {
+ "Single Slice Mode",
+ "MB Based Slice",
+ "Byte Based Slice",
+ NULL
+ };
+ static const char *const h264_video_profile[] = {
+ "Baseline Profile",
+ "Constrained Baseline Profile",
+ "Main Profile",
+ "Extended Profile",
+ "High Profile",
+ "High Profile 10",
+ "High Profile 422",
+ "High Profile 444 Predicitve",
+ "High Profile 10 Intra",
+ "High Profile 422 Intra",
+ "High Profile 444 Intra",
+ "CAVLC Profile 444 Intra",
+ "Scalable Baseline Profile",
+ "Scalable high Profile",
+ "Scalable High Intra Profile",
+ "Stereo High Profile",
+ "Multiview High Profile",
+ NULL
+ };
+ static const char *const h264_video_level[] = {
+ "Level 1 0",
+ "Level 1 B",
+ "Level 1 1",
+ "Level 1 2",
+ "Level 1 3",
+ "Level 2 0",
+ "Level 2 1",
+ "Level 2 2",
+ "Level 3 0",
+ "Level 3 1",
+ "Level 3 2",
+ "Level 4 0",
+ "Level 4 1",
+ "Level 4 2",
+ "Level 5 0",
+ "Level 5 1",
+ NULL
+ };
+ static const char *const mpeg_video_intra_refresh_mode[] = {
+ "No Intra Refresh",
+ "AIR MBS",
+ "AIR REF",
+ "CIR MBS",
+ NULL
+ };
+ static const char *const h264_loop_filter_mode[] = {
+ "Ebnabled",
+ "Disabled",
+ "Disabled At Slice Boundary",
+ NULL
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -256,6 +319,18 @@
return colorfx;
case V4L2_CID_TUNE_PREEMPHASIS:
return tune_preemphasis;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ return h264_video_entropy_mode;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ return h264_video_profile;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ return h264_video_level;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ return mpeg_video_slice_mode;
+ case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE:
+ return mpeg_video_intra_refresh_mode;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ return h264_loop_filter_mode;
default:
return NULL;
}
@@ -343,6 +418,30 @@
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: return "Entropy Mode";
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE: return "H264 Profile";
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL: return "H264 Level";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: return "Slice Mode";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: return "Slice MB Size";
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ return "Slice Byte Size";
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: return "I Frame Quantization";
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: return "P Frame Quantization";
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: return "B Frame Quantization";
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION: return "Rotation";
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL: return "Rate Control";
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL: return "CABAC Model";
+ case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE:
+ return "Intra Refresh Mode";
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: return "Intra Refresh AIR MBS";
+ case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: return "Intra Refresh AIR REF";
+ case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: return "Intra Refresh CIR MBS";
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ return "H.264 Loop Filter Mode";
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ return "H.264 Loop Filter Beta Offset";
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ return "H.264 Loop Filter Alpha Offset";
/* CAMERA controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -452,6 +551,13 @@
case V4L2_CID_EXPOSURE_AUTO:
case V4L2_CID_COLORFX:
case V4L2_CID_TUNE_PREEMPHASIS:
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+ case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
*type = V4L2_CTRL_TYPE_MENU;
break;
case V4L2_CID_RDS_TX_PS_NAME:
@@ -468,7 +574,12 @@
*min = *max = *step = *def = 0;
break;
case V4L2_CID_BG_COLOR:
- *type = V4L2_CTRL_TYPE_INTEGER;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ *type = V4L2_CTRL_TYPE_INTEGER;
*step = 1;
*min = 0;
/* Max is calculated as RGB888 that is 2^24 */
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5e44c90..d64ecb5 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -244,6 +244,8 @@
[_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
[_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
+ [_IOC_NR(VIDIOC_DECODER_CMD)] = "VIDIOC_DECODER_CMD",
+ [_IOC_NR(VIDIOC_TRY_DECODER_CMD)] = "VIDIOC_TRY_DECODER_CMD",
[_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
[_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
@@ -1775,6 +1777,28 @@
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
break;
}
+ case VIDIOC_DECODER_CMD:
+ {
+ struct v4l2_decoder_cmd *p = arg;
+
+ if (!ops->vidioc_decoder_cmd)
+ break;
+ ret = ops->vidioc_decoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+ break;
+ }
+ case VIDIOC_TRY_DECODER_CMD:
+ {
+ struct v4l2_decoder_cmd *p = arg;
+
+ if (!ops->vidioc_try_decoder_cmd)
+ break;
+ ret = ops->vidioc_try_decoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
+ break;
+ }
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *p = arg;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 2a25089..b128a61 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -41,7 +41,7 @@
};
struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf;
+static int wcd9xxx_intf = -1;
static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface_reg)
@@ -331,17 +331,35 @@
pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
idbyte_0, idbyte_1, idbyte_2, idbyte_3);
- if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+ if (wcd9xxx->slim != NULL) {
+ if (!strncmp(wcd9xxx->slim->name, "tabla", 5)) {
+ if (TABLA_IS_1_X(wcd9xxx->version)) {
+ wcd9xxx_dev = tabla1x_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
+ } else {
+ wcd9xxx_dev = tabla_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+ }
+ } else {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+ }
+ } else {
+ /* Need to add here check for Tabla.
+ * For now the read of version takes
+ * care of now only tabla.
+ */
+ pr_debug("%s : Read codec version using I2C\n", __func__);
if (TABLA_IS_1_X(wcd9xxx->version)) {
wcd9xxx_dev = tabla1x_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
- } else {
+ } else if (TABLA_IS_2_0(wcd9xxx->version)) {
wcd9xxx_dev = tabla_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
+ } else {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
- } else {
- wcd9xxx_dev = sitar_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
ret = mfd_add_devices(wcd9xxx->dev, -1,
@@ -372,7 +390,8 @@
wake_lock_destroy(&wcd9xxx->wlock);
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
- slim_remove_device(wcd9xxx->slim_slave);
+ if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ slim_remove_device(wcd9xxx->slim_slave);
kfree(wcd9xxx);
}
@@ -478,12 +497,11 @@
};
#endif
-static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_enable_supplies(struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_pdata *pdata)
{
int ret;
int i;
- struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
-
wcd9xxx->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
ARRAY_SIZE(pdata->regulator),
GFP_KERNEL);
@@ -546,10 +564,10 @@
return ret;
}
-static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_pdata *pdata)
{
int i;
- struct wcd9xxx_pdata *pdata = wcd9xxx->slim->dev.platform_data;
regulator_bulk_disable(ARRAY_SIZE(pdata->regulator),
wcd9xxx->supplies);
@@ -695,6 +713,10 @@
int ret = 0;
static int device_id;
+ if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ pr_info("tabla card is already detected in slimbus mode\n");
+ return -ENODEV;
+ }
if (device_id > 0) {
wcd9xxx_modules[device_id++].client = client;
pr_info("probe for other slaves devices of tabla\n");
@@ -721,8 +743,7 @@
dev_set_drvdata(&client->dev, wcd9xxx);
wcd9xxx->dev = &client->dev;
wcd9xxx->reset_gpio = pdata->reset_gpio;
-
- ret = wcd9xxx_enable_supplies(wcd9xxx);
+ ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret) {
pr_err("%s: Fail to enable Codec supplies\n", __func__);
goto err_codec;
@@ -759,7 +780,7 @@
err_device_init:
wcd9xxx_free_reset(wcd9xxx);
err_supplies:
- wcd9xxx_disable_supplies(wcd9xxx);
+ wcd9xxx_disable_supplies(wcd9xxx, pdata);
err_codec:
kfree(wcd9xxx);
fail:
@@ -769,10 +790,10 @@
static int __devexit wcd9xxx_i2c_remove(struct i2c_client *client)
{
struct wcd9xxx *wcd9xxx;
-
+ struct wcd9xxx_pdata *pdata = client->dev.platform_data;
pr_debug("exit\n");
wcd9xxx = dev_get_drvdata(&client->dev);
- wcd9xxx_disable_supplies(wcd9xxx);
+ wcd9xxx_disable_supplies(wcd9xxx, pdata);
wcd9xxx_device_exit(wcd9xxx);
return 0;
}
@@ -809,7 +830,7 @@
wcd9xxx->reset_gpio = pdata->reset_gpio;
wcd9xxx->dev = &slim->dev;
- ret = wcd9xxx_enable_supplies(wcd9xxx);
+ ret = wcd9xxx_enable_supplies(wcd9xxx, pdata);
if (ret)
goto err_codec;
usleep_range(5, 5);
@@ -901,7 +922,7 @@
err_reset:
wcd9xxx_free_reset(wcd9xxx);
err_supplies:
- wcd9xxx_disable_supplies(wcd9xxx);
+ wcd9xxx_disable_supplies(wcd9xxx, pdata);
err_codec:
kfree(wcd9xxx);
err:
@@ -910,6 +931,7 @@
static int wcd9xxx_slim_remove(struct slim_device *pdev)
{
struct wcd9xxx *wcd9xxx;
+ struct wcd9xxx_pdata *pdata = pdev->dev.platform_data;
#ifdef CONFIG_DEBUG_FS
debugfs_remove(debugfs_peek);
@@ -919,7 +941,7 @@
wcd9xxx = slim_get_devicedata(pdev);
wcd9xxx_deinit_slimslave(wcd9xxx);
slim_remove_device(wcd9xxx->slim_slave);
- wcd9xxx_disable_supplies(wcd9xxx);
+ wcd9xxx_disable_supplies(wcd9xxx, pdata);
wcd9xxx_device_exit(wcd9xxx);
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 3aff7f17..889c416 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -461,7 +461,13 @@
pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM -
- SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
+ if (idx < 0) {
+ pr_err("%s: Error:-Invalid index found = %d\n",
+ __func__, idx);
+ ret = -EINVAL;
+ goto err;
+ }
sph[i] = rx[idx].sph;
grph = rx[idx].grph;
}
@@ -501,6 +507,12 @@
pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM);
+ if (idx < 0) {
+ pr_err("%s: Error:- Invalid index found = %d\n",
+ __func__, idx);
+ ret = -EINVAL;
+ goto err;
+ }
sph[i] = tx[idx].sph;
grph = tx[idx].grph;
}
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 31c79a0..555dfdd 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
- * 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 as
@@ -32,6 +32,7 @@
#define ISA1200_HCTRL5_VIB_STRT 0xD5
#define ISA1200_HCTRL5_VIB_STOP 0x6B
+#define ISA1200_POWER_DOWN_MASK 0x7F
struct isa1200_chip {
struct i2c_client *client;
@@ -45,6 +46,8 @@
unsigned int period_ns;
bool is_len_gpio_valid;
struct regulator **regs;
+ bool clk_on;
+ u8 hctrl0_val;
};
static int isa1200_read_reg(struct i2c_client *client, int reg)
@@ -74,32 +77,111 @@
int rc = 0;
if (enable) {
+ /* if hen and len are seperate then enable hen
+ * otherwise set normal mode bit */
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 1);
+ else {
+ rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+ haptic->hctrl0_val | ~ISA1200_POWER_DOWN_MASK);
+ if (rc < 0) {
+ pr_err("%s: i2c write failure\n", __func__);
+ return;
+ }
+ }
+
if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
int period_us = haptic->period_ns / 1000;
+
rc = pwm_config(haptic->pwm,
(period_us * haptic->pdata->duty) / 100,
period_us);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s: pwm_config fail\n", __func__);
+ goto chip_dwn;
+ }
+
rc = pwm_enable(haptic->pwm);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s: pwm_enable fail\n", __func__);
+ goto chip_dwn;
+ }
} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+ /* vote for clock */
+ if (haptic->pdata->clk_enable && !haptic->clk_on) {
+ rc = haptic->pdata->clk_enable(true);
+ if (rc < 0) {
+ pr_err("%s: clk enable failed\n",
+ __func__);
+ goto chip_dwn;
+ }
+ haptic->clk_on = true;
+ }
+
rc = isa1200_write_reg(haptic->client,
ISA1200_HCTRL5,
ISA1200_HCTRL5_VIB_STRT);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s: start vibartion fail\n", __func__);
+ goto dis_clk;
+ }
}
} else {
- if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
+ /* if hen and len are seperate then pull down hen
+ * otherwise set power down bit */
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+ else {
+ rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+ haptic->hctrl0_val & ISA1200_POWER_DOWN_MASK);
+ if (rc < 0) {
+ pr_err("%s: i2c write failure\n", __func__);
+ return;
+ }
+ }
+
+ if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
pwm_disable(haptic->pwm);
- else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+ } else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
rc = isa1200_write_reg(haptic->client,
ISA1200_HCTRL5,
ISA1200_HCTRL5_VIB_STOP);
if (rc < 0)
pr_err("%s: stop vibartion fail\n", __func__);
+
+ /* de-vote clock */
+ if (haptic->pdata->clk_enable && haptic->clk_on) {
+ rc = haptic->pdata->clk_enable(false);
+ if (rc < 0) {
+ pr_err("%s: clk disable failed\n",
+ __func__);
+ return;
+ }
+ haptic->clk_on = false;
+ }
+ }
+ }
+
+ return;
+
+dis_clk:
+ if (haptic->pdata->clk_enable && haptic->clk_on) {
+ rc = haptic->pdata->clk_enable(false);
+ if (rc < 0) {
+ pr_err("%s: clk disable failed\n", __func__);
+ return;
+ }
+ haptic->clk_on = false;
+ }
+chip_dwn:
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+ else {
+ rc = isa1200_write_reg(haptic->client, ISA1200_HCTRL0,
+ haptic->hctrl0_val & ISA1200_POWER_DOWN_MASK);
+ if (rc < 0) {
+ pr_err("%s: i2c write failure\n", __func__);
+ return;
}
}
}
@@ -168,7 +250,8 @@
static int isa1200_setup(struct i2c_client *client)
{
struct isa1200_chip *haptic = i2c_get_clientdata(client);
- int value, temp, rc;
+ int temp, rc;
+ u8 value;
gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
if (haptic->is_len_gpio_valid == true)
@@ -218,6 +301,20 @@
goto reset_hctrl1;
}
+ /* if hen and len are seperate then pull down hen
+ * otherwise set power down bit */
+ if (haptic->is_len_gpio_valid == true)
+ gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+ else {
+ rc = isa1200_write_reg(client, ISA1200_HCTRL0,
+ value & ISA1200_POWER_DOWN_MASK);
+ if (rc < 0) {
+ pr_err("%s: i2c write failure\n", __func__);
+ goto reset_hctrl1;
+ }
+ }
+
+ haptic->hctrl0_val = value;
dump_isa1200_reg("new:", client);
return 0;
@@ -388,6 +485,7 @@
spin_lock_init(&haptic->lock);
INIT_WORK(&haptic->work, isa1200_chip_work);
+ haptic->clk_on = false;
hrtimer_init(&haptic->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
haptic->timer.function = isa1200_vib_timer_func;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 925c032..15ddd83 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -228,16 +228,17 @@
complete(&mrq->completion);
}
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
if (mmc_card_removed(host->card)) {
mrq->cmd->error = -ENOMEDIUM;
complete(&mrq->completion);
- return;
+ return -ENOMEDIUM;
}
mmc_start_request(host, mrq);
+ return 0;
}
static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -315,6 +316,7 @@
{
int err = 0;
struct mmc_async_req *data = host->areq;
+ int start_err = 0;
/* Prepare a new request */
if (areq)
@@ -323,24 +325,23 @@
if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, host->areq);
- if (err) {
- mmc_post_req(host, host->areq->mrq, 0);
- if (areq)
- mmc_post_req(host, areq->mrq, -EINVAL);
-
- host->areq = NULL;
- goto out;
- }
}
- if (areq)
- __mmc_start_req(host, areq->mrq);
+ if (!err && areq)
+ start_err = __mmc_start_req(host, areq->mrq);
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
- host->areq = areq;
- out:
+ /* Cancel a prepared request if it was not started. */
+ if ((err || start_err) && areq)
+ mmc_post_req(host, areq->mrq, -EINVAL);
+
+ if (err)
+ host->areq = NULL;
+ else
+ host->areq = areq;
+
if (error)
*error = err;
return data;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0d11dca..717f1d3 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -55,6 +55,7 @@
#include <mach/dma.h>
#include <mach/sdio_al.h>
#include <mach/mpm.h>
+#include <mach/msm_bus.h>
#include "msm_sdcc.h"
#include "msm_sdcc_dml.h"
@@ -72,6 +73,8 @@
/* Use SPS only if transfer size is more than this macro */
#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
+#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
+
#if defined(CONFIG_DEBUG_FS)
static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
static struct dentry *debugfs_dir;
@@ -1164,6 +1167,8 @@
if (data->flags & MMC_DATA_READ)
datactrl |= (MCI_DPSM_DIRECTION | MCI_RX_DATA_PEND);
+ else if (host->curr.use_wr_data_pend)
+ datactrl |= MCI_DATA_PEND;
clks = (unsigned long long)data->timeout_ns * host->clk_rate;
do_div(clks, 1000000000UL);
@@ -1639,13 +1644,11 @@
msmsdcc_request_end(host, cmd->mrq);
}
}
- } else if ((cmd == host->curr.mrq->sbc) && cmd->data) {
- if (cmd->data->flags & MMC_DATA_READ)
- msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
- else
- msmsdcc_request_start(host, host->curr.mrq);
} else if (cmd->data) {
- if (!(cmd->data->flags & MMC_DATA_READ))
+ if (cmd == host->curr.mrq->sbc)
+ msmsdcc_start_command(host, host->curr.mrq->cmd, 0);
+ else if ((cmd->data->flags & MMC_DATA_WRITE) &&
+ !host->curr.use_wr_data_pend)
msmsdcc_start_data(host, cmd->data, NULL, 0);
}
}
@@ -1688,14 +1691,17 @@
* will take care of signaling sdio irq during
* mmc_sdio_resume().
*/
- if (host->sdcc_suspended)
+ if (host->sdcc_suspended) {
/*
* This is a wakeup interrupt so hold wakelock
* until SDCC resume is handled.
*/
wake_lock(&host->sdio_wlock);
- else
+ } else {
+ spin_unlock(&host->lock);
mmc_signal_sdio_irq(host->mmc);
+ spin_lock(&host->lock);
+ }
ret = 1;
break;
}
@@ -1722,7 +1728,9 @@
if (status & MCI_SDIOINTROPE) {
if (host->sdcc_suspending)
wake_lock(&host->sdio_suspend_wlock);
+ spin_unlock(&host->lock);
mmc_signal_sdio_irq(host->mmc);
+ spin_lock(&host->lock);
}
data = host->curr.data;
@@ -1921,12 +1929,17 @@
static void
msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
{
- if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
+ if (mrq->data) {
/* Queue/read data, daisy-chain command when data starts */
- if (mrq->sbc)
- msmsdcc_start_data(host, mrq->data, mrq->sbc, 0);
+ if ((mrq->data->flags & MMC_DATA_READ) ||
+ host->curr.use_wr_data_pend)
+ msmsdcc_start_data(host, mrq->data,
+ mrq->sbc ? mrq->sbc : mrq->cmd,
+ 0);
else
- msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
+ msmsdcc_start_command(host,
+ mrq->sbc ? mrq->sbc : mrq->cmd,
+ 0);
} else {
msmsdcc_start_command(host, mrq->cmd, 0);
}
@@ -2022,20 +2035,18 @@
host->sdcc_version) {
host->curr.wait_for_auto_prog_done = 1;
}
+ if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
+ (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
+ host->curr.use_wr_data_pend = true;
}
if (mrq->data && mrq->sbc) {
mrq->sbc->mrq = mrq;
mrq->sbc->data = mrq->data;
- if (mrq->data->flags & MMC_DATA_WRITE) {
+ if (mrq->data->flags & MMC_DATA_WRITE)
host->curr.wait_for_auto_prog_done = 1;
- msmsdcc_start_command(host, mrq->sbc, 0);
- } else {
- msmsdcc_request_start(host, mrq);
- }
- } else {
- msmsdcc_request_start(host, mrq);
}
+ msmsdcc_request_start(host, mrq);
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -2614,6 +2625,179 @@
}
}
+/* Returns required bandwidth in Bytes per Sec */
+static unsigned int msmsdcc_get_bw_required(struct msmsdcc_host *host,
+ struct mmc_ios *ios)
+{
+ unsigned int bw;
+
+ bw = host->clk_rate;
+ /*
+ * For DDR mode, SDCC controller clock will be at
+ * the double rate than the actual clock that goes to card.
+ */
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ bw /= 2;
+ else if (ios->bus_width == MMC_BUS_WIDTH_1)
+ bw /= 8;
+
+ return bw;
+}
+
+static int msmsdcc_msm_bus_get_vote_for_bw(struct msmsdcc_host *host,
+ unsigned int bw)
+{
+ unsigned int *table = host->plat->msm_bus_voting_data->bw_vecs;
+ unsigned int size = host->plat->msm_bus_voting_data->bw_vecs_size;
+ int i;
+
+ if (host->msm_bus_vote.is_max_bw_needed && bw)
+ return host->msm_bus_vote.max_bw_vote;
+
+ for (i = 0; i < size; i++) {
+ if (bw <= table[i])
+ break;
+ }
+
+ if (i && (i == size))
+ i--;
+
+ return i;
+}
+
+static int msmsdcc_msm_bus_register(struct msmsdcc_host *host)
+{
+ int rc = 0;
+ struct msm_bus_scale_pdata *use_cases;
+
+ if (host->plat->msm_bus_voting_data &&
+ host->plat->msm_bus_voting_data->use_cases &&
+ host->plat->msm_bus_voting_data->bw_vecs &&
+ host->plat->msm_bus_voting_data->bw_vecs_size) {
+ use_cases = host->plat->msm_bus_voting_data->use_cases;
+ host->msm_bus_vote.client_handle =
+ msm_bus_scale_register_client(use_cases);
+ } else {
+ return 0;
+ }
+
+ if (!host->msm_bus_vote.client_handle) {
+ pr_err("%s: msm_bus_scale_register_client() failed\n",
+ mmc_hostname(host->mmc));
+ rc = -EFAULT;
+ } else {
+ /* cache the vote index for minimum and maximum bandwidth */
+ host->msm_bus_vote.min_bw_vote =
+ msmsdcc_msm_bus_get_vote_for_bw(host, 0);
+ host->msm_bus_vote.max_bw_vote =
+ msmsdcc_msm_bus_get_vote_for_bw(host, UINT_MAX);
+ }
+
+ return rc;
+}
+
+static void msmsdcc_msm_bus_unregister(struct msmsdcc_host *host)
+{
+ if (host->msm_bus_vote.client_handle)
+ msm_bus_scale_unregister_client(
+ host->msm_bus_vote.client_handle);
+}
+
+/*
+ * This function must be called with host lock acquired.
+ * Caller of this function should also ensure that msm bus client
+ * handle is not null.
+ */
+static inline int msmsdcc_msm_bus_set_vote(struct msmsdcc_host *host,
+ int vote,
+ unsigned long flags)
+{
+ int rc = 0;
+
+ if (vote != host->msm_bus_vote.curr_vote) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ rc = msm_bus_scale_client_update_request(
+ host->msm_bus_vote.client_handle, vote);
+ if (rc)
+ pr_err("%s: msm_bus_scale_client_update_request() failed."
+ " bus_client_handle=0x%x, vote=%d, err=%d\n",
+ mmc_hostname(host->mmc),
+ host->msm_bus_vote.client_handle, vote, rc);
+ spin_lock_irqsave(&host->lock, flags);
+ if (!rc)
+ host->msm_bus_vote.curr_vote = vote;
+ }
+
+ return rc;
+}
+
+/*
+ * Internal work. Work to set 0 bandwidth for msm bus.
+ */
+static void msmsdcc_msm_bus_work(struct work_struct *work)
+{
+ struct msmsdcc_host *host = container_of(work,
+ struct msmsdcc_host,
+ msm_bus_vote.vote_work.work);
+ unsigned long flags;
+
+ if (!host->msm_bus_vote.client_handle)
+ return;
+
+ spin_lock_irqsave(&host->lock, flags);
+ /* don't vote for 0 bandwidth if any request is in progress */
+ if (!host->curr.mrq)
+ msmsdcc_msm_bus_set_vote(host,
+ host->msm_bus_vote.min_bw_vote, flags);
+ else
+ pr_warning("%s: %s: SDCC transfer in progress. skipping"
+ " bus voting to 0 bandwidth\n",
+ mmc_hostname(host->mmc), __func__);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * This function cancels any scheduled delayed work
+ * and sets the bus vote based on ios argument.
+ * If "ios" argument is NULL, bandwidth required is 0 else
+ * calculate the bandwidth based on ios parameters.
+ */
+static void msmsdcc_msm_bus_cancel_work_and_set_vote(
+ struct msmsdcc_host *host,
+ struct mmc_ios *ios)
+{
+ unsigned long flags;
+ unsigned int bw;
+ int vote;
+
+ if (!host->msm_bus_vote.client_handle)
+ return;
+
+ bw = ios ? msmsdcc_get_bw_required(host, ios) : 0;
+
+ cancel_delayed_work_sync(&host->msm_bus_vote.vote_work);
+ spin_lock_irqsave(&host->lock, flags);
+ vote = msmsdcc_msm_bus_get_vote_for_bw(host, bw);
+ msmsdcc_msm_bus_set_vote(host, vote, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/* This function queues a work which will set the bandwidth requiement to 0 */
+static void msmsdcc_msm_bus_queue_work(struct msmsdcc_host *host)
+{
+ unsigned long flags;
+
+ if (!host->msm_bus_vote.client_handle)
+ return;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->msm_bus_vote.min_bw_vote != host->msm_bus_vote.curr_vote)
+ queue_delayed_work(system_nrt_wq,
+ &host->msm_bus_vote.vote_work,
+ msecs_to_jiffies(MSM_MMC_BUS_VOTING_DELAY));
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static void
msmsdcc_cfg_sdio_wakeup(struct msmsdcc_host *host, bool enable_wakeup_irq)
{
@@ -2926,15 +3110,14 @@
* clocks mci_irqenable will be written to MASK0 register.
*/
+ spin_lock_irqsave(&host->lock, flags);
if (enable) {
- spin_lock_irqsave(&host->lock, flags);
host->mci_irqenable |= MCI_SDIOINTOPERMASK;
if (host->clks_on) {
writel_relaxed(readl_relaxed(host->base + MMCIMASK0) |
MCI_SDIOINTOPERMASK, host->base + MMCIMASK0);
mb();
}
- spin_unlock_irqrestore(&host->lock, flags);
} else {
host->mci_irqenable &= ~MCI_SDIOINTOPERMASK;
if (host->clks_on) {
@@ -2943,6 +3126,7 @@
mb();
}
}
+ spin_unlock_irqrestore(&host->lock, flags);
}
#ifdef CONFIG_PM_RUNTIME
@@ -2969,14 +3153,14 @@
msmsdcc_pm_qos_update_latency(host, 1);
if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ goto out;
if (host->sdcc_suspended && host->pending_resume &&
!pm_runtime_suspended(dev)) {
host->pending_resume = false;
pm_runtime_get_noresume(dev);
rc = msmsdcc_runtime_resume(dev);
- goto out;
+ goto skip_get_sync;
}
if (dev->power.runtime_status == RPM_SUSPENDING) {
@@ -2988,14 +3172,15 @@
rc = pm_runtime_get_sync(dev);
-out:
+skip_get_sync:
if (rc < 0) {
pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
__func__, rc);
msmsdcc_print_rpm_info(host);
return rc;
}
-
+out:
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3006,8 +3191,10 @@
msmsdcc_pm_qos_update_latency(host, 0);
- if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ if (mmc->card && mmc_card_sdio(mmc->card)) {
+ rc = 0;
+ goto out;
+ }
if (host->plat->disable_runtime_pm)
return -ENOTSUPP;
@@ -3027,7 +3214,9 @@
return rc;
}
- return 0;
+out:
+ msmsdcc_msm_bus_queue_work(host);
+ return rc;
}
#else
static void msmsdcc_print_rpm_info(struct msmsdcc_host *host) {}
@@ -3041,8 +3230,10 @@
msmsdcc_pm_qos_update_latency(host, 1);
- if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ if (mmc->card && mmc_card_sdio(mmc->card)) {
+ rc = 0;
+ goto out;
+ }
if (host->sdcc_suspended && host->pending_resume) {
host->pending_resume = false;
@@ -3067,7 +3258,7 @@
__func__, rc);
return rc;
}
-
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, &mmc->ios);
return 0;
}
@@ -3079,7 +3270,7 @@
msmsdcc_pm_qos_update_latency(host, 0);
if (mmc->card && mmc_card_sdio(mmc->card))
- return 0;
+ goto out;
mutex_lock(&host->clk_mutex);
spin_lock_irqsave(&host->lock, flags);
@@ -3092,6 +3283,8 @@
spin_unlock_irqrestore(&host->lock, flags);
mutex_unlock(&host->clk_mutex);
+out:
+ msmsdcc_msm_bus_queue_work(host);
return 0;
}
#endif
@@ -3746,10 +3939,13 @@
}
if (host->plat->is_sdio_al_client) {
wake_lock(&host->sdio_wlock);
+ spin_unlock(&host->lock);
mmc_signal_sdio_irq(host->mmc);
+ goto out_unlocked;
}
spin_unlock(&host->lock);
+out_unlocked:
return IRQ_HANDLED;
}
@@ -4211,10 +4407,46 @@
static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
show_polling, set_polling);
+
+static ssize_t
+show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ host->msm_bus_vote.is_max_bw_needed);
+}
+
+static ssize_t
+set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ uint32_t value;
+ unsigned long flags;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ spin_lock_irqsave(&host->lock, flags);
+ host->msm_bus_vote.is_max_bw_needed = !!value;
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
+ show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
+
static struct attribute *dev_attrs[] = {
- &dev_attr_polling.attr,
+ &dev_attr_max_bus_bw.attr,
+ /* if polling is enabled, this will be filled with dev_attr_polling */
+ NULL,
NULL,
};
+
static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
@@ -4716,6 +4948,14 @@
pm_qos_add_request(&host->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+ ret = msmsdcc_msm_bus_register(host);
+ if (ret)
+ goto pm_qos_remove;
+
+ if (host->msm_bus_vote.client_handle)
+ INIT_DELAYED_WORK(&host->msm_bus_vote.vote_work,
+ msmsdcc_msm_bus_work);
+
ret = msmsdcc_vreg_init(host, true);
if (ret) {
pr_err("%s: msmsdcc_vreg_init() failed (%d)\n", __func__, ret);
@@ -4965,11 +5205,12 @@
#if defined(CONFIG_DEBUG_FS)
msmsdcc_dbg_createhost(host);
#endif
- if (!plat->status_irq) {
- ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
- if (ret)
- goto platform_irq_free;
- }
+ if (!plat->status_irq)
+ dev_attrs[1] = &dev_attr_polling.attr;
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+ if (ret)
+ goto platform_irq_free;
return 0;
platform_irq_free:
@@ -4999,6 +5240,8 @@
msmsdcc_vreg_init(host, false);
clk_disable:
clk_disable(host->clk);
+ msmsdcc_msm_bus_unregister(host);
+ pm_qos_remove:
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
clk_put:
@@ -5076,6 +5319,11 @@
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
+ if (host->msm_bus_vote.client_handle) {
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ msmsdcc_msm_bus_unregister(host);
+ }
+
msmsdcc_vreg_init(host, false);
if (host->is_dma_mode) {
@@ -5190,9 +5438,11 @@
int rc = 0;
unsigned long flags;
+ if (host->plat->is_sdio_al_client) {
+ rc = 0;
+ goto out;
+ }
- if (host->plat->is_sdio_al_client)
- return 0;
pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
if (mmc) {
host->sdcc_suspending = 1;
@@ -5247,6 +5497,9 @@
wake_unlock(&host->sdio_suspend_wlock);
}
pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
+out:
+ /* set bus bandwidth to 0 immediately */
+ msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
return rc;
}
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index e6bd16c..78c12c1 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -78,6 +78,7 @@
#define MCI_DPSM_DIRECTION (1 << 1)
#define MCI_DPSM_MODE (1 << 2)
#define MCI_DPSM_DMAENABLE (1 << 3)
+#define MCI_DATA_PEND (1 << 17)
#define MCI_AUTO_PROG_DONE (1 << 19)
#define MCI_RX_DATA_PEND (1 << 20)
@@ -294,6 +295,7 @@
int got_dataend;
int wait_for_auto_prog_done;
int got_auto_prog_done;
+ bool use_wr_data_pend;
int user_pages;
};
@@ -319,6 +321,15 @@
struct tasklet_struct tlet;
};
+struct msmsdcc_msm_bus_vote {
+ uint32_t client_handle;
+ uint32_t curr_vote;
+ int min_bw_vote;
+ int max_bw_vote;
+ bool is_max_bw_needed;
+ struct delayed_work vote_work;
+};
+
struct msmsdcc_host {
struct resource *core_irqres;
struct resource *bam_irqres;
@@ -398,6 +409,7 @@
bool sdio_wakeupirq_disabled;
struct mutex clk_mutex;
bool pending_resume;
+ struct msmsdcc_msm_bus_vote msm_bus_vote;
};
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dedf3da..e13b5c3 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1437,6 +1437,8 @@
dto -= 13;
else
dto = 0;
+ /* Use the maximum timeout value allowed in the standard of 14
+ or 0xE */
if (dto > 14)
dto = 14;
}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e7797b1..b1a16bb 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1555,6 +1555,26 @@
pr_debug("Enter charge=%d\n", mA);
+ if (!the_chip) {
+ pr_err("chip not yet initalized\n");
+ return;
+ }
+
+ /*
+ * Reject VBUS requests if USB connection is the only available
+ * power source. This makes sure that if booting without
+ * battery the iusb_max value is not decreased avoiding potential
+ * brown_outs.
+ *
+ * This would also apply when the battery has been
+ * removed from the running system.
+ */
+ if (!get_prop_batt_present(the_chip)
+ && !is_dc_chg_plugged_in(the_chip)) {
+ pr_err("rejected: no other power source connected\n");
+ return;
+ }
+
if (usb_max_current && mA > usb_max_current) {
pr_warn("restricting usb current to %d instead of %d\n",
usb_max_current, mA);
@@ -3363,13 +3383,6 @@
return rc;
}
- /* init with the lowest USB current */
- rc = pm_chg_iusbmax_set(chip, 0);
- if (rc) {
- pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
- return rc;
- }
-
if (chip->safety_time != 0) {
rc = pm_chg_tchg_max_set(chip, chip->safety_time);
if (rc) {
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 02b2cc3..b2a013c 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -153,7 +153,7 @@
.wNdpOutDivisor = cpu_to_le16(4),
.wNdpOutPayloadRemainder = cpu_to_le16(0),
.wNdpOutAlignment = cpu_to_le16(4),
- .wNtbOutMaxDatagrams = cpu_to_le16(4),
+ .wNtbOutMaxDatagrams = 0,
};
/*
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0e619e6..87244e9 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -708,7 +708,8 @@
ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL);
if (ret < 0) {
DBG(cdev, "send_file_work: xfer error %d\n", ret);
- dev->state = STATE_ERROR;
+ if (dev->state != STATE_OFFLINE)
+ dev->state = STATE_ERROR;
r = -EIO;
break;
}
@@ -760,7 +761,8 @@
ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
if (ret < 0) {
r = -EIO;
- dev->state = STATE_ERROR;
+ if (dev->state != STATE_OFFLINE)
+ dev->state = STATE_ERROR;
break;
}
}
@@ -772,7 +774,8 @@
DBG(cdev, "vfs_write %d\n", ret);
if (ret != write_req->actual) {
r = -EIO;
- dev->state = STATE_ERROR;
+ if (dev->state != STATE_OFFLINE)
+ dev->state = STATE_ERROR;
break;
}
write_req = NULL;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index fcbc75c..f7230fe 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -525,7 +525,7 @@
}
dev->notify->driver_data = dev;
- if (!dev->port.in->driver_data) {
+ if (!dev->port.in->desc || !dev->port.out->desc) {
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;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5ee1908..82373e2 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -340,6 +340,15 @@
}
disable_irq(hcd->irq);
+
+ /* make sure we don't race against a remote wakeup */
+ if (test_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags) ||
+ readl_relaxed(USB_PORTSC) & PORT_RESUME) {
+ dev_dbg(mehci->dev, "wakeup pending, aborting suspend\n");
+ enable_irq(hcd->irq);
+ return -EBUSY;
+ }
+
/*
* PHY may take some time or even fail to enter into low power
* mode (LPM). Hence poll for 500 msec and reset the PHY and link
@@ -973,6 +982,7 @@
#ifdef CONFIG_PM_SLEEP
static int msm_hsic_pm_suspend(struct device *dev)
{
+ int ret;
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -981,7 +991,12 @@
if (device_may_wakeup(dev))
enable_irq_wake(hcd->irq);
- return msm_hsic_suspend(mehci);
+ ret = msm_hsic_suspend(mehci);
+
+ if (ret && device_may_wakeup(dev))
+ disable_irq_wake(hcd->irq);
+
+ return ret;
}
static int msm_hsic_pm_suspend_noirq(struct device *dev)
@@ -1033,14 +1048,7 @@
#ifdef CONFIG_PM_RUNTIME
static int msm_hsic_runtime_idle(struct device *dev)
{
- struct usb_hcd *hcd = dev_get_drvdata(dev);
-
dev_dbg(dev, "EHCI runtime idle\n");
-
- /*don't allow runtime suspend in the middle of remote wakeup*/
- if (readl_relaxed(USB_PORTSC) & PORT_RESUME)
- return -EAGAIN;
-
return 0;
}
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index 0ee1827..891a4e2 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -889,7 +889,13 @@
if (can_phy_power_collapse(dev) && dev->pdata->ldo_enable)
dev->pdata->ldo_enable(1);
- msm_otg_get_resume(dev);
+ if (pm_runtime_enabled(dev->otg.dev)) {
+ msm_otg_get_resume(dev);
+ } else {
+ pm_runtime_get_noresume(dev->otg.dev);
+ msm_otg_resume(dev);
+ pm_runtime_set_active(dev->otg.dev);
+ }
if (!is_phy_clk_disabled())
goto phy_resumed;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4dd6aff..0ff0a48 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -697,6 +697,9 @@
/* Remote wakeup or resume */
set_bit(A_BUS_REQ, &motg->inputs);
otg->state = OTG_STATE_A_HOST;
+
+ /* ensure hardware is not in low power mode */
+ pm_runtime_resume(otg->dev);
break;
default:
break;
@@ -1189,10 +1192,12 @@
/*
* if entering host mode tell the charger to not draw any current
- * from usb - if exiting host mode let the charger draw current
+ * from usb before turning on the boost.
+ * if exiting host mode disable the boost before enabling to draw
+ * current from the source.
*/
- pm8921_disable_source_current(on);
if (on) {
+ pm8921_disable_source_current(on);
ret = regulator_enable(vbus_otg);
if (ret) {
pr_err("unable to enable vbus_otg\n");
@@ -1205,6 +1210,7 @@
pr_err("unable to disable vbus_otg\n");
return;
}
+ pm8921_disable_source_current(on);
vbus_is_on = false;
}
}
@@ -2511,7 +2517,10 @@
pr_debug("OTG IRQ: in LPM\n");
disable_irq_nosync(irq);
motg->async_int = 1;
- pm_request_resume(otg->dev);
+ if (atomic_read(&motg->pm_suspended))
+ motg->sm_work_pending = true;
+ else
+ pm_request_resume(otg->dev);
return IRQ_HANDLED;
}
@@ -2676,7 +2685,10 @@
return;
}
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (atomic_read(&motg->pm_suspended))
+ motg->sm_work_pending = true;
+ else
+ queue_work(system_nrt_wq, &motg->sm_work);
}
static irqreturn_t msm_pmic_id_irq(int irq, void *data)
@@ -2695,8 +2707,12 @@
set_bit(A_BUS_REQ, &motg->inputs);
}
- if (motg->otg.state != OTG_STATE_UNDEFINED)
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (motg->otg.state != OTG_STATE_UNDEFINED) {
+ if (atomic_read(&motg->pm_suspended))
+ motg->sm_work_pending = true;
+ else
+ queue_work(system_nrt_wq, &motg->sm_work);
+ }
return IRQ_HANDLED;
}
@@ -3533,28 +3549,42 @@
#ifdef CONFIG_PM_SLEEP
static int msm_otg_pm_suspend(struct device *dev)
{
+ int ret = 0;
struct msm_otg *motg = dev_get_drvdata(dev);
dev_dbg(dev, "OTG PM suspend\n");
- return msm_otg_suspend(motg);
+
+ atomic_set(&motg->pm_suspended, 1);
+ ret = msm_otg_suspend(motg);
+ if (ret)
+ atomic_set(&motg->pm_suspended, 0);
+
+ return ret;
}
static int msm_otg_pm_resume(struct device *dev)
{
+ int ret = 0;
struct msm_otg *motg = dev_get_drvdata(dev);
- int ret;
dev_dbg(dev, "OTG PM resume\n");
- ret = msm_otg_resume(motg);
- if (ret)
- return ret;
- /* Update runtime PM status */
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ atomic_set(&motg->pm_suspended, 0);
+ if (motg->sm_work_pending) {
+ motg->sm_work_pending = false;
- return 0;
+ pm_runtime_get_noresume(dev);
+ ret = msm_otg_resume(motg);
+
+ /* Update runtime PM status */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ queue_work(system_nrt_wq, &motg->sm_work);
+ }
+
+ return ret;
}
#endif
diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c
index c061e86..1b5d7c5 100644
--- a/drivers/video/msm/logo.c
+++ b/drivers/video/msm/logo.c
@@ -76,6 +76,12 @@
max = fb_width(info) * fb_height(info);
ptr = data;
+ if (info->node == 1 || info->node == 2) {
+ err = -EPERM;
+ pr_err("%s:%d no info->creen_base on fb%d!\n",
+ __func__, __LINE__, info->node);
+ goto err_logo_free_data;
+ }
bits = (unsigned short *)(info->screen_base);
while (count > 3) {
unsigned n = ptr[0];
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 471ed4e..3d35dd5 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -659,6 +659,7 @@
goto error_extra;
INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work);
+ mgmt->hist = NULL;
mdp_hist_mgmt_array[index] = mgmt;
return 0;
@@ -685,7 +686,8 @@
{
struct mdp_hist_mgmt *temp;
int i, ret;
- mdp_hist_wq = alloc_workqueue("mdp_hist_wq", WQ_UNBOUND, 0);
+ mdp_hist_wq = alloc_workqueue("mdp_hist_wq",
+ WQ_NON_REENTRANT | WQ_UNBOUND, 0);
for (i = 0; i < MDP_HIST_MGMT_MAX; i++)
mdp_hist_mgmt_array[i] = NULL;
@@ -897,6 +899,7 @@
mgmt->frame_cnt = req->frame_cnt;
mgmt->bit_mask = req->bit_mask;
mgmt->num_bins = req->num_bins;
+ mgmt->hist = NULL;
ret = mdp_histogram_enable(mgmt);
@@ -1080,8 +1083,11 @@
goto error;
}
- /* if read was triggered by an underrun, don't wake up readers*/
- if (mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
+ /*
+ * if read was triggered by an underrun or failed copying,
+ * don't wake up readers
+ */
+ if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) {
mgmt->hist = NULL;
complete(&mgmt->mdp_hist_comp);
}
@@ -1177,6 +1183,11 @@
goto error_lock;
}
+ if (mgmt->hist != NULL) {
+ pr_err("%s; histogram attempted to be read twice\n", __func__);
+ ret = -EPERM;
+ goto error_lock;
+ }
mgmt->hist = hist;
mutex_unlock(&mgmt->mdp_hist_mutex);
@@ -1740,7 +1751,6 @@
spin_lock_init(&mdp_spin_lock);
mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
- mdp_hist_wq = create_singlethread_workqueue("mdp_hist_wq");
mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
mdp_pipe_ctrl_workqueue_handler);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 34fd399..2e69ea6 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2354,14 +2354,16 @@
return;
if (mfd->use_ov0_blt) {
- if (mfd->panel_info.type == LCDC_PANEL)
+ if (mfd->panel_info.type == LCDC_PANEL ||
+ mfd->panel_info.type == LVDS_PANEL)
mdp4_lcdc_overlay_blt_start(mfd);
else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
mdp4_dsi_video_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_overlay_blt_start(mfd);
} else {
- if (mfd->panel_info.type == LCDC_PANEL)
+ if (mfd->panel_info.type == LCDC_PANEL ||
+ mfd->panel_info.type == LVDS_PANEL)
mdp4_lcdc_overlay_blt_stop(mfd);
else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
mdp4_dsi_video_blt_stop(mfd);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index b4d8db0..ce8744b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1179,18 +1179,26 @@
if (!remainder_mode2)
remainder_mode2 = PAGE_SIZE;
- /* calculate smem_len based on max size of two supplied modes */
- fix->smem_len = MAX((msm_fb_line_length(mfd->index, panel_info->xres,
- bpp) *
- panel_info->yres + PAGE_SIZE -
- remainder) * mfd->fb_page,
- (msm_fb_line_length(mfd->index,
- panel_info->mode2_xres,
- bpp) *
- panel_info->mode2_yres + PAGE_SIZE -
- remainder_mode2) * mfd->fb_page);
-
-
+ /*
+ * calculate smem_len based on max size of two supplied modes.
+ * Only fb0 has mem. fb1 and fb2 don't have mem.
+ */
+ if (mfd->index == 0)
+ fix->smem_len = MAX((msm_fb_line_length(mfd->index,
+ panel_info->xres,
+ bpp) *
+ panel_info->yres + PAGE_SIZE -
+ remainder) * mfd->fb_page,
+ (msm_fb_line_length(mfd->index,
+ panel_info->mode2_xres,
+ bpp) *
+ panel_info->mode2_yres + PAGE_SIZE -
+ remainder_mode2) * mfd->fb_page);
+ else if (mfd->index == 1 || mfd->index == 2) {
+ pr_debug("%s:%d no memory is allocated for fb%d!\n",
+ __func__, __LINE__, mfd->index);
+ fix->smem_len = 0;
+ }
mfd->var_xres = panel_info->xres;
mfd->var_yres = panel_info->yres;
@@ -1294,10 +1302,11 @@
fbram_phys += fbram_offset;
fbram_size -= fbram_offset;
- if (fbram_size < fix->smem_len) {
- printk(KERN_ERR "error: no more framebuffer memory!\n");
- return -ENOMEM;
- }
+ if (mfd->index == 0)
+ if (fbram_size < fix->smem_len) {
+ pr_err("error: no more framebuffer memory!\n");
+ return -ENOMEM;
+ }
fbi->screen_base = fbram;
fbi->fix.smem_start = (unsigned long)fbram_phys;
@@ -1311,8 +1320,8 @@
fbi->fix.smem_start, mfd->map_buffer->iova[0],
mfd->map_buffer->iova[1]);
}
-
- memset(fbi->screen_base, 0x0, fix->smem_len);
+ if (mfd->index == 0)
+ memset(fbi->screen_base, 0x0, fix->smem_len);
mfd->op_enable = TRUE;
mfd->panel_power_on = FALSE;
@@ -1517,7 +1526,11 @@
}
if (!mfd->ref_cnt) {
- mdp_set_dma_pan_info(info, NULL, TRUE);
+ if ((info->node != 1) && (info->node != 2)) {
+ mdp_set_dma_pan_info(info, NULL, TRUE);
+ } else
+ pr_debug("%s:%d no mdp_set_dma_pan_info %d\n",
+ __func__, __LINE__, info->node);
if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
printk(KERN_ERR "msm_fb_open: can't turn on display!\n");
@@ -1565,6 +1578,15 @@
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct msm_fb_panel_data *pdata;
+ /*
+ * If framebuffer is 1 or 2, io pen display is not allowed.
+ */
+ if (info->node == 1 || info->node == 2) {
+ pr_err("%s: no pan display for fb%d!",
+ __func__, info->node);
+ return -EPERM;
+ }
+
if (info->node != 0 || mfd->cont_splash_done) /* primary */
if ((!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
@@ -1585,6 +1607,7 @@
/* "UPDT" */
if (var->reserved[0] == 0x54445055) {
+
dirty.xoffset = var->reserved[1] & 0xffff;
dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
@@ -1738,9 +1761,12 @@
if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
return -EINVAL;
- if (info->fix.smem_len <
- (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
- return -EINVAL;
+ if ((info->node != 1) && (info->node != 2))
+ if (info->fix.smem_len <
+ (var->xres_virtual*
+ var->yres_virtual*
+ (var->bits_per_pixel/8)))
+ return -EINVAL;
if ((var->xres == 0) || (var->yres == 0))
return -EINVAL;
@@ -2593,7 +2619,11 @@
struct mdp_blit_req_list req_list_header;
int count, i, req_list_count;
-
+ if (info->node == 1 || info->node == 2) {
+ pr_err("%s: no pan display for fb%d.",
+ __func__, info->node);
+ return -EPERM;
+ }
/* Get the count size for the total BLIT request. */
if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
return -EFAULT;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 0d5ba9c..5019d31 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -502,7 +502,12 @@
}
rc = ddl_set_property(cctxt->ddl_handle, prop_hdr, prop_val);
- VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+ if (rc) {
+ /* Some properties aren't known to ddl that we can handle */
+ if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+ VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+ }
+
switch (prop_hdr->prop_id) {
case VCD_I_META_BUFFER_MODE:
{
@@ -537,16 +542,30 @@
break;
}
case VCD_I_INTRA_PERIOD:
- {
- struct vcd_property_i_period *iperiod =
- (struct vcd_property_i_period *)prop_val;
- cctxt->bframe = iperiod->b_frames;
- break;
- }
+ {
+ struct vcd_property_i_period *iperiod =
+ (struct vcd_property_i_period *)prop_val;
+ cctxt->bframe = iperiod->b_frames;
+ break;
+ }
case VCD_REQ_PERF_LEVEL:
rc = vcd_req_perf_level(cctxt,
- (struct vcd_property_perf_level *)prop_val);
+ (struct vcd_property_perf_level *)prop_val);
break;
+ case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+ {
+ struct vcd_property_vop_timing_constant_delta *delta =
+ prop_val;
+
+ if (delta->constant_delta > 0) {
+ cctxt->time_frame_delta = delta->constant_delta;
+ rc = VCD_S_SUCCESS;
+ } else {
+ VCD_MSG_ERROR("Frame delta must be positive");
+ rc = VCD_ERR_ILLEGAL_PARM;
+ }
+ break;
+ }
default:
{
break;
@@ -559,6 +578,7 @@
(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_hdr *prop_hdr, void *prop_val)
{
+ int rc;
VCD_MSG_LOW("vcd_get_property_cmn in %d:", cctxt->clnt_state.state);
VCD_MSG_LOW("property Id = %d", prop_hdr->prop_id);
if (!prop_hdr->sz || !prop_hdr->prop_id) {
@@ -566,7 +586,24 @@
return VCD_ERR_ILLEGAL_PARM;
}
- return ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+ rc = ddl_get_property(cctxt->ddl_handle, prop_hdr, prop_val);
+ if (rc) {
+ /* Some properties aren't known to ddl that we can handle */
+ if (prop_hdr->prop_id != VCD_I_VOP_TIMING_CONSTANT_DELTA)
+ VCD_FAILED_RETURN(rc, "Failed: ddl_set_property");
+ }
+
+ switch (prop_hdr->prop_id) {
+ case VCD_I_VOP_TIMING_CONSTANT_DELTA:
+ {
+ struct vcd_property_vop_timing_constant_delta *delta =
+ (struct vcd_property_vop_timing_constant_delta *)
+ prop_val;
+ delta->constant_delta = cctxt->time_frame_delta;
+ rc = VCD_S_SUCCESS;
+ }
+ }
+ return rc;
}
static u32 vcd_set_buffer_requirements_cmn
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index d228146..7ae4f45 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -191,6 +191,7 @@
u32 frm_p_units;
u32 reqd_perf_lvl;
u32 time_resoln;
+ u32 time_frame_delta;
struct vcd_buffer_pool in_buf_pool;
struct vcd_buffer_pool out_buf_pool;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 2df7144..1218794 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -2387,6 +2387,7 @@
u32 rc, seqhdr_present = 0;
struct vcd_property_hdr prop_hdr;
struct vcd_sequence_hdr seq_hdr;
+ struct vcd_property_sps_pps_for_idr_enable idr_enable;
struct vcd_property_codec codec;
*handled = true;
prop_hdr.prop_id = DDL_I_SEQHDR_PRESENT;
@@ -2403,29 +2404,64 @@
rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &codec);
if (!VCD_FAILED(rc)) {
if (codec.codec != VCD_CODEC_H263) {
- prop_hdr.prop_id = VCD_I_SEQ_HEADER;
- prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
- seq_hdr.sequence_header = frm_entry->virtual;
- seq_hdr.sequence_header_len =
- frm_entry->alloc_len;
- rc = ddl_get_property(cctxt->ddl_handle,
- &prop_hdr, &seq_hdr);
- if (!VCD_FAILED(rc)) {
- frm_entry->data_len =
- seq_hdr.sequence_header_len;
- frm_entry->time_stamp = 0;
- frm_entry->flags |=
- VCD_FRAME_FLAG_CODECCONFIG;
+ /*
+ * The seq. header is stored in a seperate internal
+ * buffer and is memcopied into the output buffer
+ * that we provide. In secure sessions, we aren't
+ * allowed to touch these buffers. In these cases
+ * seq. headers are returned to client as part of
+ * I-frames. So for secure session, just return
+ * empty buffer.
+ */
+ if (!cctxt->secure) {
+ prop_hdr.prop_id = VCD_I_SEQ_HEADER;
+ prop_hdr.sz = sizeof(struct vcd_sequence_hdr);
+ seq_hdr.sequence_header = frm_entry->virtual;
+ seq_hdr.sequence_header_len =
+ frm_entry->alloc_len;
+ rc = ddl_get_property(cctxt->ddl_handle,
+ &prop_hdr, &seq_hdr);
+ if (!VCD_FAILED(rc)) {
+ frm_entry->data_len =
+ seq_hdr.sequence_header_len;
+ frm_entry->time_stamp = 0;
+ frm_entry->flags |=
+ VCD_FRAME_FLAG_CODECCONFIG;
+ } else
+ VCD_MSG_ERROR("rc = 0x%x. Failed:"
+ "ddl_get_property: VCD_I_SEQ_HEADER",
+ rc);
+ } else {
+ /*
+ * First check that the proper props are enabled
+ * so client can get the proper info eventually
+ */
+ prop_hdr.prop_id = VCD_I_ENABLE_SPS_PPS_FOR_IDR;
+ prop_hdr.sz = sizeof(idr_enable);
+ rc = ddl_get_property(cctxt->ddl_handle,
+ &prop_hdr, &idr_enable);
+ if (!VCD_FAILED(rc)) {
+ if (!idr_enable.
+ sps_pps_for_idr_enable_flag) {
+ VCD_MSG_ERROR("SPS/PPS per IDR "
+ "needs to be enabled");
+ rc = VCD_ERR_BAD_STATE;
+ } else {
+ /* Send zero len frame */
+ frm_entry->data_len = 0;
+ frm_entry->time_stamp = 0;
+ frm_entry->flags = 0;
+ }
+ }
+
+ }
+
+ if (!VCD_FAILED(rc))
cctxt->callback(VCD_EVT_RESP_OUTPUT_DONE,
- VCD_S_SUCCESS, frm_entry,
- sizeof(struct vcd_frame_data),
- cctxt,
- cctxt->client_data);
- } else
- VCD_MSG_ERROR(
- "rc = 0x%x. Failed:\
- ddl_get_property: VCD_I_SEQ_HEADER",
- rc);
+ VCD_S_SUCCESS, frm_entry,
+ sizeof(struct vcd_frame_data),
+ cctxt,
+ cctxt->client_data);
} else
VCD_MSG_LOW("Codec Type is H.263\n");
} else
@@ -3052,13 +3088,15 @@
u32 frm_delta;
u64 temp, max = ~((u64)0);
- if (frame->time_stamp >= cctxt->status.prev_ts)
+ if (cctxt->time_frame_delta)
+ temp = cctxt->time_frame_delta;
+ else if (frame->time_stamp >= cctxt->status.prev_ts)
temp = frame->time_stamp - cctxt->status.prev_ts;
else
temp = (max - cctxt->status.prev_ts) +
frame->time_stamp;
- VCD_MSG_LOW("Curr_ts=%lld Prev_ts=%lld Diff=%llu",
+ VCD_MSG_LOW("Curr_ts=%lld Prev_ts=%lld Diff=%llu\n",
frame->time_stamp, cctxt->status.prev_ts, temp);
temp *= cctxt->time_resoln;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index e50a054..537960b 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -52,7 +52,7 @@
#define APQ8030_TOOLS_ID 4079
#define MSM8627_TOOLS_ID 4080
#define MSM8227_TOOLS_ID 4081
-#define MSM8974_TOOLS_ID 4072
+#define MSM8974_TOOLS_ID 4083
#define MSG_MASK_0 (0x00000001)
#define MSG_MASK_1 (0x00000002)
diff --git a/include/linux/i2c/isa1200.h b/include/linux/i2c/isa1200.h
index 4c36d59..9dab3eb 100644
--- a/include/linux/i2c/isa1200.h
+++ b/include/linux/i2c/isa1200.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
- * 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 as
@@ -55,6 +55,7 @@
u8 num_regulators;
int (*power_on)(int on);
int (*dev_setup)(bool on);
+ int (*clk_enable)(bool on);
};
#endif /* __LINUX_ISA1200_H */
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 7525e38..b693b75 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -84,6 +84,7 @@
extern void memblock_enforce_memory_limit(phys_addr_t memory_limit);
extern int memblock_is_memory(phys_addr_t addr);
extern int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
+extern int memblock_overlaps_memory(phys_addr_t base, phys_addr_t size);
extern int memblock_is_reserved(phys_addr_t addr);
extern int memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 8ec9796..1807cb0 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -133,4 +133,12 @@
};
+#define Q5V2_MVS_MAX_VOC_PKT_SIZE 320
+
+struct q5v2_msm_audio_mvs_frame {
+ uint32_t frame_type;
+ uint32_t len;
+ uint8_t voc_pkt[Q5V2_MVS_MAX_VOC_PKT_SIZE];
+
+};
#endif /* __MSM_AUDIO_MVS_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index b53d9dd..6e96f85 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -293,6 +293,8 @@
#define B_BUS_REQ 16
unsigned long inputs;
struct work_struct sm_work;
+ bool sm_work_pending;
+ atomic_t pm_suspended;
atomic_t in_lpm;
int async_int;
unsigned cur_power;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 147b068..eda60c0 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -656,6 +656,7 @@
/* Cache handling flags */
#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800
#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000
+#define V4L2_BUF_FLAG_EOS 0x2000
/*
* O V E R L A Y P R E V I E W
@@ -1458,6 +1459,7 @@
#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP (V4L2_CID_MPEG_BASE+403)
#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP (V4L2_CID_MPEG_BASE+404)
#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL (V4L2_CID_MPEG_BASE+405)
+
enum v4l2_mpeg_video_mpeg4_level {
V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 = 0,
V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B = 1,
@@ -1549,6 +1551,84 @@
#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_MPEG_MFC51_BASE+53)
#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_MPEG_MFC51_BASE+54)
+/* MPEG-class control IDs specific to the msm_vidc driver */
+#define V4L2_CID_MPEG_MSM_VIDC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+0)
+#define V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+1)
+#define V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+2)
+#define V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+3)
+enum v4l2_mpeg_vidc_video_divx_format_type {
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4 = 0,
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5 = 1,
+ V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+4)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+5)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+6)
+enum v4l2_mpeg_vidc_video_stream_format {
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES = 0,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER = 1,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH = 2,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH = 3,
+ V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH = 4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+7)
+enum v4l2_mpeg_vidc_video_output_order {
+ V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0,
+ V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE (V4L2_CID_MPEG_MSM_VIDC_BASE+8)
+#define V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD (V4L2_CID_MPEG_MSM_VIDC_BASE+9)
+#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+10)
+#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+11)
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME (V4L2_CID_MPEG_MSM_VIDC_BASE+12)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL (V4L2_CID_MPEG_MSM_VIDC_BASE+13)
+enum v4l2_mpeg_vidc_video_rate_control {
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR = 3,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR = 4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ROTATION (V4L2_CID_MPEG_MSM_VIDC_BASE+14)
+enum v4l2_mpeg_vidc_video_rotation {
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180 = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270 = 3,
+};
+#define MSM_VIDC_BASE V4L2_CID_MPEG_MSM_VIDC_BASE
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL (MSM_VIDC_BASE+15)
+enum v4l2_mpeg_vidc_h264_cabac_model {
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0 = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1 = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2 = 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE (MSM_VIDC_BASE+16)
+enum v4l2_mpeg_vidc_video_intra_refresh_mode {
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE = 0,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC = 1,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE = 2,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE = 3,
+ V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM = 4,
+};
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+17)
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE+18)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+19)
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
@@ -1780,6 +1860,54 @@
};
};
+/* Decoder commands */
+#define V4L2_DEC_CMD_START (0)
+#define V4L2_DEC_CMD_STOP (1)
+#define V4L2_DEC_CMD_PAUSE (2)
+#define V4L2_DEC_CMD_RESUME (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK (1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK (1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY (1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE (0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP (1)
+
+/* The structure must be zeroed before use by the application
+ This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+ __u32 cmd;
+ __u32 flags;
+ union {
+ struct {
+ __u64 pts;
+ } stop;
+
+ struct {
+ /* 0 or 1000 specifies normal speed,
+ 1 specifies forward single stepping,
+ -1 specifies backward single stepping,
+ >1: playback at speed/1000 of the normal speed,
+ <-1: reverse playback at (-speed/1000) of the normal speed. */
+ __s32 speed;
+ __u32 format;
+ } start;
+
+ struct {
+ __u32 data[16];
+ } raw;
+ };
+};
#endif
@@ -2146,6 +2274,15 @@
#define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers)
#define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer)
+/* Experimental selection API */
+#define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection)
+#define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection)
+
+/* Experimental, these two ioctls may change over the next couple of kernel
+ versions. */
+#define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd)
+
/* 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 8dfb0fc..03951ce 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -4,4 +4,4 @@
header-y += vcap_fmt.h
header-y += msm_isp.h
header-y += msm_gemini.h
-header-y += msm_v4l2_overlay.h
+header-y += msm_gestures.h
diff --git a/include/media/msm/vcd_api.h b/include/media/msm/vcd_api.h
index 32a1759..c93b696 100644
--- a/include/media/msm/vcd_api.h
+++ b/include/media/msm/vcd_api.h
@@ -66,7 +66,7 @@
u32 alloc_len;
u32 data_len;
u32 offset;
- s64 time_stamp;
+ s64 time_stamp; /* in usecs*/
u32 flags;
u32 frm_clnt_data;
struct vcd_property_dec_output_buffer dec_op_prop;
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index e776d41..cd00800 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -53,6 +53,7 @@
#define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
#define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
#define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
+#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -300,6 +301,10 @@
u32 vop_time_resolution;
};
+struct vcd_property_vop_timing_constant_delta {
+ u32 constant_delta; /*In usecs */
+};
+
struct vcd_property_short_header {
u32 short_header;
};
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 3f647dc..d4cf1d2 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1433,6 +1433,9 @@
#define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
+#define MSM_CAM_IOCTL_SEND_EVENT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+
struct msm_camera_v4l2_ioctl_t {
void __user *ioctl_ptr;
};
diff --git a/include/media/msm_gestures.h b/include/media/msm_gestures.h
new file mode 100644
index 0000000..c9af034
--- /dev/null
+++ b/include/media/msm_gestures.h
@@ -0,0 +1,66 @@
+/* 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 __LINUX_MSM_GESTURES_H
+#define __LINUX_MSM_GESTURES_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <media/msm_camera.h>
+
+#define MSM_GES_IOCTL_CTRL_COMMAND \
+ _IOW('V', BASE_VIDIOC_PRIVATE + 20, struct v4l2_control)
+
+#define VIDIOC_MSM_GESTURE_EVT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 21, struct v4l2_event)
+
+#define MSM_GES_GET_EVT_PAYLOAD \
+ _IOW('V', BASE_VIDIOC_PRIVATE + 22, struct msm_ges_evt)
+
+#define VIDIOC_MSM_GESTURE_CAM_EVT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 23, int)
+
+#define MSM_GES_RESP_V4L2 MSM_CAM_RESP_MAX
+#define MSM_GES_RESP_MAX (MSM_GES_RESP_V4L2 + 1)
+
+#define MSM_SVR_RESP_MAX MSM_GES_RESP_MAX
+
+
+#define MSM_V4L2_GES_BASE 100
+#define MSM_V4L2_GES_OPEN (MSM_V4L2_GES_BASE + 0)
+#define MSM_V4L2_GES_CLOSE (MSM_V4L2_GES_BASE + 1)
+#define MSM_V4L2_GES_CAM_OPEN (MSM_V4L2_GES_BASE + 2)
+#define MSM_V4L2_GES_CAM_CLOSE (MSM_V4L2_GES_BASE + 3)
+
+#define MSM_GES_APP_EVT_MIN (V4L2_EVENT_PRIVATE_START + 0x14)
+#define MSM_GES_APP_NOTIFY_EVENT (MSM_GES_APP_EVT_MIN + 0)
+#define MSM_GES_APP_NOTIFY_ERROR_EVENT (MSM_GES_APP_EVT_MIN + 1)
+#define MSM_GES_APP_EVT_MAX (MSM_GES_APP_EVT_MIN + 2)
+
+#define MSM_GESTURE_CID_CTRL_CMD V4L2_CID_BRIGHTNESS
+
+#define MAX_GES_EVENTS 25
+
+struct msm_ges_ctrl_cmd {
+ int type;
+ void *value;
+ int len;
+ int fd;
+ uint32_t cookie;
+};
+
+struct msm_ges_evt {
+ void *evt_data;
+ int evt_len;
+};
+
+#endif /*__LINUX_MSM_GESTURES_H*/
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
new file mode 100644
index 0000000..baa6a28
--- /dev/null
+++ b/include/media/msm_vidc.h
@@ -0,0 +1,49 @@
+/* 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_VIDC_H_
+#define _MSM_VIDC_H_
+
+#include <linux/videodev2.h>
+#include <linux/poll.h>
+
+enum core_id {
+ MSM_VIDC_CORE_0 = 0,
+ MSM_VIDC_CORES_MAX,
+};
+
+enum session_type {
+ MSM_VIDC_ENCODER = 0,
+ MSM_VIDC_DECODER,
+ MSM_VIDC_MAX_DEVICES,
+};
+
+int msm_vidc_open(void *vidc_inst, int core_id, int session_type);
+int msm_vidc_close(void *instance);
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *pt);
+#endif
diff --git a/include/media/user-rc-input.h b/include/media/user-rc-input.h
new file mode 100644
index 0000000..e58e40f
--- /dev/null
+++ b/include/media/user-rc-input.h
@@ -0,0 +1,21 @@
+/* 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 __USER_RC_INPUT_H__
+#define __USER_RC_INPUT_H__
+
+#define USER_CONTROL_PRESSED 0x01
+#define USER_CONTROL_REPEATED 0x02
+#define USER_CONTROL_RELEASED 0x03
+
+#endif /* __USER_RC_INPUT_H__ */
+
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 4d1c74a..46c13ba 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -207,6 +207,10 @@
struct v4l2_encoder_cmd *a);
int (*vidioc_try_encoder_cmd) (struct file *file, void *fh,
struct v4l2_encoder_cmd *a);
+ int (*vidioc_decoder_cmd) (struct file *file, void *fh,
+ struct v4l2_decoder_cmd *a);
+ int (*vidioc_try_decoder_cmd) (struct file *file, void *fh,
+ struct v4l2_decoder_cmd *a);
/* Stream type-dependent parameter ioctls */
int (*vidioc_g_parm) (struct file *file, void *fh,
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 968d46e..54a9187 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -13,7 +13,6 @@
#define __Q6_ASM_H__
#include <mach/qdsp6v2/apr.h>
-#include <mach/msm_subsystem_map.h>
#include <sound/apr_audio.h>
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#include <linux/ion.h>
@@ -110,7 +109,7 @@
struct ion_handle *handle;
struct ion_client *client;
#else
- struct msm_mapped_buffer *mem_buffer;
+ void *mem_buffer;
#endif
};
diff --git a/mm/memblock.c b/mm/memblock.c
index 5338237..b7abce5 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -720,6 +720,12 @@
memblock.memory.regions[idx].size) >= end;
}
+int __init_memblock memblock_overlaps_memory(phys_addr_t base, phys_addr_t size)
+{
+ memblock_cap_size(base, &size);
+ return memblock_overlaps_region(&memblock.memory, base, size) >= 0;
+}
+
int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
{
memblock_cap_size(base, &size);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 2d5eab2..cad9907 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1741,6 +1741,10 @@
(choice == TABLA_BANDGAP_AUDIO_MODE)) {
tabla_codec_enable_audio_mode_bandgap(codec);
} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
+ /* bandgap mode becomes fast,
+ * mclk should be off or clk buff source souldn't be VBG
+ * Let's turn off mclk always */
+ WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
0x2);
snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
@@ -1770,9 +1774,10 @@
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
pr_debug("%s\n", __func__);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
- ndelay(160);
+ usleep_range(50, 50);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+ usleep_range(50, 50);
tabla->clock_active = false;
}
@@ -1813,21 +1818,23 @@
pr_debug("%s: enable = %d\n", __func__, enable);
if (enable) {
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+ /* bandgap mode to fast */
snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
usleep_range(5, 5);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
- 0x80);
+ 0x80);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
- 0x80);
+ 0x80);
usleep_range(10, 10);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
- usleep_range(20, 20);
+ usleep_range(10000, 10000);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
} else {
snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
- 0);
+ 0);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
- snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+ /* clk source to ext clk and clk buff ref to VBG */
+ snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
}
tabla->config_mode_active = enable ? true : false;
@@ -1835,29 +1842,32 @@
}
static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
- int config_mode)
+ int config_mode)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+ /* transit to RCO requires mclk off */
+ WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
if (config_mode) {
+ /* enable RCO and switch to it */
tabla_codec_enable_config_mode(codec, 1);
- snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
- snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
usleep_range(1000, 1000);
- } else
+ } else {
+ /* switch to MCLK */
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
- if (!config_mode && tabla->mbhc_polling_active) {
- snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
- tabla_codec_enable_config_mode(codec, 0);
-
+ if (tabla->mbhc_polling_active) {
+ snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+ tabla_codec_enable_config_mode(codec, 0);
+ }
}
- snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+ snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+ /* on MCLK */
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
usleep_range(50, 50);
@@ -3689,16 +3699,18 @@
if (mclk_enable) {
tabla->mclk_enabled = true;
- if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
+ if (tabla->mbhc_polling_active) {
tabla_codec_pause_hs_polling(codec);
+ tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_AUDIO_MODE);
+ TABLA_BANDGAP_AUDIO_MODE);
tabla_codec_enable_clock_block(codec, 0);
tabla_codec_calibrate_hs_polling(codec);
tabla_codec_start_hs_polling(codec);
} else {
+ tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_AUDIO_MODE);
+ TABLA_BANDGAP_AUDIO_MODE);
tabla_codec_enable_clock_block(codec, 0);
}
} else {
@@ -3712,21 +3724,20 @@
tabla->mclk_enabled = false;
if (tabla->mbhc_polling_active) {
- if (!tabla->mclk_enabled) {
- tabla_codec_pause_hs_polling(codec);
- tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_MBHC_MODE);
- tabla_enable_rx_bias(codec, 1);
- tabla_codec_enable_clock_block(codec, 1);
- tabla_codec_calibrate_hs_polling(codec);
- tabla_codec_start_hs_polling(codec);
- }
+ tabla_codec_pause_hs_polling(codec);
+ tabla_codec_disable_clock_block(codec);
+ tabla_codec_enable_bandgap(codec,
+ TABLA_BANDGAP_MBHC_MODE);
+ tabla_enable_rx_bias(codec, 1);
+ tabla_codec_enable_clock_block(codec, 1);
+ tabla_codec_calibrate_hs_polling(codec);
+ tabla_codec_start_hs_polling(codec);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
0x05, 0x01);
} else {
tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_OFF);
+ TABLA_BANDGAP_OFF);
}
}
if (dapm)
@@ -3852,6 +3863,7 @@
tx_slot[0] = tx_ch[cnt];
tx_slot[1] = tx_ch[1 + cnt];
tx_slot[2] = tx_ch[5 + cnt];
+ tx_slot[3] = tx_ch[3 + cnt];
} else if (dai->id == AIF3_CAP) {
*tx_num = tabla_dai[dai->id - 1].capture.channels_max;
tx_slot[cnt] = tx_ch[2 + cnt];
@@ -4569,7 +4581,7 @@
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
- SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
0, tabla_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -4762,6 +4774,7 @@
}
if (!tabla->mclk_enabled) {
+ tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
tabla_enable_rx_bias(codec, 1);
tabla_codec_enable_clock_block(codec, 1);
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index f02a7ef..7060677 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -16,6 +16,7 @@
#include <linux/mfd/pm8xxx/pm8018.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -26,6 +27,7 @@
#include <mach/socinfo.h>
#include "msm-pcm-routing.h"
#include "../codecs/wcd9310.h"
+#include <mach/gpiomux.h>
/* 9615 machine driver */
@@ -56,8 +58,189 @@
#define TABLA_MBHC_DEF_BUTTONS 8
#define TABLA_MBHC_DEF_RLOADS 5
-static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(18);
-static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(19);
+/*
+ * Added for I2S
+ */
+#define GPIO_SPKR_I2S_MCLK 24
+#define GPIO_PRIM_I2S_SCK 20
+#define GPIO_PRIM_I2S_DOUT 23
+#define GPIO_PRIM_I2S_WS 21
+#define GPIO_PRIM_I2S_DIN 22
+#define GPIO_SEC_I2S_SCK 25
+#define GPIO_SEC_I2S_WS 26
+#define GPIO_SEC_I2S_DOUT 28
+#define GPIO_SEC_I2S_DIN 27
+
+static struct gpiomux_setting cdc_i2s_mclk = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_sclk = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_dout = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_ws = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting cdc_i2s_din = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct msm_gpiomux_config msm9615_audio_prim_i2s_codec_configs[] = {
+ {
+ .gpio = GPIO_SPKR_I2S_MCLK,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_SCK,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_sclk,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_DOUT,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_dout,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_WS,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_ws,
+ },
+ },
+ {
+ .gpio = GPIO_PRIM_I2S_DIN,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &cdc_i2s_din,
+ },
+ },
+};
+
+/* Physical address for LPA CSR
+ * LPA SIF mux registers. These are
+ * ioremap( ) for Virtual address.
+ */
+#define LPASS_CSR_BASE 0x28000000
+#define LPA_IF_BASE 0x28100000
+#define SIF_MUX_REG_BASE (LPASS_CSR_BASE + 0x00000000)
+#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
+#define LPASS_SIF_MUX_ADDR (SIF_MUX_REG_BASE + 0x00004000)
+#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
+/* SIF & SPARE MUX Values */
+#define MSM_SIF_FUNC_PCM 0
+#define MSM_SIF_FUNC_I2S_MIC 1
+#define MSM_SIF_FUNC_I2S_SPKR 2
+#define MSM_LPAIF_SPARE_DISABLE 0x0
+#define MSM_LPAIF_SPARE_BOTH_ENABLE 0x3
+
+/* I2S INTF CTL */
+#define MSM_INTF_PRIM 0
+#define MSM_INTF_SECN 1
+#define MSM_INTF_BOTH 2
+
+/* I2S Dir CTL */
+#define MSM_DIR_RX 0
+#define MSM_DIR_TX 1
+#define MSM_DIR_BOTH 2
+#define MSM_DIR_MAX 3
+
+/* I2S HW Params */
+#define NO_OF_BITS_PER_SAMPLE 16
+#define I2S_MIC_SCLK_RATE 1536000
+static int msm9615_i2s_rx_ch = 1;
+static int msm9615_i2s_tx_ch = 1;
+static int msm9615_i2s_spk_control;
+/* SIF mux bit mask & shift */
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK 0x30000
+#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT 0x10
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK 0x3
+#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT 0x0
+
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK 0x3
+#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT 0x2
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK 0x3
+#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT 0x0
+
+static u32 spare_shadow;
+static u32 sif_shadow;
+
+
+struct msm_i2s_mux_ctl {
+ const u8 sifconfig;
+ const u8 spareconfig;
+};
+struct msm_clk {
+ struct clk *osr_clk;
+ struct clk *bit_clk;
+ int clk_enable;
+};
+struct msm_i2s_clk {
+ struct msm_clk rx_clk;
+ struct msm_clk tx_clk;
+};
+struct msm_i2s_ctl {
+ struct msm_i2s_clk prim_clk;
+ struct msm_i2s_clk sec_clk;
+ struct msm_i2s_mux_ctl mux_ctl[MSM_DIR_MAX];
+ u8 intf_status[MSM_INTF_BOTH][MSM_DIR_BOTH];
+ void *sif_virt_addr;
+ void *spare_virt_addr;
+};
+static struct msm_i2s_ctl msm9x15_i2s_ctl = {
+ {{NULL, NULL, 0}, {NULL, NULL, 0} }, /* prim_clk */
+ {{NULL, NULL, 0}, {NULL, NULL, 0} }, /* sec_clk */
+ /* mux_ctl */
+ {
+ /* Rx path only */
+ { MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_DISABLE },
+ /* Tx path only */
+ { MSM_SIF_FUNC_I2S_MIC, MSM_LPAIF_SPARE_DISABLE },
+ /* Rx + Tx path only */
+ { MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_BOTH_ENABLE },
+ },
+ /* intf_status */
+ {
+ /* Prim I2S */
+ {0, 0},
+ /* Sec I2S */
+ {0, 0}
+ },
+ /* sif_virt_addr */
+ NULL,
+ /* spare_virt_addr */
+ NULL,
+};
+
+enum msm9x15_set_i2s_clk {
+ MSM_I2S_CLK_SET_FALSE,
+ MSM_I2S_CLK_SET_TRUE,
+ MSM_I2S_CLK_SET_RATE0,
+};
+/*
+ * Added for I2S
+ */
+
+static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(3);
+static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
static int mdm9615_spk_control;
static int mdm9615_ext_bottom_spk_pamp;
static int mdm9615_ext_top_spk_pamp;
@@ -318,16 +501,15 @@
pr_debug("%s: clk_users = %d\n", __func__, clk_users);
if (clk_users != 1)
return 0;
+ if (IS_ERR(codec_clk)) {
- if (codec_clk) {
- clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
- clk_prepare_enable(codec_clk);
- tabla_mclk_enable(codec, 1, dapm);
- } else {
pr_err("%s: Error setting Tabla MCLK\n", __func__);
clk_users--;
return -EINVAL;
}
+ clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ tabla_mclk_enable(codec, 1, dapm);
} else {
pr_debug("%s: clk_users = %d\n", __func__, clk_users);
if (clk_users == 0)
@@ -651,6 +833,20 @@
return tabla_cal;
}
+static int msm9615_i2s_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (msm9615_i2s_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ msm9615_i2s_spk_control = ucontrol->value.integer.value[0];
+ mdm9615_ext_control(codec);
+ return 1;
+}
+
static int mdm9615_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -704,13 +900,567 @@
__func__);
goto end;
}
-
-
}
end:
return ret;
}
+static int msm9615_i2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
+ msm9615_i2s_rx_ch);
+ ucontrol->value.integer.value[0] = msm9615_i2s_rx_ch - 1;
+ return 0;
+}
+
+static int msm9615_i2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm9615_i2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
+ msm9615_i2s_rx_ch);
+ return 1;
+}
+
+static int msm9615_i2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
+ msm9615_i2s_tx_ch);
+ ucontrol->value.integer.value[0] = msm9615_i2s_tx_ch - 1;
+ return 0;
+}
+
+static int msm9615_i2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm9615_i2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
+ msm9615_i2s_tx_ch);
+ return 1;
+}
+
+static int msm9615_i2s_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm9615_spk_control = %d", __func__, mdm9615_spk_control);
+ ucontrol->value.integer.value[0] = msm9615_i2s_spk_control;
+ return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm9615_i2s_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], msm9615_i2s_get_spk,
+ msm9615_i2s_set_spk),
+ SOC_ENUM_EXT("PRI_RX Channels", mdm9615_enum[1],
+ msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
+ SOC_ENUM_EXT("PRI_TX Channels", mdm9615_enum[2],
+ msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
+};
+
+static int msm9615_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ err = snd_soc_add_controls(codec, tabla_msm9615_i2s_controls,
+ ARRAY_SIZE(tabla_msm9615_i2s_controls));
+ if (err < 0) {
+ pr_err("returning loc 1 err = %d\n", err);
+ return err;
+ }
+
+ snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
+ ARRAY_SIZE(mdm9615_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, common_audio_map,
+ ARRAY_SIZE(common_audio_map));
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
+ snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
+
+ snd_soc_dapm_sync(dapm);
+
+ err = snd_soc_jack_new(codec, "Headset Jack",
+ (SND_JACK_HEADSET | SND_JACK_OC_HPHL|
+ SND_JACK_OC_HPHR), &hs_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+ err = snd_soc_jack_new(codec, "Button Jack",
+ TABLA_JACK_BUTTON_MASK, &button_jack);
+ if (err) {
+ pr_err("failed to create new jack\n");
+ return err;
+ }
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ err = tabla_hs_detect(codec, &mbhc_cfg);
+ return err;
+}
+
+static int msm9615_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm9615_i2s_rx_ch;
+
+ return 0;
+}
+
+static int msm9615_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ rate->min = rate->max = 48000;
+
+ channels->min = channels->max = msm9615_i2s_tx_ch;
+
+ return 0;
+}
+
+static int mdm9615_i2s_free_gpios(u8 i2s_intf, u8 i2s_dir)
+{
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ if (i2s_intf == MSM_INTF_PRIM) {
+ if (i2s_dir == MSM_DIR_RX)
+ gpio_free(GPIO_PRIM_I2S_DOUT);
+ if (i2s_dir == MSM_DIR_TX)
+ gpio_free(GPIO_PRIM_I2S_DIN);
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ gpio_free(GPIO_PRIM_I2S_SCK);
+ gpio_free(GPIO_PRIM_I2S_WS);
+ }
+ } else if (i2s_intf == MSM_INTF_SECN) {
+ if (i2s_dir == MSM_DIR_RX)
+ gpio_free(GPIO_SEC_I2S_DOUT);
+ if (i2s_dir == MSM_DIR_TX)
+ gpio_free(GPIO_SEC_I2S_DIN);
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ gpio_free(GPIO_SEC_I2S_WS);
+ gpio_free(GPIO_SEC_I2S_SCK);
+ }
+ }
+ return 0;
+}
+
+int msm9615_i2s_intf_dir_sel(const char *cpu_dai_name,
+ u8 *i2s_intf, u8 *i2s_dir)
+{
+ int ret = 0;
+ if (i2s_intf == NULL || i2s_dir == NULL || cpu_dai_name == NULL) {
+ ret = 1;
+ goto err;
+ }
+ if (!strncmp(cpu_dai_name, "msm-dai-q6.0", 12)) {
+ *i2s_intf = MSM_INTF_PRIM;
+ *i2s_dir = MSM_DIR_RX;
+ } else if (!strncmp(cpu_dai_name, "msm-dai-q6.1", 12)) {
+ *i2s_intf = MSM_INTF_PRIM;
+ *i2s_dir = MSM_DIR_TX;
+ } else if (!strncmp(cpu_dai_name, "msm-dai-q6.4", 12)) {
+ *i2s_intf = MSM_INTF_SECN;
+ *i2s_dir = MSM_DIR_RX;
+ } else if (!strncmp(cpu_dai_name, "msm-dai-q6.5", 12)) {
+ *i2s_intf = MSM_INTF_SECN;
+ *i2s_dir = MSM_DIR_TX;
+ } else {
+ pr_err("Error in I2S cpu dai name\n");
+ ret = 1;
+ }
+err:
+ return ret;
+}
+
+int msm9615_enable_i2s_gpio(u8 i2s_intf, u8 i2s_dir)
+{
+ u8 ret = 0;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ if (i2s_intf == MSM_INTF_PRIM) {
+ if (i2s_dir == MSM_DIR_TX) {
+ ret = gpio_request(GPIO_PRIM_I2S_DIN, "I2S_PRIM_DIN");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_DIN);
+ goto err;
+ }
+ } else if (i2s_dir == MSM_DIR_RX) {
+ ret = gpio_request(GPIO_PRIM_I2S_DOUT,
+ "I2S_PRIM_DOUT");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_DOUT);
+ goto err;
+ }
+ } else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ ret = gpio_request(GPIO_PRIM_I2S_SCK, "I2S_PRIM_SCK");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_SCK);
+ goto err;
+ }
+ ret = gpio_request(GPIO_PRIM_I2S_WS, "I2S_PRIM_WS");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_PRIM_I2S_WS);
+ goto err;
+ }
+ }
+ } else if (i2s_intf == MSM_INTF_SECN) {
+ if (i2s_dir == MSM_DIR_RX) {
+ ret = gpio_request(GPIO_SEC_I2S_DOUT, "I2S_SEC_DOUT");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_DOUT);
+ goto err;
+ }
+ } else if (i2s_dir == MSM_DIR_TX) {
+ ret = gpio_request(GPIO_SEC_I2S_DIN, "I2S_SEC_DIN");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_DIN);
+ goto err;
+ }
+ } else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
+ pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
+ ret = gpio_request(GPIO_SEC_I2S_SCK, "I2S_SEC_SCK");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_SCK);
+ goto err;
+ }
+ ret = gpio_request(GPIO_SEC_I2S_WS, "I2S_SEC_WS");
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, GPIO_SEC_I2S_WS);
+ goto err;
+ }
+ }
+ }
+err:
+ return ret;
+}
+
+static int msm9615_set_i2s_osr_bit_clk(struct snd_soc_dai *cpu_dai,
+ u8 i2s_intf, u8 i2s_dir,
+ enum msm9x15_set_i2s_clk enable)
+{
+
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ struct msm_i2s_clk *pclk = &pintf->prim_clk;
+ struct msm_clk *clk_ctl = &pclk->rx_clk;
+ u8 ret = 0;
+ pr_debug("Dev name %s Intf =%d, Dir = %d, Enable=%d\n",
+ cpu_dai->name, i2s_intf, i2s_dir, enable);
+ if (i2s_intf == MSM_INTF_PRIM)
+ pclk = &pintf->prim_clk;
+ else if (i2s_intf == MSM_INTF_SECN)
+ pclk = &pintf->sec_clk;
+
+ if (i2s_dir == MSM_DIR_TX)
+ clk_ctl = &pclk->tx_clk;
+ else if (i2s_dir == MSM_DIR_RX)
+ clk_ctl = &pclk->rx_clk;
+
+ if (enable == MSM_I2S_CLK_SET_TRUE ||
+ enable == MSM_I2S_CLK_SET_RATE0) {
+ if (clk_ctl->clk_enable != 0) {
+ pr_info("%s: I2S Clk is already enabled"
+ "clk users %d\n", __func__,
+ clk_ctl->clk_enable);
+ ret = 0;
+ goto err;
+ }
+ clk_ctl->osr_clk = clk_get(cpu_dai->dev, "osr_clk");
+ if (IS_ERR(clk_ctl->osr_clk)) {
+ pr_err("%s: Fail to get OSR CLK\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = clk_prepare(clk_ctl->osr_clk);
+ if (ret != 0) {
+ pr_err("Unable to prepare i2s_spkr_osr_clk\n");
+ goto err;
+ }
+ clk_set_rate(clk_ctl->osr_clk, TABLA_EXT_CLK_RATE);
+ ret = clk_enable(clk_ctl->osr_clk);
+ if (ret != 0) {
+ pr_err("Fail to enable i2s_spkr_osr_clk\n");
+ clk_unprepare(clk_ctl->osr_clk);
+ goto err;
+ }
+ clk_ctl->bit_clk = clk_get(cpu_dai->dev, "bit_clk");
+ if (IS_ERR(clk_ctl->bit_clk)) {
+ pr_err("Fail to get i2s_spkr_bit_clk\n");
+ clk_disable(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_put(clk_ctl->osr_clk);
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = clk_prepare(clk_ctl->bit_clk);
+ if (ret != 0) {
+ clk_disable(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_put(clk_ctl->osr_clk);
+ pr_err("Fail to prepare i2s_spkr_osr_clk\n");
+ goto err;
+ }
+ if (enable == MSM_I2S_CLK_SET_RATE0)
+ clk_set_rate(clk_ctl->bit_clk, 0);
+ else
+ clk_set_rate(clk_ctl->bit_clk, 8);
+ ret = clk_enable(clk_ctl->bit_clk);
+ if (ret != 0) {
+ clk_disable(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_put(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->bit_clk);
+ pr_err("Unable to enable i2s_spkr_osr_clk\n");
+ goto err;
+ }
+ clk_ctl->clk_enable++;
+ } else if (enable == MSM_I2S_CLK_SET_FALSE &&
+ clk_ctl->clk_enable != 0) {
+ clk_disable(clk_ctl->osr_clk);
+ clk_disable(clk_ctl->bit_clk);
+ clk_unprepare(clk_ctl->osr_clk);
+ clk_unprepare(clk_ctl->bit_clk);
+ clk_put(clk_ctl->bit_clk);
+ clk_put(clk_ctl->osr_clk);
+ clk_ctl->bit_clk = NULL;
+ clk_ctl->osr_clk = NULL;
+ clk_ctl->clk_enable--;
+ ret = 0;
+ }
+err:
+ return ret;
+}
+
+void msm9615_config_i2s_sif_mux(u8 value)
+{
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ sif_shadow = 0x00000;
+ sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
+ (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
+ iowrite32(sif_shadow, pintf->sif_virt_addr);
+ /* Dont read SIF register. Device crashes. */
+ pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+}
+
+void msm9615_config_i2s_spare_mux(u8 value, u8 i2s_intf)
+{
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ if (i2s_intf == MSM_INTF_PRIM) {
+ /* Configure Primary SIF */
+ spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK
+ ) | (value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
+ }
+ if (i2s_intf == MSM_INTF_SECN) {
+ /*Secondary interface configuration*/
+ spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK
+ ) | (value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
+ }
+ iowrite32(spare_shadow, pintf->spare_virt_addr);
+ /* Dont read SPARE register. Device crashes. */
+ pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_shadow);
+}
+
+static int msm9615_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ int rate = params_rate(params);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ struct msm_i2s_clk *pclk = &pintf->prim_clk;
+ struct msm_clk *clk_ctl = &pclk->rx_clk;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int bit_clk_set = 0;
+ u8 i2s_intf, i2s_dir;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!msm9615_i2s_intf_dir_sel(cpu_dai->name,
+ &i2s_intf, &i2s_dir)) {
+ bit_clk_set = TABLA_EXT_CLK_RATE /
+ (rate * 2 * NO_OF_BITS_PER_SAMPLE);
+ if (bit_clk_set != 8) {
+ if (i2s_intf == MSM_INTF_PRIM)
+ pclk = &pintf->prim_clk;
+ else if (i2s_intf == MSM_INTF_SECN)
+ pclk = &pintf->sec_clk;
+ clk_ctl = &pclk->rx_clk;
+ pr_debug("%s( ): New rate = %d",
+ __func__, bit_clk_set);
+ clk_set_rate(clk_ctl->bit_clk, bit_clk_set);
+ }
+ }
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ bit_clk_set = I2S_MIC_SCLK_RATE / (rate * 2 *
+ NO_OF_BITS_PER_SAMPLE);
+ /* Not required to modify TX rate.
+ * Speaker clock are looped back
+ * to Mic.
+ */
+ }
+ return 1;
+}
+
+static int msm9615_i2s_startup(struct snd_pcm_substream *substream)
+{
+ u8 ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ u8 i2s_intf, i2s_dir;
+ if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+ pr_debug("%s( ): cpu name = %s intf =%d dir = %d\n",
+ __func__, cpu_dai->name, i2s_intf, i2s_dir);
+ pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+ pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+ msm9615_enable_i2s_gpio(i2s_intf, i2s_dir);
+ if (i2s_dir == MSM_DIR_TX) {
+ if (pintf->intf_status[i2s_intf][MSM_DIR_RX] > 0) {
+ /* This means that Rx is enabled before */
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+ i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_RATE0);
+ if (ret != 0) {
+ pr_err("%s: Fail enable I2S clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_i2s_sif_mux(
+ pintf->mux_ctl[MSM_DIR_BOTH].sifconfig);
+ msm9615_config_i2s_spare_mux(
+ pintf->mux_ctl[MSM_DIR_BOTH].spareconfig,
+ i2s_intf);
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt codec dai failed\n");
+ } else if (pintf->intf_status[i2s_intf][i2s_dir] == 0) {
+ /* This means that Rx is
+ * not enabled before.
+ * only Tx will be used.
+ */
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+ i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_TRUE);
+ if (ret != 0) {
+ pr_err("%s: Fail Tx I2S clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_i2s_sif_mux(
+ pintf->mux_ctl[MSM_DIR_TX].sifconfig);
+ msm9615_config_i2s_spare_mux(
+ pintf->mux_ctl[MSM_DIR_TX].spareconfig,
+ i2s_intf);
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt codec dai failed\n");
+ }
+ } else if (i2s_dir == MSM_DIR_RX) {
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0) {
+ pr_err("%s: Error shutdown Tx first\n",
+ __func__);
+ return -EINVAL;
+ } else if (pintf->intf_status[i2s_intf][i2s_dir]
+ == 0) {
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
+ i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_TRUE);
+ if (ret != 0) {
+ pr_err("%s: Fail Rx I2S clock\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_i2s_sif_mux(
+ pintf->mux_ctl[MSM_DIR_RX].sifconfig);
+ msm9615_config_i2s_spare_mux(
+ pintf->mux_ctl[MSM_DIR_RX].spareconfig,
+ i2s_intf);
+ ret = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt codec dai failed\n");
+ }
+ }
+ pintf->intf_status[i2s_intf][i2s_dir]++;
+ } else {
+ pr_err("%s: Err in i2s_intf_dir_sel\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("Exit %s() Enable status Rx =%d Tx = %d\n", __func__,
+ pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+ return ret;
+}
+
+static void msm9615_i2s_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
+ u8 i2s_intf = 0, i2s_dir = 0, ret = 0;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ pr_debug("%s( ): Enable status Rx =%d Tx = %d\n",
+ __func__, pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+ if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
+ pr_debug("%s( ): intf =%d dir = %d\n", __func__,
+ i2s_intf, i2s_dir);
+ if (i2s_dir == MSM_DIR_RX)
+ if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0)
+ pr_err("%s: Shutdown Tx First then by RX\n",
+ __func__);
+ ret = msm9615_set_i2s_osr_bit_clk(cpu_dai, i2s_intf, i2s_dir,
+ MSM_I2S_CLK_SET_FALSE);
+ if (ret != 0)
+ pr_err("%s: Cannot disable I2S clock\n",
+ __func__);
+ pintf->intf_status[i2s_intf][i2s_dir]--;
+ mdm9615_i2s_free_gpios(i2s_intf, i2s_dir);
+ }
+ pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
+ pintf->intf_status[i2s_intf][MSM_DIR_RX],
+ pintf->intf_status[i2s_intf][MSM_DIR_TX]);
+}
+
+static struct snd_soc_ops msm9615_i2s_be_ops = {
+ .startup = msm9615_i2s_startup,
+ .shutdown = msm9615_i2s_shutdown,
+ .hw_params = msm9615_i2s_hw_params,
+};
+
static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -896,6 +1646,7 @@
return 0;
}
+
static int mdm9615_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -1107,8 +1858,37 @@
};
-static struct snd_soc_dai_link mdm9615_dai_delta_tabla[] = {
- /* Backend DAI Links */
+static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
+ /* Backend I2S DAI Links */
+ {
+ .name = LPASS_BE_PRI_I2S_RX,
+ .stream_name = "Primary I2S Playback",
+ .cpu_dai_name = "msm-dai-q6.0",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_i2s_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
+ .init = &msm9615_i2s_audrx_init,
+ .be_hw_params_fixup = msm9615_i2s_rx_be_hw_params_fixup,
+ .ops = &msm9615_i2s_be_ops,
+ },
+ {
+ .name = LPASS_BE_PRI_I2S_TX,
+ .stream_name = "Primary I2S Capture",
+ .cpu_dai_name = "msm-dai-q6.1",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_i2s_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
+ .be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
+ .ops = &msm9615_i2s_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link mdm9615_dai_slimbus_tabla[] = {
+ /* Backend SlimBus DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
.stream_name = "Slimbus Playback",
@@ -1136,14 +1916,17 @@
},
};
-static struct snd_soc_dai_link mdm9615_dai[
+static struct snd_soc_dai_link mdm9615_i2s_dai[
ARRAY_SIZE(mdm9615_dai_common) +
- ARRAY_SIZE(mdm9615_dai_delta_tabla)];
+ ARRAY_SIZE(mdm9615_dai_i2s_tabla)];
+
+static struct snd_soc_dai_link mdm9615_slimbus_dai[
+ ARRAY_SIZE(mdm9615_dai_common) +
+ ARRAY_SIZE(mdm9615_dai_slimbus_tabla)];
+
static struct snd_soc_card snd_soc_card_mdm9615 = {
.name = "mdm9615-tabla-snd-card",
- .dai_link = mdm9615_dai,
- .num_links = ARRAY_SIZE(mdm9615_dai),
};
static struct platform_device *mdm9615_snd_device;
@@ -1199,6 +1982,11 @@
}
}
+void __init install_codec_i2s_gpio(void)
+{
+ msm_gpiomux_install(msm9615_audio_prim_i2s_codec_configs,
+ ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
+}
static int __init mdm9615_audio_init(void)
{
int ret;
@@ -1220,11 +2008,28 @@
kfree(mbhc_cfg.calibration);
return -ENOMEM;
}
-
- memcpy(mdm9615_dai, mdm9615_dai_common, sizeof(mdm9615_dai_common));
- memcpy(mdm9615_dai + ARRAY_SIZE(mdm9615_dai_common),
- mdm9615_dai_delta_tabla, sizeof(mdm9615_dai_delta_tabla));
-
+ pr_err("%s: Interface Type = %d\n", __func__,
+ wcd9xxx_get_intf_type());
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ memcpy(mdm9615_slimbus_dai, mdm9615_dai_common,
+ sizeof(mdm9615_dai_common));
+ memcpy(mdm9615_slimbus_dai + ARRAY_SIZE(mdm9615_dai_common),
+ mdm9615_dai_slimbus_tabla,
+ sizeof(mdm9615_dai_slimbus_tabla));
+ snd_soc_card_mdm9615.dai_link = mdm9615_slimbus_dai;
+ snd_soc_card_mdm9615.num_links =
+ ARRAY_SIZE(mdm9615_slimbus_dai);
+ } else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
+ install_codec_i2s_gpio();
+ memcpy(mdm9615_i2s_dai, mdm9615_dai_common,
+ sizeof(mdm9615_dai_common));
+ memcpy(mdm9615_i2s_dai + ARRAY_SIZE(mdm9615_dai_common),
+ mdm9615_dai_i2s_tabla,
+ sizeof(mdm9615_dai_i2s_tabla));
+ snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
+ snd_soc_card_mdm9615.num_links =
+ ARRAY_SIZE(mdm9615_i2s_dai);
+ }
platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
ret = platform_device_add(mdm9615_snd_device);
if (ret) {
@@ -1232,13 +2037,15 @@
kfree(mbhc_cfg.calibration);
return ret;
}
-
if (mdm9615_configure_headset_mic_gpios()) {
pr_err("%s Fail to configure headset mic gpios\n", __func__);
mdm9615_headset_gpios_configured = 0;
} else
mdm9615_headset_gpios_configured = 1;
+ msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
+ msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
+
return ret;
}
@@ -1253,6 +2060,9 @@
mdm9615_free_headset_mic_gpios();
platform_device_unregister(mdm9615_snd_device);
kfree(mbhc_cfg.calibration);
+ iounmap(msm9x15_i2s_ctl.sif_virt_addr);
+ iounmap(msm9x15_i2s_ctl.spare_virt_addr);
+
}
module_exit(mdm9615_audio_exit);
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 50f527f..14f4f61 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1219,18 +1219,6 @@
.ignore_suspend = 1,
/* .be_id = do not care */
},
- /* MI2S TX Hostless */
- {
- .name = "MI2S_TX Hostless",
- .stream_name = "MI2S_TX Hostless",
- .cpu_dai_name = "MI2S_TX_HOSTLESS",
- .platform_name = "msm-pcm-hostless",
- .dynamic = 1,
- .dsp_link = &tx_hl_media,
- .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .no_codec = 1,
- .ignore_suspend = 1,
- },
/* HDMI Hostless */
{
.name = "HDMI_RX_HOSTLESS",
@@ -1243,6 +1231,18 @@
.no_codec = 1,
.ignore_suspend = 1,
},
+ /* MI2S TX Hostless */
+ {
+ .name = "MI2S_TX Hostless",
+ .stream_name = "MI2S_TX Hostless",
+ .cpu_dai_name = "MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &tx_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .no_codec = 1,
+ .ignore_suspend = 1,
+ },
/* Secondary I2S RX Hostless */
{
.name = "SEC_I2S_RX Hostless",
diff --git a/sound/soc/msm/msm-dai-q6-hdmi.c b/sound/soc/msm/msm-dai-q6-hdmi.c
index 3333344..dfb090e 100644
--- a/sound/soc/msm/msm-dai-q6-hdmi.c
+++ b/sound/soc/msm/msm-dai-q6-hdmi.c
@@ -38,6 +38,46 @@
union afe_port_config port_config;
};
+static int msm_dai_q6_hdmi_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+ int value = ucontrol->value.integer.value[0];
+ dai_data->port_config.hdmi_multi_ch.data_type = value;
+ pr_debug("%s: value = %d\n", __func__, value);
+ return 0;
+}
+
+static int msm_dai_q6_hdmi_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.hdmi_multi_ch.data_type;
+ return 0;
+}
+
+
+/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
+ * 0: linear PCM
+ * 1: non-linear PCM
+ */
+static const char *hdmi_format[] = {
+ "LPCM",
+ "Compr"
+};
+
+static const struct soc_enum hdmi_config_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, hdmi_format),
+};
+
+static const struct snd_kcontrol_new hdmi_config_controls[] = {
+ SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
+ msm_dai_q6_hdmi_format_get,
+ msm_dai_q6_hdmi_format_put),
+};
/* Current implementation assumes hw_param is called once
* This may not be the case but what to do when ADM and AFE
@@ -54,7 +94,6 @@
dai_data->channels = params_channels(params);
dai_data->rate = params_rate(params);
- dai_data->port_config.hdmi_multi_ch.data_type = 0;
dai_data->port_config.hdmi_multi_ch.reserved = 0;
switch (dai_data->channels) {
@@ -78,9 +117,11 @@
return -EINVAL;
}
dev_dbg(dai->dev, "%s() num_ch = %u rate =%u"
- " channel_allocation = %u\n", __func__, dai_data->channels,
+ " channel_allocation = %u data type = %d\n", __func__,
+ dai_data->channels,
dai_data->rate,
- dai_data->port_config.hdmi_multi_ch.channel_allocation);
+ dai_data->port_config.hdmi_multi_ch.channel_allocation,
+ dai_data->port_config.hdmi_multi_ch.data_type);
return 0;
}
@@ -168,6 +209,7 @@
static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
{
struct msm_dai_q6_hdmi_dai_data *dai_data;
+ const struct snd_kcontrol_new *kcontrol;
int rc = 0;
dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
@@ -180,6 +222,10 @@
} else
dev_set_drvdata(dai->dev, dai_data);
+ kcontrol = &hdmi_config_controls[0];
+
+ rc = snd_ctl_add(dai->card->snd_card,
+ snd_ctl_new1(kcontrol, dai_data));
return rc;
}
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 02cc6ce..7fbb592 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1125,6 +1125,18 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+};
+
static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1258,6 +1270,9 @@
SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1294,6 +1309,9 @@
SOC_SINGLE_EXT("INTERNAL_BT_SCO_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_BACKEND_DAI_INT_BT_SCO_RX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
@@ -1320,6 +1338,12 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new mi2s_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
+
static const struct snd_kcontrol_new fm_switch_mixer_controls =
SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
0, 1, 0, msm_routing_get_switch_mixer,
@@ -1667,6 +1691,10 @@
SND_SOC_NOPM, 0, 0,
hdmi_rx_voice_mixer_controls,
ARRAY_SIZE(hdmi_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(mi2s_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("Voice_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_voice_mixer_controls,
ARRAY_SIZE(tx_voice_mixer_controls)),
@@ -1714,6 +1742,8 @@
SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Port Mixer",
SND_SOC_NOPM, 0, 0, sbus_3_rx_port_mixer_controls,
ARRAY_SIZE(sbus_3_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0,
+ mi2s_rx_port_mixer_controls, ARRAY_SIZE(mi2s_rx_port_mixer_controls)),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -1880,6 +1910,7 @@
{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
+ {"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -1887,6 +1918,8 @@
{"SLIMBUS_1_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
+ {"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
@@ -1896,6 +1929,7 @@
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
{"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
+ {"SLIMBUS_3_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Port Mixer"},
@@ -1904,6 +1938,9 @@
{"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_RX Port Mixer"},
+
+ {"MI2S_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
+ {"MI2S_RX", NULL, "MI2S_RX Port Mixer"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index a2c6f5f..b31ed65 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -13,7 +13,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/mfd/pm8xxx/spk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -36,6 +36,9 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+#define SPK_AMP_POS 0x1
+#define SPK_AMP_NEG 0x2
+#define SPKR_BOOST_GPIO 15
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -45,6 +48,7 @@
static int msm8930_slim_0_rx_ch = 1;
static int msm8930_slim_0_tx_ch = 1;
+static int msm8930_ext_spk_pamp;
static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
static int msm8930_btsco_ch = 1;
@@ -111,11 +115,107 @@
return 1;
}
+static void msm8960_ext_spk_power_amp_on(u32 spk)
+{
+ int ret = 0;
+
+ if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+ if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+ (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+ pr_debug("%s() External Bottom Speaker Ampl already "
+ "turned on. spk = 0x%08x\n", __func__, spk);
+ return;
+ }
+
+ msm8930_ext_spk_pamp |= spk;
+
+ if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+ (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+ if (machine_is_msm8930_mtp()
+ || machine_is_msm8930_fluid()) {
+ pr_debug("%s: Configure Speaker Boost GPIO %u",
+ __func__, SPKR_BOOST_GPIO);
+ ret = gpio_request(SPKR_BOOST_GPIO,
+ "SPKR_BOOST_EN");
+ if (ret) {
+ pr_err("%s: Failed to configure speaker boost "
+ "gpio %u\n", __func__, SPKR_BOOST_GPIO);
+ return;
+ }
+
+ pr_debug("%s: Enable Speaker boost gpio %u\n",
+ __func__, SPKR_BOOST_GPIO);
+ gpio_direction_output(SPKR_BOOST_GPIO, 1);
+ }
+
+ pm8xxx_spk_enable(MSM8930_SPK_ON);
+ pr_debug("%s: slepping 4 ms after turning on external "
+ " Left Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+ }
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void msm8960_ext_spk_power_amp_off(u32 spk)
+{
+ if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+ if (!msm8930_ext_spk_pamp)
+ return;
+ if (machine_is_msm8930_mtp()
+ || machine_is_msm8930_fluid()) {
+ pr_debug("%s: Free speaker boost gpio %u\n",
+ __func__, SPKR_BOOST_GPIO);
+ gpio_direction_output(SPKR_BOOST_GPIO, 0);
+ gpio_free(SPKR_BOOST_GPIO);
+ }
+
+ pm8xxx_spk_enable(MSM8930_SPK_OFF);
+ msm8930_ext_spk_pamp = 0;
+ pr_debug("%s: slepping 4 ms after turning on external "
+ " Left Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
- /* TODO: add external speaker power amps support */
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+ msm8960_ext_spk_power_amp_on(SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+ msm8960_ext_spk_power_amp_on(SPK_AMP_NEG);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+ msm8960_ext_spk_power_amp_off(SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+ msm8960_ext_spk_power_amp_off(SPK_AMP_NEG);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -174,7 +274,7 @@
msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk Left Neg", msm8930_spkramp_event),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Digital Mic1", NULL),
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index ba5c79d..fc08febf 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -38,7 +38,6 @@
#include <mach/peripheral-loader.h>
#include <mach/qdsp6v2/audio_acdb.h>
#include <mach/qdsp6v2/rtac.h>
-#include <mach/msm_subsystem_map.h>
#include <sound/apr_audio.h>
#include <sound/q6asm.h>
@@ -258,7 +257,7 @@
"%ld\n", __func__,
PTR_ERR((void *)port->buf[cnt].mem_buffer));
else {
- if (msm_subsystem_unmap_buffer(
+ if (iounmap(
port->buf[cnt].mem_buffer) < 0)
pr_err("%s: unmap buffer"
" failed\n", __func__);
@@ -328,7 +327,7 @@
"%ld\n", __func__,
PTR_ERR((void *)port->buf[0].mem_buffer));
else {
- if (msm_subsystem_unmap_buffer(
+ if (iounmap(
port->buf[0].mem_buffer) < 0)
pr_err("%s: unmap buffer"
" failed\n", __func__);
@@ -574,11 +573,8 @@
mutex_unlock(&ac->cmd_lock);
goto fail;
}
- flags = MSM_SUBSYSTEM_MAP_KADDR |
- MSM_SUBSYSTEM_MAP_CACHED;
buf[cnt].mem_buffer =
- msm_subsystem_map_buffer(buf[cnt].phys,
- bufsz, flags, NULL, 0);
+ ioremap(buf[cnt].phys, bufsz);
if (IS_ERR(
(void *)buf[cnt].mem_buffer)) {
pr_err("%s:map_buffer failed,"
@@ -588,7 +584,7 @@
goto fail;
}
buf[cnt].data =
- buf[cnt].mem_buffer->vaddr;
+ buf[cnt].mem_buffer;
if (!buf[cnt].data) {
pr_err("%s:invalid vaddr,"
" iomap failed\n", __func__);
@@ -700,9 +696,7 @@
goto fail;
}
- flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
- buf[0].mem_buffer = msm_subsystem_map_buffer(buf[0].phys,
- bufsz * bufcnt, flags, NULL, 0);
+ buf[0].mem_buffer = ioremap(buf[0].phys, bufsz * bufcnt);
if (IS_ERR((void *)buf[cnt].mem_buffer)) {
pr_err("%s:map_buffer failed,"
"error = %ld\n",
@@ -711,7 +705,7 @@
mutex_unlock(&ac->cmd_lock);
goto fail;
}
- buf[0].data = buf[0].mem_buffer->vaddr;
+ buf[0].data = buf[0].mem_buffer;
#endif
if (!buf[0].data) {
pr_err("%s:invalid vaddr,"