Merge "ALSA: Add jack type SND_JACK_UNSUPPORTED" into msm-3.0
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 002431a..308f992 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,17 +7,15 @@
Required properties:
- compatible: Must be "qcom,pil-q6v5-lpass"
-- reg: Three pairs of physical base addresses and region sizes
+- reg: Two pairs of physical base addresses and region sizes
of memory mapped registers. The first region corresponds
- to QDSP6SS_PUB, the second corresponds to LPASS_CC, and
- the third to LPASS_HALTREQ.
+ to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
Example:
qcom,lpass@fe200000 {
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
- <0xfe000000 0x40000>,
<0xfd485100 0x00010>;
qcom,firmware-name = "lpass";
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 48d5720..bb26e00 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -313,6 +313,7 @@
regulator-max-microvolt = <1150000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
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 89a726e..aa7adc5 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -75,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 {
@@ -114,7 +134,7 @@
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
- spi-max-frequency = <24000000>;
+ spi-max-frequency = <25000000>;
};
slim@fe12f000 {
@@ -256,7 +276,6 @@
qcom,lpass@fe200000 {
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
- <0xfe000000 0x40000>,
<0xfd485100 0x00010>;
qcom,firmware-name = "lpass";
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 eb2c2c8..c644cf9 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -126,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 11b1f73..255d92a 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -331,6 +331,7 @@
CONFIG_MT9M114=y
CONFIG_IMX074_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_FLASH_TPS61310=y
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 886a691..62b1a57 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -340,6 +340,7 @@
CONFIG_MT9M114=y
CONFIG_IMX074_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_FLASH_TPS61310=y
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 6107331..2295679 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -152,6 +152,7 @@
obj-$(CONFIG_MSM_HW3D) += hw3d.o
obj-$(CONFIG_PM) += pm-boot.o
obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
obj-$(CONFIG_MSM_PM2) += pm2.o
obj-$(CONFIG_MSM_NOPM) += no-pm.o
@@ -317,7 +318,7 @@
ifdef CONFIG_VCM
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
-obj-$(CONFIG_MSM_OCMEM) += ocmem.o
+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..6986a29 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -370,6 +370,7 @@
},
[L2] = {
.hfpll_base = MSM_HFPLL_BASE + 0x400,
+ .hfpll_vdd_tbl = hfpll_vdd_dig_tbl_8930,
.aux_clk_sel = MSM_APCS_GCC_BASE + 0x028,
.l2cpmr_iaddr = L2CPMR_IADDR,
.vreg[VREG_HFPLL_B] = { "hfpll_l2", 1800000,
@@ -653,23 +654,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-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 36953ef..114b271 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -188,6 +188,7 @@
.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+ ._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
};
static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 3431cd0..e873498 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -342,6 +342,12 @@
.pull = GPIOMUX_PULL_KEEPER,
};
+static struct gpiomux_setting mbhc_hs_detect = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting cdc_mclk = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_8MA,
@@ -730,6 +736,12 @@
static struct msm_gpiomux_config apq8064_audio_codec_configs[] __initdata = {
{
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mbhc_hs_detect,
+ },
+ },
+ {
.gpio = 39,
.settings = {
[GPIOMUX_SUSPENDED] = &cdc_mclk,
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 91fd400..1a0a287 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -127,6 +127,7 @@
/* TABLA CODEC RESET */
PM8921_GPIO_OUTPUT(34, 1, MED),
PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
+ PM8921_GPIO_OUTPUT(13, 0, HIGH), /* PCIE_CLK_PWR_EN */
};
static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
@@ -146,6 +147,8 @@
PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
/*MPP9 is used to detect docking station connection/removal on Liquid*/
PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
+ /* PCIE_RESET_N */
+ PM8921_MPP_INIT(1, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_HIGH),
};
void __init apq8064_pm8xxx_gpio_mpp_init(void)
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 58e83a0..40222b8 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -157,6 +157,8 @@
REGULATOR_SUPPLY("HSUSB_VDDCX", "msm_ehci_host.1"),
REGULATOR_SUPPLY("HSIC_VDDCX", "msm_hsic_host"),
REGULATOR_SUPPLY("riva_vddcx", "wcnss_wlan.0"),
+ REGULATOR_SUPPLY("vp_pcie", "msm_pcie"),
+ REGULATOR_SUPPLY("vptx_pcie", "msm_pcie"),
};
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8921_s4", NULL),
@@ -213,6 +215,7 @@
};
VREG_CONSUMERS(LVS6) = {
REGULATOR_SUPPLY("8921_lvs6", NULL),
+ REGULATOR_SUPPLY("vdd_pcie_vph", "msm_pcie"),
};
VREG_CONSUMERS(LVS7) = {
REGULATOR_SUPPLY("8921_lvs7", NULL),
@@ -256,6 +259,7 @@
REGULATOR_SUPPLY("lvds_vccs_3p3v", "lvds.0"),
REGULATOR_SUPPLY("dsi1_vccs_3p3v", "mipi_dsi.1"),
REGULATOR_SUPPLY("hdmi_mux_vdd", "hdmi_msm.0"),
+ REGULATOR_SUPPLY("pcie_ext_3p3v", "msm_pcie"),
};
VREG_CONSUMERS(EXT_TS_SW) = {
REGULATOR_SUPPLY("ext_ts_sw", NULL),
@@ -545,7 +549,7 @@
* ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 1),
/* ID name always_on pd en_t supply reg_ID */
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ed17cc4..d04e5e4 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -69,6 +69,7 @@
#include <sound/cs8427.h>
#include <media/gpio-ir-recv.h>
#include <linux/fmem.h>
+#include <mach/msm_pcie.h>
#include "msm_watchdog.h"
#include "board-8064.h"
@@ -94,14 +95,15 @@
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000
#define MSM_ION_SF_SIZE 0
+#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
#define MSM_ION_HEAP_NUM 7
#else
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
+#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_QSECOM_SIZE 0x300000 /* (3MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#else
@@ -114,6 +116,10 @@
#define MSM_MM_FW_SIZE 0x200000
#define APQ8064_FW_START (APQ8064_FIXED_AREA_START - MSM_MM_FW_SIZE)
+/* PCIe power enable pmic gpio */
+#define PCIE_PWR_EN_PMIC_GPIO 13
+#define PCIE_RST_N_PMIC_MPP 1
+
#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
static int __init pmem_kernel_ebi1_size_setup(char *p)
@@ -1124,23 +1130,31 @@
#define ISA1200_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
#define ISA1200_HAP_CLK PM8921_GPIO_PM_TO_SYS(44)
-static int isa1200_power(int on)
+static int isa1200_clk_enable(bool on)
{
int rc = 0;
- gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+ gpio_set_value_cansleep(ISA1200_HAP_CLK, on);
- if (on)
+ if (on) {
rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_1, true);
- else
+ if (rc) {
+ pr_err("%s: unable to write aux clock register(%d)\n",
+ __func__, rc);
+ goto err_gpio_dis;
+ }
+ } else {
rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_NONE, true);
-
- if (rc) {
- pr_err("%s: unable to write aux clock register(%d)\n",
- __func__, rc);
+ if (rc)
+ pr_err("%s: unable to write aux clock register(%d)\n",
+ __func__, rc);
}
return rc;
+
+err_gpio_dis:
+ gpio_set_value_cansleep(ISA1200_HAP_CLK, !on);
+ return rc;
}
static int isa1200_dev_setup(bool enable)
@@ -1182,7 +1196,7 @@
static struct isa1200_platform_data isa1200_1_pdata = {
.name = "vibrator",
.dev_setup = isa1200_dev_setup,
- .power_on = isa1200_power,
+ .clk_enable = isa1200_clk_enable,
.hap_en_gpio = ISA1200_HAP_EN_GPIO,
.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
.max_timeout = 15000,
@@ -1998,6 +2012,22 @@
msm_bus_8064_cpss_fpb.dev.platform_data = &msm_bus_8064_cpss_fpb_pdata;
}
+/* PCIe gpios */
+static struct msm_pcie_gpio_info_t msm_pcie_gpio_info[MSM_PCIE_MAX_GPIO] = {
+ {"rst_n", PM8921_MPP_PM_TO_SYS(PCIE_RST_N_PMIC_MPP), 0},
+ {"pwr_en", PM8921_GPIO_PM_TO_SYS(PCIE_PWR_EN_PMIC_GPIO), 1},
+};
+
+static struct msm_pcie_platform msm_pcie_platform_data = {
+ .gpio = msm_pcie_gpio_info,
+};
+
+static void __init mpq8064_pcie_init(void)
+{
+ msm_device_pcie.dev.platform_data = &msm_pcie_platform_data;
+ platform_device_register(&msm_device_pcie);
+}
+
static struct platform_device apq8064_device_ext_5v_vreg __devinitdata = {
.name = GPIO_REGULATOR_DEV_NAME,
.id = PM8921_MPP_PM_TO_SYS(7),
@@ -2258,6 +2288,33 @@
.id = -1,
};
+static int rf4ce_gpio_init(void)
+{
+ if (!machine_is_mpq8064_cdp())
+ return -EINVAL;
+
+ /* CC2533 SRDY Input */
+ if (!gpio_request(SX150X_GPIO(4, 6), "rf4ce_srdy")) {
+ gpio_direction_input(SX150X_GPIO(4, 6));
+ gpio_export(SX150X_GPIO(4, 6), true);
+ }
+
+ /* CC2533 MRDY Output */
+ if (!gpio_request(SX150X_GPIO(4, 5), "rf4ce_mrdy")) {
+ gpio_direction_output(SX150X_GPIO(4, 5), 1);
+ gpio_export(SX150X_GPIO(4, 5), true);
+ }
+
+ /* CC2533 Reset Output */
+ if (!gpio_request(SX150X_GPIO(4, 7), "rf4ce_reset")) {
+ gpio_direction_output(SX150X_GPIO(4, 7), 0);
+ gpio_export(SX150X_GPIO(4, 7), true);
+ }
+
+ return 0;
+}
+late_initcall(rf4ce_gpio_init);
+
static struct platform_device *mpq_devices[] __initdata = {
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
@@ -2877,6 +2934,7 @@
machine_is_mpq8064_dtv()) {
enable_avc_i2c_bus();
platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
+ mpq8064_pcie_init();
} else {
ethernet_init();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index cc5b13c..c9d720c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -198,12 +198,9 @@
#ifdef CONFIG_MSM_CAMERA_FLASH
static struct msm_camera_sensor_flash_src msm_flash_src = {
.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
- ._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
- ._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
-#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
- defined(CONFIG_GPIO_SX150X_MODULE))
- ._fsrc.ext_driver_src.expander_info = cam_expander_info,
-#endif
+ ._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+ ._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+ ._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_TPS61310,
};
#endif
@@ -536,7 +533,8 @@
};
static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
- .flash_type = MSM_CAMERA_FLASH_NONE,
+ .flash_type = MSM_CAMERA_FLASH_LED,
+ .flash_src = &msm_flash_src
};
static struct msm_camera_csi_lane_params s5k3l1yx_csi_lane_params = {
@@ -585,6 +583,15 @@
struct msm_camera_sensor_info *s_info;
s_info = &msm_camera_sensor_s5k3l1yx_data;
s_info->sensor_platform_info->mount_angle = 0;
+ msm_flash_src._fsrc.ext_driver_src.led_en =
+ GPIO_CAM_GP_LED_EN1;
+ msm_flash_src._fsrc.ext_driver_src.led_flash_en =
+ GPIO_CAM_GP_LED_EN2;
+#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+ defined(CONFIG_GPIO_SX150X_MODULE))
+ msm_flash_src._fsrc.ext_driver_src.expander_info =
+ cam_expander_info;
+#endif
}
platform_device_register(&msm_camera_server);
@@ -615,11 +622,9 @@
I2C_BOARD_INFO("s5k3l1yx", 0x20),
.platform_data = &msm_camera_sensor_s5k3l1yx_data,
},
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
{
- I2C_BOARD_INFO("sc628a", 0x6E),
+ I2C_BOARD_INFO("tps61310", 0x66),
},
-#endif
};
struct msm_camera_board_info msm8930_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index e23b76c..3c3843a 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -115,7 +115,7 @@
static struct kgsl_device_platform_data kgsl_3d0_pdata = {
.pwrlevel = {
{
- .gpu_freq = 400000000,
+ .gpu_freq = 450000000,
.bus_freq = 3,
.io_fraction = 0,
},
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index fc89a11..2f24c95 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -84,6 +84,9 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar-slim"),
+ REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
REGULATOR_SUPPLY("vddp", "0-0048"),
};
VREG_CONSUMERS(L12) = {
@@ -118,6 +121,8 @@
REGULATOR_SUPPLY("8038_l20", NULL),
REGULATOR_SUPPLY("VDDD_CDC_D", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "sitar-slim"),
+ REGULATOR_SUPPLY("VDDD_CDC_D", "sitar1p1-slim"),
+ REGULATOR_SUPPLY("CDC_VDDA_A_1P2V", "sitar1p1-slim"),
};
VREG_CONSUMERS(L21) = {
REGULATOR_SUPPLY("8038_l21", NULL),
@@ -159,6 +164,7 @@
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8038_s4", NULL),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar-slim"),
+ REGULATOR_SUPPLY("CDC_VDD_CP", "sitar1p1-slim"),
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8038_s5", NULL),
@@ -446,11 +452,11 @@
* ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 375000, 1050000, 200, "8038_s3",
0, 0),
- PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 375000, 1050000, 200, "8038_s3",
0, 1),
- PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 1050000, 1050000, 200, "8038_s3",
+ PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 375000, 1050000, 200, "8038_s3",
0, 2),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 1c4251c..0fff814 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -131,14 +131,15 @@
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
+#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
#define MSM_ION_HEAP_NUM 7
#else
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_QSECOM_SIZE 0x300000 /* (3MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
@@ -797,6 +798,70 @@
.platform_data = &sitar_platform_data,
},
};
+
+static struct wcd9xxx_pdata sitar1p1_platform_data = {
+ .slimbus_slave_device = {
+ .name = "sitar-slave",
+ .e_addr = {0, 0, 0x70, 0, 0x17, 2},
+ },
+ .irq = MSM_GPIO_TO_INT(62),
+ .irq_base = SITAR_INTERRUPT_BASE,
+ .num_irqs = NR_WCD9XXX_IRQS,
+ .reset_gpio = 42,
+ .micbias = {
+ .ldoh_v = SITAR_LDOH_2P85_V,
+ .cfilt1_mv = 1800,
+ .cfilt2_mv = 1800,
+ .bias1_cfilt_sel = SITAR_CFILT1_SEL,
+ .bias2_cfilt_sel = SITAR_CFILT2_SEL,
+ },
+ .regulator = {
+ {
+ .name = "CDC_VDD_CP",
+ .min_uV = 1950000,
+ .max_uV = 2200000,
+ .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 = 1200000,
+ .max_uV = 1200000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
+ },
+ {
+ .name = "CDC_VDDA_A_1P2V",
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
+ },
+ },
+};
+
+static struct slim_device msm_slim_sitar1p1 = {
+ .name = "sitar1p1-slim",
+ .e_addr = {0, 1, 0x70, 0, 0x17, 2},
+ .dev = {
+ .platform_data = &sitar1p1_platform_data,
+ },
+};
#endif
@@ -806,6 +871,10 @@
.bus_num = 1,
.slim_slave = &msm_slim_sitar,
},
+ {
+ .bus_num = 1,
+ .slim_slave = &msm_slim_sitar1p1,
+ },
#endif
/* add more slimbus slaves as needed */
};
@@ -2267,6 +2336,8 @@
platform_device_register(&msm8930_device_rpm_regulator);
msm_clock_init(&msm8930_clock_init_data);
msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
+ android_usb_pdata.swfi_latency =
+ msm_rpmrs_levels[0].latency_us;
msm8930_init_gpiomux();
msm8960_device_qup_spi_gsbi1.dev.platform_data =
&msm8960_qup_spi_gsbi1_pdata;
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 371bb53..ad9b03d 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -197,6 +197,7 @@
.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+ ._fsrc.ext_driver_src.flash_id = MAM_CAMERA_EXT_LED_FLASH_SC628A,
};
#endif
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 978eb09..1c6c600 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -55,6 +55,21 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting external_vfr[] = {
+ /* Suspended state */
+ {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+ /* Active state */
+ {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+};
+
static struct gpiomux_setting gsbi_uart = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_8MA,
@@ -424,6 +439,16 @@
},
};
+static struct msm_gpiomux_config msm8960_external_vfr_configs[] __initdata = {
+ {
+ .gpio = 23, /* EXTERNAL VFR */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &external_vfr[0],
+ [GPIOMUX_ACTIVE] = &external_vfr[1],
+ },
+ },
+};
+
static struct msm_gpiomux_config msm8960_gsbi8_uart_configs[] __initdata = {
{
.gpio = 34, /* GSBI8 UART3 */
@@ -953,15 +978,19 @@
else
msm_gpiomux_install(msm8960_gsbi5_uart_configs,
ARRAY_SIZE(msm8960_gsbi5_uart_configs));
- /* For 8960 Fusion 2.2 Primary IPC */
- if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE)
+
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
+ /* For 8960 Fusion 2.2 Primary IPC */
msm_gpiomux_install(msm8960_fusion_gsbi_configs,
ARRAY_SIZE(msm8960_fusion_gsbi_configs));
+ /* For SGLTE 8960 Fusion External VFR */
+ msm_gpiomux_install(msm8960_external_vfr_configs,
+ ARRAY_SIZE(msm8960_external_vfr_configs));
+ }
#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
msm_gpiomux_install(msm8960_sdcc2_configs,
ARRAY_SIZE(msm8960_sdcc2_configs));
#endif
-
return 0;
}
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 3923ecf..edb6f03 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -497,11 +497,11 @@
* ID name always_on pd min_uV max_uV en_t supply
* system_uA reg_ID
*/
- PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 1),
- PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 2),
- PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+ PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 375000, 1050000, 200, "8921_s7",
0, 3),
PM8XXX_LDO(L29, "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
0, 4),
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index 3df5000..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,
@@ -307,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;
@@ -333,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.c b/arch/arm/mach-msm/board-9615.c
index 3b99e6c..67697d2 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -127,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},
@@ -657,6 +754,7 @@
.phy_type = SNPS_28NM_INTEGRATED_PHY,
.vbus_power = msm_hsusb_vbus_power,
.disable_reset_on_disconnect = true,
+ .enable_lpm_on_dev_suspend = true,
};
static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
@@ -876,7 +974,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-copper.c b/arch/arm/mach-msm/board-copper.c
index eb06b81..c28d172 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -390,6 +390,40 @@
.id = -1,
};
+#define SHARED_IMEM_TZ_BASE 0xFE805720
+static struct resource tzlog_resources[] = {
+ {
+ .start = SHARED_IMEM_TZ_BASE,
+ .end = SHARED_IMEM_TZ_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device apq_device_tz_log = {
+ .name = "tz_log",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tzlog_resources),
+ .resource = tzlog_resources,
+};
+
+#ifdef CONFIG_HW_RANDOM_MSM
+/* PRNG device */
+#define MSM_PRNG_PHYS 0xF9BFF000
+static struct resource rng_resources = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_PRNG_PHYS,
+ .end = MSM_PRNG_PHYS + SZ_512 - 1,
+};
+
+struct platform_device msm8974_device_rng = {
+ .name = "msm_rng",
+ .id = 0,
+ .num_resources = 1,
+ .resource = &rng_resources,
+};
+#endif
+
+
void __init msm_copper_add_devices(void)
{
#ifdef CONFIG_ION_MSM
@@ -399,6 +433,10 @@
platform_device_register(&android_usb_device);
platform_add_devices(msm_copper_stub_regulator_devices,
msm_copper_stub_regulator_devices_len);
+ platform_device_register(&apq_device_tz_log);
+#ifdef CONFIG_HW_RANDOM_MSM
+ platform_device_register(&msm8974_device_rng);
+#endif
}
/*
@@ -463,10 +501,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 c069aab..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"},
@@ -194,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,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index b0799c2..e172481 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2639,7 +2639,11 @@
#define MSM_SMI_SIZE 0x4000000
#define KERNEL_SMI_BASE (MSM_SMI_BASE)
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+#define KERNEL_SMI_SIZE 0x000000
+#else
#define KERNEL_SMI_SIZE 0x600000
+#endif
#define USER_SMI_BASE (KERNEL_SMI_BASE + KERNEL_SMI_SIZE)
#define USER_SMI_SIZE (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
@@ -2648,7 +2652,7 @@
#define MSM_ION_SF_SIZE 0x4000000 /* 64MB */
#define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE
#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) Must be a multiple of 64K */
+#define MSM_ION_MM_SIZE 0x3c00000 /* (60MB) Must be a multiple of 64K */
#define MSM_ION_MFC_SIZE SZ_8K
#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
#define MSM_ION_WB_SIZE 0xC00000 /* 12MB */
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index f51eb5b..fcd6386 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2651,14 +2651,14 @@
}
#endif /* CONFIG_DEBUG_FS */
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
};
static struct clk measure_clk = {
.dbg_name = "measure_clk",
- .ops = &measure_clk_ops,
+ .ops = &clk_ops_measure,
CLK_INIT(measure_clk),
};
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 3a0b87e..93251a4 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4882,7 +4882,7 @@
}
#endif /* CONFIG_DEBUG_FS */
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
};
@@ -4890,7 +4890,7 @@
static struct measure_clk measure_clk = {
.c = {
.dbg_name = "measure_clk",
- .ops = &measure_clk_ops,
+ .ops = &clk_ops_measure,
CLK_INIT(measure_clk.c),
},
.multiplier = 1,
@@ -4992,9 +4992,9 @@
CLK_LOOKUP("iface_clk", sdc2_p_clk.c, "msm_sdcc.2"),
CLK_LOOKUP("iface_clk", sdc3_p_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", sdc4_p_clk.c, "msm_sdcc.4"),
- CLK_LOOKUP("iface_clk", pcie_p_clk.c, ""),
- CLK_LOOKUP("ref_clk", pcie_phy_ref_clk.c, ""),
- CLK_LOOKUP("bus_clk", pcie_a_clk.c, ""),
+ CLK_LOOKUP("iface_clk", pcie_p_clk.c, "msm_pcie"),
+ CLK_LOOKUP("ref_clk", pcie_phy_ref_clk.c, "msm_pcie"),
+ CLK_LOOKUP("bus_clk", pcie_a_clk.c, "msm_pcie"),
CLK_LOOKUP("core_clk", adm0_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", adm0_p_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", pmic_arb0_p_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 8d2b37a..6972302 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3445,7 +3445,7 @@
}
#endif /* CONFIG_DEBUG_FS */
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
};
@@ -3453,7 +3453,7 @@
static struct measure_clk measure_clk = {
.c = {
.dbg_name = "measure_clk",
- .ops = &measure_clk_ops,
+ .ops = &clk_ops_measure,
CLK_INIT(measure_clk.c),
},
.multiplier = 1,
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index a950e46..66d849a 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -1560,7 +1560,7 @@
}
#endif /* CONFIG_DEBUG_FS */
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
};
@@ -1568,7 +1568,7 @@
static struct measure_clk measure_clk = {
.c = {
.dbg_name = "measure_clk",
- .ops = &measure_clk_ops,
+ .ops = &clk_ops_measure,
CLK_INIT(measure_clk.c),
},
.multiplier = 1,
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 03667d7..c0245a3 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -4699,7 +4699,7 @@
}
#endif /* CONFIG_DEBUG_FS */
-static struct clk_ops measure_clk_ops = {
+static struct clk_ops clk_ops_measure = {
.set_parent = measure_clk_set_parent,
.get_rate = measure_clk_get_rate,
};
@@ -4707,7 +4707,7 @@
static struct measure_clk measure_clk = {
.c = {
.dbg_name = "measure_clk",
- .ops = &measure_clk_ops,
+ .ops = &clk_ops_measure,
CLK_INIT(measure_clk.c),
},
.multiplier = 1,
@@ -4906,10 +4906,11 @@
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("core_clk", q6ss_xo_clk.c, "pil-q6v5-lpass"),
+ CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+ CLK_DUMMY("core_clk", PRNG_CLK , "msm_rng.0", OFF),
/* TODO: Remove dummy clocks as soon as they become unnecessary */
CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index e1b3381..4f365fa 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -627,20 +627,16 @@
return HANDOFF_ENABLED_CLK;
}
-struct clk_ops clk_ops_gnd = {
-};
+struct clk_ops clk_ops_empty;
struct fixed_clk gnd_clk = {
.c = {
.dbg_name = "ground_clk",
- .ops = &clk_ops_gnd,
+ .ops = &clk_ops_empty,
CLK_INIT(gnd_clk.c),
},
};
-struct clk_ops clk_ops_measure = {
-};
-
static int branch_clk_enable(struct clk *clk)
{
unsigned long flags;
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index a419d69..ffc7057 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -77,7 +77,7 @@
*/
#define DEFINE_CLK_MEASURE(name) \
struct clk name = { \
- .ops = &clk_ops_measure, \
+ .ops = &clk_ops_empty, \
.dbg_name = #name, \
CLK_INIT(name), \
}; \
@@ -264,7 +264,7 @@
struct clk c;
};
-extern struct clk_ops clk_ops_measure;
+extern struct clk_ops clk_ops_empty;
static inline struct measure_clk *to_measure_clk(struct clk *clk)
{
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index c8d53cb..547e633 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -153,8 +153,6 @@
struct clk c;
};
-extern struct clk_ops clk_ops_measure;
-
static inline struct measure_clk *to_measure_clk(struct clk *clk)
{
return container_of(clk, struct measure_clk, c);
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index d842d45..f71d6d5 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -39,7 +39,7 @@
.id = PLL_0,
.mode_reg = PLLn_MODE(0),
.c = {
- .ops = &clk_pll_ops,
+ .ops = &clk_ops_pll,
.dbg_name = "pll0_clk",
CLK_INIT(pll0_clk.c),
},
@@ -49,7 +49,7 @@
.id = PLL_1,
.mode_reg = PLLn_MODE(1),
.c = {
- .ops = &clk_pll_ops,
+ .ops = &clk_ops_pll,
.dbg_name = "pll1_clk",
CLK_INIT(pll1_clk.c),
},
@@ -59,7 +59,7 @@
.id = PLL_2,
.mode_reg = PLLn_MODE(2),
.c = {
- .ops = &clk_pll_ops,
+ .ops = &clk_ops_pll,
.dbg_name = "pll2_clk",
CLK_INIT(pll2_clk.c),
},
@@ -69,7 +69,7 @@
.id = PLL_4,
.mode_reg = PLL4_MODE,
.c = {
- .ops = &clk_pll_ops,
+ .ops = &clk_ops_pll,
.dbg_name = "pll4_clk",
CLK_INIT(pll4_clk.c),
},
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index 3a232c5..ead4fcb 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -427,7 +427,7 @@
return HANDOFF_ENABLED_CLK;
}
-struct clk_ops clk_pll_ops = {
+struct clk_ops clk_ops_pll = {
.enable = pll_clk_enable,
.disable = pll_clk_disable,
.handoff = pll_clk_handoff,
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
index 231668f..a8c642f 100644
--- a/arch/arm/mach-msm/clock-pll.h
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -43,7 +43,7 @@
void *const __iomem *base;
};
-extern struct clk_ops clk_pll_ops;
+extern struct clk_ops clk_ops_pll;
static inline struct pll_shared_clk *to_pll_shared_clk(struct clk *clk)
{
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f6eee76..424edce 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -82,6 +82,25 @@
#define MSM_HSUSB4_PHYS 0x12530000
#define MSM_HSUSB4_SIZE SZ_4K
+/* Address of PCIE20 PARF */
+#define PCIE20_PARF_PHYS 0x1b600000
+#define PCIE20_PARF_SIZE SZ_128
+
+/* Address of PCIE20 ELBI */
+#define PCIE20_ELBI_PHYS 0x1b502000
+#define PCIE20_ELBI_SIZE SZ_256
+
+/* Address of PCIE20 */
+#define PCIE20_PHYS 0x1b500000
+#define PCIE20_SIZE SZ_4K
+
+/* AXI address for PCIE device BAR resources */
+#define PCIE_AXI_BAR_PHYS 0x08000000
+#define PCIE_AXI_BAR_SIZE SZ_8M
+
+/* AXI address for PCIE device config space */
+#define PCIE_AXI_CONF_PHYS 0x08c00000
+#define PCIE_AXI_CONF_SIZE SZ_4K
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
@@ -458,13 +477,24 @@
*/
struct msm_dai_auxpcm_pdata apq_auxpcm_pdata = {
.clk = "pcm_clk",
- .mode = AFE_PCM_CFG_MODE_PCM,
- .sync = AFE_PCM_CFG_SYNC_INT,
- .frame = AFE_PCM_CFG_FRM_256BPF,
- .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
- .slot = 0,
- .data = AFE_PCM_CFG_CDATAOE_MASTER,
- .pcm_clk_rate = 2048000,
+ .mode_8k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 2048000,
+ },
+ .mode_16k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 4096000,
+ }
};
struct platform_device apq_cpudai_auxpcm_rx = {
@@ -1518,6 +1548,46 @@
},
};
+static struct resource resources_msm_pcie[] = {
+ {
+ .name = "parf",
+ .start = PCIE20_PARF_PHYS,
+ .end = PCIE20_PARF_PHYS + PCIE20_PARF_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "elbi",
+ .start = PCIE20_ELBI_PHYS,
+ .end = PCIE20_ELBI_PHYS + PCIE20_ELBI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "pcie20",
+ .start = PCIE20_PHYS,
+ .end = PCIE20_PHYS + PCIE20_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "axi_bar",
+ .start = PCIE_AXI_BAR_PHYS,
+ .end = PCIE_AXI_BAR_PHYS + PCIE_AXI_BAR_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "axi_conf",
+ .start = PCIE_AXI_CONF_PHYS,
+ .end = PCIE_AXI_CONF_PHYS + PCIE_AXI_CONF_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm_device_pcie = {
+ .name = "msm_pcie",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_msm_pcie),
+ .resource = resources_msm_pcie,
+};
+
#ifdef CONFIG_HW_RANDOM_MSM
/* PRNG device */
#define MSM_PRNG_PHYS 0x1A500000
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index f1553b6..e474e36 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1892,13 +1892,24 @@
*/
struct msm_dai_auxpcm_pdata auxpcm_pdata = {
.clk = "pcm_clk",
- .mode = AFE_PCM_CFG_MODE_PCM,
- .sync = AFE_PCM_CFG_SYNC_INT,
- .frame = AFE_PCM_CFG_FRM_256BPF,
- .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
- .slot = 0,
- .data = AFE_PCM_CFG_CDATAOE_MASTER,
- .pcm_clk_rate = 2048000,
+ .mode_8k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 2048000,
+ },
+ .mode_16k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 4096000,
+ }
};
struct platform_device msm_cpudai_auxpcm_rx = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 8eb1580..76d79a6 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -135,6 +135,8 @@
},
};
+#define MSM_HSUSB_RESUME_GPIO 79
+
static struct resource resources_hsusb[] = {
{
.start = MSM9615_HSUSB_PHYS,
@@ -146,6 +148,12 @@
.end = USB1_HS_IRQ,
.flags = IORESOURCE_IRQ,
},
+ {
+ .start = MSM_HSUSB_RESUME_GPIO,
+ .end = MSM_HSUSB_RESUME_GPIO,
+ .name = "USB_RESUME",
+ .flags = IORESOURCE_IO,
+ },
};
static struct resource resources_usb_bam[] = {
@@ -448,13 +456,24 @@
*/
struct msm_dai_auxpcm_pdata auxpcm_pdata = {
.clk = "pcm_clk",
- .mode = AFE_PCM_CFG_MODE_PCM,
- .sync = AFE_PCM_CFG_SYNC_INT,
- .frame = AFE_PCM_CFG_FRM_256BPF,
- .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
- .slot = 0,
- .data = AFE_PCM_CFG_CDATAOE_MASTER,
- .pcm_clk_rate = 2048000,
+ .mode_8k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 2048000,
+ },
+ .mode_16k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 4096000,
+ }
};
struct platform_device msm_cpudai_auxpcm_rx = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index 9a03afd..2e0253b 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -568,26 +568,26 @@
.mids = {1, -1}
};
-static struct msm_iommu_ctx_dev mdp_vg1_ctx = {
- .name = "mdp_vg1",
+static struct msm_iommu_ctx_dev mdp_port0_cb0_ctx = {
+ .name = "mdp_port0_cb0",
.num = 0,
.mids = {0, 2, -1}
};
-static struct msm_iommu_ctx_dev mdp_rgb1_ctx = {
- .name = "mdp_rgb1",
+static struct msm_iommu_ctx_dev mdp_port0_cb1_ctx = {
+ .name = "mdp_port0_cb1",
.num = 1,
.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
};
-static struct msm_iommu_ctx_dev mdp_vg2_ctx = {
- .name = "mdp_vg2",
+static struct msm_iommu_ctx_dev mdp_port1_cb0_ctx = {
+ .name = "mdp_port1_cb0",
.num = 0,
.mids = {0, 2, -1}
};
-static struct msm_iommu_ctx_dev mdp_rgb2_ctx = {
- .name = "mdp_rgb2",
+static struct msm_iommu_ctx_dev mdp_port1_cb1_ctx = {
+ .name = "mdp_port1_cb1",
.num = 1,
.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
};
@@ -732,39 +732,39 @@
},
};
-static struct platform_device msm_device_mdp_vg1_ctx = {
+static struct platform_device msm_device_mdp_port0_cb0_ctx = {
.name = "msm_iommu_ctx",
.id = 4,
.dev = {
.parent = &msm_device_iommu_mdp0.dev,
- .platform_data = &mdp_vg1_ctx,
+ .platform_data = &mdp_port0_cb0_ctx,
},
};
-static struct platform_device msm_device_mdp_rgb1_ctx = {
+static struct platform_device msm_device_mdp_port0_cb1_ctx = {
.name = "msm_iommu_ctx",
.id = 5,
.dev = {
.parent = &msm_device_iommu_mdp0.dev,
- .platform_data = &mdp_rgb1_ctx,
+ .platform_data = &mdp_port0_cb1_ctx,
},
};
-static struct platform_device msm_device_mdp_vg2_ctx = {
+static struct platform_device msm_device_mdp_port1_cb0_ctx = {
.name = "msm_iommu_ctx",
.id = 6,
.dev = {
.parent = &msm_device_iommu_mdp1.dev,
- .platform_data = &mdp_vg2_ctx,
+ .platform_data = &mdp_port1_cb0_ctx,
},
};
-static struct platform_device msm_device_mdp_rgb2_ctx = {
+static struct platform_device msm_device_mdp_port1_cb1_ctx = {
.name = "msm_iommu_ctx",
.id = 7,
.dev = {
.parent = &msm_device_iommu_mdp1.dev,
- .platform_data = &mdp_rgb2_ctx,
+ .platform_data = &mdp_port1_cb1_ctx,
},
};
@@ -950,10 +950,10 @@
static struct platform_device *msm_iommu_common_ctx_devs[] = {
&msm_device_vpe_src_ctx,
&msm_device_vpe_dst_ctx,
- &msm_device_mdp_vg1_ctx,
- &msm_device_mdp_rgb1_ctx,
- &msm_device_mdp_vg2_ctx,
- &msm_device_mdp_rgb2_ctx,
+ &msm_device_mdp_port0_cb0_ctx,
+ &msm_device_mdp_port0_cb1_ctx,
+ &msm_device_mdp_port1_cb0_ctx,
+ &msm_device_mdp_port1_cb1_ctx,
&msm_device_rot_src_ctx,
&msm_device_rot_dst_ctx,
&msm_device_ijpeg_src_ctx,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8f42ede..100d99a 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -167,6 +167,8 @@
extern struct platform_device msm_device_dmov_adm0;
extern struct platform_device msm_device_dmov_adm1;
+extern struct platform_device msm_device_pcie;
+
extern struct platform_device msm_device_nand;
extern struct platform_device msm_device_tssc;
@@ -394,3 +396,7 @@
extern struct platform_device apq8064_rtb_device;
extern struct platform_device msm8960_cache_dump_device;
+
+extern struct platform_device apq_device_tz_log;
+
+extern struct platform_device msm8974_device_rng;
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 56210d5..17ac3ac 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -125,9 +125,15 @@
const struct pmic8058_leds_platform_data *driver_channel;
};
+enum msm_camera_ext_led_flash_id {
+ MAM_CAMERA_EXT_LED_FLASH_SC628A,
+ MAM_CAMERA_EXT_LED_FLASH_TPS61310,
+};
+
struct msm_camera_sensor_flash_external {
uint32_t led_en;
uint32_t led_flash_en;
+ enum msm_camera_ext_led_flash_id flash_id;
struct msm_cam_expander_info *expander_info;
};
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/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index dfb100c..1a3a022 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -56,14 +56,28 @@
unsigned int domain_alloc_flags;
};
+
+struct msm_iova_partition {
+ unsigned long start;
+ unsigned long size;
+};
+
+struct msm_iova_layout {
+ struct msm_iova_partition *partitions;
+ int npartitions;
+ const char *client_name;
+ unsigned int domain_flags;
+};
+
#if defined(CONFIG_MSM_IOMMU)
extern struct iommu_domain *msm_get_iommu_domain(int domain_num);
-extern unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+extern int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
- unsigned long align);
+ unsigned long align,
+ unsigned long *iova);
extern void msm_free_iova_address(unsigned long iova,
unsigned int iommu_domain,
@@ -97,16 +111,19 @@
unsigned int partition_no,
unsigned long size);
+extern int msm_register_domain(struct msm_iova_layout *layout);
+
#else
static inline struct iommu_domain
*msm_get_iommu_domain(int subsys_id) { return NULL; }
-static inline unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+static inline int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
- unsigned long align) { return 0; }
+ unsigned long align,
+ unsigned long *iova) { return -ENOMEM; }
static inline void msm_free_iova_address(unsigned long iova,
unsigned int iommu_domain,
@@ -153,6 +170,11 @@
{
return;
}
+
+static inline int msm_register_domain(struct msm_iova_layout *layout)
+{
+ return -ENODEV;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d46b4..daf32a5 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -74,4 +74,8 @@
};
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);
+unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
+int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
#endif
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 34c16d1..271e252b 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -10,27 +10,34 @@
* GNU General Public License for more details.
*/
-#include <mach/msm_subsystem_map.h>
-#include <linux/memory_alloc.h>
+#include <linux/init.h>
#include <linux/iommu.h>
+#include <linux/memory_alloc.h>
#include <linux/platform_device.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/sizes.h>
#include <asm/page.h>
-#include <linux/init.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
+#include <mach/msm_subsystem_map.h>
/* dummy 64K for overmapping */
char iommu_dummy[2*SZ_64K-4];
-struct msm_iommu_domain_state {
- struct msm_iommu_domain *domains;
- int ndomains;
+struct msm_iova_data {
+ struct rb_node node;
+ struct mem_pool *pools;
+ int npools;
+ struct iommu_domain *domain;
+ int domain_num;
};
-static struct msm_iommu_domain_state domain_state;
+static struct rb_root domain_root;
+DEFINE_MUTEX(domain_mutex);
+static atomic_t domain_nums = ATOMIC_INIT(-1);
int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
@@ -127,9 +134,10 @@
if (size & (align - 1))
return -EINVAL;
- iova = msm_allocate_iova_address(domain_no, partition_no, size, align);
+ ret = msm_allocate_iova_address(domain_no, partition_no, size, align,
+ &iova);
- if (!iova)
+ if (ret)
return -ENOMEM;
ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
@@ -152,73 +160,210 @@
msm_free_iova_address(iova, domain_no, partition_no, size);
}
+static struct msm_iova_data *find_domain(int domain_num)
+{
+ struct rb_root *root = &domain_root;
+ struct rb_node *p = root->rb_node;
+
+ mutex_lock(&domain_mutex);
+
+ while (p) {
+ struct msm_iova_data *node;
+
+ node = rb_entry(p, struct msm_iova_data, node);
+ if (domain_num < node->domain_num)
+ p = p->rb_left;
+ else if (domain_num > domain_num)
+ p = p->rb_right;
+ else {
+ mutex_unlock(&domain_mutex);
+ return node;
+ }
+ }
+ mutex_unlock(&domain_mutex);
+ return NULL;
+}
+
+static int add_domain(struct msm_iova_data *node)
+{
+ struct rb_root *root = &domain_root;
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+
+ mutex_lock(&domain_mutex);
+ while (*p) {
+ struct msm_iova_data *tmp;
+ parent = *p;
+
+ tmp = rb_entry(parent, struct msm_iova_data, node);
+
+ if (node->domain_num < tmp->domain_num)
+ p = &(*p)->rb_left;
+ else if (node->domain_num > tmp->domain_num)
+ p = &(*p)->rb_right;
+ else
+ BUG();
+ }
+ rb_link_node(&node->node, parent, p);
+ rb_insert_color(&node->node, root);
+ mutex_unlock(&domain_mutex);
+ return 0;
+}
+
struct iommu_domain *msm_get_iommu_domain(int domain_num)
{
- if (domain_num >= 0 && domain_num < domain_state.ndomains)
- return domain_state.domains[domain_num].domain;
+ struct msm_iova_data *data;
+
+ data = find_domain(domain_num);
+
+ if (data)
+ return data->domain;
else
return NULL;
}
-unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
+int msm_allocate_iova_address(unsigned int iommu_domain,
unsigned int partition_no,
unsigned long size,
- unsigned long align)
+ unsigned long align,
+ unsigned long *iova)
{
+ struct msm_iova_data *data;
struct mem_pool *pool;
- unsigned long iova;
+ unsigned long va;
- if (iommu_domain >= domain_state.ndomains)
- return 0;
+ data = find_domain(iommu_domain);
- if (partition_no >= domain_state.domains[iommu_domain].npools)
- return 0;
+ if (!data)
+ return -EINVAL;
- pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
+ if (partition_no >= data->npools)
+ return -EINVAL;
+
+ pool = &data->pools[partition_no];
if (!pool->gpool)
- return 0;
+ return -EINVAL;
- iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
- if (iova)
+ va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
+ if (va) {
pool->free -= size;
+ /* Offset because genpool can't handle 0 addresses */
+ if (pool->paddr == 0)
+ va -= SZ_4K;
+ *iova = va;
+ return 0;
+ }
- return iova;
+ return -ENOMEM;
}
void msm_free_iova_address(unsigned long iova,
- unsigned int iommu_domain,
- unsigned int partition_no,
- unsigned long size)
+ unsigned int iommu_domain,
+ unsigned int partition_no,
+ unsigned long size)
{
+ struct msm_iova_data *data;
struct mem_pool *pool;
- if (iommu_domain >= domain_state.ndomains) {
+ data = find_domain(iommu_domain);
+
+ if (!data) {
WARN(1, "Invalid domain %d\n", iommu_domain);
return;
}
- if (partition_no >= domain_state.domains[iommu_domain].npools) {
+ if (partition_no >= data->npools) {
WARN(1, "Invalid partition %d for domain %d\n",
partition_no, iommu_domain);
return;
}
- pool = &domain_state.domains[iommu_domain].iova_pools[partition_no];
+ pool = &data->pools[partition_no];
if (!pool)
return;
pool->free += size;
+
+ /* Offset because genpool can't handle 0 addresses */
+ if (pool->paddr == 0)
+ iova += SZ_4K;
+
gen_pool_free(pool->gpool, iova, size);
}
+int msm_register_domain(struct msm_iova_layout *layout)
+{
+ int i;
+ struct msm_iova_data *data;
+ struct mem_pool *pools;
+
+ if (!layout)
+ return -EINVAL;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+ if (!data)
+ return -ENOMEM;
+
+ pools = kmalloc(sizeof(struct mem_pool) * layout->npartitions,
+ GFP_KERNEL);
+
+ if (!pools)
+ goto out;
+
+ for (i = 0; i < layout->npartitions; i++) {
+ if (layout->partitions[i].size == 0)
+ continue;
+
+ pools[i].gpool = gen_pool_create(PAGE_SHIFT, -1);
+
+ if (!pools[i].gpool)
+ continue;
+
+ pools[i].paddr = layout->partitions[i].start;
+ pools[i].size = layout->partitions[i].size;
+
+ /*
+ * genalloc can't handle a pool starting at address 0.
+ * For now, solve this problem by offsetting the value
+ * put in by 4k.
+ * gen pool address = actual address + 4k
+ */
+ if (pools[i].paddr == 0)
+ layout->partitions[i].start += SZ_4K;
+
+ if (gen_pool_add(pools[i].gpool,
+ layout->partitions[i].start,
+ layout->partitions[i].size, -1)) {
+ gen_pool_destroy(pools[i].gpool);
+ pools[i].gpool = NULL;
+ continue;
+ }
+ }
+
+ data->pools = pools;
+ data->npools = layout->npartitions;
+ data->domain_num = atomic_inc_return(&domain_nums);
+ data->domain = iommu_domain_alloc(layout->domain_flags);
+
+ add_domain(data);
+
+ return data->domain_num;
+
+out:
+ kfree(data);
+
+ return -EINVAL;
+}
+
int msm_use_iommu()
{
/*
* If there are no domains, don't bother trying to use the iommu
*/
- return domain_state.ndomains && iommu_found();
+ return iommu_found();
}
static int __init iommu_domain_probe(struct platform_device *pdev)
@@ -229,64 +374,52 @@
if (!p)
return -ENODEV;
- domain_state.domains = p->domains;
- domain_state.ndomains = p->ndomains;
+ for (i = 0; i < p->ndomains; i++) {
+ struct msm_iova_layout l;
+ struct msm_iova_partition *part;
+ struct msm_iommu_domain *domains;
- for (i = 0; i < domain_state.ndomains; i++) {
- domain_state.domains[i].domain = iommu_domain_alloc(
- p->domain_alloc_flags);
- if (!domain_state.domains[i].domain)
+ domains = p->domains;
+ l.npartitions = domains[i].npools;
+ part = kmalloc(
+ sizeof(struct msm_iova_partition) * l.npartitions,
+ GFP_KERNEL);
+
+ if (!part) {
+ pr_info("%s: could not allocate space for domain %d",
+ __func__, i);
continue;
-
- for (j = 0; j < domain_state.domains[i].npools; j++) {
- struct mem_pool *pool = &domain_state.domains[i].
- iova_pools[j];
- mutex_init(&pool->pool_mutex);
- if (pool->size) {
- pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
-
- if (!pool->gpool) {
- pr_err("%s: could not allocate pool\n",
- __func__);
- pr_err("%s: domain %d iova space %d\n",
- __func__, i, j);
- continue;
- }
-
- if (gen_pool_add(pool->gpool, pool->paddr,
- pool->size, -1)) {
- pr_err("%s: could not add memory\n",
- __func__);
- pr_err("%s: domain %d pool %d\n",
- __func__, i, j);
- gen_pool_destroy(pool->gpool);
- pool->gpool = NULL;
- continue;
- }
- } else {
- pool->gpool = NULL;
- }
}
+
+ for (j = 0; j < l.npartitions; j++) {
+ part[j].start = p->domains[i].iova_pools[j].paddr;
+ part[j].size = p->domains[i].iova_pools[j].size;
+ }
+
+ l.partitions = part;
+
+ msm_register_domain(&l);
+
+ kfree(part);
}
for (i = 0; i < p->nnames; i++) {
- int domain_idx;
struct device *ctx = msm_iommu_get_ctx(
p->domain_names[i].name);
+ struct iommu_domain *domain;
if (!ctx)
continue;
- domain_idx = p->domain_names[i].domain;
+ domain = msm_get_iommu_domain(p->domain_names[i].domain);
- if (!domain_state.domains[domain_idx].domain)
+ if (!domain)
continue;
- if (iommu_attach_device(domain_state.domains[domain_idx].domain,
- ctx)) {
- WARN(1, "%s: could not attach domain %d to context %s."
+ if (iommu_attach_device(domain, ctx)) {
+ WARN(1, "%s: could not attach domain %p to context %s."
" iommu programming will not occur.\n",
- __func__, domain_idx,
+ __func__, domain,
p->domain_names[i].name);
continue;
}
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
index af39dc3..ed0b2f0 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -29,6 +29,7 @@
unsigned long p_start;
unsigned long p_size;
unsigned long p_min;
+ unsigned int p_tail;
};
struct ocmem_plat_data {
@@ -70,19 +71,20 @@
unsigned long start;
unsigned long size;
unsigned long min;
+ unsigned int tail;
};
/* 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},
+ /* name, id, start, size, min, tail */
+ { "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000, 0},
+ { "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000, 1},
+ { "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0, 0},
+ { "voice", OCMEM_VOICE, 0x0, 0x0, 0x0, 0 },
+ { "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
+ { "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
+ { "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000, 0},
+ { "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
};
static inline int get_id(const char *name)
@@ -142,6 +144,7 @@
parts[j].p_size = qt[i].size;
parts[j].p_start = qt[i].start;
parts[j].p_min = qt[i].min;
+ parts[j].p_tail = qt[i].tail;
j++;
}
BUG_ON(j != nr_parts);
@@ -225,6 +228,13 @@
zone->max_regions = 0;
INIT_LIST_HEAD(&zone->region_list);
zone->z_ops = z_ops;
+ if (part->p_tail) {
+ z_ops->allocate = allocate_tail;
+ z_ops->free = free_tail;
+ } else {
+ z_ops->allocate = allocate_head;
+ z_ops->free = free_head;
+ }
active_zones++;
if (active_zones == 1)
diff --git a/arch/arm/mach-msm/ocmem_allocator.c b/arch/arm/mach-msm/ocmem_allocator.c
new file mode 100644
index 0000000..71cacda
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_allocator.c
@@ -0,0 +1,105 @@
+/* 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 */
+
+/* The allocators work as follows:
+ Constraints:
+ 1) There is no IOMMU access to OCMEM hence successive allocations
+ in the zone must be physically contiguous
+ 2) Allocations must be freed in reverse order within a zone.
+
+ z->z_start: Fixed pointer to the start of a zone
+ z->z_end: Fixed pointer to the end of a zone
+
+ z->z_head: Movable pointer to the next free area when growing at head
+ Fixed on zones that grow from tail
+
+ z->z_tail: Movable pointer to the next free area when growing at tail
+ Fixed on zones that grow from head
+
+ z->z_free: Free space in a zone that is updated on an allocation/free
+
+ reserve: Enable libgenpool to simulate tail allocations
+*/
+
+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;
+}
+
+unsigned long allocate_tail(struct ocmem_zone *z, unsigned long size)
+{
+ unsigned long offset;
+ unsigned long reserve;
+ unsigned long head;
+
+ if (z->z_tail < (z->z_head + size))
+ return -ENOMEM;
+
+ reserve = z->z_tail - z->z_head - size;
+ if (reserve) {
+ head = gen_pool_alloc(z->z_pool, reserve);
+ offset = gen_pool_alloc(z->z_pool, size);
+ gen_pool_free(z->z_pool, head, reserve);
+ } else
+ offset = gen_pool_alloc(z->z_pool, size);
+
+ if (!offset)
+ return -ENOMEM;
+
+ z->z_tail -= 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;
+}
+
+int free_tail(struct ocmem_zone *z, unsigned long offset,
+ unsigned long size)
+{
+ if (offset > z->z_tail) {
+ pr_err("ocmem: Detected out of order free "
+ "leading to fragmentation\n");
+ return -EINVAL;
+ }
+ gen_pool_free(z->z_pool, offset, size);
+ z->z_tail += 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..9d0ce0d 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;
}
@@ -575,6 +578,10 @@
"invalid proxy voting. ignoring\n"))
((struct pil_reset_ops *)desc->ops)->proxy_unvote = NULL;
+ WARN(desc->ops->proxy_unvote && !desc->proxy_timeout,
+ "A proxy timeout of 0 ms was specified for %s. Specify one in "
+ "desc->proxy_timeout.\n", desc->name);
+
pil = kzalloc(sizeof(*pil), GFP_KERNEL);
if (!pil)
return ERR_PTR(-ENOMEM);
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 8446e42..131a74b 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -116,14 +116,9 @@
int err;
struct q6v4_data *drv = dev_get_drvdata(dev);
- err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+ err = regulator_set_voltage(drv->vreg, 375000, 375000);
if (err) {
- dev_err(dev, "Failed to set regulator's voltage.\n");
- return err;
- }
- err = regulator_set_optimum_mode(drv->vreg, 100000);
- if (err < 0) {
- dev_err(dev, "Failed to set regulator's mode.\n");
+ dev_err(dev, "Failed to set regulator's voltage step.\n");
return err;
}
err = regulator_enable(drv->vreg);
@@ -131,6 +126,18 @@
dev_err(dev, "Failed to enable regulator.\n");
return err;
}
+
+ /*
+ * Q6 hardware requires a two step voltage ramp-up.
+ * Delay between the steps.
+ */
+ udelay(100);
+
+ err = regulator_set_voltage(drv->vreg, 1050000, 1050000);
+ if (err) {
+ dev_err(dev, "Failed to set regulator's voltage.\n");
+ return err;
+ }
drv->vreg_enabled = true;
return 0;
}
@@ -411,6 +418,12 @@
if (IS_ERR(drv->vreg))
return PTR_ERR(drv->vreg);
+ ret = regulator_set_optimum_mode(drv->vreg, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+ return ret;
+ }
+
drv->xo = devm_clk_get(&pdev->dev, "xo");
if (IS_ERR(drv->xo))
return PTR_ERR(drv->xo);
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 5eac539..311f8a7 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -15,66 +15,34 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/iopoll.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/clk.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
-/* Register Offsets */
#define QDSP6SS_RST_EVB 0x010
-#define LPASS_Q6SS_BCR 0x06000
-#define LPASS_Q6SS_AHB_LFABIF_CBCR 0x22000
-#define LPASS_Q6SS_XO_CBCR 0x26000
-#define AXI_HALTREQ 0x0
-#define AXI_HALTACK 0x4
-#define AXI_IDLE 0x8
-
-#define HALT_ACK_TIMEOUT_US 100000
-
-static void clk_reg_enable(void __iomem *reg)
-{
- u32 val;
- val = readl_relaxed(reg);
- val |= BIT(0);
- writel_relaxed(val, reg);
-}
-
-static void clk_reg_disable(void __iomem *reg)
-{
- u32 val;
- val = readl_relaxed(reg);
- val &= ~BIT(0);
- writel_relaxed(val, reg);
-}
+#define PROXY_TIMEOUT_MS 10000
static int pil_lpass_shutdown(struct pil_desc *pil)
{
struct q6v5_data *drv = dev_get_drvdata(pil->dev);
- int ret;
- u32 status;
- writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
- ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
- status, status, 50, HALT_ACK_TIMEOUT_US);
- if (ret)
- dev_err(pil->dev, "Port halt timeout\n");
- else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
- dev_err(pil->dev, "Port halt failed\n");
- writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base);
- /* Make sure Q6 registers are accessible */
- writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
- clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
- mb();
+ /*
+ * If the shutdown function is called before the reset function, clocks
+ * will not be enabled yet. Enable them here so that register writes
+ * performed during the shutdown succeed.
+ */
+ if (drv->is_booted == false)
+ pil_q6v5_enable_clks(pil);
pil_q6v5_shutdown(pil);
+ pil_q6v5_disable_clks(pil);
- /* Disable clocks and assert subsystem resets. */
- clk_reg_disable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
- clk_reg_disable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
- writel_relaxed(1, drv->clk_base + LPASS_Q6SS_BCR);
+ drv->is_booted = false;
return 0;
}
@@ -82,21 +50,25 @@
static int pil_lpass_reset(struct pil_desc *pil)
{
struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
- /*
- * Bring subsystem out of reset and enable required
- * regulators and clocks.
- */
- writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
- clk_reg_enable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
- clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
- mb();
+ ret = pil_q6v5_enable_clks(pil);
+ if (ret)
+ return ret;
/* Program Image Address */
writel_relaxed(((drv->start_addr >> 4) & 0x0FFFFFF0),
drv->reg_base + QDSP6SS_RST_EVB);
- return pil_q6v5_reset(pil);
+ ret = pil_q6v5_reset(pil);
+ if (ret) {
+ pil_q6v5_disable_clks(pil);
+ return ret;
+ }
+
+ drv->is_booted = true;
+
+ return 0;
}
static struct pil_reset_ops pil_lpass_ops = {
@@ -111,7 +83,6 @@
{
struct q6v5_data *drv;
struct pil_desc *desc;
- struct resource *res;
desc = pil_q6v5_init(pdev);
if (IS_ERR(desc))
@@ -123,12 +94,7 @@
desc->ops = &pil_lpass_ops;
desc->owner = THIS_MODULE;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!drv->axi_halt_base)
- return -ENOMEM;
+ desc->proxy_timeout = PROXY_TIMEOUT_MS;
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil))
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index cd58a4c..6a96990 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -15,19 +15,29 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/elf.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/clk.h>
+#include <mach/clk.h>
+
#include "peripheral-loader.h"
#include "pil-q6v5.h"
-/* Register Offsets */
+/* QDSP6SS Register Offsets */
#define QDSP6SS_RESET 0x014
#define QDSP6SS_GFMUX_CTL 0x020
#define QDSP6SS_PWR_CTL 0x030
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ 0x0
+#define AXI_HALTACK 0x4
+#define AXI_IDLE 0x8
+
+#define HALT_ACK_TIMEOUT_US 100000
+
/* QDSP6SS_RESET */
#define Q6SS_CORE_ARES BIT(1)
#define Q6SS_ETM_ISDB_ARES BIT(3)
@@ -66,6 +76,27 @@
}
EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base)
+{
+ int ret;
+ u32 status;
+
+ /* Assert halt request */
+ writel_relaxed(1, halt_base + AXI_HALTREQ);
+
+ /* Wait for halt */
+ ret = readl_poll_timeout(halt_base + AXI_HALTACK,
+ status, status != 0, 50, HALT_ACK_TIMEOUT_US);
+ if (ret)
+ dev_warn(pil->dev, "Port %p halt timeout\n", halt_base);
+ else if (!readl_relaxed(halt_base + AXI_IDLE))
+ dev_warn(pil->dev, "Port %p halt failed\n", halt_base);
+
+ /* Clear halt request (port will remain halted until reset) */
+ writel_relaxed(0, halt_base + AXI_HALTREQ);
+}
+EXPORT_SYMBOL(pil_q6v5_halt_axi_port);
+
int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
@@ -76,6 +107,42 @@
}
EXPORT_SYMBOL(pil_q6v5_init_image);
+int pil_q6v5_enable_clks(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
+
+ ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+ if (ret)
+ goto err_reset;
+ ret = clk_prepare_enable(drv->core_clk);
+ if (ret)
+ goto err_core_clk;
+ ret = clk_prepare_enable(drv->bus_clk);
+ if (ret)
+ goto err_bus_clk;
+
+ return 0;
+
+err_bus_clk:
+ clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+ clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+ return ret;
+}
+EXPORT_SYMBOL(pil_q6v5_enable_clks);
+
+void pil_q6v5_disable_clks(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+ clk_disable_unprepare(drv->bus_clk);
+ clk_disable_unprepare(drv->core_clk);
+ clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+}
+EXPORT_SYMBOL(pil_q6v5_disable_clks);
+
void pil_q6v5_shutdown(struct pil_desc *pil)
{
u32 val;
@@ -172,11 +239,10 @@
resource_size(res));
if (!drv->reg_base)
return ERR_PTR(-ENOMEM);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- drv->clk_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!drv->clk_base)
+ drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->axi_halt_base)
return ERR_PTR(-ENOMEM);
desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
@@ -192,6 +258,14 @@
if (IS_ERR(drv->xo))
return ERR_CAST(drv->xo);
+ drv->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(drv->bus_clk))
+ return ERR_CAST(drv->bus_clk);
+
+ drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(drv->core_clk))
+ return ERR_CAST(drv->core_clk);
+
desc->dev = &pdev->dev;
return desc;
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index b17d4e7..a9a8d07 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -21,23 +21,27 @@
struct q6v5_data {
void __iomem *reg_base;
- void __iomem *clk_base;
+ struct clk *xo;
+ struct clk *bus_clk;
+ struct clk *core_clk;
void __iomem *axi_halt_base;
void __iomem *rmb_base;
unsigned long start_addr;
struct regulator *vreg;
- bool vreg_enabled;
+ bool is_booted;
int self_auth;
- struct clk *xo;
struct pil_device *pil;
};
int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
void pil_q6v5_remove_proxy_votes(struct pil_desc *pil);
+void pil_q6v5_halt_axi_port(struct pil_desc *pil, void __iomem *halt_base);
int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
size_t size);
void pil_q6v5_shutdown(struct pil_desc *pil);
int pil_q6v5_reset(struct pil_desc *pil);
+int pil_q6v5_enable_clks(struct pil_desc *pil);
+void pil_q6v5_disable_clks(struct pil_desc *pil);
struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
#endif
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 3826b12..91f1133 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -170,6 +170,8 @@
{
unsigned long timeout;
+ preset_lpj = loops_per_jiffy;
+
if (cold_boot_done == false) {
if (msm8625_release_secondary()) {
pr_err("Failed to release secondary core\n");
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index cbe5201..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;
@@ -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.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 6d8f2a2..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>
@@ -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,
@@ -765,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
*****************************************************************************/
@@ -1187,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();
@@ -1214,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());
@@ -1501,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
@@ -1519,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;
@@ -1621,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
}
/*
@@ -1681,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()) {
@@ -1692,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);
@@ -1711,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();
@@ -1744,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 {
@@ -1752,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]) {
@@ -1873,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;
@@ -1956,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
@@ -1972,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/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index abcd336..b9cba8c 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -40,7 +40,7 @@
#ifdef CONFIG_ARCH_FSM9XXX
#define NUM_SMD_PKT_PORTS 4
#else
-#define NUM_SMD_PKT_PORTS 14
+#define NUM_SMD_PKT_PORTS 15
#endif
#define LOOPBACK_INX (NUM_SMD_PKT_PORTS - 1)
@@ -677,6 +677,7 @@
"apr_apps2",
"smdcntl8",
"smd_sns_adsp",
+ "smd_cxm_qmi",
"smd_pkt_loopback",
};
@@ -694,6 +695,7 @@
"apr_apps2",
"DATA40_CNTL",
"SENSOR",
+ "CXM_QMI_PORT_8064",
"LOOPBACK",
};
@@ -711,6 +713,7 @@
SMD_APPS_QDSP,
SMD_APPS_MODEM,
SMD_APPS_QDSP,
+ SMD_APPS_WCNSS,
SMD_APPS_MODEM,
};
#endif
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index 4a1285b..916686f 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -375,12 +375,13 @@
partition_no = msm_subsystem_get_partition_no(
subsys_ids[i]);
- iova_start = msm_allocate_iova_address(domain_no,
+ ret = msm_allocate_iova_address(domain_no,
partition_no,
map_size,
- max(min_align, SZ_4K));
+ max(min_align, SZ_4K),
+ &iova_start);
- if (!iova_start) {
+ if (ret) {
pr_err("%s: could not allocate iova address\n",
__func__);
continue;
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 404538a..bacba58 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -159,6 +159,22 @@
tst r5, #FPSCR_IXE
bne process_exception
+#ifdef CONFIG_ARCH_MSM_KRAIT
+ @ Krait does not set FPEXC.DEX for unsupported short vector instructions
+ mrc p15, 0, r2, c0, c0, 0
+ ldr r4, =0xff00fc00
+ and r4, r2, r4
+ ldr r2, =0x51000400
+ cmp r2, r4
+ bne skip
+
+ tst r5, #FPSCR_LENGTH_MASK
+ beq skip
+ orr r1, r1, #FPEXC_DEX
+ b process_exception
+skip:
+#endif
+
@ Fall into hand on to next handler - appropriate coproc instr
@ not recognised by VFP
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/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index bbb13f3..56f986d 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1674,12 +1674,158 @@
return size;
}
+/**
+ * Searches through a clients handles to find if the buffer is owned
+ * by this client. Used for debug output.
+ * @param client pointer to candidate owner of buffer
+ * @param buf pointer to buffer that we are trying to find the owner of
+ * @return 1 if found, 0 otherwise
+ */
+static int ion_debug_find_buffer_owner(const struct ion_client *client,
+ const struct ion_buffer *buf)
+{
+ struct rb_node *n;
+
+ for (n = rb_first(&client->handles); n; n = rb_next(n)) {
+ const struct ion_handle *handle = rb_entry(n,
+ const struct ion_handle,
+ node);
+ if (handle->buffer == buf)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Adds mem_map_data pointer to the tree of mem_map
+ * Used for debug output.
+ * @param mem_map The mem_map tree
+ * @param data The new data to add to the tree
+ */
+static void ion_debug_mem_map_add(struct rb_root *mem_map,
+ struct mem_map_data *data)
+{
+ struct rb_node **p = &mem_map->rb_node;
+ struct rb_node *parent = NULL;
+ struct mem_map_data *entry;
+
+ while (*p) {
+ parent = *p;
+ entry = rb_entry(parent, struct mem_map_data, node);
+
+ if (data->addr < entry->addr) {
+ p = &(*p)->rb_left;
+ } else if (data->addr > entry->addr) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_err("%s: mem_map_data already found.", __func__);
+ BUG();
+ }
+ }
+ rb_link_node(&data->node, parent, p);
+ rb_insert_color(&data->node, mem_map);
+}
+
+/**
+ * Search for an owner of a buffer by iterating over all ION clients.
+ * @param dev ion device containing pointers to all the clients.
+ * @param buffer pointer to buffer we are trying to find the owner of.
+ * @return name of owner.
+ */
+const char *ion_debug_locate_owner(const struct ion_device *dev,
+ const struct ion_buffer *buffer)
+{
+ struct rb_node *j;
+ const char *client_name = NULL;
+
+ for (j = rb_first(&dev->user_clients); j && !client_name;
+ j = rb_next(j)) {
+ struct ion_client *client = rb_entry(j, struct ion_client,
+ node);
+ if (ion_debug_find_buffer_owner(client, buffer))
+ client_name = client->name;
+ }
+ for (j = rb_first(&dev->kernel_clients); j && !client_name;
+ j = rb_next(j)) {
+ struct ion_client *client = rb_entry(j, struct ion_client,
+ node);
+ if (ion_debug_find_buffer_owner(client, buffer))
+ client_name = client->name;
+ }
+ return client_name;
+}
+
+/**
+ * Create a mem_map of the heap.
+ * @param s seq_file to log error message to.
+ * @param heap The heap to create mem_map for.
+ * @param mem_map The mem map to be created.
+ */
+void ion_debug_mem_map_create(struct seq_file *s, struct ion_heap *heap,
+ struct rb_root *mem_map)
+{
+ struct ion_device *dev = heap->dev;
+ struct rb_node *n;
+
+ for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+ struct ion_buffer *buffer =
+ rb_entry(n, struct ion_buffer, node);
+ if (buffer->heap->id == heap->id) {
+ struct mem_map_data *data =
+ kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ seq_printf(s, "ERROR: out of memory. "
+ "Part of memory map will not be logged\n");
+ break;
+ }
+ data->addr = buffer->priv_phys;
+ data->addr_end = buffer->priv_phys + buffer->size-1;
+ data->size = buffer->size;
+ data->client_name = ion_debug_locate_owner(dev, buffer);
+ ion_debug_mem_map_add(mem_map, data);
+ }
+ }
+}
+
+/**
+ * Free the memory allocated by ion_debug_mem_map_create
+ * @param mem_map The mem map to free.
+ */
+static void ion_debug_mem_map_destroy(struct rb_root *mem_map)
+{
+ if (mem_map) {
+ struct rb_node *n;
+ while ((n = rb_first(mem_map)) != 0) {
+ struct mem_map_data *data =
+ rb_entry(n, struct mem_map_data, node);
+ rb_erase(&data->node, mem_map);
+ kfree(data);
+ }
+ }
+}
+
+/**
+ * Print heap debug information.
+ * @param s seq_file to log message to.
+ * @param heap pointer to heap that we will print debug information for.
+ */
+static void ion_heap_print_debug(struct seq_file *s, struct ion_heap *heap)
+{
+ if (heap->ops->print_debug) {
+ struct rb_root mem_map = RB_ROOT;
+ ion_debug_mem_map_create(s, heap, &mem_map);
+ heap->ops->print_debug(heap, s, &mem_map);
+ ion_debug_mem_map_destroy(&mem_map);
+ }
+}
+
static int ion_debug_heap_show(struct seq_file *s, void *unused)
{
struct ion_heap *heap = s->private;
struct ion_device *dev = heap->dev;
struct rb_node *n;
+ mutex_lock(&dev->lock);
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
for (n = rb_first(&dev->user_clients); n; n = rb_next(n)) {
struct ion_client *client = rb_entry(n, struct ion_client,
@@ -1703,8 +1849,8 @@
seq_printf(s, "%16.s %16u %16x\n", client->name, client->pid,
size);
}
- if (heap->ops->print_debug)
- heap->ops->print_debug(heap, s);
+ ion_heap_print_debug(s, heap);
+ mutex_unlock(&dev->lock);
return 0;
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index ca2380b..710583b 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -251,7 +251,8 @@
return 0;
}
-static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_carveout_print_debug(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *mem_map)
{
struct ion_carveout_heap *carveout_heap =
container_of(heap, struct ion_carveout_heap, heap);
@@ -260,6 +261,44 @@
carveout_heap->allocated_bytes);
seq_printf(s, "total heap size: %lx\n", carveout_heap->total_size);
+ if (mem_map) {
+ unsigned long base = carveout_heap->base;
+ unsigned long size = carveout_heap->total_size;
+ unsigned long end = base+size;
+ unsigned long last_end = base;
+ struct rb_node *n;
+
+ seq_printf(s, "\nMemory Map\n");
+ seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+ "client", "start address", "end address",
+ "size (hex)");
+
+ for (n = rb_first(mem_map); n; n = rb_next(n)) {
+ struct mem_map_data *data =
+ rb_entry(n, struct mem_map_data, node);
+ const char *client_name = "(null)";
+
+ if (last_end < data->addr) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ "FREE", last_end, data->addr-1,
+ data->addr-last_end,
+ data->addr-last_end);
+ }
+
+ if (data->client_name)
+ client_name = data->client_name;
+
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ client_name, data->addr,
+ data->addr_end,
+ data->size, data->size);
+ last_end = data->addr_end+1;
+ }
+ if (last_end < end) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+ last_end, end-1, end-last_end, end-last_end);
+ }
+ }
return 0;
}
@@ -287,13 +326,12 @@
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 7f57fe6..fcbf1d4 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__);
@@ -561,7 +563,8 @@
return 0;
}
-static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_cp_print_debug(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *mem_map)
{
unsigned long total_alloc;
unsigned long total_size;
@@ -586,6 +589,45 @@
seq_printf(s, "heap protected: %s\n", heap_protected ? "Yes" : "No");
seq_printf(s, "reusable: %s\n", cp_heap->reusable ? "Yes" : "No");
+ if (mem_map) {
+ unsigned long base = cp_heap->base;
+ unsigned long size = cp_heap->total_size;
+ unsigned long end = base+size;
+ unsigned long last_end = base;
+ struct rb_node *n;
+
+ seq_printf(s, "\nMemory Map\n");
+ seq_printf(s, "%16.s %14.s %14.s %14.s\n",
+ "client", "start address", "end address",
+ "size (hex)");
+
+ for (n = rb_first(mem_map); n; n = rb_next(n)) {
+ struct mem_map_data *data =
+ rb_entry(n, struct mem_map_data, node);
+ const char *client_name = "(null)";
+
+ if (last_end < data->addr) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ "FREE", last_end, data->addr-1,
+ data->addr-last_end,
+ data->addr-last_end);
+ }
+
+ if (data->client_name)
+ client_name = data->client_name;
+
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n",
+ client_name, data->addr,
+ data->addr_end,
+ data->size, data->size);
+ last_end = data->addr_end+1;
+ }
+ if (last_end < end) {
+ seq_printf(s, "%16.s %14lx %14lx %14lu (%lx)\n", "FREE",
+ last_end, end-1, end-last_end, end-last_end);
+ }
+ }
+
return 0;
}
@@ -645,13 +687,15 @@
}
if (!ret_value && domain) {
unsigned long temp_phys = cp_heap->base;
- unsigned long temp_iova =
- msm_allocate_iova_address(domain_num, partition,
- virt_addr_len, SZ_64K);
- if (!temp_iova) {
+ unsigned long temp_iova;
+
+ ret_value = msm_allocate_iova_address(domain_num, partition,
+ virt_addr_len, SZ_64K,
+ &temp_iova);
+
+ if (ret_value) {
pr_err("%s: could not allocate iova from domain %lu, partition %d\n",
__func__, domain_num, partition);
- ret_value = -ENOMEM;
goto out;
}
cp_heap->iommu_iova[domain_num] = temp_iova;
@@ -740,13 +784,12 @@
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
@@ -916,6 +959,14 @@
cp_heap = NULL;
}
+void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
+ unsigned long *size) \
+{
+ struct ion_cp_heap *cp_heap =
+ container_of(heap, struct ion_cp_heap, heap);
+ *base = cp_heap->base;
+ *size = cp_heap->total_size;
+}
/* SCM related code for locking down memory for content protection */
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 312ca42..70bdc7f 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -190,13 +190,12 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (!data->iova_addr)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 98e11cf..00ce33f 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -155,7 +155,8 @@
unsigned long iova_length,
unsigned long flags);
void (*unmap_iommu)(struct ion_iommu_map *data);
- int (*print_debug)(struct ion_heap *heap, struct seq_file *s);
+ int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *mem_map);
int (*secure_heap)(struct ion_heap *heap);
int (*unsecure_heap)(struct ion_heap *heap);
};
@@ -185,7 +186,22 @@
const char *name;
};
-
+/**
+ * struct mem_map_data - represents information about the memory map for a heap
+ * @node: rb node used to store in the tree of mem_map_data
+ * @addr: start address of memory region.
+ * @addr: end address of memory region.
+ * @size: size of memory region
+ * @client_name: name of the client who owns this buffer.
+ *
+ */
+struct mem_map_data {
+ struct rb_node node;
+ unsigned long addr;
+ unsigned long addr_end;
+ unsigned long size;
+ const char *client_name;
+};
#define iommu_map_domain(__m) ((__m)->domain_info[1])
#define iommu_map_partition(__m) ((__m)->domain_info[0])
@@ -298,4 +314,9 @@
void *uaddr, unsigned long offset, unsigned long len,
unsigned int cmd);
+void ion_cp_heap_get_base(struct ion_heap *heap, unsigned long *base,
+ unsigned long *size);
+
+void ion_mem_map_show(struct ion_heap *heap);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index ed9ae27..26c6632 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -204,7 +204,8 @@
return 0;
}
-static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s)
+static int ion_system_print_debug(struct ion_heap *heap, struct seq_file *s,
+ const struct rb_root *unused)
{
seq_printf(s, "total bytes currently allocated: %lx\n",
(unsigned long) atomic_read(&system_heap_allocated));
@@ -240,13 +241,12 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
@@ -423,7 +423,8 @@
}
static int ion_system_contig_print_debug(struct ion_heap *heap,
- struct seq_file *s)
+ struct seq_file *s,
+ const struct rb_root *unused)
{
seq_printf(s, "total bytes currently allocated: %lx\n",
(unsigned long) atomic_read(&system_contig_heap_allocated));
@@ -458,13 +459,12 @@
data->mapped_size = iova_length;
extra = iova_length - buffer->size;
- data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
- data->mapped_size, align);
+ ret = msm_allocate_iova_address(domain_num, partition_num,
+ data->mapped_size, align,
+ &data->iova_addr);
- if (!data->iova_addr) {
- ret = -ENOMEM;
+ if (ret)
goto out;
- }
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 96390ac..2f503ae 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -21,6 +21,7 @@
#include "kgsl_pwrscale.h"
#include "kgsl_cffdump.h"
#include "kgsl_sharedmem.h"
+#include "kgsl_iommu.h"
#include "adreno.h"
#include "adreno_pm4types.h"
@@ -158,7 +159,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 },
@@ -243,7 +244,144 @@
return result;
}
-static void adreno_setstate(struct kgsl_device *device,
+static void adreno_iommu_setstate(struct kgsl_device *device,
+ uint32_t flags)
+{
+ unsigned int pt_val, reg_pt_val;
+ unsigned int link[200];
+ unsigned int *cmds = &link[0];
+ int sizedwords = 0;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct kgsl_memdesc **reg_map_desc;
+ void *reg_map_array;
+ int num_iommu_units, i;
+
+ if (!adreno_dev->drawctxt_active)
+ return kgsl_mmu_device_setstate(&device->mmu, flags);
+ num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
+ ®_map_array);
+ reg_map_desc = reg_map_array;
+
+ if (kgsl_mmu_enable_clk(&device->mmu,
+ KGSL_IOMMU_CONTEXT_USER))
+ goto done;
+
+ if (adreno_is_a225(adreno_dev))
+ cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ else
+ cmds += adreno_add_bank_change_cmds(cmds,
+ KGSL_IOMMU_CONTEXT_USER,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+ if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+ pt_val = kgsl_mmu_pt_get_base_addr(device->mmu.hwpagetable);
+ /*
+ * We need to perfrom the following operations for all
+ * IOMMU units
+ */
+ for (i = 0; i < num_iommu_units; i++) {
+ reg_pt_val = (pt_val &
+ (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT)) +
+ kgsl_mmu_get_pt_lsb(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER);
+ /*
+ * Set address of the new pagetable by writng to IOMMU
+ * TTBR0 register
+ */
+ *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+ *cmds++ = reg_map_desc[i]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER <<
+ KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0;
+ *cmds++ = reg_pt_val;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
+ /*
+ * Read back the ttbr0 register as a barrier to ensure
+ * above writes have completed
+ */
+ cmds += adreno_add_read_cmds(device, cmds,
+ reg_map_desc[i]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER <<
+ KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+ reg_pt_val,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+ /* set the asid */
+ *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+ *cmds++ = reg_map_desc[i]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER <<
+ KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_CONTEXTIDR;
+ *cmds++ = kgsl_mmu_get_hwpagetable_asid(&device->mmu);
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
+ /* Read back asid to ensure above write completes */
+ cmds += adreno_add_read_cmds(device, cmds,
+ reg_map_desc[i]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER <<
+ KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_CONTEXTIDR,
+ kgsl_mmu_get_hwpagetable_asid(&device->mmu),
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ }
+ /* invalidate all base pointers */
+ *cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
+ *cmds++ = 0x7fff;
+
+ if (flags & KGSL_MMUFLAGS_TLBFLUSH)
+ cmds += __adreno_add_idle_indirect_cmds(cmds,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ }
+ if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+ /*
+ * tlb flush based on asid, no need to flush entire tlb
+ */
+ for (i = 0; i < num_iommu_units; i++) {
+ *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+ *cmds++ = (reg_map_desc[i]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER <<
+ KGSL_IOMMU_CTX_SHIFT) +
+ KGSL_IOMMU_CTX_TLBIASID);
+ *cmds++ = kgsl_mmu_get_hwpagetable_asid(&device->mmu);
+ cmds += adreno_add_read_cmds(device, cmds,
+ reg_map_desc[i]->gpuaddr +
+ (KGSL_IOMMU_CONTEXT_USER <<
+ KGSL_IOMMU_CTX_SHIFT) +
+ KGSL_IOMMU_CONTEXTIDR,
+ kgsl_mmu_get_hwpagetable_asid(&device->mmu),
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ }
+ }
+
+ if (adreno_is_a225(adreno_dev))
+ cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
+ reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+ else
+ cmds += adreno_add_bank_change_cmds(cmds,
+ KGSL_IOMMU_CONTEXT_PRIV,
+ device->mmu.setstate_memory.gpuaddr +
+ KGSL_IOMMU_SETSTATE_NOP_OFFSET);
+
+ sizedwords += (cmds - &link[0]);
+ if (sizedwords)
+ adreno_ringbuffer_issuecmds(device,
+ KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+done:
+ if (num_iommu_units)
+ kfree(reg_map_array);
+}
+
+static void adreno_gpummu_setstate(struct kgsl_device *device,
uint32_t flags)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -253,16 +391,6 @@
unsigned int mh_mmu_invalidate = 0x00000003; /*invalidate all and tc */
/*
- * A3XX doesn't support the fast path (the registers don't even exist)
- * so just bail out early
- */
-
- if (adreno_is_a3xx(adreno_dev)) {
- kgsl_mmu_device_setstate(&device->mmu, flags);
- return;
- }
-
- /*
* If possible, then set the state via the command stream to avoid
* a CPU idle. Otherwise, use the default setstate which uses register
* writes For CFF dump we must idle and use the registers so that it is
@@ -348,6 +476,16 @@
}
}
+static void adreno_setstate(struct kgsl_device *device,
+ uint32_t flags)
+{
+ /* call the mmu specific handler */
+ if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype())
+ return adreno_gpummu_setstate(device, flags);
+ else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+ return adreno_iommu_setstate(device, flags);
+}
+
static unsigned int
a3xx_getchipid(struct kgsl_device *device)
{
@@ -362,10 +500,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 +1279,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 +1295,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 +1344,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 +1405,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 +1475,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/adreno.h b/drivers/gpu/msm/adreno.h
index a7ea20c..4ce56a4 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -16,6 +16,7 @@
#include "kgsl_device.h"
#include "adreno_drawctxt.h"
#include "adreno_ringbuffer.h"
+#include "kgsl_iommu.h"
#define DEVICE_3D_NAME "kgsl-3d"
#define DEVICE_3D0_NAME "kgsl-3d0"
@@ -223,4 +224,70 @@
return (ilog2(size) - 5) << 29;
}
+static inline int __adreno_add_idle_indirect_cmds(unsigned int *cmds,
+ unsigned int nop_gpuaddr)
+{
+ /* Adding an indirect buffer ensures that the prefetch stalls until
+ * the commands in indirect buffer have completed. We need to stall
+ * prefetch with a nop indirect buffer when updating pagetables
+ * because it provides stabler synchronization */
+ *cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
+ *cmds++ = nop_gpuaddr;
+ *cmds++ = 2;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ return 5;
+}
+
+static inline int adreno_add_change_mh_phys_limit_cmds(unsigned int *cmds,
+ unsigned int new_phys_limit,
+ unsigned int nop_gpuaddr)
+{
+ unsigned int *start = cmds;
+
+ cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+ *cmds++ = cp_type0_packet(MH_MMU_MPU_END, 1);
+ *cmds++ = new_phys_limit;
+ cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+ return cmds - start;
+}
+
+static inline int adreno_add_bank_change_cmds(unsigned int *cmds,
+ int cur_ctx_bank,
+ unsigned int nop_gpuaddr)
+{
+ unsigned int *start = cmds;
+
+ cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+ *cmds++ = cp_type0_packet(REG_CP_STATE_DEBUG_INDEX, 1);
+ *cmds++ = (cur_ctx_bank ? 0 : 0x20);
+ cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+ return cmds - start;
+}
+
+/*
+ * adreno_read_cmds - Add pm4 packets to perform read
+ * @device - Pointer to device structure
+ * @cmds - Pointer to memory where read commands need to be added
+ * @addr - gpu address of the read
+ * @val - The GPU will wait until the data at address addr becomes
+ * equal to value
+ */
+static inline int adreno_add_read_cmds(struct kgsl_device *device,
+ unsigned int *cmds, unsigned int addr,
+ unsigned int val, unsigned int nop_gpuaddr)
+{
+ unsigned int *start = cmds;
+
+ *cmds++ = cp_type3_packet(CP_WAIT_REG_MEM, 5);
+ /* MEM SPACE = memory, FUNCTION = equals */
+ *cmds++ = 0x13;
+ *cmds++ = addr;
+ *cmds++ = val;
+ *cmds++ = 0xFFFFFFFF;
+ *cmds++ = 0xFFFFFFFF;
+ cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
+ return cmds - start;
+}
+
#endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index eb936f8..8a132df 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -830,9 +830,6 @@
*cmds++ = 0x00010000;
if (adreno_is_a22x(adreno_dev)) {
- *cmds++ = cp_type3_packet(CP_SET_DRAW_INIT_FLAGS, 1);
- *cmds++ = 0;
-
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(REG_A220_RB_LRZ_VSC_CONTROL);
*cmds++ = 0x0000000;
@@ -1052,9 +1049,6 @@
*cmds++ = 0x00010000;
if (adreno_is_a22x(adreno_dev)) {
- *cmds++ = cp_type3_packet(CP_SET_DRAW_INIT_FLAGS, 1);
- *cmds++ = 0;
-
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
*cmds++ = CP_REG(REG_A220_RB_LRZ_VSC_CONTROL);
*cmds++ = 0x0000000;
@@ -1848,8 +1842,13 @@
/* NQ and External Memory Swap */
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
- /* Protected mode error checking */
- GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
+ /* Protected mode error checking
+ * If iommu is used then protection needs to be turned off
+ * to enable context bank switching */
+ if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype())
+ GSL_RB_WRITE(cmds, cmds_gpu, 0);
+ else
+ GSL_RB_WRITE(cmds, cmds_gpu, GSL_RB_PROTECTED_MODE_CONTROL);
/* Disable header dumping and Header dump address */
GSL_RB_WRITE(cmds, cmds_gpu, 0x00000000);
/* Header dump size */
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.h b/drivers/gpu/msm/kgsl.h
index da3e4b2..7f38b72 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -122,6 +122,8 @@
int (*map_kernel_mem)(struct kgsl_memdesc *);
};
+#define KGSL_MEMDESC_GUARD_PAGE BIT(0)
+
/* shared memory allocation */
struct kgsl_memdesc {
struct kgsl_pagetable *pagetable;
@@ -133,6 +135,7 @@
struct scatterlist *sg;
unsigned int sglen;
struct kgsl_memdesc_ops *ops;
+ int flags;
};
/* List of different memory entry types */
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 ab47f40..8f61ab6 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -591,7 +591,7 @@
{
unsigned int numpages;
unsigned int pte, ptefirst, ptelast, superpte;
- unsigned int range = memdesc->size;
+ unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
struct kgsl_gpummu_pt *gpummu_pt = mmu_specific_pt;
/* All GPU addresses as assigned are page aligned, but some
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index c2d46e2..1f1571b 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
@@ -499,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:
@@ -580,16 +588,26 @@
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
+ [iommu->unit_count - 1].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);
if (status) {
@@ -621,6 +639,7 @@
CONTEXTIDR);
kgsl_iommu_disable_clk(mmu);
+ mmu->flags |= KGSL_FLAGS_STARTED;
done:
if (status) {
@@ -635,7 +654,7 @@
struct kgsl_memdesc *memdesc)
{
int ret;
- unsigned int range = memdesc->size;
+ unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
/* All GPU addresses as assigned are page aligned, but some
@@ -665,6 +684,7 @@
int ret;
unsigned int iommu_virt_addr;
struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
BUG_ON(NULL == iommu_pt);
@@ -672,11 +692,11 @@
iommu_virt_addr = memdesc->gpuaddr;
ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
- memdesc->size, (IOMMU_READ | IOMMU_WRITE));
+ size, (IOMMU_READ | IOMMU_WRITE));
if (ret) {
KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
"failed with err: %d\n", iommu_pt->domain,
- iommu_virt_addr, memdesc->sg, memdesc->size,
+ iommu_virt_addr, memdesc->sg, size,
(IOMMU_READ | IOMMU_WRITE), ret);
return ret;
}
@@ -701,6 +721,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;
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index c2e84a6..d4de656 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -55,6 +55,9 @@
(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 663ba0f..9092b96 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -545,8 +545,7 @@
struct kgsl_device *device = mmu->device;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return;
- else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
- kgsl_mmu_type))
+ else if (device->ftbl->setstate)
device->ftbl->setstate(device, flags);
else if (mmu->mmu_ops->mmu_device_setstate)
mmu->mmu_ops->mmu_device_setstate(mmu, flags);
@@ -596,6 +595,7 @@
{
int ret;
struct gen_pool *pool;
+ int size;
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
if (memdesc->sglen == 1) {
@@ -615,13 +615,15 @@
}
}
+ size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+
/* Allocate from kgsl pool if it exists for global mappings */
pool = _get_pool(pagetable, memdesc->priv);
- memdesc->gpuaddr = gen_pool_alloc(pool, memdesc->size);
+ memdesc->gpuaddr = gen_pool_alloc(pool, size);
if (memdesc->gpuaddr == 0) {
KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
- memdesc->size,
+ size,
(pool == pagetable->kgsl_pool) ?
"kgsl_pool" : "general_pool");
KGSL_CORE_ERR(" [%d] allocated=%d, entries=%d\n",
@@ -645,7 +647,7 @@
KGSL_STATS_ADD(1, pagetable->stats.entries,
pagetable->stats.max_entries);
- KGSL_STATS_ADD(memdesc->size, pagetable->stats.mapped,
+ KGSL_STATS_ADD(size, pagetable->stats.mapped,
pagetable->stats.max_mapped);
spin_unlock(&pagetable->lock);
@@ -654,7 +656,7 @@
err_free_gpuaddr:
spin_unlock(&pagetable->lock);
- gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
+ gen_pool_free(pool, memdesc->gpuaddr, size);
memdesc->gpuaddr = 0;
return ret;
}
@@ -665,6 +667,8 @@
struct kgsl_memdesc *memdesc)
{
struct gen_pool *pool;
+ int size;
+
if (memdesc->size == 0 || memdesc->gpuaddr == 0)
return 0;
@@ -672,6 +676,9 @@
memdesc->gpuaddr = 0;
return 0;
}
+
+ size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+
if (KGSL_MMU_TYPE_IOMMU != kgsl_mmu_get_mmutype())
spin_lock(&pagetable->lock);
pagetable->pt_ops->mmu_unmap(pagetable->priv, memdesc);
@@ -679,12 +686,12 @@
spin_lock(&pagetable->lock);
/* Remove the statistics */
pagetable->stats.entries--;
- pagetable->stats.mapped -= memdesc->size;
+ pagetable->stats.mapped -= size;
spin_unlock(&pagetable->lock);
pool = _get_pool(pagetable, memdesc->priv);
- gen_pool_free(pool, memdesc->gpuaddr, memdesc->size);
+ gen_pool_free(pool, memdesc->gpuaddr, 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 df4a64b..2db327b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -261,4 +261,37 @@
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/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 3a29d71..2aaefba 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -706,6 +706,7 @@
}
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
+ kgsl_mmu_disable_clk(&device->mmu);
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
if (device->idle_wakelock.name)
wake_unlock(&device->idle_wakelock);
@@ -749,6 +750,7 @@
gpu_freq);
_sleep_accounting(device);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
+ kgsl_mmu_disable_clk(&device->mmu);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
wake_unlock(&device->idle_wakelock);
pm_qos_update_request(&device->pm_qos_req_dma,
@@ -888,6 +890,7 @@
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
+ kgsl_mmu_disable_clk(&device->mmu);
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
}
EXPORT_SYMBOL(kgsl_pwrctrl_disable);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index a51f29f..8829102 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -63,6 +63,13 @@
}
+/*
+ * One page allocation for a guard region to protect against over-zealous
+ * GPU pre-fetch
+ */
+
+static struct page *kgsl_guard_page;
+
/**
* Given a kobj, find the process structure attached to it
*/
@@ -333,13 +340,20 @@
{
int i = 0;
struct scatterlist *sg;
+ int sglen = memdesc->sglen;
+
+ /* Don't free the guard page if it was used */
+ if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+ sglen--;
+
kgsl_driver.stats.page_alloc -= memdesc->size;
+
if (memdesc->hostptr) {
vunmap(memdesc->hostptr);
kgsl_driver.stats.vmalloc -= memdesc->size;
}
if (memdesc->sg)
- for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+ for_each_sg(memdesc->sg, sg, sglen, i)
__free_page(sg_page(sg));
}
@@ -362,17 +376,23 @@
pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
struct page **pages = NULL;
struct scatterlist *sg;
+ int sglen = memdesc->sglen;
int i;
+
+ /* Don't map the guard page if it exists */
+ if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
+ sglen--;
+
/* create a list of pages to call vmap */
- pages = vmalloc(memdesc->sglen * sizeof(struct page *));
+ pages = vmalloc(sglen * sizeof(struct page *));
if (!pages) {
KGSL_CORE_ERR("vmalloc(%d) failed\n",
- memdesc->sglen * sizeof(struct page *));
+ sglen * sizeof(struct page *));
return -ENOMEM;
}
- for_each_sg(memdesc->sg, sg, memdesc->sglen, i)
+ for_each_sg(memdesc->sg, sg, sglen, i)
pages[i] = sg_page(sg);
- memdesc->hostptr = vmap(pages, memdesc->sglen,
+ memdesc->hostptr = vmap(pages, sglen,
VM_IOREMAP, page_prot);
KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.vmalloc,
kgsl_driver.stats.vmalloc_max);
@@ -471,6 +491,14 @@
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
int i;
+ /*
+ * Add guard page to the end of the allocation when the
+ * IOMMU is in use.
+ */
+
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
+ sglen++;
+
memdesc->size = size;
memdesc->pagetable = pagetable;
memdesc->priv = KGSL_MEMFLAGS_CACHED;
@@ -490,7 +518,7 @@
memdesc->sglen = sglen;
sg_init_table(memdesc->sg, sglen);
- for (i = 0; i < memdesc->sglen; i++) {
+ for (i = 0; i < PAGE_ALIGN(size) / PAGE_SIZE; i++) {
struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO |
__GFP_HIGHMEM);
if (!page) {
@@ -501,6 +529,22 @@
flush_dcache_page(page);
sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
}
+
+ /* ADd the guard page to the end of the sglist */
+
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) {
+ if (kgsl_guard_page == NULL)
+ kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+ __GFP_HIGHMEM);
+
+ if (kgsl_guard_page != NULL) {
+ sg_set_page(&memdesc->sg[sglen - 1], kgsl_guard_page,
+ PAGE_SIZE, 0);
+ memdesc->flags |= KGSL_MEMDESC_GUARD_PAGE;
+ } else
+ memdesc->sglen--;
+ }
+
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen,
KGSL_CACHE_OP_FLUSH);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index fb8dd95..034ade4 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -157,4 +157,15 @@
return ret;
}
+static inline int kgsl_sg_size(struct scatterlist *sg, int sglen)
+{
+ int i, size = 0;
+ struct scatterlist *s;
+
+ for_each_sg(sg, s, sglen, i) {
+ size += s->length;
+ }
+
+ return size;
+}
#endif /* __KGSL_SHAREDMEM_H */
diff --git a/drivers/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/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index ff0c9d8..a57ad44 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -136,6 +136,8 @@
struct timespec timeout);
int (*start_filtering) (struct dmx_ts_feed* feed);
int (*stop_filtering) (struct dmx_ts_feed* feed);
+ int (*set_indexing_params) (struct dmx_ts_feed *feed,
+ struct dmx_indexing_video_params *params);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index ed3f731..1d310f2 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1186,6 +1186,24 @@
return ret;
}
+ /* Support indexing for video PES */
+ if ((para->pes_type == DMX_PES_VIDEO0) ||
+ (para->pes_type == DMX_PES_VIDEO1) ||
+ (para->pes_type == DMX_PES_VIDEO2) ||
+ (para->pes_type == DMX_PES_VIDEO3)) {
+
+ if (tsfeed->set_indexing_params) {
+ ret = tsfeed->set_indexing_params(tsfeed,
+ ¶->video_params);
+
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux,
+ tsfeed);
+ return ret;
+ }
+ }
+ }
+
ret = tsfeed->start_filtering(tsfeed);
if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
@@ -1464,6 +1482,23 @@
if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
return -EINVAL;
+ if (params->flags & DMX_ENABLE_INDEXING) {
+ if (!(dmxdev->capabilities & DMXDEV_CAP_INDEXING))
+ return -EINVAL;
+
+ /* can do indexing only on video PES */
+ if ((params->pes_type != DMX_PES_VIDEO0) &&
+ (params->pes_type != DMX_PES_VIDEO1) &&
+ (params->pes_type != DMX_PES_VIDEO2) &&
+ (params->pes_type != DMX_PES_VIDEO3))
+ return -EINVAL;
+
+ /* can do indexing only when recording */
+ if ((params->output != DMX_OUT_TS_TAP) &&
+ (params->output != DMX_OUT_TSDEMUX_TAP))
+ return -EINVAL;
+ }
+
dmxdevfilter->type = DMXDEV_TYPE_PES;
memcpy(&dmxdevfilter->params, params,
sizeof(struct dmx_pes_filter_params));
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 82f8f6d..4c52e84 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -108,6 +108,7 @@
#define DMXDEV_CAP_DUPLEX 0x1
#define DMXDEV_CAP_PULL_MODE 0x2
#define DMXDEV_CAP_PCR_EXTRACTION 0x4
+#define DMXDEV_CAP_INDEXING 0x8
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 966b48d..0ff2a55 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1027,6 +1027,18 @@
return ret;
}
+static int dmx_ts_set_indexing_params(
+ struct dmx_ts_feed *ts_feed,
+ struct dmx_indexing_video_params *params)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+ memcpy(&feed->indexing_params, params,
+ sizeof(struct dmx_indexing_video_params));
+
+ return 0;
+}
+
static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
struct dmx_ts_feed **ts_feed,
dmx_ts_cb callback)
@@ -1048,6 +1060,8 @@
feed->pid = 0xffff;
feed->peslen = 0xfffa;
feed->buffer = NULL;
+ memset(&feed->indexing_params, 0,
+ sizeof(struct dmx_indexing_video_params));
/* default behaviour - pass first PES data even if it is
* partial PES data from previous PES that we didn't receive its header.
@@ -1063,6 +1077,7 @@
(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
(*ts_feed)->set = dmx_ts_feed_set;
+ (*ts_feed)->set_indexing_params = dmx_ts_set_indexing_params;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 297f3df..17f4960 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -95,10 +95,12 @@
int cc;
int pusi_seen; /* prevents feeding of garbage from previous section */
- u16 peslen;
+ u32 peslen;
struct list_head list_head;
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
+
+ struct dmx_indexing_video_params indexing_params;
};
struct dvb_demux {
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..ab4a6f2 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -177,6 +177,15 @@
supports spotlight and flash light modes with
differrent current levels.
+config MSM_CAMERA_FLASH_TPS61310
+ bool "Qualcomm MSM camera tps61310 flash support"
+ depends on MSM_CAMERA
+ default n
+ ---help---
+ Enable support for LED flash for msm camera.
+ It is a Texas Instruments multiple LED Flash
+ for camera flash and video light applications.
+
config IMX072
bool "Sensor imx072 (Sony 5M)"
default n
@@ -271,3 +280,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/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 2d7fefd..e8be393 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -435,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 0d17e13..ba86d8c 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,54 +30,54 @@
MSM_CAM_FLASH_ON,
};
-#if defined CONFIG_MSM_CAMERA_FLASH_SC628A
static struct i2c_client *sc628a_client;
-static const struct i2c_device_id sc628a_i2c_id[] = {
- {"sc628a", 0},
- { }
-};
-
-static int32_t sc628a_i2c_txdata(unsigned short saddr,
+static int32_t flash_i2c_txdata(struct i2c_client *client,
unsigned char *txdata, int length)
{
struct i2c_msg msg[] = {
{
- .addr = saddr,
+ .addr = client->addr >> 1,
.flags = 0,
.len = length,
.buf = txdata,
},
};
- if (i2c_transfer(sc628a_client->adapter, msg, 1) < 0) {
- CDBG("sc628a_i2c_txdata faild 0x%x\n", saddr);
+ if (i2c_transfer(client->adapter, msg, 1) < 0) {
+ CDBG("flash_i2c_txdata faild 0x%x\n", client->addr >> 1);
return -EIO;
}
return 0;
}
-static int32_t sc628a_i2c_write_b_flash(uint8_t waddr, uint8_t bdata)
+static int32_t flash_i2c_write_b(struct i2c_client *client,
+ uint8_t baddr, uint8_t bdata)
{
int32_t rc = -EFAULT;
unsigned char buf[2];
- if (!sc628a_client)
+ if (!client)
return -ENOTSUPP;
memset(buf, 0, sizeof(buf));
- buf[0] = waddr;
+ buf[0] = baddr;
buf[1] = bdata;
- rc = sc628a_i2c_txdata(sc628a_client->addr>>1, buf, 2);
+ rc = flash_i2c_txdata(client, buf, 2);
if (rc < 0) {
CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- waddr, bdata);
+ baddr, bdata);
}
usleep_range(4000, 5000);
return rc;
}
+static const struct i2c_device_id sc628a_i2c_id[] = {
+ {"sc628a", 0},
+ { }
+};
+
static int sc628a_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -91,7 +91,7 @@
sc628a_client = client;
- CDBG("sc628a_probe successed! rc = %d\n", rc);
+ CDBG("sc628a_probe success rc = %d\n", rc);
return 0;
probe_failure:
@@ -107,7 +107,49 @@
.name = "sc628a",
},
};
-#endif
+
+static struct i2c_client *tps61310_client;
+
+static const struct i2c_device_id tps61310_i2c_id[] = {
+ {"tps61310", 0},
+ { }
+};
+
+static int tps61310_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ CDBG("%s enter\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("i2c_check_functionality failed\n");
+ goto probe_failure;
+ }
+
+ tps61310_client = client;
+
+ rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+ if (rc < 0) {
+ tps61310_client = NULL;
+ goto probe_failure;
+ }
+
+ CDBG("%s success! rc = %d\n", __func__, rc);
+ return 0;
+
+probe_failure:
+ pr_err("%s failed! rc = %d\n", __func__, rc);
+ return rc;
+}
+
+static struct i2c_driver tps61310_i2c_driver = {
+ .id_table = tps61310_i2c_id,
+ .probe = tps61310_i2c_probe,
+ .remove = __exit_p(tps61310_i2c_remove),
+ .driver = {
+ .name = "tps61310",
+ },
+};
static int config_flash_gpio_table(enum msm_cam_flash_stat stat,
struct msm_camera_sensor_strobe_flash_data *sfdata)
@@ -278,18 +320,34 @@
{
int rc = 0;
-#if defined CONFIG_MSM_CAMERA_FLASH_SC628A
switch (led_state) {
case MSM_CAMERA_LED_INIT:
- if (!sc628a_client) {
- rc = i2c_add_driver(&sc628a_i2c_driver);
- if (rc < 0 || sc628a_client == NULL) {
- rc = -ENOTSUPP;
- CDBG("I2C add driver failed");
- return rc;
+ if (external->flash_id == MAM_CAMERA_EXT_LED_FLASH_SC628A) {
+ if (!sc628a_client) {
+ rc = i2c_add_driver(&sc628a_i2c_driver);
+ if (rc < 0 || sc628a_client == NULL) {
+ pr_err("sc628a_i2c_driver add failed\n");
+ rc = -ENOTSUPP;
+ return rc;
+ }
}
+ } else if (external->flash_id ==
+ MAM_CAMERA_EXT_LED_FLASH_TPS61310) {
+ if (!tps61310_client) {
+ rc = i2c_add_driver(&tps61310_i2c_driver);
+ if (rc < 0 || tps61310_client == NULL) {
+ pr_err("tps61310_i2c_driver add failed\n");
+ rc = -ENOTSUPP;
+ return rc;
+ }
+ }
+ } else {
+ pr_err("Flash id not supported\n");
+ rc = -ENOTSUPP;
+ return rc;
}
+
#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
if (external->expander_info && !sx150x_client) {
struct i2c_adapter *adapter =
@@ -298,20 +356,37 @@
sx150x_client = i2c_new_device(adapter,
external->expander_info->board_info);
if (!sx150x_client || !adapter) {
+ pr_err("sx150x_client is not available\n");
rc = -ENOTSUPP;
- i2c_del_driver(&sc628a_i2c_driver);
- sc628a_client = NULL;
+ if (sc628a_client) {
+ i2c_del_driver(&sc628a_i2c_driver);
+ sc628a_client = NULL;
+ }
+ if (tps61310_client) {
+ i2c_del_driver(&tps61310_i2c_driver);
+ tps61310_client = NULL;
+ }
return rc;
}
+ i2c_put_adapter(adapter);
}
#endif
- rc = gpio_request(external->led_en, "sc628a");
+ if (sc628a_client)
+ rc = gpio_request(external->led_en, "sc628a");
+ if (tps61310_client)
+ rc = gpio_request(external->led_en, "tps61310");
+
if (!rc) {
gpio_direction_output(external->led_en, 0);
} else {
- goto err1;
+ goto error;
}
- rc = gpio_request(external->led_flash_en, "sc628a");
+
+ if (sc628a_client)
+ rc = gpio_request(external->led_flash_en, "sc628a");
+ if (tps61310_client)
+ rc = gpio_request(external->led_flash_en, "tps61310");
+
if (!rc) {
gpio_direction_output(external->led_flash_en, 0);
break;
@@ -319,19 +394,32 @@
gpio_set_value_cansleep(external->led_en, 0);
gpio_free(external->led_en);
-
-err1:
- i2c_del_driver(&sc628a_i2c_driver);
- sc628a_client = NULL;
-
+error:
+ pr_err("%s gpio request failed\n", __func__);
+ if (sc628a_client) {
+ i2c_del_driver(&sc628a_i2c_driver);
+ sc628a_client = NULL;
+ }
+ if (tps61310_client) {
+ i2c_del_driver(&tps61310_i2c_driver);
+ tps61310_client = NULL;
+ }
break;
case MSM_CAMERA_LED_RELEASE:
- if (sc628a_client) {
+ if (sc628a_client || tps61310_client) {
gpio_set_value_cansleep(external->led_en, 0);
gpio_free(external->led_en);
gpio_set_value_cansleep(external->led_flash_en, 0);
gpio_free(external->led_flash_en);
+ if (sc628a_client) {
+ i2c_del_driver(&sc628a_i2c_driver);
+ sc628a_client = NULL;
+ }
+ if (tps61310_client) {
+ i2c_del_driver(&tps61310_i2c_driver);
+ tps61310_client = NULL;
+ }
}
#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
if (external->expander_info && sx150x_client) {
@@ -342,37 +430,38 @@
break;
case MSM_CAMERA_LED_OFF:
- rc = sc628a_i2c_write_b_flash(0x02, 0x0);
- if (sc628a_client) {
- gpio_set_value_cansleep(external->led_en, 0);
- gpio_set_value_cansleep(external->led_flash_en, 0);
- }
+ if (sc628a_client)
+ rc = flash_i2c_write_b(sc628a_client, 0x02, 0x00);
+ if (tps61310_client)
+ rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+ gpio_set_value_cansleep(external->led_en, 0);
+ gpio_set_value_cansleep(external->led_flash_en, 0);
break;
case MSM_CAMERA_LED_LOW:
- if (sc628a_client) {
- gpio_set_value_cansleep(external->led_en, 1);
- gpio_set_value_cansleep(external->led_flash_en, 1);
- usleep_range(2000, 3000);
- }
- rc = sc628a_i2c_write_b_flash(0x02, 0x06);
+ gpio_set_value_cansleep(external->led_en, 1);
+ gpio_set_value_cansleep(external->led_flash_en, 1);
+ usleep_range(2000, 3000);
+ if (sc628a_client)
+ rc = flash_i2c_write_b(sc628a_client, 0x02, 0x06);
+ if (tps61310_client)
+ rc = flash_i2c_write_b(tps61310_client, 0x01, 0x86);
break;
case MSM_CAMERA_LED_HIGH:
- if (sc628a_client) {
- gpio_set_value_cansleep(external->led_en, 1);
- gpio_set_value_cansleep(external->led_flash_en, 1);
- usleep_range(2000, 3000);
- }
- rc = sc628a_i2c_write_b_flash(0x02, 0x49);
+ gpio_set_value_cansleep(external->led_en, 1);
+ gpio_set_value_cansleep(external->led_flash_en, 1);
+ usleep_range(2000, 3000);
+ if (sc628a_client)
+ rc = flash_i2c_write_b(sc628a_client, 0x02, 0x49);
+ if (tps61310_client)
+ rc = flash_i2c_write_b(tps61310_client, 0x01, 0x8B);
break;
default:
rc = -EFAULT;
break;
}
-#endif
-
return rc;
}
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index d678d86..315f218 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -246,7 +246,6 @@
pr_err("%s: Invalid vdata type: %d\n", __func__, vdata->type);
break;
}
- msm_isp_sync_free(vdata);
return rc;
}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index 90ba214..89615ec 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -423,20 +423,15 @@
static void vfe31_subdev_notify(int id, int path)
{
- struct msm_vfe_resp *rp;
+ struct msm_vfe_resp rp;
unsigned long flags;
spin_lock_irqsave(&vfe31_ctrl->sd_notify_lock, flags);
- rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
- if (!rp) {
- CDBG("rp: cannot allocate buffer\n");
- spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
- return;
- }
+ memset(&rp, 0, sizeof(struct msm_vfe_resp));
CDBG("vfe31_subdev_notify : msgId = %d\n", id);
- rp->evt_msg.type = MSM_CAMERA_MSG;
- rp->evt_msg.msg_id = path;
- rp->type = id;
- v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+ rp.evt_msg.type = MSM_CAMERA_MSG;
+ rp.evt_msg.msg_id = path;
+ rp.type = id;
+ v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
}
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 3e8d3be..d50b778 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -418,19 +418,15 @@
static void vfe32_subdev_notify(int id, int path)
{
- struct msm_vfe_resp *rp;
+ struct msm_vfe_resp rp;
unsigned long flags = 0;
spin_lock_irqsave(&vfe32_ctrl->sd_notify_lock, flags);
- rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
- if (!rp) {
- CDBG("rp: cannot allocate buffer\n");
- return;
- }
CDBG("vfe32_subdev_notify : msgId = %d\n", id);
- rp->evt_msg.type = MSM_CAMERA_MSG;
- rp->evt_msg.msg_id = path;
- rp->type = id;
- v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+ memset(&rp, 0, sizeof(struct msm_vfe_resp));
+ rp.evt_msg.type = MSM_CAMERA_MSG;
+ rp.evt_msg.msg_id = path;
+ rp.type = id;
+ v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
spin_unlock_irqrestore(&vfe32_ctrl->sd_notify_lock, flags);
}
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 2d9d607..f9414a5 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},
@@ -488,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;
@@ -556,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;
@@ -665,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;
}
}
@@ -833,19 +840,15 @@
static void vfe2x_subdev_notify(int id, int path)
{
- struct msm_vfe_resp *rp;
+ struct msm_vfe_resp rp;
unsigned long flags = 0;
spin_lock_irqsave(&vfe2x_ctrl->sd_notify_lock, flags);
- rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
- if (!rp) {
- CDBG("rp: cannot allocate buffer\n");
- return;
- }
+ memset(&rp, 0, sizeof(struct msm_vfe_resp));
CDBG("vfe2x_subdev_notify : msgId = %d\n", id);
- rp->evt_msg.type = MSM_CAMERA_MSG;
- rp->evt_msg.msg_id = path;
- rp->type = id;
- v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+ rp.evt_msg.type = MSM_CAMERA_MSG;
+ rp.evt_msg.msg_id = path;
+ rp.type = id;
+ v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
spin_unlock_irqrestore(&vfe2x_ctrl->sd_notify_lock, flags);
}
@@ -1268,7 +1271,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);
@@ -1586,29 +1592,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,
@@ -1619,7 +1626,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);
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/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
similarity index 100%
rename from drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
rename to drivers/media/video/msm/sensors/ov7692_v4l2.c
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 8cad387..c94fa13 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -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;
}
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 2242aa8..4f6c09d 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -498,7 +498,6 @@
if (rc)
WFD_MSG_ERR("Failed to free output buffer\n");
wfd_unregister_out_buf(inst, minfo);
- wfd_free_input_buffers(wfd_dev, inst);
}
static int mdp_output_thread(void *data)
@@ -1344,12 +1343,13 @@
inst = filp->private_data;
if (inst) {
wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- vb2_queue_release(&inst->vid_bufq);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
MDP_CLOSE, (void *)inst->mdp_inst);
if (rc)
WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
+ vb2_queue_release(&inst->vid_bufq);
+ wfd_free_input_buffers(wfd_dev, inst);
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
CLOSE, (void *)inst->venc_inst);
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_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index f125cdc..550fbde 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -41,11 +41,49 @@
};
struct msm_v4l2_vid_inst {
- void *vidc_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)
{
@@ -79,7 +117,6 @@
struct msm_video_device *vid_dev =
container_of(vdev, struct msm_video_device, vdev);
struct msm_vidc_core *core = video_drvdata(filp);
- void *inst;
struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
GFP_KERNEL);
if (!v4l2_inst) {
@@ -93,16 +130,17 @@
rc = -ENOMEM;
goto fail_mem_client;
}
- inst = msm_vidc_open(core->id, vid_dev->type);
- if (!inst) {
+ 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);
- v4l2_inst->vidc_inst = inst;
- filp->private_data = v4l2_inst;
+ 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);
@@ -117,8 +155,11 @@
int rc;
struct list_head *ptr, *next;
struct buffer_info *binfo;
- struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
- rc = msm_vidc_close(v4l2_inst->vidc_inst);
+ 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);
@@ -133,60 +174,94 @@
static int msm_v4l2_querycap(struct file *filp, void *fh,
struct v4l2_capability *cap)
{
- struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
- return msm_vidc_querycap(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_enum_fmt(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_s_fmt(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_g_fmt(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_s_ctrl(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_g_ctrl(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_reqbufs(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
struct msm_smem *handle;
struct buffer_info *binfo;
- int rc = 0;
- int i;
+ 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;
@@ -229,7 +304,7 @@
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);
+ rc = msm_vidc_prepare_buf(&v4l2_inst->vidc_inst, b);
exit:
return rc;
}
@@ -237,10 +312,13 @@
int msm_v4l2_qbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ 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],
@@ -258,7 +336,7 @@
pr_debug("Queueing device address = %ld\n",
binfo->handle->device_addr);
}
- rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
+ rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
err_invalid_buff:
return rc;
}
@@ -266,22 +344,47 @@
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_dqbuf(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_streamon(v4l2_inst->vidc_inst, 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_v4l2_vid_inst *v4l2_inst = file->private_data;
- return msm_vidc_streamoff(v4l2_inst->vidc_inst, 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,
@@ -299,6 +402,9 @@
.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 = {
@@ -307,8 +413,8 @@
static unsigned int msm_v4l2_poll(struct file *filp,
struct poll_table_struct *pt)
{
- struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
- return msm_vidc_poll(v4l2_inst->vidc_inst, filp, 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 = {
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 879d324..3011a2b 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -239,31 +239,12 @@
{
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;
}
- spin_lock_irqsave(&inst->lock, flags);
- 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);
- }
- list_for_each_safe(ptr, next, &inst->extradatabufs) {
- ebuf = list_entry(ptr, struct extradata_buf, list);
- list_del(&ebuf->list);
- msm_smem_free(inst->mem_client, ebuf->handle);
- kfree(ebuf);
- }
- spin_unlock_irqrestore(&inst->lock, flags);
-
pr_debug("Calling streamoff\n");
rc = vb2_streamoff(q, i);
if (rc)
@@ -280,8 +261,7 @@
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
- struct extradata_buf *binfo;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
for (i = 0; i < b->length; i++) {
pr_err("device_addr = %ld, size = %d\n",
b->m.planes[i].m.userptr,
@@ -291,19 +271,8 @@
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;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
if (rc) {
@@ -312,7 +281,40 @@
}
}
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:
+ for (i = 0; i < b->length; i++) {
+ pr_debug("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;
+ buffer_info.extradata_addr = 0;
+ 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;
@@ -345,7 +347,7 @@
}
rc = vb2_dqbuf(q, b, true);
if (rc)
- pr_err("Failed to qbuf, %d\n", rc);
+ pr_err("Failed to dqbuf, %d\n", rc);
return rc;
}
@@ -385,6 +387,10 @@
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) {
@@ -579,7 +585,6 @@
struct hal_nal_stream_format_supported stream_format;
struct hal_enable_picture enable_picture;
struct hal_enable hal_property;
- struct hal_enable prop;
u32 control_idx = 0;
enum hal_property property_id = 0;
u32 property_val = 0;
@@ -662,12 +667,6 @@
}
}
- prop.enable = 1;
- rc = vidc_hal_session_set_property((void *)inst->session,
- HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, &prop);
- if (rc)
- pr_err("Failed to set smooth streaming\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",
@@ -709,6 +708,7 @@
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;
@@ -732,9 +732,12 @@
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:
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ 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);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 6529065..1242fb4 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -26,6 +26,7 @@
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);
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 718acf0..5dfea04f 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -365,9 +365,9 @@
static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
{
- int stride = (width + 31) & (~31);
- return height * stride * 3/2;
+ 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;
@@ -375,8 +375,9 @@
static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
{
- return width * height / 2;
+ 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
@@ -896,7 +897,7 @@
break;
}
if (property_id) {
- pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ pr_debug("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
property_id,
msm_venc_ctrls[control_idx].id,
control.value);
@@ -1110,7 +1111,7 @@
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
for (i = 0; i < b->length; i++) {
- pr_err("device_addr = %ld, size = %d\n",
+ 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;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 7fcb522..09d37ce 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,17 @@
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);
@@ -129,6 +135,14 @@
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;
@@ -208,9 +222,9 @@
return vb2_queue_init(q);
}
-void *msm_vidc_open(int core_id, int session_type)
+int msm_vidc_open(void *vidc_inst, int core_id, int session_type)
{
- struct msm_vidc_inst *inst = NULL;
+ struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst;
struct msm_vidc_core *core = NULL;
unsigned long flags;
int rc = 0;
@@ -227,17 +241,11 @@
goto err_invalid_core;
}
- inst = kzalloc(sizeof(*inst), GFP_KERNEL);
- if (!inst) {
- pr_err("Unable to allocate video instance\n");
- goto err_no_mem;
- }
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);
@@ -254,6 +262,7 @@
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);
@@ -275,15 +284,14 @@
spin_lock_irqsave(&core->lock, flags);
list_add_tail(&inst->list, &core->instances);
spin_unlock_irqrestore(&core->lock, flags);
- return inst;
+ return rc;
fail_init:
msm_smem_delete_client(inst->mem_client);
fail_mem_client:
kfree(inst);
inst = NULL;
-err_no_mem:
err_invalid_core:
- return inst;
+ return rc;
}
static void cleanup_instance(struct msm_vidc_inst *inst)
@@ -292,25 +300,24 @@
struct list_head *ptr, *next;
struct vb2_buf_entry *entry;
struct internal_buf *buf;
- struct extradata_buf *ebuf;
if (inst) {
spin_lock_irqsave(&inst->lock, flags);
- 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->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ entry = list_entry(ptr, struct vb2_buf_entry,
+ list);
+ list_del(&entry->list);
+ kfree(entry);
+ }
}
- 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);
- }
- list_for_each_safe(ptr, next, &inst->extradatabufs) {
- ebuf = list_entry(ptr, struct extradata_buf, list);
- list_del(&ebuf->list);
- msm_smem_free(inst->mem_client, ebuf->handle);
- kfree(ebuf);
+ 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);
@@ -328,15 +335,13 @@
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) {
+ if (temp == inst)
list_del(&inst->list);
- kfree(inst);
- }
}
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 init state\n");
+ 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
index e889b1c..31879b7 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -183,15 +183,54 @@
{
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;
@@ -223,11 +262,22 @@
{
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 done\n");
+ pr_err("Failed to get valid response for start\n");
}
}
@@ -235,11 +285,22 @@
{
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 done\n");
+ pr_err("Failed to get valid response for stop\n");
}
}
@@ -251,18 +312,51 @@
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 done\n");
+ 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");
}
@@ -320,7 +414,7 @@
(u32)fill_buf_done->packet_buffer1);
if (vb) {
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
- pr_err("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+ 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);
@@ -361,6 +455,12 @@
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;
@@ -792,21 +892,9 @@
&frame_data);
pr_debug("Sent etb to HAL\n");
} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- struct extradata_buf *addr;
- struct list_head *ptr, *next;
frame_data.filled_len = 0;
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
frame_data.extradata_addr = 0;
- list_for_each_safe(ptr, next, &inst->extradatabufs) {
- addr = list_entry(ptr,
- struct extradata_buf, 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,
@@ -850,35 +938,20 @@
return rc;
}
-int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
- struct extradata_buf *binfo)
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
{
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;
+ 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;
}
- 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:
+exit:
+ mutex_unlock(&inst->sync_lock);
return rc;
}
@@ -887,12 +960,26 @@
int rc = 0;
struct msm_smem *handle;
struct internal_buf *binfo;
+ struct list_head *ptr, *next;
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);
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->internalbufs)) {
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ binfo = list_entry(ptr, struct internal_buf,
+ list);
+ list_del(&binfo->list);
+ msm_smem_free(inst->mem_client, binfo->handle);
+ kfree(binfo);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+
+
for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
i++) {
handle = msm_smem_alloc(inst->mem_client,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 45bfa7b..2fafa79 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -27,8 +27,6 @@
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) (\
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index dce2dee..fb1ab58 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -21,6 +21,7 @@
#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>
@@ -32,6 +33,8 @@
#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
@@ -72,6 +75,11 @@
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;
@@ -82,12 +90,6 @@
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];
@@ -141,11 +143,14 @@
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;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index b32c190..036091b 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -18,7 +18,7 @@
#define CONTAINS(__a, __sz, __t) ({\
int __rc = __t >= __a && \
- __t <= __a + __sz; \
+ __t < __a + __sz; \
__rc; \
})
@@ -834,6 +834,8 @@
u32 device_id;
u32 session_id;
u32 status;
+ u32 height;
+ u32 width;
};
/* Data callback structure */
diff --git a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
index 0fbcc1f..cb44d3a 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -74,6 +74,59 @@
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)
{
@@ -94,6 +147,7 @@
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");
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 219f7a0..fb02676 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -279,20 +279,16 @@
struct v4l2_format *f)
{
int size;
-#ifdef NEW_S_FMT
+ struct vcap_priv_fmt *priv_fmt;
struct v4l2_format_vc_ext *vc_format;
-#endif
struct vcap_client_data *c_data = file->private_data;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-#ifdef NEW_S_FMT
- vc_format = (struct v4l2_format_vc_ext *) f->fmt.raw_data;
+ priv_fmt = (struct vcap_priv_fmt *) f->fmt.raw_data;
+
+ switch (priv_fmt->type) {
+ case VC_TYPE:
+ vc_format = (struct v4l2_format_vc_ext *) &priv_fmt->u.timing;
c_data->vc_format = *vc_format;
-#else
- c_data->vc_format =
- vcap_vc_lut[f->fmt.pix.priv];
-#endif
config_vc_format(c_data);
@@ -304,22 +300,20 @@
else
size *= 2;
-#ifndef NEW_S_FMT
- f->fmt.pix.bytesperline = size;
+ priv_fmt->u.timing.bytesperline = size;
size *= (c_data->vc_format.vactive_end -
c_data->vc_format.vactive_start);
- f->fmt.pix.sizeimage = size;
-#endif
+ priv_fmt->u.timing.sizeimage = size;
vcap_ctrl->vc_client = c_data;
break;
- case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
+ case VP_IN_TYPE:
c_data->vp_buf_type_field = V4L2_BUF_TYPE_INTERLACED_IN_DECODER;
c_data->vp_format.field = f->fmt.pix.field;
c_data->vp_format.height = f->fmt.pix.height;
c_data->vp_format.width = f->fmt.pix.width;
c_data->vp_format.pixelformat = f->fmt.pix.pixelformat;
break;
- case V4L2_BUF_TYPE_INTERLACED_IN_AFE:
+ case VP_OUT_TYPE:
break;
default:
break;
@@ -522,6 +516,8 @@
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_s_fmt_type_private = vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_type_private = vidioc_g_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index ed0bc25..84b52b2 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -34,401 +34,6 @@
printk(KERN_DEBUG "VC: " fmt, ## arg); \
} while (0)
-struct v4l2_format_vc_ext vcap_vc_lut[] = {
- /* 1080p */
- {
- HAL_VCAP_YUV_1080p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
- 32, 2200, 192, 2112, 4, 24, 0, 2, 0, 44, 0, 0, 0, 0,
- 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
- 1125, 2200, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_1080p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 148.5,
- 1125, 2200, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_24_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 1125, 2750, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_24_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 112, 2750, 192, 2112, 4, 110, 0, 2, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_24_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 1125, 275, 19, 211, 41, 1121, 0, 5, 0, 16, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_60_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
- 1125, 200, 22, 182, 41, 1121, 0, 5, 0, 16, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
- 1125, 2640, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_50_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 148.5,
- 15, 2640, 192, 2112, 6, 13, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_25_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 1125, 2640, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0,
- 0, 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_25_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 10, 2640, 192, 2112, 4, 8, 0, 2, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1080p_30_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 1125, 2200, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_1080p_25_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 74.25,
- 1125, 2640, 192, 2112, 41, 1121, 0, 5, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_1080p_25_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 74.25,
- 10, 2640, 192, 2112, 4, 8, 0, 2, 0, 44, 0, 0, 0,
- 0, 0, 0
- },
- /* 1080i */
- {
- HAL_VCAP_YUV_1080i_60_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 1125, 2200, 192, 2112, 20, 560, 0, 5, 0, 44, 583, 1123, 1100,
- 1100, 563, 568
- },
- {
- HAL_VCAP_YUV_1080i_60_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 18, 2200, 192, 2112, 3, 7, 0, 2, 0, 44, 11, 15, 1100,
- 1100, 8, 10
- },
- {
- HAL_VCAP_YUV_1080i_60_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 1125, 220, 19, 211, 20, 560, 0, 5, 0, 4, 583, 1123, 110,
- 110, 563, 568
- },
- {
- HAL_VCAP_YUV_1080i_50_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 72.00,
- 1125, 2640, 192, 2112, 20, 560, 0, 5, 0, 44, 583, 1123, 1320,
- 1320, 563, 568
- },
- {
- HAL_VCAP_YUV_1080i_50_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 72.00,
- 52, 2640, 192, 2112, 4, 24, 0, 2, 0, 44, 30, 50, 1320,
- 1320, 26, 28},
- {
- HAL_VCAP_YUV_1080i_50_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 72.00,
- 1125, 264, 19, 211, 20, 560, 0, 5, 0, 4, 583, 1123, 110,
- 110, 563, 568
- },
- {
- HAL_VCAP_RGB_1080i_50_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 72.00,
- 1125, 2640, 192, 2112, 20, 560, 0, 5, 0, 44, 583, 1123, 1320,
- 1320, 563, 568
- },
- {
- HAL_VCAP_RGB_1080i_50_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 72.00,
- 52, 2640, 192, 2112, 4, 24, 0, 2, 0, 44, 30, 50, 1320,
- 1320, 26, 28
- },
- /* 480i */
- {
- HAL_VCAP_YUV_480i_60_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
- 20, 1716, 238, 1678, 3, 7, 0, 2, 0, 124, 14, 18, 820,
- 820, 10, 12
- },
- {
- HAL_VCAP_YUV_480i_60_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
- 525, 1716, 238, 1678, 18, 258, 0, 3, 0, 124, 281, 521, 858,
- 858, 262, 265
- },
- {
- HAL_VCAP_YUV_480i_60_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
- 525, 172, 24, 168, 18, 258, 0, 3, 0, 12, 281, 521, 86,
- 86, 262, 265
- },
- {
- HAL_VCAP_YUV_2880_480i_60_FL, HAL_VCAP_MODE_INT,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 54.000, 525, 3432, 476, 3356, 18, 258, 0, 3,
- 0, 248, 281, 521, 1716, 1716, 262, 265
- },
- {
- HAL_VCAP_YUV_2880_480i_60_RH, HAL_VCAP_MODE_INT,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 54.000, 32, 3432, 476, 3356, 4, 14, 0, 3, 0,
- 248, 20, 30, 1716, 1716, 16, 19
- },
- /* 480p */
- {
- HAL_VCAP_YUV_480p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
- 8, 858, 122, 842, 2, 5, 0, 1, 0, 62, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_480p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 27.027,
- 52, 858, 122, 842, 3, 50, 0, 2, 0, 62, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_480p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 27.027,
- 525, 858, 122, 842, 36, 516, 0, 6, 0, 62, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_480p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
- 525, 858, 122, 842, 36, 516, 0, 6, 0, 62, 0, 0, 0, 0, 0, 0
- },
- {
- HAL_VCAP_YUV_480p_60_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.027,
- 525, 86, 12, 84, 36, 516, 0, 6, 0, 6, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_2880_480p_60_FL, HAL_VCAP_MODE_PRO,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 108.000, 525, 3432, 488, 3368, 36, 516, 0, 6,
- 0, 248, 0, 0, 0, 0, 0, 0
- },
- {
- HAL_VCAP_YUV_2880_480p_60_RH, HAL_VCAP_MODE_PRO,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 108.000, 25, 3432, 488, 3368, 8, 22, 0, 6, 0,
- 248, 0, 0, 0, 0, 0, 0
- },
- /* 720p */
- {
- HAL_VCAP_YUV_720p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 750, 1650, 260, 1540, 25, 745, 0, 5, 0, 40, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_720p_60_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 74.25,
- 750, 1650, 260, 1540, 25, 745, 0, 5, 0, 40, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_720p_60_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 750, 165, 26, 154, 25, 745, 0, 5, 0, 4, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_720p_60_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 35, 1650, 260, 1540, 5, 32, 0, 3, 0, 40, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_720p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 750, 1980, 260, 1540, 25, 745, 0, 5, 0, 40, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_720p_50_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 750, 198, 26, 154, 25, 745, 0, 5, 0, 4, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_720p_50_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 74.25,
- 6, 1980, 260, 1540, 2, 5, 0, 1, 0, 40, 0, 0, 0,
- 0, 0, 0
- },
- /* 576p */
- {
- HAL_VCAP_YUV_576p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
- 625, 864, 132, 852, 44, 620, 0, 5, 0, 64, 0, 0, 0,
- 0, 0, 0},
- {
- HAL_VCAP_RGB_576p_50_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 27.0,
- 625, 864, 132, 852, 44, 620, 0, 5, 0, 64, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_576p_50_RW, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
- 625, 86, 13, 85, 44, 620, 0, 5, 0, 6, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_576p_50_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
- 25, 864, 132, 852, 4, 23, 0, 3, 0, 64, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_1440_576p_50_RH, HAL_VCAP_MODE_PRO,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 54.000, 25, 1728, 264, 1704, 6, 23, 0, 5, 0,
- 128, 0, 0, 0, 0, 0, 0
- },
- {
- HAL_VCAP_YUV_2880_576p_50_FL, HAL_VCAP_MODE_PRO,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 108.000, 625, 3456, 528, 3408, 44, 620, 0, 5,
- 0, 256, 0, 0, 0, 0, 0, 0
- },
- {
- HAL_VCAP_YUV_2880_576p_50_RH, HAL_VCAP_MODE_PRO,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS,
- HAL_VCAP_YUV, 108.000, 25, 3456, 528, 3408, 6, 23, 0, 5, 0,
- 256, 0, 0, 0, 0, 0, 0
- },
- /* 576i */
- {
- HAL_VCAP_YUV_576i_50_FL, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
- 625, 1728, 264, 1704, 22, 310, 0, 3, 0, 126, 335, 623, 864,
- 864, 313, 316
- },
- {
- HAL_VCAP_YUV_576i_50_RW, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
- 625, 172, 26, 170, 22, 310, 0, 3, 0, 13, 335, 623, 86,
- 86, 313, 316
- },
- {
- HAL_VCAP_YUV_576i_50_RH, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_NEG, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 27.0,
- 29, 1728, 264, 1704, 3, 13, 0, 1, 0, 126, 16, 26, 864, 864,
- 14, 15
- },
- /* XGA 1024x768 */
- {
- HAL_VCAP_YUV_XGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 63.5,
- 798, 1328, 256, 1280, 27, 795, 0, 4, 0, 104, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_XGA_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 63.5,
- 12, 1328, 256, 1280, 6, 10, 0, 4, 0, 104, 0, 0, 0, 0,
- 0, 0
- },
- {
- HAL_VCAP_YUV_XGA_RB, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 63.5,
- 12, 1216, 112, 1136, 6, 10, 0, 4, 0, 32, 0, 0, 0, 0,
- 0, 0
- },
- /* SXGA 1280x1024 */
- {
- HAL_VCAP_YUV_SXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 109.0,
- 1063, 1712, 352, 1632, 36, 1060, 0, 7, 0, 136, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_RGB_SXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 109.0,
- 1063, 1712, 352, 1632, 36, 1060, 0, 7, 0, 136, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_SXGA_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 109.0,
- 17, 1712, 352, 1632, 8, 15, 0, 7, 0, 136, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_SXGA_RB, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 109.0,
- 17, 1440, 112, 1392, 8, 15, 0, 7, 0, 32, 0, 0, 0, 0,
- 0, 0
- },
- /* UXGA 1600x1200 */
- {
- HAL_VCAP_YUV_UXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 161.0,
- 1245, 2160, 448, 2048, 42, 1242, 0, 4, 0, 168, 0,
- 0, 0, 0, 0, 0
- },
- {
- HAL_VCAP_RGB_UXGA_FL, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_RGB, 161.0,
- 1245, 2160, 448, 2048, 42, 1242, 0, 4, 0, 168, 0,
- 0, 0, 0, 0, 0
- },
- {
- HAL_VCAP_YUV_UXGA_RH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 161.0,
- 12, 2160, 448, 2048, 6, 10, 0, 4, 0, 168, 0, 0, 0,
- 0, 0, 0
- },
- {
- HAL_VCAP_YUV_UXGA_RB, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_NEG,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_POS, HAL_VCAP_YUV, 161.0,
- 12, 1808, 112, 1712, 6, 10, 0, 4, 0, 32, 0, 0, 0, 0,
- 0, 0
- },
- /* test odd height */
- {
- HAL_VCAP_ODD_HEIGHT, HAL_VCAP_MODE_INT, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_NEG, HAL_VCAP_YUV, 148.5,
- 65, 1728, 264, 1704, 5, 20, 0, 3, 0, 126, 25, 40, 864,
- 864, 21, 24
- },
- /* test odd width RGB only */
- {
- HAL_VCAP_ODD_WIDTH, HAL_VCAP_MODE_PRO, HAL_VCAP_POLAR_POS,
- HAL_VCAP_POLAR_POS, HAL_VCAP_POLAR_NEG, HAL_VCAP_RGB, 148.5,
- 52, 859, 122, 843, 3, 50, 0, 2, 0, 62, 0, 0, 0, 0, 0, 0
- },
-};
-
void config_buffer(struct vcap_client_data *c_data,
struct vcap_buffer *buf,
void __iomem *y_addr,
@@ -655,10 +260,8 @@
writel_relaxed(0x00000002, VCAP_VC_NPL_CTRL);
writel_relaxed(0x00000004 | vc_format->color_space << 1, VCAP_VC_CTRL);
- writel_relaxed(vc_format->h_polar << 4 |
- vc_format->v_polar << 0, VCAP_VC_POLARITY);
-
- writel_relaxed(vc_format->h_polar << 4 |
+ writel_relaxed(vc_format->d_polar << 8 |
+ vc_format->h_polar << 4 |
vc_format->v_polar << 0, VCAP_VC_POLARITY);
writel_relaxed(((vc_format->htotal << 16) | vc_format->vtotal),
VCAP_VC_V_H_TOTAL);
diff --git a/drivers/media/video/vcap_vc.h b/drivers/media/video/vcap_vc.h
index e431038..57d13cd 100644
--- a/drivers/media/video/vcap_vc.h
+++ b/drivers/media/video/vcap_vc.h
@@ -13,11 +13,9 @@
#ifndef VCAP_VC_H
#define VCAP_VC_H
-/* #define NEW_S_FMT */
#include <linux/interrupt.h>
#include <media/vcap_v4l2.h>
-extern struct v4l2_format_vc_ext vcap_vc_lut[];
#define VCAP_HARDWARE_VERSION 0x10000000
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 76d38c1..e2dff4b 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -564,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);
@@ -780,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:
@@ -790,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;
}
@@ -922,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:
@@ -931,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);
@@ -940,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;
}
@@ -1053,6 +1054,22 @@
.suspend = wcd9xxx_slim_suspend,
};
+static const struct slim_device_id sitar1p1_slimtest_id[] = {
+ {"sitar1p1-slim", 0},
+ {}
+};
+static struct slim_driver sitar1p1_slim_driver = {
+ .driver = {
+ .name = "sitar1p1-slim",
+ .owner = THIS_MODULE,
+ },
+ .probe = wcd9xxx_slim_probe,
+ .remove = wcd9xxx_slim_remove,
+ .id_table = sitar1p1_slimtest_id,
+ .resume = wcd9xxx_slim_resume,
+ .suspend = wcd9xxx_slim_suspend,
+};
+
static const struct slim_device_id slimtest_id[] = {
{"tabla-slim", 0},
{}
@@ -1115,7 +1132,7 @@
static int __init wcd9xxx_init(void)
{
- int ret1, ret2, ret3, ret4;
+ int ret1, ret2, ret3, ret4, ret5;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -1130,10 +1147,14 @@
pr_err("failed to add the I2C driver\n");
ret4 = slim_driver_register(&sitar_slim_driver);
- if (ret1 != 0)
+ if (ret4 != 0)
pr_err("Failed to register sitar SB driver: %d\n", ret4);
- return (ret1 && ret2 && ret3 && ret4) ? -1 : 0;
+ ret5 = slim_driver_register(&sitar1p1_slim_driver);
+ if (ret5 != 0)
+ pr_err("Failed to register sitar SB driver: %d\n", ret5);
+
+ return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
}
module_init(wcd9xxx_init);
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/misc/qseecom.c b/drivers/misc/qseecom.c
index 2c42bc7..4c92ee5 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1271,9 +1271,11 @@
{
struct ion_handle *ihandle; /* Ion handle */
struct qseecom_load_img_req load_img_req;
- int32_t ret;
+ int ret;
+ int set_cpu_ret = 0;
ion_phys_addr_t pa = 0;
uint32_t len;
+ struct cpumask mask;
struct qseecom_load_app_ireq load_req;
struct qseecom_command_scm_resp resp;
@@ -1302,14 +1304,25 @@
load_req.img_len = load_img_req.img_len;
load_req.phy_addr = pa;
+ /* SCM_CALL tied to Core0 */
+ mask = CPU_MASK_CPU0;
+ set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+ if (set_cpu_ret) {
+ pr_err("set_cpus_allowed_ptr failed : ret %d\n",
+ set_cpu_ret);
+ ret = -EFAULT;
+ goto qseecom_load_external_elf_set_cpu_err;
+ }
+
/* SCM_CALL to load the external elf */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &load_req,
sizeof(struct qseecom_load_app_ireq),
&resp, sizeof(resp));
if (ret) {
- pr_err("scm_call to unload failed : ret %d\n",
+ pr_err("scm_call to load failed : ret %d\n",
ret);
ret = -EFAULT;
+ goto qseecom_load_external_elf_scm_err;
}
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
@@ -1324,6 +1337,18 @@
ret = -EFAULT;
}
}
+
+qseecom_load_external_elf_scm_err:
+ /* Restore the CPU mask */
+ mask = CPU_MASK_ALL;
+ set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+ if (set_cpu_ret) {
+ pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
+ set_cpu_ret);
+ ret = -EFAULT;
+ }
+
+qseecom_load_external_elf_set_cpu_err:
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -1334,11 +1359,23 @@
static int qseecom_unload_external_elf(struct qseecom_dev_handle *data)
{
int ret = 0;
+ int set_cpu_ret = 0;
struct qseecom_command_scm_resp resp;
struct qseecom_unload_app_ireq req;
+ struct cpumask mask;
/* Populate the structure for sending scm call to unload image */
req.qsee_cmd_id = QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND;
+
+ /* SCM_CALL tied to Core0 */
+ mask = CPU_MASK_CPU0;
+ ret = set_cpus_allowed_ptr(current, &mask);
+ if (ret) {
+ pr_err("set_cpus_allowed_ptr failed : ret %d\n",
+ ret);
+ return -EFAULT;
+ }
+
/* SCM_CALL to unload the external elf */
ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(struct qseecom_unload_app_ireq),
@@ -1346,7 +1383,8 @@
if (ret) {
pr_err("scm_call to unload failed : ret %d\n",
ret);
- return -EFAULT;
+ ret = -EFAULT;
+ goto qseecom_unload_external_elf_scm_err;
}
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
@@ -1360,6 +1398,17 @@
ret = -EFAULT;
}
}
+
+qseecom_unload_external_elf_scm_err:
+ /* Restore the CPU mask */
+ mask = CPU_MASK_ALL;
+ set_cpu_ret = set_cpus_allowed_ptr(current, &mask);
+ if (set_cpu_ret) {
+ pr_err("set_cpus_allowed_ptr failed to restore mask: ret %d\n",
+ set_cpu_ret);
+ ret = -EFAULT;
+ }
+
return ret;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index a162586..ca54265 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -363,33 +363,24 @@
show_perf(struct device *dev, struct device_attribute *attr, char *buf)
{
struct mmc_host *host = dev_get_drvdata(dev);
- int64_t rtime_mmcq, wtime_mmcq, rtime_drv, wtime_drv;
- unsigned long rbytes_mmcq, wbytes_mmcq, rbytes_drv, wbytes_drv;
+ int64_t rtime_drv, wtime_drv;
+ unsigned long rbytes_drv, wbytes_drv;
spin_lock(&host->lock);
- rbytes_mmcq = host->perf.rbytes_mmcq;
- wbytes_mmcq = host->perf.wbytes_mmcq;
rbytes_drv = host->perf.rbytes_drv;
wbytes_drv = host->perf.wbytes_drv;
- rtime_mmcq = ktime_to_us(host->perf.rtime_mmcq);
- wtime_mmcq = ktime_to_us(host->perf.wtime_mmcq);
rtime_drv = ktime_to_us(host->perf.rtime_drv);
wtime_drv = ktime_to_us(host->perf.wtime_drv);
spin_unlock(&host->lock);
- return snprintf(buf, PAGE_SIZE, "Write performance at MMCQ Level:"
- "%lu bytes in %lld microseconds\n"
- "Read performance at MMCQ Level:"
- "%lu bytes in %lld microseconds\n"
- "Write performance at driver Level:"
+ return snprintf(buf, PAGE_SIZE, "Write performance at driver Level:"
"%lu bytes in %lld microseconds\n"
"Read performance at driver Level:"
"%lu bytes in %lld microseconds\n",
- wbytes_mmcq, wtime_mmcq, rbytes_mmcq,
- rtime_mmcq, wbytes_drv, wtime_drv,
+ wbytes_drv, wtime_drv,
rbytes_drv, rtime_drv);
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 9385087..8fce9a6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -464,6 +464,11 @@
ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+ card->ext_csd.max_packed_writes =
+ ext_csd[EXT_CSD_MAX_PACKED_WRITES];
+ card->ext_csd.max_packed_reads =
+ ext_csd[EXT_CSD_MAX_PACKED_READS];
}
out:
@@ -1183,6 +1188,25 @@
card->ext_csd.cache_ctrl = err ? 0 : 1;
}
+ if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
+ (card->ext_csd.max_packed_writes > 0) &&
+ (card->ext_csd.max_packed_reads > 0)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_EXP_EVENTS_CTRL,
+ EXT_CSD_PACKED_EVENT_EN,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warning("%s: Enabling packed event failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.packed_event_en = 0;
+ err = 0;
+ } else {
+ card->ext_csd.packed_event_en = 1;
+ }
+ }
+
if (!oldcard)
host->card = card;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4967c4e..717f1d3 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1691,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;
}
@@ -1725,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;
@@ -3105,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) {
@@ -3122,6 +3126,7 @@
mb();
}
}
+ spin_unlock_irqrestore(&host->lock, flags);
}
#ifdef CONFIG_PM_RUNTIME
@@ -3934,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;
}
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/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 2fc95af..152bbb4 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -392,6 +392,7 @@
u32 num_transfers;
atomic_set(&dd->rx_irq_called, 0);
+ atomic_set(&dd->tx_irq_called, 0);
if (dd->write_len && !dd->read_len) {
/* WR-WR transfer */
bytes_sent = dd->cur_msg_len - dd->tx_bytes_remaining;
@@ -712,6 +713,8 @@
readl_relaxed(dd->base + SPI_OPERATIONAL) &
SPI_OP_MAX_OUTPUT_DONE_FLAG) {
msm_spi_ack_transfer(dd);
+ if (atomic_inc_return(&dd->tx_irq_called) == 1)
+ return IRQ_HANDLED;
msm_spi_complete(dd);
return IRQ_HANDLED;
}
@@ -1586,9 +1589,12 @@
}
/* restore original context */
dd = container_of(cmd, struct msm_spi, tx_hdr);
- if (result & DMOV_RSLT_DONE)
+ if (result & DMOV_RSLT_DONE) {
dd->stat_dmov_tx++;
- else {
+ if ((atomic_inc_return(&dd->tx_irq_called) == 1))
+ return;
+ complete(&dd->transfer_complete);
+ } else {
/* Error or flush */
if (result & DMOV_RSLT_ERROR) {
dev_err(dd->dev, "DMA error (0x%08x)\n", result);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index a434bbb..223fce6 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -285,6 +285,7 @@
int output_block_size;
int burst_size;
atomic_t rx_irq_called;
+ atomic_t tx_irq_called;
/* Used to pad messages unaligned to block size */
u8 *tx_padding;
dma_addr_t tx_padding_dma;
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index fbb377e..78a1292 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -723,7 +723,8 @@
} else if (tmdev->hw_type == APQ_8064) {
reg_cntl |= TSENS_8960_SLP_CLK_ENA |
(TSENS_MEASURE_PERIOD << 18) |
- TSENS_8064_SENSORS_EN;
+ (((1 << tmdev->tsens_num_sensor) - 1)
+ << TSENS_SENSOR0_SHIFT);
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_status_cntl |= TSENS_MIN_STATUS_MASK |
@@ -823,7 +824,8 @@
} else if (tmdev->hw_type == APQ_8064) {
reg_cntl |= TSENS_8960_SLP_CLK_ENA |
(TSENS_MEASURE_PERIOD << 18) |
- TSENS_8064_SENSORS_EN;
+ (((1 << tmdev->tsens_num_sensor) - 1)
+ << TSENS_SENSOR0_SHIFT);
writel_relaxed(reg_cntl, TSENS_CNTL_ADDR);
reg_status_cntl = readl_relaxed(TSENS_8064_STATUS_CNTL);
reg_status_cntl |= TSENS_LOWER_STATUS_CLR |
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index d310381..d0b8323 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1964,12 +1964,25 @@
INIT_WORK(&msm_uport->clock_off_w, hsuart_clock_off_work);
mutex_init(&msm_uport->clk_mutex);
+ clk_prepare_enable(msm_uport->clk);
+ if (msm_uport->pclk)
+ clk_prepare_enable(msm_uport->pclk);
+
ret = uartdm_init_port(uport);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ clk_disable_unprepare(msm_uport->clk);
+ if (msm_uport->pclk)
+ clk_disable_unprepare(msm_uport->pclk);
return ret;
+ }
/* configure the CR Protection to Enable */
msm_hs_write(uport, UARTDM_CR_ADDR, CR_PROTECTION_EN);
+
+ clk_disable_unprepare(msm_uport->clk);
+ if (msm_uport->pclk)
+ clk_disable_unprepare(msm_uport->pclk);
+
/*
* Enable Command register protection before going ahead as this hw
* configuration makes sure that issued cmd to CR register gets complete
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index d74959e..15fc0c1 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -223,6 +223,7 @@
char **uevent_envp = NULL;
static enum android_device_state last_uevent, next_state;
unsigned long flags;
+ int pm_qos_vote = -1;
spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config) {
@@ -232,13 +233,16 @@
uevent_envp = dev->connected ? connected : disconnected;
next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
if (dev->connected && strncmp(dev->pm_qos, "low", 3))
- android_pm_qos_update_latency(dev, 1);
+ pm_qos_vote = 1;
else if (!dev->connected || !strncmp(dev->pm_qos, "low", 3))
- android_pm_qos_update_latency(dev, 0);
+ pm_qos_vote = 0;
}
dev->sw_connected = dev->connected;
spin_unlock_irqrestore(&cdev->lock, flags);
+ if (pm_qos_vote != -1)
+ android_pm_qos_update_latency(dev, pm_qos_vote);
+
if (uevent_envp) {
/*
* Some userspace modules, e.g. MTP, work correctly only if
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 863143b..7fd120f 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
+#include <mach/gpio.h>
#include "ci13xxx_udc.c"
@@ -24,7 +25,11 @@
struct ci13xxx_udc_context {
int irq;
void __iomem *regs;
+ int wake_gpio;
+ int wake_irq;
+ bool wake_irq_state;
};
+
static struct ci13xxx_udc_context _udc_ctxt;
static irqreturn_t msm_udc_irq(int irq, void *data)
@@ -32,22 +37,71 @@
return udc_irq();
}
+static void ci13xxx_msm_suspend(void)
+{
+ struct device *dev = _udc->gadget.dev.parent;
+ dev_dbg(dev, "ci13xxx_msm_suspend\n");
+
+ if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
+ enable_irq_wake(_udc_ctxt.wake_irq);
+ enable_irq(_udc_ctxt.wake_irq);
+ _udc_ctxt.wake_irq_state = true;
+ }
+}
+
+static void ci13xxx_msm_resume(void)
+{
+ struct device *dev = _udc->gadget.dev.parent;
+ dev_dbg(dev, "ci13xxx_msm_resume\n");
+
+ if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
+ disable_irq_wake(_udc_ctxt.wake_irq);
+ disable_irq(_udc_ctxt.wake_irq);
+ _udc_ctxt.wake_irq_state = false;
+ }
+}
+
static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
{
struct device *dev = udc->gadget.dev.parent;
switch (event) {
case CI13XXX_CONTROLLER_RESET_EVENT:
- dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+ dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel_relaxed(0x08, USB_AHBMODE);
break;
+ case CI13XXX_CONTROLLER_DISCONNECT_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n");
+ ci13xxx_msm_resume();
+ break;
+ case CI13XXX_CONTROLLER_SUSPEND_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
+ ci13xxx_msm_suspend();
+ break;
+ case CI13XXX_CONTROLLER_RESUME_EVENT:
+ dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
+ ci13xxx_msm_resume();
+ break;
+
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");
break;
}
}
+static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
+{
+ struct ci13xxx *udc = _udc;
+
+ if (udc->transceiver && udc->vbus_active && udc->suspended)
+ otg_set_suspend(udc->transceiver, 0);
+ else if (!udc->suspended)
+ ci13xxx_msm_resume();
+
+ return IRQ_HANDLED;
+}
+
static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
.name = "ci13xxx_msm",
.flags = CI13XXX_REGS_SHARED |
@@ -60,6 +114,52 @@
.notify_event = ci13xxx_msm_notify_event,
};
+static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
+ struct resource *res)
+{
+ int wake_irq;
+ int ret;
+
+ dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
+
+ _udc_ctxt.wake_gpio = res->start;
+ gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
+ gpio_direction_input(_udc_ctxt.wake_gpio);
+ wake_irq = MSM_GPIO_TO_INT(_udc_ctxt.wake_gpio);
+ if (wake_irq < 0) {
+ dev_err(&pdev->dev, "could not register USB_RESUME GPIO.\n");
+ return -ENXIO;
+ }
+
+ dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
+ _udc_ctxt.wake_gpio, wake_irq);
+ ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "usb resume", NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
+ goto gpio_free;
+ }
+ disable_irq(wake_irq);
+ _udc_ctxt.wake_irq = wake_irq;
+
+ return 0;
+
+gpio_free:
+ gpio_free(_udc_ctxt.wake_gpio);
+ _udc_ctxt.wake_gpio = 0;
+ return ret;
+}
+
+static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
+{
+ dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
+
+ if (_udc_ctxt.wake_gpio) {
+ gpio_free(_udc_ctxt.wake_gpio);
+ _udc_ctxt.wake_gpio = 0;
+ }
+}
+
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -92,11 +192,20 @@
goto udc_remove;
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+ if (res) {
+ ret = ci13xxx_msm_install_wake_gpio(pdev, res);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpio irq install failed\n");
+ goto udc_remove;
+ }
+ }
+
ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name,
pdev);
if (ret < 0) {
dev_err(&pdev->dev, "request_irq failed\n");
- goto udc_remove;
+ goto gpio_uninstall;
}
pm_runtime_no_callbacks(&pdev->dev);
@@ -104,6 +213,8 @@
return 0;
+gpio_uninstall:
+ ci13xxx_msm_uninstall_wake_gpio(pdev);
udc_remove:
udc_remove();
iounmap:
@@ -116,6 +227,7 @@
{
pm_runtime_disable(&pdev->dev);
free_irq(_udc_ctxt.irq, pdev);
+ ci13xxx_msm_uninstall_wake_gpio(pdev);
udc_remove();
iounmap(_udc_ctxt.regs);
return 0;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b612a0b..b29ef82 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2005,6 +2005,51 @@
}
/**
+ * isr_resume_handler: USB PCI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_resume_handler(struct ci13xxx *udc)
+{
+ udc->gadget.speed = hw_port_is_high_speed() ?
+ USB_SPEED_HIGH : USB_SPEED_FULL;
+ if (udc->suspended) {
+ spin_unlock(udc->lock);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_RESUME_EVENT);
+ if (udc->transceiver)
+ otg_set_suspend(udc->transceiver, 0);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(udc->lock);
+ udc->suspended = 0;
+ }
+}
+
+/**
+ * isr_resume_handler: USB SLI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_suspend_handler(struct ci13xxx *udc)
+{
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+ udc->vbus_active) {
+ if (udc->suspended == 0) {
+ spin_unlock(udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_SUSPEND_EVENT);
+ if (udc->transceiver)
+ otg_set_suspend(udc->transceiver, 1);
+ spin_lock(udc->lock);
+ udc->suspended = 1;
+ }
+ }
+}
+
+/**
* isr_get_status_complete: get_status request complete function
* @ep: endpoint
* @req: request handled
@@ -2865,6 +2910,9 @@
} else {
hw_device_state(0);
_gadget_stop_activity(&udc->gadget);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_DISCONNECT_EVENT);
pm_runtime_put_sync(&_gadget->dev);
}
}
@@ -3174,14 +3222,7 @@
}
if (USBi_PCI & intr) {
isr_statistics.pci++;
- udc->gadget.speed = hw_port_is_high_speed() ?
- USB_SPEED_HIGH : USB_SPEED_FULL;
- if (udc->suspended) {
- spin_unlock(udc->lock);
- udc->driver->resume(&udc->gadget);
- spin_lock(udc->lock);
- udc->suspended = 0;
- }
+ isr_resume_handler(udc);
}
if (USBi_UEI & intr)
isr_statistics.uei++;
@@ -3190,15 +3231,7 @@
isr_tr_complete_handler(udc);
}
if (USBi_SLI & intr) {
- if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
- udc->suspended = 1;
- spin_unlock(udc->lock);
- udc->driver->suspend(&udc->gadget);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_SUSPEND_EVENT);
- spin_lock(udc->lock);
- }
+ isr_suspend_handler(udc);
isr_statistics.sli++;
}
retval = IRQ_HANDLED;
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 8e2b093..8cb62da 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -124,6 +124,8 @@
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
#define CI13XXX_CONTROLLER_SUSPEND_EVENT 2
#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT 3
+#define CI13XXX_CONTROLLER_RESUME_EVENT 4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT 5
void (*notify_event) (struct ci13xxx *udc, unsigned event);
};
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/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 deb4064..5b05c5b 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -673,8 +673,7 @@
{
struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
- if (aca_enabled() || (test_bit(ID, &motg->inputs) &&
- !test_bit(ID_A, &motg->inputs)))
+ if (aca_enabled())
return 0;
if (suspend) {
@@ -688,6 +687,14 @@
clear_bit(A_BUS_REQ, &motg->inputs);
queue_work(system_nrt_wq, &motg->sm_work);
break;
+ case OTG_STATE_B_PERIPHERAL:
+ pr_debug("peripheral bus suspend\n");
+ if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+ break;
+ set_bit(A_BUS_SUSPEND, &motg->inputs);
+ queue_work(system_nrt_wq, &motg->sm_work);
+ break;
+
default:
break;
}
@@ -701,6 +708,13 @@
/* ensure hardware is not in low power mode */
pm_runtime_resume(otg->dev);
break;
+ case OTG_STATE_B_PERIPHERAL:
+ pr_debug("peripheral bus resume\n");
+ if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+ break;
+ clear_bit(A_BUS_SUSPEND, &motg->inputs);
+ queue_work(system_nrt_wq, &motg->sm_work);
+ break;
default:
break;
}
@@ -718,7 +732,7 @@
struct usb_bus *bus = otg->host;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
- bool host_bus_suspend, dcp;
+ bool host_bus_suspend, device_bus_suspend, dcp;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc;
@@ -728,6 +742,9 @@
disable_irq(motg->irq);
host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
+ device_bus_suspend = otg->gadget && test_bit(ID, &motg->inputs) &&
+ test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+ motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
/*
* Chipidea 45-nm PHY suspend sequence:
@@ -791,8 +808,8 @@
* PMIC notifications are unavailable.
*/
cmd_val = readl_relaxed(USB_USBCMD);
- if (host_bus_suspend || (motg->pdata->otg_control == OTG_PHY_CONTROL &&
- dcp))
+ if (host_bus_suspend || device_bus_suspend ||
+ (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
else
cmd_val |= ULPI_STP_CTRL;
@@ -802,7 +819,8 @@
* BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
* PHY retention and collapse can not happen with VDP_SRC enabled.
*/
- if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend && !dcp) {
+ if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
+ !device_bus_suspend && !dcp) {
phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
if (motg->pdata->otg_control == OTG_PHY_CONTROL)
/* Enable PHY HV interrupts to wake MPM/Link */
@@ -1192,10 +1210,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");
@@ -1208,6 +1228,7 @@
pr_err("unable to disable vbus_otg\n");
return;
}
+ pm8921_disable_source_current(on);
vbus_is_on = false;
}
}
@@ -2130,6 +2151,13 @@
*/
otg->host->is_b_host = 1;
msm_otg_start_host(otg, 1);
+ } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+ test_bit(B_SESS_VLD, &motg->inputs)) {
+ pr_debug("a_bus_suspend && b_sess_vld\n");
+ if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
+ pm_runtime_put_noidle(otg->dev);
+ pm_runtime_suspend(otg->dev);
+ }
} else if (test_bit(ID_C, &motg->inputs)) {
msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
}
@@ -2566,6 +2594,8 @@
} else {
pr_debug("BSV clear\n");
clear_bit(B_SESS_VLD, &motg->inputs);
+ clear_bit(A_BUS_SUSPEND, &motg->inputs);
+
msm_chg_check_aca_intr(motg);
}
work = 1;
@@ -3386,6 +3416,9 @@
motg->caps = ALLOW_PHY_RETENTION;
}
+ if (motg->pdata->enable_lpm_on_dev_suspend)
+ motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
+
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 7f603dd..0212142 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -26,6 +26,8 @@
#include "external_common.h"
#include "mhl_api.h"
+#include "mdp.h"
+
struct external_common_state_type *external_common_state;
EXPORT_SYMBOL(external_common_state);
DEFINE_MUTEX(external_common_state_hpd_mutex);
@@ -77,6 +79,23 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF};
#endif /* DEBUG_EDID */
+#define DMA_E_BASE 0xB0000
+void mdp_vid_quant_set(void)
+{
+ if ((external_common_state->video_resolution == \
+ HDMI_VFRMT_720x480p60_4_3) || \
+ (external_common_state->video_resolution == \
+ HDMI_VFRMT_720x480p60_16_9)) {
+ MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x70, 0x00EB0010);
+ MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x74, 0x00EB0010);
+ MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x78, 0x00EB0010);
+ } else {
+ MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x70, 0x00FF0000);
+ MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x74, 0x00FF0000);
+ MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x78, 0x00FF0000);
+ }
+}
+
const char *video_format_2string(uint32 format)
{
switch (format) {
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 7f6585c..a372016 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -3641,8 +3641,8 @@
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/
{0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/
- {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x88, 0x04, 0x04}, /*02*/
+ {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04}, /*02*/
{0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/
{0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c
index 1b5d7c5..57d754e 100644
--- a/drivers/video/msm/logo.c
+++ b/drivers/video/msm/logo.c
@@ -37,7 +37,7 @@
}
/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
-int load_565rle_image(char *filename)
+int load_565rle_image(char *filename, bool bf_supported)
{
struct fb_info *info;
int fd, count, err = 0;
@@ -76,7 +76,7 @@
max = fb_width(info) * fb_height(info);
ptr = data;
- if (info->node == 1 || info->node == 2) {
+ if (bf_supported && (info->node == 1 || info->node == 2)) {
err = -EPERM;
pr_err("%s:%d no info->creen_base on fb%d!\n",
__func__, __LINE__, info->node);
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/mdp.h b/drivers/video/msm/mdp.h
index 6224dba..40f62b9 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -836,4 +836,5 @@
unsigned long srcp0_addr, unsigned long srcp0_size,
unsigned long srcp1_addr, unsigned long srcp1_size);
+void mdp_vid_quant_set(void);
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 860209f..de254d0 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -766,6 +766,7 @@
int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
void mdp4_iommu_attach(void);
+void mdp4_iommu_detach(void);
int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
struct mdp4_overlay_pipe **ppipe);
void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 34fd399..311599d 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -287,9 +287,7 @@
MDP_OUTP(MDP_BASE + 0xb3014, 0x1000080);
MDP_OUTP(MDP_BASE + 0xb4004, 0x67686970);
} else {
- MDP_OUTP(MDP_BASE + 0xb0070, 0xff0000);
- MDP_OUTP(MDP_BASE + 0xb0074, 0xff0000);
- MDP_OUTP(MDP_BASE + 0xb0078, 0xff0000);
+ mdp_vid_quant_set();
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -670,12 +668,14 @@
case MDP_BGR_565:
case MDP_XRGB_8888:
case MDP_RGB_888:
+ case MDP_YCBCR_H1V1:
+ case MDP_YCRCB_H1V1:
*luma_off = pipe->src_x * pipe->bpp;
break;
default:
- pr_err("Source format %u not supported for x offset adjustment\n",
- pipe->src_format);
+ pr_err("%s: fmt %u not supported for adjustment\n",
+ __func__, pipe->src_format);
break;
}
}
@@ -1552,15 +1552,14 @@
mixer, data, flush_bits);
outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
- if (pull_mode)
+ if (pull_mode) {
outpdw(MDP_BASE + 0x18000, flush_bits);
+ /* wait for vsync on both pull mode interfaces */
+ msleep(20);
+ }
}
if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
- /* wait for vsync on both pull mode interfaces */
- if (pull_mode)
- msleep(20);
-
off = 0x100F0;
ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
data = cfg[MDP4_MIXER2];
@@ -2354,14 +2353,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);
@@ -2981,33 +2982,34 @@
} msm_iommu_ctx_names[] = {
/* Display */
{
- .name = "mdp_vg1",
+ .name = "mdp_port0_cb0",
.domain = DISPLAY_DOMAIN,
},
/* Display */
{
- .name = "mdp_vg2",
+ .name = "mdp_port0_cb1",
.domain = DISPLAY_DOMAIN,
},
/* Display */
{
- .name = "mdp_rgb1",
+ .name = "mdp_port1_cb0",
.domain = DISPLAY_DOMAIN,
},
/* Display */
{
- .name = "mdp_rgb2",
+ .name = "mdp_port1_cb1",
.domain = DISPLAY_DOMAIN,
},
};
+static int iommu_enabled;
+
void mdp4_iommu_attach(void)
{
- static int done;
struct iommu_domain *domain;
int i;
- if (!done) {
+ if (!iommu_enabled) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
int domain_idx;
struct device *ctx = msm_iommu_get_ctx(
@@ -3030,7 +3032,35 @@
continue;
}
}
- done = 1;
+ pr_debug("Attached MDP IOMMU device\n");
+ iommu_enabled = 1;
+ }
+}
+
+void mdp4_iommu_detach(void)
+{
+ struct iommu_domain *domain;
+ int i;
+
+ if (iommu_enabled) {
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+ int domain_idx;
+ struct device *ctx = msm_iommu_get_ctx(
+ msm_iommu_ctx_names[i].name);
+
+ if (!ctx)
+ continue;
+
+ domain_idx = msm_iommu_ctx_names[i].domain;
+
+ domain = msm_get_iommu_domain(domain_idx);
+ if (!domain)
+ continue;
+
+ iommu_detach_device(domain, ctx);
+ }
+ pr_debug("Detached MDP IOMMU device\n");
+ iommu_enabled = 0;
}
}
@@ -3119,10 +3149,12 @@
else
mdp4_overlay_rgb_setup(pipe);
+ if (ctrl->panel_mode & MDP4_PANEL_LCDC)
+ mdp4_overlay_reg_flush(pipe, 1);
+
mdp4_mixer_stage_up(pipe);
if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
- mdp4_overlay_reg_flush(pipe, 1);
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
} else {
#ifdef CONFIG_FB_MSM_MIPI_DSI
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index dd827aa..753ff23 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -113,11 +113,10 @@
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe);
-
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
if (ret == 0)
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -185,8 +184,8 @@
pipe->srcp0_addr = (uint32)(buf + buf_offset);
}
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe);
mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_mixer_stage_up(pipe);
printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
(int)pipe, pipe->pipe_ndx);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 8ab12590..8bed42d 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -197,8 +197,6 @@
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe);
-
mdp4_overlayproc_cfg(pipe);
/*
@@ -275,6 +273,7 @@
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity);
mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
mdp_histogram_ctrl_all(TRUE);
@@ -311,6 +310,7 @@
mdp4_iommu_unmap(dsi_pipe);
}
+ mdp4_iommu_detach();
return ret;
}
@@ -386,6 +386,8 @@
mdp4_overlay_dmap_cfg(mfd, 1);
+ mdp4_overlay_reg_flush(pipe, 1);
+
mdp4_mixer_stage_up(pipe);
mb();
@@ -705,8 +707,8 @@
}
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe);
mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlay_dsi_video_start();
mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
mdp4_iommu_unmap(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index e3917e6..8692b09 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -343,8 +343,8 @@
mdp4_overlay_rgb_setup(pipe);
}
- mdp4_mixer_stage_up(pipe);
mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
dtv_pipe = pipe; /* keep it */
}
@@ -693,8 +693,8 @@
pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
mdp4_overlay_rgb_setup(pipe);
}
- mdp4_mixer_stage_up(pipe);
mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlay_dtv_start();
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
mdp4_iommu_unmap(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 3f90380..72722ef 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -159,8 +159,6 @@
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe);
-
mdp4_overlayproc_cfg(pipe);
/*
@@ -243,6 +241,7 @@
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
#ifdef CONFIG_MSM_BUS_SCALING
mdp_bus_scale_update_request(2);
@@ -291,6 +290,7 @@
mdp_bus_scale_update_request(0);
#endif
+ mdp4_iommu_detach();
return ret;
}
@@ -597,8 +597,8 @@
pipe->srcp0_addr = (uint32)(buf + buf_offset);
}
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe);
mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlay_lcdc_start();
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
mdp4_iommu_unmap(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 2fba83d..342f565 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -273,6 +273,7 @@
if (node) {
list_del(&(node->active_entry));
node->state = IN_BUSY_QUEUE;
+ mfd->writeback_active_cnt++;
}
mutex_unlock(&mfd->writeback_mutex);
@@ -295,6 +296,7 @@
mutex_lock(&mfd->writeback_mutex);
list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
mutex_unlock(&mfd->writeback_mutex);
+ mfd->writeback_active_cnt--;
mutex_unlock(&mfd->unregister_mutex);
wake_up(&mfd->wait_q);
}
@@ -323,6 +325,7 @@
if (node) {
list_del(&(node->active_entry));
node->state = IN_BUSY_QUEUE;
+ mfd->writeback_active_cnt++;
}
mutex_unlock(&mfd->writeback_mutex);
@@ -367,6 +370,7 @@
mutex_lock(&mfd->writeback_mutex);
list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
+ mfd->writeback_active_cnt--;
mutex_unlock(&mfd->writeback_mutex);
wake_up(&mfd->wait_q);
fail_no_blt_addr:
@@ -523,13 +527,26 @@
return rc;
}
+static bool is_writeback_inactive(struct msm_fb_data_type *mfd)
+{
+ bool active;
+ mutex_lock(&mfd->writeback_mutex);
+ active = !mfd->writeback_active_cnt;
+ mutex_unlock(&mfd->writeback_mutex);
+ return active;
+}
int mdp4_writeback_stop(struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
mutex_lock(&mfd->writeback_mutex);
mfd->writeback_state = WB_STOPING;
mutex_unlock(&mfd->writeback_mutex);
+ /* Wait for all pending writebacks to finish */
+ wait_event_interruptible(mfd->wait_q, is_writeback_inactive(mfd));
+
+ /* Wake up dequeue thread in case of no UI update*/
wake_up(&mfd->wait_q);
+
return 0;
}
int mdp4_writeback_init(struct fb_info *info)
@@ -549,8 +566,19 @@
struct list_head *ptr, *next;
struct msmfb_writeback_data_list *temp;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int rc = 0;
+
mutex_lock(&mfd->unregister_mutex);
mutex_lock(&mfd->writeback_mutex);
+
+ if (mfd->writeback_state != WB_STOPING &&
+ mfd->writeback_state != WB_STOP) {
+ pr_err("%s called without stopping\n", __func__);
+ rc = -EPERM;
+ goto terminate_err;
+
+ }
+
if (!list_empty(&mfd->writeback_register_queue)) {
list_for_each_safe(ptr, next,
&mfd->writeback_register_queue) {
@@ -564,7 +592,10 @@
INIT_LIST_HEAD(&mfd->writeback_register_queue);
INIT_LIST_HEAD(&mfd->writeback_busy_queue);
INIT_LIST_HEAD(&mfd->writeback_free_queue);
+
+
+terminate_err:
mutex_unlock(&mfd->writeback_mutex);
mutex_unlock(&mfd->unregister_mutex);
- return 0;
+ return rc;
}
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index baad0a8..7564016 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -178,6 +178,17 @@
clk_rate = mfd->fbi->var.pixclock;
clk_rate = min(clk_rate, mfd->panel_info.clk_max);
+ mipi_dsi_phy_ctrl(1);
+
+ if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
+ target_type = mipi_dsi_pdata->target_type;
+
+ mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
+
+ local_bh_disable();
+ mipi_dsi_clk_enable();
+ local_bh_enable();
+
MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1);
MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0);
@@ -190,17 +201,6 @@
width = mfd->panel_info.xres;
height = mfd->panel_info.yres;
- mipi_dsi_phy_ctrl(1);
-
- if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata)
- target_type = mipi_dsi_pdata->target_type;
-
- mipi_dsi_phy_init(0, &(mfd->panel_info), target_type);
-
- local_bh_disable();
- mipi_dsi_clk_enable();
- local_bh_enable();
-
mipi = &mfd->panel_info.mipi;
if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
dummy_xres = mfd->panel_info.lcdc.xres_pad;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index ce8744b..ff08548 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -48,11 +48,6 @@
#include "mdp.h"
#include "mdp4.h"
-#ifdef CONFIG_FB_MSM_LOGO
-#define INIT_IMAGE_FILE "/initlogo.rle"
-extern int load_565rle_image(char *filename);
-#endif
-
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
#define MSM_FB_NUM 3
#endif
@@ -60,6 +55,7 @@
static unsigned char *fbram;
static unsigned char *fbram_phys;
static int fbram_size;
+static boolean bf_supported;
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
@@ -375,6 +371,9 @@
#ifdef CONFIG_FB_MSM_OVERLAY
mfd->overlay_play_enable = 1;
#endif
+
+ bf_supported = mdp4_overlay_borderfill_supported();
+
rc = msm_fb_register(mfd);
if (rc)
return rc;
@@ -1183,7 +1182,7 @@
* 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)
+ if (!bf_supported || mfd->index == 0)
fix->smem_len = MAX((msm_fb_line_length(mfd->index,
panel_info->xres,
bpp) *
@@ -1302,7 +1301,7 @@
fbram_phys += fbram_offset;
fbram_size -= fbram_offset;
- if (mfd->index == 0)
+ if (!bf_supported || mfd->index == 0)
if (fbram_size < fix->smem_len) {
pr_err("error: no more framebuffer memory!\n");
return -ENOMEM;
@@ -1320,7 +1319,7 @@
fbi->fix.smem_start, mfd->map_buffer->iova[0],
mfd->map_buffer->iova[1]);
}
- if (mfd->index == 0)
+ if (!bf_supported || mfd->index == 0)
memset(fbi->screen_base, 0x0, fix->smem_len);
mfd->op_enable = TRUE;
@@ -1366,7 +1365,9 @@
mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len);
#ifdef CONFIG_FB_MSM_LOGO
- if (!load_565rle_image(INIT_IMAGE_FILE)) ; /* Flip buffer */
+ /* Flip buffer */
+ if (!load_565rle_image(INIT_IMAGE_FILE, bf_supported))
+ ;
#endif
ret = 0;
@@ -1526,9 +1527,10 @@
}
if (!mfd->ref_cnt) {
- if ((info->node != 1) && (info->node != 2)) {
+ if (!bf_supported ||
+ (info->node != 1 && info->node != 2))
mdp_set_dma_pan_info(info, NULL, TRUE);
- } else
+ else
pr_debug("%s:%d no mdp_set_dma_pan_info %d\n",
__func__, __LINE__, info->node);
@@ -1581,7 +1583,8 @@
/*
* If framebuffer is 1 or 2, io pen display is not allowed.
*/
- if (info->node == 1 || info->node == 2) {
+ if (bf_supported &&
+ (info->node == 1 || info->node == 2)) {
pr_err("%s: no pan display for fb%d!",
__func__, info->node);
return -EPERM;
@@ -1761,7 +1764,8 @@
if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
return -EINVAL;
- if ((info->node != 1) && (info->node != 2))
+ if (!bf_supported ||
+ (info->node != 1 && info->node != 2))
if (info->fix.smem_len <
(var->xres_virtual*
var->yres_virtual*
@@ -2619,7 +2623,8 @@
struct mdp_blit_req_list req_list_header;
int count, i, req_list_count;
- if (info->node == 1 || info->node == 2) {
+ if (bf_supported &&
+ (info->node == 1 || info->node == 2)) {
pr_err("%s: no pan display for fb%d.",
__func__, info->node);
return -EPERM;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index b63c022..87753b2 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -184,6 +184,7 @@
u32 use_ov0_blt, ov0_blt_state;
u32 use_ov1_blt, ov1_blt_state;
u32 writeback_state;
+ bool writeback_active_cnt;
int cont_splash_done;
};
@@ -214,4 +215,9 @@
int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd,
struct fb_info *info);
+#ifdef CONFIG_FB_MSM_LOGO
+#define INIT_IMAGE_FILE "/initlogo.rle"
+int load_565rle_image(char *filename, bool bf_supported);
+#endif
+
#endif /* MSM_FB_H */
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 86f282e..ac1ff24 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -469,6 +469,8 @@
u32 ddl_check_reconfig(struct ddl_client_context *ddl);
void ddl_handle_reconfig(u32 res_change, struct ddl_client_context *ddl);
void ddl_fill_dec_desc_buffer(struct ddl_client_context *ddl);
+void ddl_set_vidc_timeout(struct ddl_client_context *ddl);
+
#ifdef DDL_BUF_LOG
void ddl_list_buffers(struct ddl_client_context *ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index 41604b0..50c3696 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -55,6 +55,13 @@
#define DDL_HW_TIMEOUT_IN_MS 1000
#define DDL_STREAMBUF_ALIGN_GUARD_BYTES 0x7FF
+#define DDL_VIDC_1080P_48MHZ (48000000)
+#define DDL_VIDC_1080P_133MHZ (133330000)
+#define DDL_VIDC_1080P_200MHZ (200000000)
+#define DDL_VIDC_1080P_48MHZ_TIMEOUT_VALUE (0xCB8)
+#define DDL_VIDC_1080P_133MHZ_TIMEOUT_VALUE (0x2355)
+#define DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE (0x3500)
+
#define DDL_CONTEXT_MEMORY (1024 * 15 * (VCD_MAX_NO_CLIENT + 1))
#define DDL_ENC_MIN_DPB_BUFFERS 2
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 6d3a05a..b480b42 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -744,11 +744,11 @@
memset(dec_bufs->desc.align_virtual_addr,
0, buf_size.sz_desc);
msm_ion_do_cache_op(
- ddl_context->video_ion_client,
- dec_bufs->desc.alloc_handle,
- dec_bufs->desc.alloc_handle,
- dec_bufs->desc.buffer_size,
- ION_IOC_CLEAN_INV_CACHES);
+ ddl_context->video_ion_client,
+ dec_bufs->desc.alloc_handle,
+ dec_bufs->desc.virtual_base_addr,
+ dec_bufs->desc.buffer_size,
+ ION_IOC_CLEAN_INV_CACHES);
}
}
}
@@ -1061,3 +1061,24 @@
ip_bitstream->desc_buf,
ip_bitstream->desc_size);
}
+
+void ddl_set_vidc_timeout(struct ddl_client_context *ddl)
+{
+ unsigned long core_clk_rate;
+ u32 vidc_time_out = 0;
+ if (ddl->codec_data.decoder.idr_only_decoding) {
+ vidc_time_out = 2 * DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE;
+ } else {
+ res_trk_get_clk_rate(&core_clk_rate);
+ if (core_clk_rate == DDL_VIDC_1080P_48MHZ)
+ vidc_time_out = DDL_VIDC_1080P_48MHZ_TIMEOUT_VALUE;
+ else if (core_clk_rate == DDL_VIDC_1080P_133MHZ)
+ vidc_time_out = DDL_VIDC_1080P_133MHZ_TIMEOUT_VALUE;
+ else
+ vidc_time_out = DDL_VIDC_1080P_200MHZ_TIMEOUT_VALUE;
+ }
+ DDL_MSG_HIGH("%s Video core time out value = 0x%x"
+ __func__, vidc_time_out);
+ vidc_sm_set_video_core_timeout_value(
+ &ddl->shared_mem[ddl->command_channel], vidc_time_out);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index ac81916..878db62 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -243,6 +243,10 @@
#define VIDC_SM_NUM_STUFF_BYTES_CONSUME_ADDR 0X01ac
+#define VIDC_SM_TIMEOUT_VALUE_ADDR 0x0158
+#define VIDC_SM_TIMEOUT_VALUE_BMSK 0xffffffff
+#define VIDC_SM_TIMEOUT_VALUE_SHFT 0
+
#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK 0x40
#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT 6
@@ -862,3 +866,11 @@
*output_buffer_size = DDL_MEM_READ_32(shared_mem,
VIDC_SM_BATCH_OUTPUT_SIZE_ADDR);
}
+
+void vidc_sm_set_video_core_timeout_value(struct ddl_buf_addr *shared_mem,
+ u32 timeout)
+{
+ DDL_MEM_WRITE_32(shared_mem, VIDC_SM_TIMEOUT_VALUE_ADDR,
+ timeout);
+}
+
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 7d9896f..6cd75595 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -191,4 +191,6 @@
u32 output_buffer_size);
void vidc_sm_get_encoder_batch_output_size(struct ddl_buf_addr *shared_mem,
u32 *output_buffer_size);
+void vidc_sm_set_video_core_timeout_value(struct ddl_buf_addr *shared_mem,
+ u32 timeout);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 97c8d0d..d0cf4e8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -977,6 +977,7 @@
DDL_MSG_ERROR("STATE-CRITICAL");
return VCD_ERR_FAIL;
}
+ ddl_set_vidc_timeout(ddl);
ddl_vidc_decode_set_metadata_output(decoder);
if (decoder->dp_buf.no_of_dec_pic_buf <
decoder->client_output_buf_req.actual_count)
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index e71259a..c8365ce 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -382,7 +382,7 @@
return status;
}
-static u32 res_trk_get_clk_rate(unsigned long *phclk_rate)
+u32 res_trk_get_clk_rate(unsigned long *phclk_rate)
{
u32 status = true;
mutex_lock(&resource_context.lock);
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index 99b123c..2ae2512 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -49,4 +49,5 @@
int res_trk_disable_footswitch(void);
void res_trk_release_fw_addr(void);
u32 res_trk_estimate_perf_level(u32 pn_perf_lvl);
+u32 res_trk_get_clk_rate(unsigned long *phclk_rate);
#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6358a0e..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
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/dvb/dmx.h b/include/linux/dvb/dmx.h
index 7f963e6..5abadb6 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -99,16 +99,40 @@
} dmx_filter_t;
+/* Filter flags */
+#define DMX_CHECK_CRC 0x01
+#define DMX_ONESHOT 0x02
+#define DMX_IMMEDIATE_START 0x04
+#define DMX_ENABLE_INDEXING 0x08
+#define DMX_KERNEL_CLIENT 0x8000
+
struct dmx_sct_filter_params
{
__u16 pid;
dmx_filter_t filter;
__u32 timeout;
__u32 flags;
-#define DMX_CHECK_CRC 1
-#define DMX_ONESHOT 2
-#define DMX_IMMEDIATE_START 4
-#define DMX_KERNEL_CLIENT 0x8000
+};
+
+
+/* Indexing: supported video standards */
+enum dmx_indexing_video_standard {
+ DMX_INDEXING_MPEG2,
+ DMX_INDEXING_H264,
+ DMX_INDEXING_VC1
+};
+
+/* Indexing: Supported video profiles */
+enum dmx_indexing_video_profile {
+ DMX_INDEXING_MPEG2_ANY,
+ DMX_INDEXING_H264_ANY,
+ DMX_INDEXING_VC1_ANY
+};
+
+/* Indexing: video configuration parameters */
+struct dmx_indexing_video_params {
+ enum dmx_indexing_video_standard standard;
+ enum dmx_indexing_video_profile profile;
};
@@ -119,6 +143,8 @@
dmx_output_t output;
dmx_pes_type_t pes_type;
__u32 flags;
+
+ struct dmx_indexing_video_params video_params;
};
struct dmx_buffer_status {
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/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index fca9a94..7917d24 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -30,6 +30,13 @@
(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+#define SITAR_VERSION_1P0 0
+#define SITAR_VERSION_1P1 1
+#define SITAR_IS_1P0(ver) \
+ ((ver == SITAR_VERSION_1P0) ? 1 : 0)
+#define SITAR_IS_1P1(ver) \
+ ((ver == SITAR_VERSION_1P1) ? 1 : 0)
+
enum {
TABLA_IRQ_SLIMBUS = 0,
TABLA_IRQ_MBHC_REMOVAL,
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index aa808dc..14f2d43 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -52,6 +52,9 @@
u8 part_config;
u8 cache_ctrl;
u8 rst_n_function;
+ u8 max_packed_writes;
+ u8 max_packed_reads;
+ u8 packed_event_en;
unsigned int part_time; /* Units: ms */
unsigned int sa_timeout; /* Units: 100ns */
unsigned int generic_cmd6_time; /* Units: 10ms */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c9a17de..2489bb5 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -249,7 +249,11 @@
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
MMC_CAP2_HS200_1_2V_SDR)
-#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
+#define MMC_CAP2_DETECT_ON_ERR (1 << 7) /* On I/O err check card removal */
+#define MMC_CAP2_PACKED_RD (1 << 10) /* Allow packed read */
+#define MMC_CAP2_PACKED_WR (1 << 11) /* Allow packed write */
+#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
+ MMC_CAP2_PACKED_WR) /* Allow packed commands */
mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type;
#define MMC_HOST_PW_NOTIFY_NONE 0
@@ -344,12 +348,8 @@
#ifdef CONFIG_MMC_PERF_PROFILING
struct {
- unsigned long rbytes_mmcq; /* Rd bytes MMC queue */
- unsigned long wbytes_mmcq; /* Wr bytes MMC queue */
unsigned long rbytes_drv; /* Rd bytes MMC Host */
unsigned long wbytes_drv; /* Wr bytes MMC Host */
- ktime_t rtime_mmcq; /* Rd time MMC queue */
- ktime_t wtime_mmcq; /* Wr time MMC queue */
ktime_t rtime_drv; /* Rd time MMC Host */
ktime_t wtime_drv; /* Wr time MMC Host */
ktime_t start;
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index e124fbe..06539dff 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -140,6 +140,7 @@
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define R1_APP_CMD (1 << 5) /* sr, c */
+#define R1_EXP_EVENT (1 << 6) /* sr, a */
#define R1_STATE_IDLE 0
#define R1_STATE_READY 1
@@ -275,6 +276,10 @@
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
+#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
+#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
+#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
+#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
@@ -314,6 +319,8 @@
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
+#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
+#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
@@ -426,6 +433,14 @@
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
+
+#define EXT_CSD_PACKED_EVENT_EN (1 << 3)
+
+#define EXT_CSD_PACKED_FAILURE (1 << 3)
+
+#define EXT_CSD_PACKED_GENERIC_ERROR (1 << 0)
+#define EXT_CSD_PACKED_INDEXED_ERROR (1 << 1)
+
/*
* MMC_SWITCH access modes
*/
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 6e96f85..c68457e 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -177,6 +177,9 @@
* @enable_dcd: Enable Data Contact Detection circuit. if not set
* wait for 600msec before proceeding to primary
* detection.
+ * @enable_lpm_on_suspend: Enable the USB core to go into Low
+ * Power Mode, when USB bus is suspended but cable
+ * is connected.
* @bus_scale_table: parameters for bus bandwidth requirements
*/
struct msm_otg_platform_data {
@@ -192,6 +195,7 @@
bool mhl_enable;
bool disable_reset_on_disconnect;
bool enable_dcd;
+ bool enable_lpm_on_dev_suspend;
struct msm_bus_scale_pdata *bus_scale_table;
};
@@ -322,6 +326,11 @@
* voltage regulator(VDDCX).
*/
#define ALLOW_PHY_RETENTION BIT(1)
+ /*
+ * Allow putting the core in Low Power mode, when
+ * USB bus is suspended but cable is connected.
+ */
+#define ALLOW_LPM_ON_DEV_SUSPEND BIT(2)
unsigned long lpm_flags;
#define PHY_PWR_COLLAPSED BIT(0)
#define PHY_RETENTIONED BIT(1)
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index b883ffa..baa6a28 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -28,7 +28,7 @@
MSM_VIDC_MAX_DEVICES,
};
-void *msm_vidc_open(int core_id, int session_type);
+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);
@@ -38,10 +38,12 @@
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/vcap_fmt.h b/include/media/vcap_fmt.h
index 4a62bc3..e69f9b0 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -14,8 +14,8 @@
#ifndef VCAP_FMT_H
#define VCAP_FMT_H
-#define V4L2_BUF_TYPE_INTERLACED_IN_AFE (V4L2_BUF_TYPE_PRIVATE)
-#define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE + 1)
+#define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE)
+#define V4L2_BUF_TYPE_VP_OUT (V4L2_BUF_TYPE_PRIVATE + 1)
enum hal_vcap_mode {
HAL_VCAP_MODE_PRO = 0,
@@ -32,87 +32,7 @@
HAL_VCAP_RGB,
};
-enum hal_vcap_vc_fmt {
- /* 1080p */
- HAL_VCAP_YUV_1080p_60_RH = 0,
- HAL_VCAP_YUV_1080p_60_FL,
- HAL_VCAP_RGB_1080p_60_FL,
- HAL_VCAP_YUV_1080p_24_FL,
- HAL_VCAP_YUV_1080p_24_RH,
- HAL_VCAP_YUV_1080p_24_RW,
- HAL_VCAP_YUV_1080p_60_RW,
- HAL_VCAP_YUV_1080p_50_FL,
- HAL_VCAP_YUV_1080p_50_RH,
- HAL_VCAP_YUV_1080p_25_FL,
- HAL_VCAP_YUV_1080p_25_RH,
- HAL_VCAP_YUV_1080p_30_RH,
- HAL_VCAP_RGB_1080p_25_FL,
- HAL_VCAP_RGB_1080p_25_RH,
- /* 1080i */
- HAL_VCAP_YUV_1080i_60_FL,
- HAL_VCAP_YUV_1080i_60_RH,
- HAL_VCAP_YUV_1080i_60_RW,
- HAL_VCAP_YUV_1080i_50_FL,
- HAL_VCAP_YUV_1080i_50_RH,
- HAL_VCAP_YUV_1080i_50_RW,
- HAL_VCAP_RGB_1080i_50_FL,
- HAL_VCAP_RGB_1080i_50_RH,
- /* 480i */
- HAL_VCAP_YUV_480i_60_RH,
- HAL_VCAP_YUV_480i_60_FL,
- HAL_VCAP_YUV_480i_60_RW,
- HAL_VCAP_YUV_2880_480i_60_FL,
- HAL_VCAP_YUV_2880_480i_60_RH,
- /* 480p */
- HAL_VCAP_YUV_480p_60_RH,
- HAL_VCAP_RGB_480p_60_RH,
- HAL_VCAP_RGB_480p_60_FL,
- HAL_VCAP_YUV_480p_60_FL,
- HAL_VCAP_YUV_480p_60_RW,
- HAL_VCAP_YUV_2880_480p_60_FL,
- HAL_VCAP_YUV_2880_480p_60_RH,
- /* 720p */
- HAL_VCAP_YUV_720p_60_FL,
- HAL_VCAP_RGB_720p_60_FL,
- HAL_VCAP_YUV_720p_60_RW,
- HAL_VCAP_YUV_720p_60_RH,
- HAL_VCAP_YUV_720p_50_FL,
- HAL_VCAP_YUV_720p_50_RW,
- HAL_VCAP_YUV_720p_50_RH,
- /* 576p */
- HAL_VCAP_YUV_576p_50_FL,
- HAL_VCAP_RGB_576p_50_FL,
- HAL_VCAP_YUV_576p_50_RW,
- HAL_VCAP_YUV_576p_50_RH,
- HAL_VCAP_YUV_1440_576p_50_RH,
- HAL_VCAP_YUV_2880_576p_50_FL,
- HAL_VCAP_YUV_2880_576p_50_RH,
- /* 576i */
- HAL_VCAP_YUV_576i_50_FL,
- HAL_VCAP_YUV_576i_50_RW,
- HAL_VCAP_YUV_576i_50_RH,
- /* XGA 1024x768 */
- HAL_VCAP_YUV_XGA_FL,
- HAL_VCAP_YUV_XGA_RH,
- HAL_VCAP_YUV_XGA_RB,
- /* SXGA 1280x1024 */
- HAL_VCAP_YUV_SXGA_FL,
- HAL_VCAP_RGB_SXGA_FL,
- HAL_VCAP_YUV_SXGA_RH,
- HAL_VCAP_YUV_SXGA_RB,
- /* UXGA 1600x1200 */
- HAL_VCAP_YUV_UXGA_FL,
- HAL_VCAP_RGB_UXGA_FL,
- HAL_VCAP_YUV_UXGA_RH,
- HAL_VCAP_YUV_UXGA_RB,
- /* test odd height */
- HAL_VCAP_ODD_HEIGHT,
- /* test odd width RGB only */
- HAL_VCAP_ODD_WIDTH,
-};
-
struct v4l2_format_vc_ext {
- enum hal_vcap_vc_fmt format;
enum hal_vcap_mode mode;
enum hal_vcap_polar h_polar;
enum hal_vcap_polar v_polar;
@@ -136,5 +56,21 @@
uint32_t f2_vsync_h_end;
uint32_t f2_vsync_v_start;
uint32_t f2_vsync_v_end;
+ uint32_t sizeimage;
+ uint32_t bytesperline;
+};
+
+enum vcap_type {
+ VC_TYPE,
+ VP_IN_TYPE,
+ VP_OUT_TYPE,
+};
+
+struct vcap_priv_fmt {
+ enum vcap_type type;
+ union {
+ struct v4l2_format_vc_ext timing;
+ /* Once VP is created there will be another type in here */
+ } u;
};
#endif
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5749293..47b856c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -26,7 +26,7 @@
#define __HCI_CORE_H
#include <net/bluetooth/hci.h>
-
+#include <linux/wakelock.h>
/* HCI upper protocols */
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
@@ -326,7 +326,7 @@
struct work_struct work_add;
struct work_struct work_del;
-
+ struct wake_lock idle_lock;
struct device dev;
atomic_t devref;
diff --git a/include/sound/msm-dai-q6.h b/include/sound/msm-dai-q6.h
index 6328256..042aa6f 100644
--- a/include/sound/msm-dai-q6.h
+++ b/include/sound/msm-dai-q6.h
@@ -21,8 +21,7 @@
#define MSM_MI2S_CAP_RX 0
#define MSM_MI2S_CAP_TX 1
-struct msm_dai_auxpcm_pdata {
- const char *clk;
+struct msm_dai_auxpcm_config {
u16 mode;
u16 sync;
u16 frame;
@@ -36,4 +35,11 @@
u16 rx_sd_lines;
u16 tx_sd_lines;
};
+
+struct msm_dai_auxpcm_pdata {
+ const char *clk;
+ struct msm_dai_auxpcm_config mode_8k;
+ struct msm_dai_auxpcm_config mode_16k;
+};
+
#endif
diff --git a/include/sound/snd_compress_params.h b/include/sound/snd_compress_params.h
index e9f6748..f1e3ea2 100644
--- a/include/sound/snd_compress_params.h
+++ b/include/sound/snd_compress_params.h
@@ -72,6 +72,7 @@
#define SND_AUDIOCODEC_AC3 ((__u32) 0x0000000E)
#define SND_AUDIOCODEC_DTS ((__u32) 0x0000000F)
#define SND_AUDIOCODEC_AC3_PASS_THROUGH ((__u32) 0x00000010)
+#define SND_AUDIOCODEC_WMA_PRO ((__u32) 0x000000011)
/*
* Profile and modes are listed with bit masks. This allows for a
* more compact representation of fields that will not evolve
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/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 25b559b1..02ea082 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -448,6 +448,7 @@
conn->power_save = 1;
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+ wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
switch (type) {
case ACL_LINK:
@@ -521,6 +522,7 @@
/* Make sure no timers are running */
del_timer(&conn->idle_timer);
+ wake_lock_destroy(&conn->idle_lock);
del_timer(&conn->disc_timer);
del_timer(&conn->smp_timer);
__cancel_delayed_work(&conn->rssi_update_work);
@@ -962,9 +964,11 @@
}
timer:
- if (hdev->idle_timeout > 0)
+ if (hdev->idle_timeout > 0) {
mod_timer(&conn->idle_timer,
jiffies + msecs_to_jiffies(hdev->idle_timeout));
+ wake_lock(&conn->idle_lock);
+ }
}
static inline void hci_conn_stop_rssi_timer(struct hci_conn *conn)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 395a95c..9e545f3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2556,6 +2556,9 @@
else
conn->power_save = 0;
}
+ if (conn->mode == HCI_CM_SNIFF)
+ if (wake_lock_active(&conn->idle_lock))
+ wake_unlock(&conn->idle_lock);
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->pend))
hci_sco_setup(conn, ev->status);
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 9041bd7..ff83197 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1775,6 +1775,9 @@
{"HEADPHONE", NULL, "HPHL"},
{"HEADPHONE", NULL, "HPHR"},
+ {"HPHL DAC", NULL, "CP"},
+ {"HPHR DAC", NULL, "CP"},
+
{"HPHL", NULL, "HPHL DAC"},
{"HPHL DAC", "NULL", "DAC4 MUX"},
{"HPHR", NULL, "HPHR DAC"},
@@ -1950,9 +1953,11 @@
static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
{
+ struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
- snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x04);
- snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+ if (SITAR_IS_1P0(sitar_core->version))
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
+
snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
usleep_range(1000, 1000);
snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
@@ -1971,6 +1976,7 @@
enum sitar_bandgap_type choice)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *sitar_core = dev_get_drvdata(codec->dev->parent);
/* TODO lock resources accessed by audio streams and threaded
* interrupt handlers
@@ -2005,7 +2011,9 @@
} else if (choice == SITAR_BANDGAP_OFF) {
snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
- snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0xFF, 0x65);
+ if (SITAR_IS_1P0(sitar_core->version))
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
+ 0xFF, 0x65);
usleep_range(1000, 1000);
} else {
pr_err("%s: Error, Invalid bandgap settings\n", __func__);
@@ -4327,6 +4335,8 @@
}
/* Set voltage level and always use LDO */
+ snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C,
+ (pdata->micbias.ldoh_v << 2));
snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
(k1 << 2));
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 2d5eab2..5d77afd 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);
@@ -3536,6 +3546,10 @@
if (tabla_is_digital_gain_register(reg))
return 1;
+ /* HPH status registers */
+ if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
+ return 1;
+
return 0;
}
@@ -3689,16 +3703,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 +3728,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 +3867,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 +4585,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 +4778,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/apq8064.c b/sound/soc/msm/apq8064.c
index c8ef419..0c72880 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -58,6 +58,8 @@
#define TABLA_MBHC_DEF_BUTTONS 8
#define TABLA_MBHC_DEF_RLOADS 5
+#define JACK_DETECT_GPIO 38
+
/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -97,6 +99,15 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static int apq8064_hs_detect_use_gpio = -1;
+module_param(apq8064_hs_detect_use_gpio, int, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_use_gpio, "Use GPIO for headset detection");
+
+static bool apq8064_hs_detect_use_firmware;
+module_param(apq8064_hs_detect_use_firmware, bool, 0444);
+MODULE_PARM_DESC(apq8064_hs_detect_use_firmware, "Use firmware for headset "
+ "detection");
+
static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -108,7 +119,7 @@
.micbias = TABLA_MICBIAS2,
.mclk_cb_fn = msm_enable_codec_ext_clk,
.mclk_rate = TABLA_EXT_CLK_RATE,
- .gpio = 0, /* MBHC GPIO is not configured */
+ .gpio = 0,
.gpio_irq = 0,
.gpio_level_insert = 1,
};
@@ -1037,10 +1048,10 @@
return ret;
}
-
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
+ uint32_t revision;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -1097,6 +1108,48 @@
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ /* APQ8064 Rev 1.1 CDP and Liquid have mechanical switch */
+ revision = socinfo_get_version();
+ if (apq8064_hs_detect_use_gpio != -1) {
+ if (apq8064_hs_detect_use_gpio == 1)
+ pr_debug("%s: MBHC mechanical is enabled by request\n",
+ __func__);
+ else if (apq8064_hs_detect_use_gpio == 0)
+ pr_debug("%s: MBHC mechanical is disabled by request\n",
+ __func__);
+ else
+ pr_warn("%s: Invalid hs_detect_use_gpio %d\n", __func__,
+ apq8064_hs_detect_use_gpio);
+ } else if (SOCINFO_VERSION_MAJOR(revision) == 0) {
+ pr_warn("%s: Unknown HW revision detected %d.%d\n", __func__,
+ SOCINFO_VERSION_MAJOR(revision),
+ SOCINFO_VERSION_MINOR(revision));
+ } else if ((SOCINFO_VERSION_MAJOR(revision) == 1 &&
+ SOCINFO_VERSION_MINOR(revision) >= 1 &&
+ (machine_is_apq8064_cdp() ||
+ machine_is_apq8064_liquid())) ||
+ SOCINFO_VERSION_MAJOR(revision) > 1) {
+ pr_debug("%s: MBHC mechanical switch available APQ8064 "
+ "detected\n", __func__);
+ apq8064_hs_detect_use_gpio = 1;
+ }
+
+ if (apq8064_hs_detect_use_gpio == 1) {
+ pr_debug("%s: Using MBHC mechanical switch\n", __func__);
+ mbhc_cfg.gpio = JACK_DETECT_GPIO;
+ mbhc_cfg.gpio_irq = gpio_to_irq(JACK_DETECT_GPIO);
+ err = gpio_request(mbhc_cfg.gpio, "MBHC_HS_DETECT");
+ if (err < 0) {
+ pr_err("%s: gpio_request %d failed %d\n", __func__,
+ mbhc_cfg.gpio, err);
+ return err;
+ }
+ gpio_direction_input(JACK_DETECT_GPIO);
+ } else
+ pr_debug("%s: Not using MBHC mechanical switch\n", __func__);
+
+ mbhc_cfg.read_fw_bin = apq8064_hs_detect_use_firmware;
+
err = tabla_hs_detect(codec, &mbhc_cfg);
return err;
@@ -1119,7 +1172,8 @@
},
};
-static struct snd_soc_dsp_link slimbus0_hl_media = {
+/* bi-directional media definition for hostless PCM device */
+static struct snd_soc_dsp_link bidir_hl_media = {
.playback = true,
.capture = true,
.trigger = {
@@ -1128,9 +1182,8 @@
},
};
-static struct snd_soc_dsp_link int_fm_hl_media = {
+static struct snd_soc_dsp_link hdmi_rx_hl = {
.playback = true,
- .capture = true,
.trigger = {
SND_SOC_DSP_TRIGGER_POST,
SND_SOC_DSP_TRIGGER_POST
@@ -1377,7 +1430,7 @@
.name = "MSM8960 Media2",
.stream_name = "MultiMedia2",
.cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
+ .platform_name = "msm-multi-ch-pcm-dsp",
.dynamic = 1,
.dsp_link = &fe_media,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
@@ -1418,7 +1471,7 @@
.cpu_dai_name = "SLIMBUS0_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .dsp_link = &slimbus0_hl_media,
+ .dsp_link = &bidir_hl_media,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* .be_id = do not care */
@@ -1429,7 +1482,7 @@
.cpu_dai_name = "INT_FM_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .dsp_link = &int_fm_hl_media,
+ .dsp_link = &bidir_hl_media,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
/* .be_id = do not care */
@@ -1453,6 +1506,37 @@
.ignore_suspend = 1,
},
{
+ .name = "MSM8960 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .dsp_link = &lpa_fe_media,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &bidir_hl_media,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dsp_link = &hdmi_rx_hl,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .no_codec = 1,
+ .ignore_suspend = 1,
+ },
+ {
.name = "Voice Stub",
.stream_name = "Voice Stub",
.cpu_dai_name = "VOICE_STUB",
@@ -1826,6 +1910,8 @@
}
msm_free_headset_mic_gpios();
platform_device_unregister(msm_snd_device);
+ if (mbhc_cfg.gpio)
+ gpio_free(mbhc_cfg.gpio);
kfree(mbhc_cfg.calibration);
}
module_exit(msm_audio_exit);
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 776337d..68f218f 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -192,6 +192,7 @@
struct msm_audio *prtd = &compr->prtd;
struct asm_aac_cfg aac_cfg;
struct asm_wma_cfg wma_cfg;
+ struct asm_wmapro_cfg wma_pro_cfg;
int ret;
pr_debug("compressed stream prepare\n");
@@ -250,6 +251,26 @@
if (ret < 0)
pr_err("%s: CMD Format block failed\n", __func__);
break;
+ case SND_AUDIOCODEC_WMA_PRO:
+ pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
+ memset(&wma_pro_cfg, 0x0, sizeof(struct asm_wmapro_cfg));
+ wma_pro_cfg.format_tag = compr->info.codec_param.codec.format;
+ wma_pro_cfg.ch_cfg = compr->info.codec_param.codec.ch_in;
+ wma_pro_cfg.sample_rate = runtime->rate;
+ wma_pro_cfg.avg_bytes_per_sec =
+ compr->info.codec_param.codec.bit_rate/8;
+ wma_pro_cfg.block_align = compr->info.codec_param.codec.align;
+ wma_pro_cfg.valid_bits_per_sample =
+ compr->info.codec_param.codec.options.wma.bits_per_sample;
+ wma_pro_cfg.ch_mask =
+ compr->info.codec_param.codec.options.wma.channelmask;
+ wma_pro_cfg.encode_opt =
+ compr->info.codec_param.codec.options.wma.encodeopt;
+ ret = q6asm_media_format_block_wmapro(prtd->audio_client,
+ &wma_pro_cfg);
+ if (ret < 0)
+ pr_err("%s: CMD Format block failed\n", __func__);
+ break;
default:
return -EINVAL;
}
@@ -316,6 +337,7 @@
compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3_PASS_THROUGH;
compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_WMA;
+ compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_WMA_PRO;
/* Add new codecs here */
}
@@ -638,6 +660,10 @@
pr_debug("SND_AUDIOCODEC_WMA\n");
compr->codec = FORMAT_WMA_V9;
break;
+ case SND_AUDIOCODEC_WMA_PRO:
+ pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
+ compr->codec = FORMAT_WMA_V10PRO;
+ break;
default:
pr_debug("FORMAT_LINEAR_PCM\n");
compr->codec = FORMAT_LINEAR_PCM;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 6c44cba..a050771 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -256,21 +256,21 @@
{
.playback = {
.stream_name = "AUXPCM Hostless Playback",
- .rates = SNDRV_PCM_RATE_8000,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 1,
.rate_min = 8000,
- .rate_max = 8000,
+ .rate_max = 16000,
},
.capture = {
.stream_name = "AUXPCM Hostless Capture",
- .rates = SNDRV_PCM_RATE_8000,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 1,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 16000,
},
.ops = &msm_fe_dai_ops,
.name = "AUXPCM_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-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index fb7756c..a62541a 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -532,17 +532,28 @@
}
dai_data->channels = params_channels(params);
- if (params_rate(params) != 8000) {
- dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
+ dai_data->rate = params_rate(params);
+ switch (dai_data->rate) {
+ case 8000:
+ dai_data->port_config.pcm.mode = auxpcm_pdata->mode_8k.mode;
+ dai_data->port_config.pcm.sync = auxpcm_pdata->mode_8k.sync;
+ dai_data->port_config.pcm.frame = auxpcm_pdata->mode_8k.frame;
+ dai_data->port_config.pcm.quant = auxpcm_pdata->mode_8k.quant;
+ dai_data->port_config.pcm.slot = auxpcm_pdata->mode_8k.slot;
+ dai_data->port_config.pcm.data = auxpcm_pdata->mode_8k.data;
+ break;
+ case 16000:
+ dai_data->port_config.pcm.mode = auxpcm_pdata->mode_16k.mode;
+ dai_data->port_config.pcm.sync = auxpcm_pdata->mode_16k.sync;
+ dai_data->port_config.pcm.frame = auxpcm_pdata->mode_16k.frame;
+ dai_data->port_config.pcm.quant = auxpcm_pdata->mode_16k.quant;
+ dai_data->port_config.pcm.slot = auxpcm_pdata->mode_16k.slot;
+ dai_data->port_config.pcm.data = auxpcm_pdata->mode_16k.data;
+ break;
+ default:
+ dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
return -EINVAL;
}
- dai_data->rate = params_rate(params);
- dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
- dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
- dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
- dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
- dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
- dai_data->port_config.pcm.data = auxpcm_pdata->data;
return 0;
}
@@ -702,9 +713,9 @@
{
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc = 0;
-
struct msm_dai_auxpcm_pdata *auxpcm_pdata =
(struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+ unsigned long pcm_clk_rate;
mutex_lock(&aux_pcm_mutex);
@@ -753,8 +764,17 @@
afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
+ if (dai_data->rate == 8000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else if (dai_data->rate == 16000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else {
+ dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+ dai_data->rate);
+ return -EINVAL;
+ }
- rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
+ rc = clk_set_rate(pcm_clk, pcm_clk_rate);
if (rc < 0) {
pr_err("%s: clk_set_rate failed\n", __func__);
return rc;
@@ -1377,11 +1397,11 @@
static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
.playback = {
- .rates = SNDRV_PCM_RATE_8000,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 1,
- .rate_max = 8000,
+ .rate_max = 16000,
.rate_min = 8000,
},
.ops = &msm_dai_q6_auxpcm_ops,
@@ -1391,11 +1411,11 @@
static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
.capture = {
- .rates = SNDRV_PCM_RATE_8000,
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 1,
- .rate_max = 8000,
+ .rate_max = 16000,
.rate_min = 8000,
},
.ops = &msm_dai_q6_auxpcm_ops,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index b31ed65..2762bd6 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -39,6 +39,7 @@
#define SPK_AMP_POS 0x1
#define SPK_AMP_NEG 0x2
#define SPKR_BOOST_GPIO 15
+#define DEFAULT_PMIC_SPK_GAIN 0x0D
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -47,6 +48,7 @@
static int msm8930_spk_control;
static int msm8930_slim_0_rx_ch = 1;
static int msm8930_slim_0_tx_ch = 1;
+static int msm8930_pmic_spk_gain = DEFAULT_PMIC_SPK_GAIN;
static int msm8930_ext_spk_pamp;
static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
@@ -431,6 +433,39 @@
return 0;
}
+static const char *pmic_spk_gain_text[] = {
+ "NEG_6_DB", "NEG_4_DB", "NEG_2_DB", "ZERO_DB", "POS_2_DB", "POS_4_DB",
+ "POS_6_DB", "POS_8_DB", "POS_10_DB", "POS_12_DB", "POS_14_DB",
+ "POS_16_DB", "POS_18_DB", "POS_20_DB", "POS_22_DB", "POS_24_DB"
+};
+
+static const struct soc_enum msm8960_pmic_spk_gain_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pmic_spk_gain_text),
+ pmic_spk_gain_text),
+};
+
+static int msm8930_pmic_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8930_pmic_spk_gain = %d\n", __func__,
+ msm8930_pmic_spk_gain);
+ ucontrol->value.integer.value[0] = msm8930_pmic_spk_gain;
+ return 0;
+}
+
+static int msm8930_pmic_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ msm8930_pmic_spk_gain = ucontrol->value.integer.value[0];
+ ret = pm8xxx_spk_gain(msm8930_pmic_spk_gain);
+ pr_debug("%s: msm8930_pmic_spk_gain = %d"
+ " ucontrol->value.integer.value[0] = %d\n", __func__,
+ msm8930_pmic_spk_gain,
+ (int) ucontrol->value.integer.value[0]);
+ return ret;
+}
+
static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
msm8930_set_spk),
@@ -438,6 +473,8 @@
msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("PMIC SPK Gain", msm8960_pmic_spk_gain_enum[0],
+ msm8930_pmic_gain_get, msm8930_pmic_gain_put),
};
static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
@@ -642,6 +679,9 @@
mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
sitar_hs_detect(codec, &mbhc_cfg);
+ /* Initialize default PMIC speaker gain */
+ pm8xxx_spk_gain(DEFAULT_PMIC_SPK_GAIN);
+
return 0;
}
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index f78f58d..9dfef92 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -41,8 +41,8 @@
#define msm8960_SLIM_0_RX_MAX_CHANNELS 2
#define msm8960_SLIM_0_TX_MAX_CHANNELS 4
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
#define BOTTOM_SPK_AMP_POS 0x1
#define BOTTOM_SPK_AMP_NEG 0x2
@@ -70,9 +70,11 @@
static int msm8960_slim_0_rx_ch = 1;
static int msm8960_slim_0_tx_ch = 1;
-static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
static int msm8960_btsco_ch = 1;
+static int msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
+
static struct clk *codec_clk;
static int clk_users;
@@ -512,6 +514,11 @@
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static const char *auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum msm8960_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
static int msm8960_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -563,19 +570,49 @@
{
switch (ucontrol->value.integer.value[0]) {
case 0:
- msm8960_btsco_rate = BTSCO_RATE_8KHZ;
+ msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
break;
case 1:
- msm8960_btsco_rate = BTSCO_RATE_16KHZ;
+ msm8960_btsco_rate = SAMPLE_RATE_16KHZ;
break;
default:
- msm8960_btsco_rate = BTSCO_RATE_8KHZ;
+ msm8960_btsco_rate = SAMPLE_RATE_8KHZ;
break;
}
pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
return 0;
}
+static int msm8960_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm8960_auxpcm_rate = %d", __func__,
+ msm8960_auxpcm_rate);
+ ucontrol->value.integer.value[0] = msm8960_auxpcm_rate;
+ return 0;
+}
+
+static int msm8960_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
+ break;
+ case 1:
+ msm8960_auxpcm_rate = SAMPLE_RATE_16KHZ;
+ break;
+ default:
+ msm8960_auxpcm_rate = SAMPLE_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: msm8960_auxpcm_rate = %d"
+ "ucontrol->value.integer.value[0] = %d\n", __func__,
+ msm8960_auxpcm_rate,
+ (int)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
static const struct snd_kcontrol_new tabla_msm8960_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm8960_enum[0], msm8960_get_spk,
msm8960_set_spk),
@@ -590,6 +627,11 @@
msm8960_btsco_rate_get, msm8960_btsco_rate_put),
};
+static const struct snd_kcontrol_new auxpcm_rate_mixer_controls[] = {
+ SOC_ENUM_EXT("AUX PCM SampleRate", msm8960_auxpcm_enum[0],
+ msm8960_auxpcm_rate_get, msm8960_auxpcm_rate_put),
+};
+
static int msm8960_btsco_init(struct snd_soc_pcm_runtime *rtd)
{
int err = 0;
@@ -603,6 +645,19 @@
return 0;
}
+static int msm8960_auxpcm_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err = 0;
+ struct snd_soc_platform *platform = rtd->platform;
+
+ err = snd_soc_add_platform_controls(platform,
+ auxpcm_rate_mixer_controls,
+ ARRAY_SIZE(auxpcm_rate_mixer_controls));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
static void *def_tabla_mbhc_cal(void)
{
void *tabla_cal;
@@ -951,8 +1006,8 @@
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* PCM only supports mono output with 8khz sample rate */
- rate->min = rate->max = 8000;
+ rate->min = rate->max = msm8960_auxpcm_rate;
+ /* PCM only supports mono output */
channels->min = channels->max = 1;
return 0;
@@ -1279,6 +1334,7 @@
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-rx",
+ .init = &msm8960_auxpcm_init,
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index fc08febf..09bfd94 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -526,6 +526,7 @@
pr_err("%s: ION create client"
" for AUDIO failed\n",
__func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[cnt].handle = ion_alloc
@@ -536,6 +537,7 @@
pr_err("%s: ION memory"
" allocation for AUDIO failed\n",
__func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -548,6 +550,7 @@
pr_err("%s: ION Get Physical"
" for AUDIO failed, rc = %d\n",
__func__, rc);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -558,6 +561,7 @@
buf[cnt].data)) {
pr_err("%s: ION memory"
" mapping for AUDIO failed\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
memset((void *)buf[cnt].data, 0, bufsz);
@@ -661,6 +665,7 @@
buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
if (IS_ERR_OR_NULL((void *)buf[0].client)) {
pr_err("%s: ION create client for AUDIO failed\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
@@ -668,6 +673,7 @@
if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
@@ -676,12 +682,14 @@
if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
if (IS_ERR_OR_NULL((void *) buf[0].data)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
goto fail;
}
memset((void *)buf[0].data, 0, (bufsz * bufcnt));
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 2284f19..b6ddcc8a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1543,10 +1543,17 @@
trace_snd_soc_dapm_widget_power(w, power);
- if (power)
+ if (power) {
dapm_seq_insert(w, &up_list, true);
- else
+ dev_dbg(w->dapm->dev,
+ "%s(): power up . widget %s\n",
+ __func__, w->name);
+ } else {
dapm_seq_insert(w, &down_list, false);
+ dev_dbg(w->dapm->dev,
+ "%s(): power down . widget %s\n",
+ __func__, w->name);
+ }
w->power = power;
break;