Merge "power: pm8921-charger: report correct online status when disabled"
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 38b2721..9164647 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -5,7 +5,12 @@
Required properties:
- label: A string used as a descriptive name for the device.
- compatible: Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d"
-- reg: Specifies the base address and address size for this device.
+- reg: Specifies the register base address and size. The second interval
+ specifies the shader memory base address and size.
+- reg-names: Resource names used for the physical address of device registers
+ and shader memory. "kgsl_3d0_reg_memory" gives the physical address
+ and length of device registers while "kgsl_3d0_shader_memory" gives
+ physical address and length of device shader memory.
- interrupts: Interrupt mapping for GPU IRQ.
- interrupt-names: String property to describe the name of the interrupt.
- qcom,id: An integer used as an identification number for the device.
@@ -70,8 +75,9 @@
qcom,kgsl-3d0@fdb00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
- reg = <0xfdb00000 0x20000>;
- reg-names = "kgsl_3d0_reg_memory";
+ reg = <0xfdb00000 0x10000
+ 0xfdb20000 0x10000>;
+ reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_shader_memory";
interrupts = <0 33 0>;
interrupt-names = "kgsl_3d0_irq";
qcom,id = <0>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
index 33d5cc1..e458ea0 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-current.txt
@@ -11,6 +11,7 @@
- compatible : should be "qcom,qpnp-iadc" for Current ADC driver.
- reg : offset and length of the PMIC Aribter register map.
- interrupts : The USR bank peripheral IADC interrupt.
+- interrupt-names : Should contain "eoc-int-en-set".
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
- qcom,rsense : Internal rsense resistor used for current measurements.
@@ -84,6 +85,7 @@
compatible = "qcom,qpnp-iadc";
reg = <0x3200 0x100>;
interrupts = <0 0x36 0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,rsense = <1500>;
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index d7d3ec2..e23605c 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -11,6 +11,7 @@
- compatible : should be "qcom,qpnp-vadc" for Voltage ADC driver.
- reg : offset and length of the PMIC Aribter register map.
- interrupts : The USR bank peripheral VADC interrupt.
+- interrupt-names : Should contain "eoc-int-en-set".
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
@@ -82,6 +83,7 @@
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 89d4df8..6538db5 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -487,6 +487,7 @@
compatible = "qcom,qpnp-vadc";
reg = <0x3100 0x100>;
interrupts = <0x0 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
@@ -698,12 +699,24 @@
qcom,hw-settle-time = <0>;
qcom,fast-avg-setup = <0>;
};
+
+ chan@185 {
+ label = "usb_id";
+ qcom,channel-num = <185>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
};
iadc@3600 {
compatible = "qcom,qpnp-iadc";
reg = <0x3600 0x100>;
interrupts = <0x0 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,rsense = <1500>;
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 403a5cc..6623568 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -13,8 +13,9 @@
qcom,kgsl-3d0@fdb00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
- reg = <0xfdb00000 0x20000>;
- reg-names = "kgsl_3d0_reg_memory";
+ reg = <0xfdb00000 0x10000
+ 0xfdb20000 0x10000>;
+ reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory";
interrupts = <0 33 0>;
interrupt-names = "kgsl_3d0_irq";
qcom,id = <0>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 19b8828..0fd5c97 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -849,6 +849,16 @@
};
};
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+ };
+
qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
};
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f468fe0..e4b60ff 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -355,6 +355,8 @@
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 973eef9..0042406 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -357,6 +357,8 @@
CONFIG_MMC_BLOCK_MINORS=32
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 1a8bbfc..d47870e 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -21,6 +21,7 @@
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 887fcbf..42e250d 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -67,6 +67,7 @@
select MSM_PM2 if PM
select HOLES_IN_ZONE if SPARSEMEM
select MSM_MODEM_RESTART
+ select ARM_HAS_SG_CHAIN
config ARCH_QSD8X50
bool "QSD8X50"
@@ -177,6 +178,7 @@
select ARM_HAS_SG_CHAIN
select MSM_KRAIT_WFE_FIXUP
select MSM_ULTRASOUND_A
+ select MSM_IOMMU_GPU_SYNC
select GENERIC_TIME_VSYSCALL
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -213,6 +215,7 @@
select HOLES_IN_ZONE if SPARSEMEM
select ARM_HAS_SG_CHAIN
select MSM_KRAIT_WFE_FIXUP
+ select MSM_IOMMU_GPU_SYNC
select GENERIC_TIME_VSYSCALL
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -245,6 +248,7 @@
select ARM_HAS_SG_CHAIN
select MSM_KRAIT_WFE_FIXUP
select MSM_ULTRASOUND_A
+ select MSM_IOMMU_GPU_SYNC
select GENERIC_TIME_VSYSCALL
select USE_USER_ACCESSIBLE_TIMERS
select ARM_USE_USER_ACCESSIBLE_TIMERS
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 5ebb010..38ac83e 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -182,6 +182,12 @@
{
.name = KGSL_3D0_REG_MEMORY,
.start = 0x04300000, /* GFX3D address */
+ .end = 0x0430ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = KGSL_3D0_SHADER_MEMORY,
+ .start = 0x04310000, /* Shader Mem Address */
.end = 0x0431ffff,
.flags = IORESOURCE_MEM,
},
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 578c665..3eb7d8a 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -88,6 +88,12 @@
{
.name = KGSL_3D0_REG_MEMORY,
.start = 0x04300000, /* GFX3D address */
+ .end = 0x0430ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = KGSL_3D0_SHADER_MEMORY,
+ .start = 0x04310000,
.end = 0x0431ffff,
.flags = IORESOURCE_MEM,
},
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 9efc60a..b9b3a1f 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1676,7 +1676,7 @@
.reg_base_addr = MSM_SAW0_BASE,
.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464,
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
@@ -1691,7 +1691,7 @@
.reg_base_addr = MSM_SAW1_BASE,
.reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x1F,
#if defined(CONFIG_MSM_AVS_HW)
- .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x50589464,
+ .reg_init_values[MSM_SPM_REG_SAW2_AVS_CTL] = 0x58589464,
.reg_init_values[MSM_SPM_REG_SAW2_AVS_HYSTERESIS] = 0x00020000,
#endif
.reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
@@ -2890,8 +2890,18 @@
kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
/* 8960PRO nominal clock rate is 320Mhz */
kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 320000000;
+
+ /*
+ * If this an A320 GPU device (MSM8960AB), then
+ * switch the resource table to 8960AB, to reflect the
+ * separate register and shader memory mapping used in A320.
+ */
+
+ msm_kgsl_3d0.num_resources = kgsl_num_resources_8960ab;
+ msm_kgsl_3d0.resource = kgsl_3d0_resources_8960ab;
} else {
kgsl_3d0_pdata->iommu_count = 1;
+
if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 39060ad..1022616 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -621,7 +621,7 @@
#define USB_BAM_PHY_BASE 0x12502000
#define HSIC_BAM_PHY_BASE 0x12542000
#define A2_BAM_PHY_BASE 0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][4][2] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][8][2] = {
[HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 11,
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 023ce86..a25290f 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -46,6 +46,7 @@
#include <mach/usbdiag.h>
#include <mach/msm_memtypes.h>
#include <mach/msm_serial_hs.h>
+#include <mach/msm_serial_pdata.h>
#include <mach/pmic.h>
#include <mach/socinfo.h>
#include <mach/vreg.h>
@@ -82,6 +83,10 @@
.id = -1,
};
+static struct msm_serial_platform_data msm_8625_uart1_pdata = {
+ .userid = 10,
+};
+
static struct msm_gpio qup_i2c_gpios_io[] = {
{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
"qup_scl" },
@@ -994,6 +999,7 @@
if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()
|| machine_is_msm8625_evt()
|| machine_is_qrd_skud_prime()) {
+ msm8625_device_uart1.dev.platform_data = &msm_8625_uart1_pdata;
platform_add_devices(msm8625_evb_devices,
ARRAY_SIZE(msm8625_evb_devices));
platform_add_devices(qrd3_devices,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index a4d7e61..c394982 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6319,12 +6319,12 @@
*/
/*
* Initialize MM AHB registers: Enable the FPB clock and disable HW
- * gating on 8627, 8960 and 8930ab for all clocks. Also set VFE_AHB's
+ * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
* FORCE_CORE_ON bit to prevent its memory from being collapsed when
* the clock is halted. The sleep and wake-up delays are set to safe
* values.
*/
- if (cpu_is_msm8627() || cpu_is_msm8960ab() || cpu_is_msm8930ab()) {
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x000007F9, AHB_EN2_REG);
} else {
@@ -6342,7 +6342,7 @@
/* Initialize MM AXI registers: Enable HW gating for all clocks that
* support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
* delays to safe values. */
- if (cpu_is_msm8960ab() || (cpu_is_msm8960() &&
+ if ((cpu_is_msm8960() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
cpu_is_msm8627() || cpu_is_msm8930ab()) {
rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
@@ -6365,8 +6365,6 @@
if (cpu_is_msm8627() || cpu_is_msm8930ab())
rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
- else if (cpu_is_msm8960ab())
- rmwreg(0x000001C6, SAXI_EN_REG, 0x00001DF6);
else
rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index c0a553f..68bffa5 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5120,6 +5120,7 @@
CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, "msm_dwc3"),
CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_dwc3"),
+ CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_usb3"),
CLK_LOOKUP("sleep_clk", gcc_usb30_sleep_clk.c, "msm_dwc3"),
CLK_LOOKUP("sleep_a_clk", gcc_usb2a_phy_sleep_clk.c, "msm_dwc3"),
CLK_LOOKUP("sleep_b_clk", gcc_usb2b_phy_sleep_clk.c, "msm_dwc3"),
@@ -5345,10 +5346,14 @@
CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c,
+ "msm-dai-q6-mi2s.3"),
+ CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
+ "msm-dai-q6-mi2s.3"),
+ CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
+ "msm-dai-q6-mi2s.3"),
+ CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
+ "msm-dai-q6-mi2s.3"),
CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
"msm-dai-q6.4106"),
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index a839fcf..c59461a 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -3246,7 +3246,30 @@
};
#endif
-static struct resource kgsl_3d0_resources[] = {
+struct resource kgsl_3d0_resources_8960ab[] = {
+ {
+ .name = KGSL_3D0_REG_MEMORY,
+ .start = 0x04300000, /* GFX3D address */
+ .end = 0x0430ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = KGSL_3D0_SHADER_MEMORY,
+ .start = 0x04310000, /* Shader Mem Address (8960AB) */
+ .end = 0x0431ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = KGSL_3D0_IRQ,
+ .start = GFX3D_IRQ,
+ .end = GFX3D_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+int kgsl_num_resources_8960ab = ARRAY_SIZE(kgsl_3d0_resources_8960ab);
+
+static struct resource kgsl_3d0_resources_8960[] = {
{
.name = KGSL_3D0_REG_MEMORY,
.start = 0x04300000, /* GFX3D address */
@@ -3330,8 +3353,8 @@
struct platform_device msm_kgsl_3d0 = {
.name = "kgsl-3d0",
.id = 0,
- .num_resources = ARRAY_SIZE(kgsl_3d0_resources),
- .resource = kgsl_3d0_resources,
+ .num_resources = ARRAY_SIZE(kgsl_3d0_resources_8960),
+ .resource = kgsl_3d0_resources_8960,
.dev = {
.platform_data = &kgsl_3d0_pdata,
},
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index b4ef76d2..8fc5020 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -501,6 +501,18 @@
.exit_sleep3 = msm_gic_irq_exit_sleep3,
};
+void msm_clk_dump_debug_info(void)
+{
+ pr_info("%s: GLBL_CLK_ENA: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x0));
+ pr_info("%s: GLBL_CLK_STATE: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x4));
+ pr_info("%s: GRP_NS_REG: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x84));
+ pr_info("%s: CLK_HALT_STATEB: 0x%08X\n", __func__,
+ readl_relaxed(MSM_CLK_CTL_BASE + 0x10C));
+}
+
void __init msm_pm_register_irqs(void)
{
if (cpu_is_msm8625())
@@ -2135,6 +2147,7 @@
static int msm7627a_panic_handler(struct notifier_block *this,
unsigned long event, void *ptr)
{
+ msm_clk_dump_debug_info();
flush_cache_all();
outer_flush_all();
return NOTIFY_DONE;
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index bd5a20f..bd9ea49 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -327,6 +327,9 @@
extern struct platform_device msm_kgsl_2d0;
extern struct platform_device msm_kgsl_2d1;
+extern struct resource kgsl_3d0_resources_8960ab[];
+extern int kgsl_num_resources_8960ab;
+
extern struct platform_device msm_mipi_dsi1_device;
extern struct platform_device mipi_dsi_device;
extern struct platform_device msm_lcdc_device;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index cbe2040..8b5c70f 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -599,6 +599,13 @@
void msm_map_msm8910_io(void);
void msm8910_init_irq(void);
+/* Dump debug info (states, rate, etc) of clocks */
+#if defined(CONFIG_ARCH_MSM7X27)
+void msm_clk_dump_debug_info(void);
+#else
+static inline void msm_clk_dump_debug_info(void) {}
+#endif
+
struct mmc_platform_data;
int msm_add_sdcc(unsigned int controller,
struct mmc_platform_data *plat);
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 57b4bd3..ea3fb64 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -147,6 +147,59 @@
irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+enum {
+ PROC_APPS,
+ PROC_GPU,
+ PROC_MAX
+};
+
+/* Expose structure to allow kgsl iommu driver to use the same structure to
+ * communicate to GPU the addresses of the flag and turn variables.
+ */
+struct remote_iommu_petersons_spinlock {
+ uint32_t flag[PROC_MAX];
+ uint32_t turn;
+};
+
+#ifdef CONFIG_MSM_IOMMU
+void *msm_iommu_lock_initialize(void);
+void msm_iommu_mutex_lock(void);
+void msm_iommu_mutex_unlock(void);
+#else
+static inline void *msm_iommu_lock_initialize(void)
+{
+ return NULL;
+}
+static inline void msm_iommu_mutex_lock(void) { }
+static inline void msm_iommu_mutex_unlock(void) { }
+#endif
+
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+void msm_iommu_remote_p0_spin_lock(void);
+void msm_iommu_remote_p0_spin_unlock(void);
+
+#define msm_iommu_remote_lock_init() _msm_iommu_remote_spin_lock_init()
+#define msm_iommu_remote_spin_lock() msm_iommu_remote_p0_spin_lock()
+#define msm_iommu_remote_spin_unlock() msm_iommu_remote_p0_spin_unlock()
+#else
+#define msm_iommu_remote_lock_init()
+#define msm_iommu_remote_spin_lock()
+#define msm_iommu_remote_spin_unlock()
+#endif
+
+/* Allows kgsl iommu driver to acquire lock */
+#define msm_iommu_lock() \
+ do { \
+ msm_iommu_mutex_lock(); \
+ msm_iommu_remote_spin_lock(); \
+ } while (0)
+
+#define msm_iommu_unlock() \
+ do { \
+ msm_iommu_remote_spin_unlock(); \
+ msm_iommu_mutex_unlock(); \
+ } while (0)
+
#ifdef CONFIG_MSM_IOMMU
/*
* Look up an IOMMU context device by its context name. NULL if none found.
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 7aff770..8d96192 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -19,8 +19,6 @@
#define MSM_IRQ_BIT(irq) (1 << ((irq) & 31))
-#include "irqs-8625.h"
-
#if defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064) || \
defined(CONFIG_ARCH_MSM8930)
@@ -78,7 +76,8 @@
#elif defined(CONFIG_ARCH_MSM8X60)
#include "irqs-8x60.h"
#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X25) \
- || defined(CONFIG_ARCH_MSM7X27)
+ || defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM8625)
+#include "irqs-8625.h"
#include "irqs-7xxx.h"
#define NR_GPIO_IRQS 133
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index a51cc46..f07a9e8 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -27,6 +27,7 @@
(val*1000*1000U)
#define KGSL_3D0_REG_MEMORY "kgsl_3d0_reg_memory"
+#define KGSL_3D0_SHADER_MEMORY "kgsl_3d0_shader_memory"
#define KGSL_3D0_IRQ "kgsl_3d0_irq"
#define KGSL_2D0_REG_MEMORY "kgsl_2d0_reg_memory"
#define KGSL_2D0_IRQ "kgsl_2d0_irq"
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 84a7dc0..ab0e72f 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -29,6 +29,7 @@
unsigned int len;
int ahb;
const char *fabclk[NUM_CTX];
+ const char *iface_clk;
unsigned int offset;
unsigned int haltid;
unsigned int rpm_enabled;
diff --git a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
index 4153cb2..40bdc9d 100644
--- a/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
+++ b/arch/arm/mach-msm/include/mach/msm_serial_pdata.h
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef __ASM_ARCH_MSM_SERIAL_HS_H
-#define __ASM_ARCH_MSM_SERIAL_HS_H
+#ifndef __ASM_ARCH_MSM_SERIAL_H
+#define __ASM_ARCH_MSM_SERIAL_H
#include <linux/serial_core.h>
@@ -22,6 +22,7 @@
/* bool: inject char into rx tty on wakeup */
unsigned char inject_rx_on_wakeup;
char rx_to_inject;
+ int userid;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 5333c2e..a000c3e 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -160,6 +160,8 @@
SPS_O_AUTO_ENABLE = 0x20000000,
/* DISABLE endpoint synchronization for config/enable/disable */
SPS_O_NO_EP_SYNC = 0x40000000,
+ /* Allow partial polling duing IRQ mode */
+ SPS_O_HYBRID = 0x80000000,
};
/**
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
index 4d0f63a..d9320c3 100644
--- a/arch/arm/mach-msm/include/mach/usbdiag.h
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -21,6 +21,8 @@
#ifndef _DRIVERS_USB_DIAG_H_
#define _DRIVERS_USB_DIAG_H_
+#include <linux/err.h>
+
#define DIAG_LEGACY "diag"
#define DIAG_MDM "diag_mdm"
#define DIAG_QSC "diag_qsc"
@@ -46,6 +48,7 @@
void *priv_usb;
};
+#ifdef CONFIG_USB_G_ANDROID
struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
void (*notify)(void *, unsigned, struct diag_request *));
void usb_diag_close(struct usb_diag_ch *ch);
@@ -53,7 +56,32 @@
void usb_diag_free_req(struct usb_diag_ch *ch);
int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
-
-int diag_read_from_cb(unsigned char * , int);
-
+#else
+static inline struct usb_diag_ch *usb_diag_open(const char *name, void *priv,
+ void (*notify)(void *, unsigned, struct diag_request *))
+{
+ return ERR_PTR(-ENODEV);
+}
+static inline void usb_diag_close(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read)
+{
+ return -ENODEV;
+}
+static inline void usb_diag_free_req(struct usb_diag_ch *ch)
+{
+}
+static inline
+int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+ return -ENODEV;
+}
+static inline
+int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_USB_G_ANDROID */
#endif /* _DRIVERS_USB_DIAG_H_ */
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index 5c20a4e..dbfa5ec 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -642,6 +642,8 @@
.qport = qports_crypto_c0,
.mas_hw_id = MAS_CRYPTO_CORE0,
.hw_sel = MSM_BUS_NOC,
+ .prio_rd = 1,
+ .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_CRYPTO_CORE1,
@@ -653,6 +655,8 @@
.qport = qports_crypto_c1,
.mas_hw_id = MAS_CRYPTO_CORE1,
.hw_sel = MSM_BUS_NOC,
+ .prio_rd = 1,
+ .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_LPASS_PROC,
@@ -722,6 +726,7 @@
.prio_rd = 2,
.prio_wr = 2,
.hw_sel = MSM_BUS_NOC,
+ .iface_clk_node = "msm_usb3",
},
{
.id = MSM_BUS_SLAVE_AMPSS,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 12d6862..2c6efb8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -71,6 +71,7 @@
int hw_sel;
const char *slaveclk[NUM_CTX];
const char *memclk[NUM_CTX];
+ const char *iface_clk_node;
unsigned int buswidth;
unsigned int ws;
unsigned int mode;
@@ -117,6 +118,7 @@
int commit_index;
struct nodeclk nodeclk[NUM_CTX];
struct nodeclk memclk[NUM_CTX];
+ struct nodeclk iface_clk;
void *hw_data;
};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 7169440..b6870c6 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -175,6 +175,15 @@
}
}
+ if (info->node_info->iface_clk_node) {
+ info->iface_clk.clk = clk_get_sys(info->node_info->
+ iface_clk_node, "iface_clk");
+ if (IS_ERR(info->iface_clk.clk)) {
+ MSM_BUS_ERR("ERR: Couldn't get clk %s\n",
+ info->node_info->iface_clk_node);
+ }
+ }
+
ret = info->node_info->gateway ?
msm_bus_fabric_add_fab(fabric, info) :
msm_bus_fabric_add_node(fabric, info);
@@ -187,6 +196,12 @@
if (fabric->fabdev.hw_algo.node_init == NULL)
continue;
+ if (info->iface_clk.clk) {
+ MSM_BUS_DBG("Enabled iface clock for node init: %d\n",
+ info->node_info->priv_id);
+ clk_prepare_enable(info->iface_clk.clk);
+ }
+
for (j = 0; j < NUM_CTX; j++)
clk_prepare_enable(fabric->info.nodeclk[j].clk);
@@ -198,6 +213,14 @@
for (j = 0; j < NUM_CTX; j++)
clk_disable_unprepare(fabric->info.nodeclk[j].clk);
+
+ if (info->iface_clk.clk) {
+ MSM_BUS_DBG("Disable iface_clk after node init: %d\n",
+ info->node_info->priv_id);
+ clk_disable_unprepare(info->iface_clk.clk);
+ }
+
+
}
MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
@@ -355,14 +378,35 @@
return;
}
+ /* Enable clocks before accessing QoS registers */
for (i = 0; i < NUM_CTX; i++)
clk_prepare_enable(fabric->info.nodeclk[i].clk);
+ if (info->iface_clk.clk)
+ clk_prepare_enable(info->iface_clk.clk);
+
+ if (hop->iface_clk.clk)
+ clk_prepare_enable(hop->iface_clk.clk);
+
fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
master_tiers, add_bw);
+
+ /* Disable clocks after accessing QoS registers */
for (i = 0; i < NUM_CTX; i++)
clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+ if (info->iface_clk.clk) {
+ MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
+ info->node_info->priv_id);
+ clk_disable_unprepare(info->iface_clk.clk);
+ }
+
+ if (hop->iface_clk.clk) {
+ MSM_BUS_DBG("Commented Will disable clock for hop: %d\n",
+ hop->node_info->priv_id);
+ clk_disable_unprepare(hop->iface_clk.clk);
+ }
+
fabric->arb_dirty = true;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 66d6bda..08a6de6 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -20,10 +20,10 @@
obj-$(CONFIG_MSM_QDSP6_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6_CODECS) += rtac.o q6audio_v1.o q6audio_v1_aio.o
-obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
-obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
obj-$(CONFIG_MSM_ULTRASOUND_A) += ultrasound/version_a/
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index a24b9ec..cad845f 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -730,12 +730,19 @@
static int deregister_memory(void)
{
+ int i;
+
if (atomic64_read(&acdb_data.mem_len)) {
mutex_lock(&acdb_data.acdb_mutex);
+ atomic64_set(&acdb_data.mem_len, 0);
atomic_set(&acdb_data.vocstrm_total_cal_size, 0);
atomic_set(&acdb_data.vocproc_total_cal_size, 0);
atomic_set(&acdb_data.vocvol_total_cal_size, 0);
- atomic64_set(&acdb_data.mem_len, 0);
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ kfree(acdb_data.col_data[i]);
+ acdb_data.col_data[i] = NULL;
+ }
ion_unmap_kernel(acdb_data.ion_client, acdb_data.ion_handle);
ion_free(acdb_data.ion_client, acdb_data.ion_handle);
ion_client_destroy(acdb_data.ion_client);
@@ -747,12 +754,19 @@
static int register_memory(void)
{
int result;
+ int i;
unsigned long paddr;
void *kvptr;
unsigned long kvaddr;
unsigned long mem_len;
mutex_lock(&acdb_data.acdb_mutex);
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
+ atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
+ (uint32_t)acdb_data.col_data[i]);
+ }
+
acdb_data.ion_client =
msm_ion_client_create(UINT_MAX, "audio_acdb_client");
if (IS_ERR_OR_NULL(acdb_data.ion_client)) {
@@ -1029,7 +1043,6 @@
static int acdb_release(struct inode *inode, struct file *f)
{
- int i;
s32 result = 0;
atomic_dec(&usage_count);
@@ -1038,11 +1051,6 @@
pr_debug("%s: ref count %d!\n", __func__,
atomic_read(&usage_count));
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- kfree(acdb_data.col_data[i]);
- acdb_data.col_data[i] = NULL;
- }
-
if (atomic_read(&usage_count) >= 1)
result = -EBUSY;
else
@@ -1067,16 +1075,10 @@
static int __init acdb_init(void)
{
- int i;
memset(&acdb_data, 0, sizeof(acdb_data));
mutex_init(&acdb_data.acdb_mutex);
atomic_set(&usage_count, 0);
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
- atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
- (uint32_t)acdb_data.col_data[i]);
- }
return misc_register(&acdb_misc);
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
new file mode 100644
index 0000000..2889c14
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -0,0 +1,234 @@
+/* amr-wbplus audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/msm_audio_amrwbplus.h>
+#include "audio_utils_aio.h"
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations audio_amrwbplus_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+static void config_debug_fs(struct q6audio_aio *audio)
+{
+ if (audio != NULL) {
+ char name[sizeof("msm_amrwbplus_") + 5];
+ snprintf(name, sizeof(name), "msm_amrwbplus_%04x",
+ audio->ac->session);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)audio,
+ &audio_amrwbplus_debug_fops);
+ if (IS_ERR(audio->dentry))
+ pr_debug("debugfs_create_file failed\n");
+ }
+}
+#else
+static void config_debug_fs(struct q6audio_aio *)
+{
+}
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct asm_amrwbplus_cfg q6_amrwbplus_cfg;
+ struct msm_audio_amrwbplus_config_v2 *amrwbplus_drv_config;
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_err("%s[%p]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("pcm output block config failed\n");
+ break;
+ }
+ }
+ amrwbplus_drv_config =
+ (struct msm_audio_amrwbplus_config_v2 *)audio->codec_cfg;
+
+ q6_amrwbplus_cfg.size_bytes =
+ amrwbplus_drv_config->size_bytes;
+ q6_amrwbplus_cfg.version =
+ amrwbplus_drv_config->version;
+ q6_amrwbplus_cfg.num_channels =
+ amrwbplus_drv_config->num_channels;
+ q6_amrwbplus_cfg.amr_band_mode =
+ amrwbplus_drv_config->amr_band_mode;
+ q6_amrwbplus_cfg.amr_dtx_mode =
+ amrwbplus_drv_config->amr_dtx_mode;
+ q6_amrwbplus_cfg.amr_frame_fmt =
+ amrwbplus_drv_config->amr_frame_fmt;
+ q6_amrwbplus_cfg.amr_lsf_idx =
+ amrwbplus_drv_config->amr_lsf_idx;
+
+ rc = q6asm_media_format_block_amrwbplus(audio->ac,
+ &q6_amrwbplus_cfg);
+ if (rc < 0) {
+ pr_err("q6asm_media_format_block_amrwb+ failed...\n");
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("Audio Start procedure failed rc=%d\n", rc);
+ break;
+ }
+ pr_debug("%s:AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ case AUDIO_GET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("wb+ config get copy_to_user failed");
+ break;
+ }
+ } else {
+ pr_err("wb+ config v2 invalid parameters..");
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_AMRWBPLUS_CONFIG_V2: {
+ if ((audio) && (arg) && (audio->codec_cfg)) {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_amrwbplus_config_v2))) {
+ rc = -EFAULT;
+ pr_err("wb+ config set copy_to_user_failed");
+ break;
+ }
+ } else {
+ pr_err("wb+ config invalid parameters..");
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("%s[%p]: Calling utils ioctl\n", __func__, audio);
+ rc = audio->codec_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (audio == NULL) {
+ pr_err("kzalloc failed for amrwb+ decode driver\n");
+ return -ENOMEM;
+ }
+ audio->codec_cfg =
+ kzalloc(sizeof(struct msm_audio_amrwbplus_config_v2), GFP_KERNEL);
+ if (audio->codec_cfg == NULL) {
+ pr_err("%s:failed kzalloc for amrwb+ config structure",
+ __func__);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+
+ audio->ac =
+ q6asm_audio_client_alloc((app_cb) q6_audio_cb, (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("Could not allocate memory for audio client\n");
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("amrwbplus NT mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_AMR_WB_PLUS);
+ if (rc < 0) {
+ pr_err("wb+ T mode Open failed rc=%d\n", rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("audio_amrwbplus Not supported mode\n");
+ rc = -EACCES;
+ goto fail;
+ }
+ rc = audio_aio_open(audio, file);
+
+ config_debug_fs(audio);
+ pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_amrwbplus_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+struct miscdevice audio_amrwbplus_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_amrwbplus",
+ .fops = &audio_amrwbplus_fops,
+};
+
+static int __init audio_amrwbplus_init(void)
+{
+ return misc_register(&audio_amrwbplus_misc);
+}
+
+device_initcall(audio_amrwbplus_init);
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 3af066d..212ad77 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1012,6 +1012,19 @@
};
#endif /* CONFIG_LOCAL_TIMERS */
+#ifdef CONFIG_ARCH_MSM8625
+static void fixup_msm8625_timer(void)
+{
+ struct msm_clock *dgt = &msm_clocks[MSM_CLOCK_DGT];
+ struct msm_clock *gpt = &msm_clocks[MSM_CLOCK_GPT];
+ dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
+ gpt->irq = MSM8625_INT_GP_TIMER_EXP;
+ global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+}
+#else
+static inline void fixup_msm8625_timer(void) { };
+#endif
+
static void __init msm_timer_init(void)
{
int i;
@@ -1032,11 +1045,8 @@
gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT
| MSM_CLOCK_FLAGS_ODD_MATCH_WRITE
| MSM_CLOCK_FLAGS_DELAYED_WRITE_POST;
- if (cpu_is_msm8625()) {
- dgt->irq = MSM8625_INT_DEBUG_TIMER_EXP;
- gpt->irq = MSM8625_INT_GP_TIMER_EXP;
- global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
- }
+ if (cpu_is_msm8625())
+ fixup_msm8625_timer();
} else if (cpu_is_qsd8x50()) {
dgt->freq = 4800000;
gpt->regbase = MSM_TMR_BASE;
diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
index 5fd98ea..5751d28 100644
--- a/block/Kconfig.iosched
+++ b/block/Kconfig.iosched
@@ -15,7 +15,7 @@
config IOSCHED_TEST
tristate "Test I/O scheduler"
depends on DEBUG_FS
- default m
+ default y
---help---
The test I/O scheduler is a duplicate of the noop scheduler with
addition of test utlity.
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 8994d6d..93b8ef1 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1059,7 +1059,7 @@
dpm_wait_for_children(dev, async);
if (async_error)
- return 0;
+ goto Complete;
/*
* If a device configured to wake up the system from sleep states
@@ -1072,7 +1072,7 @@
if (pm_wakeup_pending()) {
async_error = -EBUSY;
- return 0;
+ goto Complete;
}
data.dev = dev;
@@ -1141,6 +1141,7 @@
del_timer_sync(&timer);
destroy_timer_on_stack(&timer);
+ Complete:
complete_all(&dev->power.completion);
if (error)
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index e6c6d98..d605a61 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -250,7 +250,7 @@
pce = cmdlistinfo->go_proc;
if (i == authk_size_in_word) {
- pce->addr = (uint32_t)(CRYPTO_GOPROC_OEM_KEY_REG +
+ pce->addr = (uint32_t)(CRYPTO_GOPROC_QC_KEY_REG +
pce_dev->phy_iobase);
} else {
pce->addr = (uint32_t)(CRYPTO_GOPROC_REG +
@@ -434,7 +434,7 @@
pce = cmdlistinfo->go_proc;
if (i == enck_size_in_word) {
use_hw_key = true;
- pce->addr = (uint32_t)(CRYPTO_GOPROC_OEM_KEY_REG +
+ pce->addr = (uint32_t)(CRYPTO_GOPROC_QC_KEY_REG +
pce_dev->phy_iobase);
} else {
pce->addr = (uint32_t)(CRYPTO_GOPROC_REG +
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 228f2f5..060e89a 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -98,6 +98,7 @@
.irq_name = KGSL_3D0_IRQ,
},
.iomemname = KGSL_3D0_REG_MEMORY,
+ .shadermemname = KGSL_3D0_SHADER_MEMORY,
.ftbl = &adreno_functable,
#ifdef CONFIG_HAS_EARLYSUSPEND
.display_off = {
@@ -392,13 +393,6 @@
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
*cmds++ = 0x7fff;
sizedwords += 2;
- /*
- * add an interrupt at the end of commands so that the smmu
- * disable clock off function will get called
- */
- *cmds++ = cp_type3_packet(CP_INTERRUPT, 1);
- *cmds++ = CP_INT_CNTL__RB_INT_MASK;
- sizedwords += 2;
/* This returns the per context timestamp but we need to
* use the global timestamp for iommu clock disablement */
adreno_ringbuffer_issuecmds(device, adreno_ctx,
@@ -2011,12 +2005,23 @@
return memdesc ? kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr) : NULL;
}
-void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
- unsigned int *value)
+/**
+ * adreno_read - General read function to read adreno device memory
+ * @device - Pointer to the GPU device struct (for adreno device)
+ * @base - Base address (kernel virtual) where the device memory is mapped
+ * @offsetwords - Offset in words from the base address, of the memory that
+ * is to be read
+ * @value - Value read from the device memory
+ * @mem_len - Length of the device memory mapped to the kernel
+ */
+static void adreno_read(struct kgsl_device *device, void *base,
+ unsigned int offsetwords, unsigned int *value,
+ unsigned int mem_len)
{
+
unsigned int *reg;
- BUG_ON(offsetwords*sizeof(uint32_t) >= device->reg_len);
- reg = (unsigned int *)(device->reg_virt + (offsetwords << 2));
+ BUG_ON(offsetwords*sizeof(uint32_t) >= mem_len);
+ reg = (unsigned int *)(base + (offsetwords << 2));
if (!in_interrupt())
kgsl_pre_hwaccess(device);
@@ -2027,6 +2032,31 @@
rmb();
}
+/**
+ * adreno_regread - Used to read adreno device registers
+ * @offsetwords - Word (4 Bytes) offset to the register to be read
+ * @value - Value read from device register
+ */
+void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
+ unsigned int *value)
+{
+ adreno_read(device, device->reg_virt, offsetwords, value,
+ device->reg_len);
+}
+
+/**
+ * adreno_shadermem_regread - Used to read GPU (adreno) shader memory
+ * @device - GPU device whose shader memory is to be read
+ * @offsetwords - Offset in words, of the shader memory address to be read
+ * @value - Pointer to where the read shader mem value is to be stored
+ */
+void adreno_shadermem_regread(struct kgsl_device *device,
+ unsigned int offsetwords, unsigned int *value)
+{
+ adreno_read(device, device->shader_mem_virt, offsetwords, value,
+ device->shader_mem_len);
+}
+
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
unsigned int value)
{
@@ -2060,6 +2090,67 @@
return context_id;
}
+static void adreno_next_event(struct kgsl_device *device,
+ struct kgsl_event *event)
+{
+ int status;
+ unsigned int ref_ts, enableflag;
+ unsigned int context_id = _get_context_id(event->context);
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ status = kgsl_check_timestamp(device, event->context, event->timestamp);
+ if (!status) {
+ kgsl_sharedmem_readl(&device->memstore, &enableflag,
+ KGSL_MEMSTORE_OFFSET(context_id, ts_cmp_enable));
+ /*
+ * Barrier is needed here to make sure the read from memstore
+ * has posted
+ */
+
+ mb();
+
+ if (enableflag) {
+ kgsl_sharedmem_readl(&device->memstore, &ref_ts,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts));
+
+ /* Make sure the memstore read has posted */
+ mb();
+ if (timestamp_cmp(ref_ts, event->timestamp) >= 0) {
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), event->timestamp);
+ /* Make sure the memstore write is posted */
+ wmb();
+ }
+ } else {
+ unsigned int cmds[2];
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ref_wait_ts), event->timestamp);
+ enableflag = 1;
+ kgsl_sharedmem_writel(&device->memstore,
+ KGSL_MEMSTORE_OFFSET(context_id,
+ ts_cmp_enable), enableflag);
+
+ /* Make sure the memstore write gets posted */
+ wmb();
+
+ /*
+ * submit a dummy packet so that even if all
+ * commands upto timestamp get executed we will still
+ * get an interrupt
+ */
+ cmds[0] = cp_type3_packet(CP_NOP, 1);
+ cmds[1] = 0;
+
+ if (adreno_dev->drawctxt_active)
+ adreno_ringbuffer_issuecmds_intr(device,
+ event->context, &cmds[0], 2);
+ }
+ }
+}
+
static int kgsl_check_interrupt_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
{
@@ -2192,178 +2283,225 @@
return hang_detected;
}
-
-/* MUST be called with the device mutex held */
-static int adreno_waittimestamp(struct kgsl_device *device,
- struct kgsl_context *context,
- unsigned int timestamp,
- unsigned int msecs)
+/**
+ * adreno_handle_hang - Process a hang detected in adreno_waittimestamp
+ * @device - pointer to a KGSL device structure
+ * @context - pointer to the active KGSL context
+ * @timestamp - the timestamp that the process was waiting for
+ *
+ * Process a possible GPU hang and try to recover from it cleanly
+ */
+static int adreno_handle_hang(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
{
- long status = 0;
- uint io = 1;
- static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
- int retries = 0;
- unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
- unsigned int time_elapsed = 0;
- unsigned int prev_reg_val[hang_detect_regs_count];
- unsigned int wait;
- unsigned int retry_ts_cmp = 0;
- unsigned int retry_ts_cmp_msecs = KGSL_SYNCOBJ_SERVER_TIMEOUT;
+ unsigned int ts_issued;
- memset(prev_reg_val, 0, sizeof(prev_reg_val));
+ /* Do one last check to see if we somehow made it through */
+ if (kgsl_check_timestamp(device, context, timestamp))
+ return 0;
ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
- /* Don't wait forever, set a max value for now */
- if (msecs == KGSL_TIMEOUT_DEFAULT)
- msecs = adreno_dev->wait_timeout;
-
- /*
- * With user generated ts, if this check fails perform this check
- * again after 'retry_ts_cmp_msecs' milliseconds.
- */
- if (timestamp_cmp(timestamp, ts_issued) > 0) {
- if (adreno_ctx == NULL ||
- !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
- if (context && !context->wait_on_invalid_ts) {
- KGSL_DRV_ERR(device,
- "Cannot wait for invalid ts <%d:0x%x>, "
- "last issued ts <%d:0x%x>\n",
- context_id, timestamp, context_id, ts_issued);
- /*
- * Prevent the above message from spamming the
- * kernel logs and causing a watchdog
- */
- context->wait_on_invalid_ts = true;
- }
- status = -EINVAL;
- goto done;
- } else
- retry_ts_cmp = 1;
- } else if (context && context->wait_on_invalid_ts) {
- /* Once we wait for a valid ts reset the invalid wait flag */
- context->wait_on_invalid_ts = false;
- }
-
- /*
- * Make the first timeout interval 100 msecs and then try to kick the
- * wptr again. This helps to ensure the wptr is updated properly. If
- * the requested timeout is less than 100 msecs, then wait 20msecs which
- * is the minimum amount of time we can safely wait at 100HZ
- */
-
- if (msecs == 0 || msecs >= 100)
- wait = 100;
- else
- wait = 20;
-
- do {
- /*
- * 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
- * will not be generated and thus the timestamp
- * work needs to be queued.
- */
- queue_work(device->work_queue, &device->ts_expired_ws);
- status = 0;
- goto done;
- }
-
- io_cnt = (io_cnt + 1) % 100;
- if (io_cnt <
- pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
- io = 0;
-
- if ((retries > 0) &&
- (adreno_hang_detect(device, prev_reg_val)))
- goto hang_dump;
-
- mutex_unlock(&device->mutex);
- /* We need to make sure that the process is
- * placed in wait-q before its condition is called
- */
- status = kgsl_wait_event_interruptible_timeout(
- device->wait_queue,
- kgsl_check_interrupt_timestamp(device,
- context, timestamp),
- msecs_to_jiffies(wait), io);
-
- mutex_lock(&device->mutex);
-
- if (status > 0) {
- /*completed before the wait finished */
- status = 0;
- goto done;
- } else if (status < 0) {
- /*an error occurred*/
- goto done;
- }
- /*this wait timed out*/
-
- time_elapsed += wait;
- wait = KGSL_TIMEOUT_PART;
-
- if (!retry_ts_cmp)
- retries++;
- else if (time_elapsed >= retry_ts_cmp_msecs) {
- ts_issued =
- adreno_dev->ringbuffer.timestamp[context_id];
- if (timestamp_cmp(timestamp, ts_issued) > 0) {
- if (context && !context->wait_on_invalid_ts) {
- KGSL_DRV_ERR(device,
- "Cannot wait for user-generated ts <%d:0x%x>, "
- "not submitted within server timeout period. "
- "last issued ts <%d:0x%x>\n",
- context_id, timestamp, context_id,
- ts_issued);
- context->wait_on_invalid_ts = true;
- }
- status = -EINVAL;
- goto done;
- } else if (context && context->wait_on_invalid_ts) {
- context->wait_on_invalid_ts = false;
- }
- retry_ts_cmp = 0;
- }
-
- } while (!msecs || time_elapsed < msecs);
-
-hang_dump:
- /*
- * Check if timestamp has retired here because we may have hit
- * recovery which can take some time and cause waiting threads
- * to timeout
- */
- if (kgsl_check_timestamp(device, context, timestamp))
- goto done;
- status = -ETIMEDOUT;
KGSL_DRV_ERR(device,
"Device hang detected while waiting for timestamp: "
"<%d:0x%x>, last submitted timestamp: <%d:0x%x>, "
"wptr: 0x%x\n",
context_id, timestamp, context_id, ts_issued,
adreno_dev->ringbuffer.wptr);
- if (!adreno_dump_and_recover(device)) {
- /* The timestamp that this process wanted
- * to wait on may be invalid or expired now
- * after successful recovery */
- status = 0;
+
+ /* Return 0 after a successful recovery */
+ if (!adreno_dump_and_recover(device))
+ return 0;
+
+ return -ETIMEDOUT;
+}
+
+static int _check_pending_timestamp(struct kgsl_device *device,
+ struct kgsl_context *context, unsigned int timestamp)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ unsigned int context_id = _get_context_id(context);
+ unsigned int ts_issued;
+
+ if (context_id == KGSL_CONTEXT_INVALID)
+ return -EINVAL;
+
+ ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
+
+ if (timestamp_cmp(timestamp, ts_issued) <= 0)
+ return 0;
+
+ if (context && !context->wait_on_invalid_ts) {
+ KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id, ts_issued);
+
+ /* Only print this message once */
+ context->wait_on_invalid_ts = true;
}
-done:
- return (int)status;
+
+ return -EINVAL;
+}
+
+/**
+ * adreno_waittimestamp - sleep while waiting for the specified timestamp
+ * @device - pointer to a KGSL device structure
+ * @context - pointer to the active kgsl context
+ * @timestamp - GPU timestamp to wait for
+ * @msecs - amount of time to wait (in milliseconds)
+ *
+ * Wait 'msecs' milliseconds for the specified timestamp to expire. Wake up
+ * every KGSL_TIMEOUT_PART milliseconds to check for a device hang and process
+ * one if it happened. Otherwise, spend most of our time in an interruptible
+ * wait for the timestamp interrupt to be processed. This function must be
+ * called with the mutex already held.
+ */
+static int adreno_waittimestamp(struct kgsl_device *device,
+ struct kgsl_context *context,
+ unsigned int timestamp,
+ unsigned int msecs)
+{
+ static unsigned int io_cnt;
+ struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ unsigned int context_id = _get_context_id(context);
+ unsigned int prev_reg_val[hang_detect_regs_count];
+ unsigned int time_elapsed = 0;
+ unsigned int wait;
+ int ts_compare = 1;
+ int io, ret = -ETIMEDOUT;
+
+ /* Get out early if the context has already been destroyed */
+
+ if (context_id == KGSL_CONTEXT_INVALID) {
+ KGSL_DRV_WARN(device, "context was detached");
+ return -EINVAL;
+ }
+
+ /*
+ * Check to see if the requested timestamp is "newer" then the last
+ * timestamp issued. If it is complain once and return error. Only
+ * print the message once per context so that badly behaving
+ * applications don't spam the logs
+ */
+
+ if (adreno_ctx && !(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+ if (_check_pending_timestamp(device, context, timestamp))
+ return -EINVAL;
+
+ /* Reset the invalid timestamp flag on a valid wait */
+ context->wait_on_invalid_ts = false;
+ }
+
+
+ /* Clear the registers used for hang detection */
+ memset(prev_reg_val, 0, sizeof(prev_reg_val));
+
+ /*
+ * On the first time through the loop only wait 100ms.
+ * this gives enough time for the engine to start moving and oddly
+ * provides better hang detection results than just going the full
+ * KGSL_TIMEOUT_PART right off the bat. The exception to this rule
+ * is if msecs happens to be < 100ms then just use the full timeout
+ */
+
+ wait = 100;
+
+ do {
+ long status;
+
+ if (wait > (msecs - time_elapsed))
+ wait = msecs - time_elapsed;
+
+ /*
+ * if the timestamp happens while we're not
+ * waiting, there's a chance that an interrupt
+ * will not be generated and thus the timestamp
+ * work needs to be queued.
+ */
+
+ if (kgsl_check_timestamp(device, context, timestamp)) {
+ queue_work(device->work_queue, &device->ts_expired_ws);
+ ret = 0;
+ break;
+ }
+
+ /* Check to see if the GPU is hung */
+ if (adreno_hang_detect(device, prev_reg_val)) {
+ ret = adreno_handle_hang(device, context, timestamp);
+ break;
+ }
+
+ /*
+ * For proper power accounting sometimes we need to call
+ * io_wait_interruptible_timeout and sometimes we need to call
+ * plain old wait_interruptible_timeout. We call the regular
+ * timeout N times out of 100, where N is a number specified by
+ * the current power level
+ */
+
+ io_cnt = (io_cnt + 1) % 100;
+ io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction)
+ ? 0 : 1;
+
+ mutex_unlock(&device->mutex);
+
+ /* Wait for a timestamp event */
+ status = kgsl_wait_event_interruptible_timeout(
+ device->wait_queue,
+ kgsl_check_interrupt_timestamp(device, context,
+ timestamp), msecs_to_jiffies(wait), io);
+
+ mutex_lock(&device->mutex);
+
+ /*
+ * If status is non zero then either the condition was satisfied
+ * or there was an error. In either event, this is the end of
+ * the line for us
+ */
+
+ if (status != 0) {
+ ret = (status > 0) ? 0 : (int) status;
+ break;
+ }
+
+ time_elapsed += wait;
+
+ /* If user specified timestamps are being used, wait at least
+ * KGSL_SYNCOBJ_SERVER_TIMEOUT msecs for the user driver to
+ * issue a IB for a timestamp before checking to see if the
+ * current timestamp we are waiting for is valid or not
+ */
+
+ if (ts_compare && (adreno_ctx &&
+ (adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS))) {
+ if (time_elapsed > KGSL_SYNCOBJ_SERVER_TIMEOUT) {
+ ret = _check_pending_timestamp(device, context,
+ timestamp);
+ if (ret)
+ break;
+
+ /* Don't do this check again */
+ ts_compare = 0;
+
+ /*
+ * Reset the invalid timestamp flag on a valid
+ * wait
+ */
+ context->wait_on_invalid_ts = false;
+ }
+ }
+
+ /*
+ * all subsequent trips through the loop wait the full
+ * KGSL_TIMEOUT_PART interval
+ */
+ wait = KGSL_TIMEOUT_PART;
+
+ } while (!msecs || time_elapsed < msecs);
+
+ return ret;
}
static unsigned int adreno_readtimestamp(struct kgsl_device *device,
@@ -2522,6 +2660,7 @@
.drawctxt_destroy = adreno_drawctxt_destroy,
.setproperty = adreno_setproperty,
.postmortem_dump = adreno_dump,
+ .next_event = adreno_next_event,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index f9d0316..61378fe 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -181,6 +181,10 @@
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
unsigned int value);
+void adreno_shadermem_regread(struct kgsl_device *device,
+ unsigned int offsetwords,
+ unsigned int *value);
+
int adreno_dump(struct kgsl_device *device, int manual);
unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device
*adreno_dev);
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index e4f5733..1243dd0 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/io.h>
#include "kgsl.h"
#include "adreno.h"
#include "kgsl_snapshot.h"
@@ -19,14 +20,27 @@
#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+ sizeof(struct kgsl_snapshot_debug))
+/* Shader memory size in words */
#define SHADER_MEMORY_SIZE 0x4000
+/**
+ * a3xx_snapshot_shader_memory - Helper function to dump the GPU shader
+ * memory to the snapshot buffer.
+ * @device - GPU device whose shader memory is to be dumped
+ * @snapshot - Pointer to binary snapshot data blob being made
+ * @remain - Number of remaining bytes in the snapshot blob
+ * @priv - Unused parameter
+ */
static int a3xx_snapshot_shader_memory(struct kgsl_device *device,
void *snapshot, int remain, void *priv)
{
struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int i;
unsigned int *data = snapshot + sizeof(*header);
- int i;
+ unsigned int shader_read_len = SHADER_MEMORY_SIZE;
+
+ if (SHADER_MEMORY_SIZE > (device->shader_mem_len >> 2))
+ shader_read_len = (device->shader_mem_len >> 2);
if (remain < DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE)) {
SNAPSHOT_ERR_NOMEM(device, "SHADER MEMORY");
@@ -36,8 +50,22 @@
header->type = SNAPSHOT_DEBUG_SHADER_MEMORY;
header->size = SHADER_MEMORY_SIZE;
- for (i = 0; i < SHADER_MEMORY_SIZE; i++)
- adreno_regread(device, 0x4000 + i, &data[i]);
+ /* Map shader memory to kernel, for dumping */
+ if (device->shader_mem_virt == NULL)
+ device->shader_mem_virt = devm_ioremap(device->dev,
+ device->shader_mem_phys,
+ device->shader_mem_len);
+
+ if (device->shader_mem_virt == NULL) {
+ KGSL_DRV_ERR(device,
+ "Unable to map shader memory region\n");
+ return 0;
+ }
+
+ /* Now, dump shader memory to snapshot */
+ for (i = 0; i < shader_read_len; i++)
+ adreno_shadermem_regread(device, i, &data[i]);
+
return DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE);
}
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index e069fa5..6e0d6ad 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -12,6 +12,7 @@
*/
#include <linux/vmalloc.h>
+#include <mach/board.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
@@ -737,6 +738,8 @@
mb();
+ msm_clk_dump_debug_info();
+
if (adreno_is_a2xx(adreno_dev))
adreno_dump_a2xx(device);
else if (adreno_is_a3xx(adreno_dev))
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c040bf3..e61b040 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -504,6 +504,22 @@
kfree(event);
}
+ /* Send the next pending event for each context to the device */
+ if (device->ftbl->next_event) {
+ unsigned int id = KGSL_MEMSTORE_GLOBAL;
+
+ list_for_each_entry(event, &device->events, list) {
+
+ if (!event->context)
+ continue;
+
+ if (event->context->id != id) {
+ device->ftbl->next_event(device, event);
+ id = event->context->id;
+ }
+ }
+ }
+
mutex_unlock(&device->mutex);
}
EXPORT_SYMBOL(kgsl_timestamp_expired);
@@ -2475,6 +2491,7 @@
kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
+ /* Get starting physical address of device registers */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
device->iomemname);
if (res == NULL) {
@@ -2492,6 +2509,33 @@
device->reg_phys = res->start;
device->reg_len = resource_size(res);
+ /*
+ * Check if a shadermemname is defined, and then get shader memory
+ * details including shader memory starting physical address
+ * and shader memory length
+ */
+ if (device->shadermemname != NULL) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ device->shadermemname);
+
+ if (res == NULL) {
+ KGSL_DRV_ERR(device,
+ "Shader memory: platform_get_resource_byname failed\n");
+ }
+
+ else {
+ device->shader_mem_phys = res->start;
+ device->shader_mem_len = resource_size(res);
+ }
+
+ if (!devm_request_mem_region(device->dev,
+ device->shader_mem_phys,
+ device->shader_mem_len,
+ device->name)) {
+ KGSL_DRV_ERR(device, "request_mem_region_failed\n");
+ }
+ }
+
if (!devm_request_mem_region(device->dev, device->reg_phys,
device->reg_len, device->name)) {
KGSL_DRV_ERR(device, "request_mem_region failed\n");
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index d962bf1..35ffc1b 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -58,6 +58,7 @@
struct kgsl_device_private;
struct kgsl_context;
struct kgsl_power_stats;
+struct kgsl_event;
struct kgsl_functable {
/* Mandatory functions - these functions must be implemented
@@ -112,6 +113,8 @@
enum kgsl_property_type type, void *value,
unsigned int sizebytes);
int (*postmortem_dump) (struct kgsl_device *device, int manual);
+ void (*next_event)(struct kgsl_device *device,
+ struct kgsl_event *event);
};
/* MH register values */
@@ -140,11 +143,27 @@
unsigned int ver_minor;
uint32_t flags;
enum kgsl_deviceid id;
+
+ /* Starting physical address for GPU registers */
unsigned long reg_phys;
+
+ /* Starting Kernel virtual address for GPU registers */
void *reg_virt;
+
+ /* Total memory size for all GPU registers */
unsigned int reg_len;
+
+ /* Kernel virtual address for GPU shader memory */
+ void *shader_mem_virt;
+
+ /* Starting physical address for GPU shader memory */
+ unsigned long shader_mem_phys;
+
+ /* GPU shader memory size */
+ unsigned int shader_mem_len;
struct kgsl_memdesc memstore;
const char *iomemname;
+ const char *shadermemname;
struct kgsl_mh mh;
struct kgsl_mmu mmu;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6fe119d..bf39587 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -25,6 +25,7 @@
#include "kgsl_mmu.h"
#include "kgsl_device.h"
#include "kgsl_sharedmem.h"
+#include "adreno.h"
#define KGSL_MMU_ALIGN_SHIFT 13
#define KGSL_MMU_ALIGN_MASK (~((1 << KGSL_MMU_ALIGN_SHIFT) - 1))
@@ -536,6 +537,12 @@
uint32_t flags)
{
struct kgsl_device *device = mmu->device;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ if (!(flags & (KGSL_MMUFLAGS_TLBFLUSH | KGSL_MMUFLAGS_PTUPDATE))
+ && !adreno_is_a2xx(adreno_dev))
+ return;
+
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return;
else if (device->ftbl->setstate)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7a7a8dc..27f198b 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -86,63 +86,296 @@
clkstats->start = ktime_get();
}
+/*
+ * Given a requested power level do bounds checking on the constraints and
+ * return the nearest possible level
+ */
+
+static inline int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level)
+{
+ unsigned int max_pwrlevel = max_t(int, pwr->thermal_pwrlevel,
+ pwr->max_pwrlevel);
+
+ unsigned int min_pwrlevel = max_t(int, pwr->thermal_pwrlevel,
+ pwr->min_pwrlevel);
+
+ if (level < max_pwrlevel)
+ return max_pwrlevel;
+ if (level > min_pwrlevel)
+ return min_pwrlevel;
+
+ return level;
+}
+
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int new_level)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
- if (new_level < (pwr->num_pwrlevels - 1) &&
- new_level >= pwr->thermal_pwrlevel &&
- new_level != pwr->active_pwrlevel) {
- struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[new_level];
- int diff = new_level - pwr->active_pwrlevel;
- int d = (diff > 0) ? 1 : -1;
- int level = pwr->active_pwrlevel;
- /* Update the clock stats */
- update_clk_statistics(device, true);
- /* Finally set active level */
- pwr->active_pwrlevel = new_level;
- if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
- (device->state == KGSL_STATE_NAP)) {
- /*
- * On some platforms, instability is caused on
- * changing clock freq when the core is busy.
- * Idle the gpu core before changing the clock freq.
- */
- if (pwr->idle_needed == true)
- device->ftbl->idle(device);
+ struct kgsl_pwrlevel *pwrlevel;
+ int delta;
- /* Don't shift by more than one level at a time to
- * avoid glitches.
- */
- while (level != new_level) {
- level += d;
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[level].gpu_freq);
- }
+ /* Adjust the power level to the current constraints */
+ new_level = _adjust_pwrlevel(pwr, new_level);
+
+ if (new_level == pwr->active_pwrlevel)
+ return;
+
+ delta = new_level < pwr->active_pwrlevel ? -1 : 1;
+
+ update_clk_statistics(device, true);
+
+ if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags) ||
+ (device->state == KGSL_STATE_NAP)) {
+
+ /*
+ * On some platforms, instability is caused on
+ * changing clock freq when the core is busy.
+ * Idle the gpu core before changing the clock freq.
+ */
+
+ if (pwr->idle_needed == true)
+ device->ftbl->idle(device);
+
+ /*
+ * Don't shift by more than one level at a time to
+ * avoid glitches.
+ */
+
+ while (pwr->active_pwrlevel != new_level) {
+ pwr->active_pwrlevel += delta;
+
+ clk_set_rate(pwr->grp_clks[0],
+ pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
}
- if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
- if (pwr->pcl)
- msm_bus_scale_client_update_request(pwr->pcl,
- pwrlevel->bus_freq);
- else if (pwr->ebi1_clk)
- clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
- }
- trace_kgsl_pwrlevel(device, pwr->active_pwrlevel,
- pwrlevel->gpu_freq);
}
+
+ pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
+
+ if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
+
+ if (pwr->pcl)
+ msm_bus_scale_client_update_request(pwr->pcl,
+ pwrlevel->bus_freq);
+ else if (pwr->ebi1_clk)
+ clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
+ }
+
+ trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq);
}
+
EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
-static int __gpuclk_store(int max, struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{ int ret, i, delta = 5000000;
- unsigned long val;
+static int kgsl_pwrctrl_thermal_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
+ int ret, level;
if (device == NULL)
return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%d", &level);
+ if (ret != 1)
+ return count;
+
+ if (level < 0)
+ return count;
+
+ mutex_lock(&device->mutex);
+
+ if (level > pwr->num_pwrlevels - 2)
+ level = pwr->num_pwrlevels - 2;
+
+ pwr->thermal_pwrlevel = level;
+
+ /*
+ * If there is no power policy set the clock to the requested thermal
+ * level - if thermal now happens to be higher than max, then that will
+ * be limited by the pwrlevel change function. Otherwise if there is
+ * a policy only change the active clock if it is higher then the new
+ * thermal level
+ */
+
+ if (device->pwrscale.policy == NULL ||
+ pwr->thermal_pwrlevel > pwr->active_pwrlevel)
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_thermal_pwrlevel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->thermal_pwrlevel);
+}
+
+static int kgsl_pwrctrl_max_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int ret, level, max_level;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%d", &level);
+ if (ret != 1)
+ return count;
+
+ /* If the use specifies a negative number, then don't change anything */
+ if (level < 0)
+ return count;
+
+ mutex_lock(&device->mutex);
+
+ /* You can't set a maximum power level lower than the minimum */
+ if (level > pwr->min_pwrlevel)
+ level = pwr->min_pwrlevel;
+
+ pwr->max_pwrlevel = level;
+
+
+ max_level = max_t(int, pwr->thermal_pwrlevel, pwr->max_pwrlevel);
+
+ /*
+ * If there is no policy then move to max by default. Otherwise only
+ * move max if the current level happens to be higher then the new max
+ */
+
+ if (device->pwrscale.policy == NULL ||
+ (max_level > pwr->active_pwrlevel))
+ kgsl_pwrctrl_pwrlevel_change(device, max_level);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_max_pwrlevel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->max_pwrlevel);
+}
+
+static int kgsl_pwrctrl_min_pwrlevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int ret, level, min_level;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%d", &level);
+ if (ret != 1)
+ return count;
+
+ /* Don't do anything on obviously incorrect values */
+ if (level < 0)
+ return count;
+
+ mutex_lock(&device->mutex);
+ if (level > pwr->num_pwrlevels - 2)
+ level = pwr->num_pwrlevels - 2;
+
+ /* You can't set a minimum power level lower than the maximum */
+ if (level < pwr->max_pwrlevel)
+ level = pwr->max_pwrlevel;
+
+ pwr->min_pwrlevel = level;
+
+ min_level = max_t(int, pwr->thermal_pwrlevel, pwr->min_pwrlevel);
+
+ /* Only move the power level higher if minimum is higher then the
+ * current level
+ */
+
+ if (min_level < pwr->active_pwrlevel)
+ kgsl_pwrctrl_pwrlevel_change(device, min_level);
+
+ mutex_unlock(&device->mutex);
+
+ return count;
+}
+
+static int kgsl_pwrctrl_min_pwrlevel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->min_pwrlevel);
+}
+
+static int kgsl_pwrctrl_num_pwrlevels_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ return snprintf(buf, PAGE_SIZE, "%d\n", pwr->num_pwrlevels - 1);
+}
+
+/* Given a GPU clock value, return the nearest powerlevel */
+
+static int _get_nearest_pwrlevel(struct kgsl_pwrctrl *pwr, unsigned int clock)
+{
+ int i;
+
+ for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
+ if (abs(pwr->pwrlevels[i].gpu_freq - clock) < 5000000)
+ return i;
+ }
+
+ return -ERANGE;
+}
+
+static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ unsigned long val;
+ int ret, level;
+
+ if (device == NULL)
+ return 0;
+
pwr = &device->pwrctrl;
ret = sscanf(buf, "%ld", &val);
@@ -150,44 +383,30 @@
return count;
mutex_lock(&device->mutex);
- for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
- if (abs(pwr->pwrlevels[i].gpu_freq - val) < delta) {
- if (max)
- pwr->thermal_pwrlevel = i;
- break;
- }
- }
-
- if (i == (pwr->num_pwrlevels - 1))
+ level = _get_nearest_pwrlevel(pwr, val);
+ if (level < 0)
goto done;
+ pwr->thermal_pwrlevel = level;
+
/*
- * If the current or requested clock speed is greater than the
- * thermal limit, bump down immediately.
+ * if the thermal limit is lower than the current setting,
+ * move the speed down immediately
*/
- if (pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq >
- pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq)
+ if (pwr->thermal_pwrlevel > pwr->active_pwrlevel)
kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
- else if (!max || (NULL == device->pwrscale.policy))
- kgsl_pwrctrl_pwrlevel_change(device, i);
done:
mutex_unlock(&device->mutex);
return count;
}
-static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return __gpuclk_store(1, dev, attr, buf, count);
-}
-
static int kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
if (device == NULL)
@@ -201,7 +420,27 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- return __gpuclk_store(0, dev, attr, buf, count);
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ unsigned long val;
+ int ret, level;
+
+ if (device == NULL)
+ return 0;
+
+ pwr = &device->pwrctrl;
+
+ ret = sscanf(buf, "%ld", &val);
+ if (ret != 1)
+ return count;
+
+ mutex_lock(&device->mutex);
+ level = _get_nearest_pwrlevel(pwr, val);
+ if (level >= 0)
+ kgsl_pwrctrl_pwrlevel_change(device, level);
+
+ mutex_unlock(&device->mutex);
+ return count;
}
static int kgsl_pwrctrl_gpuclk_show(struct device *dev,
@@ -382,6 +621,18 @@
DEVICE_ATTR(gpu_available_frequencies, 0444,
kgsl_pwrctrl_gpu_available_frequencies_show,
NULL);
+DEVICE_ATTR(max_pwrlevel, 0644,
+ kgsl_pwrctrl_max_pwrlevel_show,
+ kgsl_pwrctrl_max_pwrlevel_store);
+DEVICE_ATTR(min_pwrlevel, 0644,
+ kgsl_pwrctrl_min_pwrlevel_show,
+ kgsl_pwrctrl_min_pwrlevel_store);
+DEVICE_ATTR(thermal_pwrlevel, 0644,
+ kgsl_pwrctrl_thermal_pwrlevel_show,
+ kgsl_pwrctrl_thermal_pwrlevel_store);
+DEVICE_ATTR(num_pwrlevels, 0444,
+ kgsl_pwrctrl_num_pwrlevels_show,
+ NULL);
static const struct device_attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk,
@@ -391,6 +642,10 @@
&dev_attr_gpubusy,
&dev_attr_gputop,
&dev_attr_gpu_available_frequencies,
+ &dev_attr_max_pwrlevel,
+ &dev_attr_min_pwrlevel,
+ &dev_attr_thermal_pwrlevel,
+ &dev_attr_num_pwrlevels,
NULL
};
@@ -623,6 +878,13 @@
goto done;
}
pwr->num_pwrlevels = pdata->num_levels;
+
+ /* Initialize the user and thermal clock constraints */
+
+ pwr->max_pwrlevel = 0;
+ pwr->min_pwrlevel = pdata->num_levels - 2;
+ pwr->thermal_pwrlevel = 0;
+
pwr->active_pwrlevel = pdata->init_level;
pwr->default_pwrlevel = pdata->init_level;
for (i = 0; i < pdata->num_levels; i++) {
@@ -885,6 +1147,9 @@
kgsl_pwrstate_to_str(device->state));
break;
}
+
+ kgsl_mmu_disable_clk_on_ts(&device->mmu, 0, false);
+
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index c02a9fc..e51ec54 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -38,6 +38,30 @@
unsigned int elapsed_old;
};
+/**
+ * struct kgsl_pwrctrl - Power control settings for a KGSL device
+ * @interrupt_num - The interrupt number for the device
+ * @ebi1_clk - Pointer to the EBI clock structure
+ * @grp_clks - Array of clocks structures that we control
+ * @power_flags - Control flags for power
+ * @pwrlevels - List of supported power levels
+ * @active_pwrlevel - The currently active power level
+ * @thermal_pwrlevel - maximum powerlevel constraint from thermal
+ * @max_pwrlevel - maximum allowable powerlevel per the user
+ * @min_pwrlevel - minimum allowable powerlevel per the user
+ * @num_pwrlevels - number of available power levels
+ * @interval_timeout - timeout in jiffies to be idle before a power event
+ * @strtstp_sleepwake - true if the device supports low latency GPU start/stop
+ * @gpu_reg - pointer to the regulator structure for gpu_reg
+ * @gpu_cx - pointer to the regulator structure for gpu_cx
+ * @pcl - bus scale identifier
+ * @nap_allowed - true if the device supports naps
+ * @idle_needed - true if the device needs a idle before clock change
+ * @irq_name - resource name for the IRQ
+ * @restore_slumber - Flag to indicate that we are in a suspend/restore sequence
+ * @clk_stats - structure of clock statistics
+ */
+
struct kgsl_pwrctrl {
int interrupt_num;
struct clk *ebi1_clk;
@@ -47,6 +71,8 @@
unsigned int active_pwrlevel;
int thermal_pwrlevel;
unsigned int default_pwrlevel;
+ unsigned int max_pwrlevel;
+ unsigned int min_pwrlevel;
unsigned int num_pwrlevels;
unsigned int interval_timeout;
bool strtstp_sleepwake;
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index f6277b3..aad1a8d 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -299,8 +299,14 @@
{
if (device->pwrscale.policy != NULL) {
device->pwrscale.policy->close(device, &device->pwrscale);
+
+ /*
+ * Try to set max pwrlevel which will be limited to thermal by
+ * kgsl_pwrctrl_pwrlevel_change if thermal is indeed lower
+ */
+
kgsl_pwrctrl_pwrlevel_change(device,
- device->pwrctrl.thermal_pwrlevel);
+ device->pwrctrl.max_pwrlevel);
}
device->pwrscale.policy = NULL;
}
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 7c2514b..e01932b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -93,7 +93,7 @@
priv->governor = TZ_GOVERNOR_PERFORMANCE;
if (priv->governor == TZ_GOVERNOR_PERFORMANCE)
- kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
mutex_unlock(&device->mutex);
return count;
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index e319813..5fb041d 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -616,6 +616,63 @@
}
EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
+{
+ int64_t adc_voltage = 0;
+ struct qpnp_vadc_linear_graph param1;
+ int negative_offset;
+
+ qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
+
+ adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
+ if (adc_voltage < 0) {
+ negative_offset = 1;
+ adc_voltage = -adc_voltage;
+ }
+
+ do_div(adc_voltage, param1.dy);
+
+ qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ adc_voltage, result);
+ if (negative_offset)
+ adc_voltage = -adc_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
+
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
+{
+ struct qpnp_vadc_linear_graph param1;
+ int rc;
+
+ qpnp_get_vadc_gain_and_offset(¶m1, CALIB_RATIOMETRIC);
+
+ rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ param->low_thr_temp, ¶m->low_thr_voltage);
+ if (rc)
+ return rc;
+
+ param->low_thr_voltage *= param1.dy;
+ do_div(param->low_thr_voltage, param1.adc_vref);
+ param->low_thr_voltage += param1.adc_gnd;
+
+ rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ param->high_thr_temp, ¶m->high_thr_voltage);
+ if (rc)
+ return rc;
+
+ param->high_thr_voltage *= param1.dy;
+ do_div(param->high_thr_voltage, param1.adc_vref);
+ param->high_thr_voltage += param1.adc_gnd;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
+
int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
@@ -689,6 +746,65 @@
}
EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
+int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{
+ struct qpnp_vadc_linear_graph usb_param;
+
+ qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_ABSOLUTE);
+
+ *low_threshold = param->low_thr * usb_param.dy;
+ do_div(*low_threshold, usb_param.adc_vref);
+ *low_threshold += usb_param.adc_gnd;
+
+ *high_threshold = param->high_thr * usb_param.dy;
+ do_div(*high_threshold, usb_param.adc_vref);
+ *high_threshold += usb_param.adc_gnd;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
+
+int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{
+ struct qpnp_vadc_linear_graph btm_param;
+ int64_t *low_output = 0, *high_output = 0;
+ int rc = 0;
+
+ qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
+
+ rc = qpnp_adc_map_temp_voltage(
+ adcmap_btm_threshold,
+ ARRAY_SIZE(adcmap_btm_threshold),
+ (param->low_temp),
+ low_output);
+ if (rc)
+ return rc;
+
+ *low_output *= btm_param.dy;
+ do_div(*low_output, btm_param.adc_vref);
+ *low_output += btm_param.adc_gnd;
+
+ rc = qpnp_adc_map_temp_voltage(
+ adcmap_btm_threshold,
+ ARRAY_SIZE(adcmap_btm_threshold),
+ (param->high_temp),
+ high_output);
+ if (rc)
+ return rc;
+
+ *high_output *= btm_param.dy;
+ do_div(*high_output, btm_param.adc_vref);
+ *high_output += btm_param.adc_gnd;
+
+ low_threshold = (uint32_t *) low_output;
+ high_threshold = (uint32_t *) high_output;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
+
int32_t qpnp_vadc_check_result(int32_t *data)
{
if (*data < QPNP_VADC_MIN_ADC_CODE)
@@ -731,7 +847,7 @@
return -ENOMEM;
}
adc_channel_list = devm_kzalloc(&spmi->dev,
- sizeof(struct qpnp_vadc_amux) * count_adc_channel_list,
+ ((sizeof(struct qpnp_vadc_amux)) * count_adc_channel_list),
GFP_KERNEL);
if (!adc_channel_list) {
dev_err(&spmi->dev, "Unable to allocate memory\n");
@@ -844,8 +960,9 @@
adc_qpnp->offset = res->start;
/* Register the ADC peripheral interrupt */
- adc_qpnp->adc_irq = spmi_get_irq(spmi, 0, 0);
- if (adc_qpnp->adc_irq < 0) {
+ adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
+ "eoc-int-en-set");
+ if (adc_qpnp->adc_irq_eoc < 0) {
pr_err("Invalid irq\n");
return -ENXIO;
}
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 0e82cf7..b5ee104 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -695,14 +695,14 @@
return -EINVAL;
}
- rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq,
+ rc = devm_request_irq(&spmi->dev, iadc->adc->adc_irq_eoc,
qpnp_iadc_isr,
IRQF_TRIGGER_RISING, "qpnp_iadc_interrupt", iadc);
if (rc) {
dev_err(&spmi->dev, "failed to request adc irq\n");
return rc;
} else
- enable_irq_wake(iadc->adc->adc_irq);
+ enable_irq_wake(iadc->adc->adc_irq_eoc);
iadc->iadc_init_calib = false;
dev_set_drvdata(&spmi->dev, iadc);
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index c59aa5b..b71c998 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -509,6 +509,39 @@
return rc;
}
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+ enum qpnp_adc_calib_type calib_type)
+{
+
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+
+ switch (calib_type) {
+ case CALIB_RATIOMETRIC:
+ param->dy =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dy;
+ param->dx =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx;
+ param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
+ param->adc_gnd =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
+ break;
+ case CALIB_ABSOLUTE:
+ param->dy =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
+ param->dx =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
+ param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
+ param->adc_gnd =
+ vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset);
+
int32_t qpnp_vadc_is_ready(void)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -743,7 +776,7 @@
return rc;
}
- rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq,
+ rc = devm_request_irq(&spmi->dev, vadc->adc->adc_irq_eoc,
qpnp_vadc_isr, IRQF_TRIGGER_RISING,
"qpnp_vadc_interrupt", vadc);
if (rc) {
@@ -751,7 +784,7 @@
"failed to request adc irq with error %d\n", rc);
return rc;
} else {
- enable_irq_wake(vadc->adc->adc_irq);
+ enable_irq_wake(vadc->adc->adc_irq_eoc);
}
qpnp_vadc = vadc;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ec3429b..332138c 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -25,6 +25,17 @@
If unsure, say N here.
+# MSM IOMMU CPU-GPU sync programming support
+config MSM_IOMMU_GPU_SYNC
+ bool "MSM IOMMU CPU-GPU Sync Support"
+ depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU && MSM_REMOTE_SPINLOCK_SFPB
+ help
+ Say Y here if you want to synchronize access to IOMMU configuration
+ port between CPU and GPU. CPU will grab a remote spinlock before
+ accessing IOMMU configuration registers and GPU will do the same.
+
+ If unsure, say N here.
+
config IOMMU_PGTABLES_L2
bool "Allow SMMU page tables in the L2 cache (Experimental)"
depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index f8c9809..4c72df7 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,7 @@
#include <mach/iommu_hw-8xxx.h>
#include <mach/iommu.h>
+#include <mach/msm_smsm.h>
#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
@@ -66,6 +67,69 @@
DEFINE_MUTEX(msm_iommu_lock);
+/**
+ * Remote spinlock implementation based on Peterson's algorithm to be used
+ * to synchronize IOMMU config port access between CPU and GPU.
+ * This implements Process 0 of the spin lock algorithm. GPU implements
+ * Process 1. Flag and turn is stored in shared memory to allow GPU to
+ * access these.
+ */
+struct msm_iommu_remote_lock {
+ int initialized;
+ struct remote_iommu_petersons_spinlock *lock;
+};
+
+static struct msm_iommu_remote_lock msm_iommu_remote_lock;
+
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+static void _msm_iommu_remote_spin_lock_init(void)
+{
+ msm_iommu_remote_lock.lock = smem_alloc(SMEM_SPINLOCK_ARRAY, 32);
+ memset(msm_iommu_remote_lock.lock, 0,
+ sizeof(*msm_iommu_remote_lock.lock));
+}
+
+void msm_iommu_remote_p0_spin_lock(void)
+{
+ msm_iommu_remote_lock.lock->flag[PROC_APPS] = 1;
+ msm_iommu_remote_lock.lock->turn = 1;
+
+ smp_mb();
+
+ while (msm_iommu_remote_lock.lock->flag[PROC_GPU] == 1 &&
+ msm_iommu_remote_lock.lock->turn == 1)
+ cpu_relax();
+}
+
+void msm_iommu_remote_p0_spin_unlock(void)
+{
+ smp_mb();
+
+ msm_iommu_remote_lock.lock->flag[PROC_APPS] = 0;
+}
+#endif
+
+inline void msm_iommu_mutex_lock(void)
+{
+ mutex_lock(&msm_iommu_lock);
+}
+
+inline void msm_iommu_mutex_unlock(void)
+{
+ mutex_unlock(&msm_iommu_lock);
+}
+
+void *msm_iommu_lock_initialize(void)
+{
+ mutex_lock(&msm_iommu_lock);
+ if (!msm_iommu_remote_lock.initialized) {
+ msm_iommu_remote_lock_init();
+ msm_iommu_remote_lock.initialized = 1;
+ }
+ mutex_unlock(&msm_iommu_lock);
+ return msm_iommu_remote_lock.lock;
+}
+
struct msm_priv {
unsigned long *pgtable;
int redirect;
@@ -116,12 +180,17 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
asid | (va & TLBIVA_VA));
mb();
+
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
}
fail:
@@ -148,11 +217,16 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
mb();
+
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
}
fail:
@@ -189,6 +263,9 @@
{
unsigned int prrr, nmrr;
int i, j, found;
+
+ msm_iommu_remote_spin_lock();
+
__reset_context(base, ctx);
/* Set up HTW mode */
@@ -278,6 +355,8 @@
/* Enable the MMU */
SET_M(base, ctx, 1);
mb();
+
+ msm_iommu_remote_spin_unlock();
}
static int msm_iommu_domain_init(struct iommu_domain *domain, int flags)
@@ -417,10 +496,15 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
SET_TLBIASID(iommu_drvdata->base, ctx_dev->num,
GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_dev->num));
__reset_context(iommu_drvdata->base, ctx_dev->num);
+
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
@@ -1083,6 +1167,8 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
SET_V2PPR(base, ctx, va & V2Pxx_VA);
mb();
@@ -1097,6 +1183,8 @@
if (GET_FAULT(base, ctx))
ret = 0;
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(iommu_drvdata);
fail:
mutex_unlock(&msm_iommu_lock);
@@ -1157,6 +1245,8 @@
if (ret)
goto fail;
+ msm_iommu_remote_spin_lock();
+
fsr = GET_FSR(base, num);
if (fsr) {
@@ -1188,6 +1278,8 @@
} else
ret = IRQ_NONE;
+ msm_iommu_remote_spin_unlock();
+
__disable_clocks(drvdata);
fail:
mutex_unlock(&msm_iommu_lock);
@@ -1258,6 +1350,8 @@
if (!msm_soc_version_supports_iommu_v1())
return -ENODEV;
+ msm_iommu_lock_initialize();
+
setup_iommu_tex_classes();
bus_set_iommu(&platform_bus_type, &msm_iommu_ops);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index af31b3a..507c014 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -465,6 +465,90 @@
return NULL;
}
+static int dvr_input_thread_entry(void *arg)
+{
+ struct dmxdev *dmxdev = arg;
+ struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+ int ret;
+ size_t todo;
+ size_t split;
+
+ while (1) {
+ /* wait for input */
+ ret = wait_event_interruptible(src->queue,
+ (!src->data) ||
+ (dvb_ringbuffer_avail(src)) ||
+ (src->error != 0) ||
+ (dmxdev->dvr_in_exit) ||
+ kthread_should_stop());
+
+ if ((ret < 0) || kthread_should_stop())
+ break;
+
+ spin_lock(&dmxdev->dvr_in_lock);
+
+ if (!src->data || dmxdev->exit || dmxdev->dvr_in_exit) {
+ spin_unlock(&dmxdev->dvr_in_lock);
+ break;
+ }
+
+ if (src->error) {
+ spin_unlock(&dmxdev->dvr_in_lock);
+ wake_up_all(&src->queue);
+ break;
+ }
+
+ dmxdev->dvr_processing_input = 1;
+
+ ret = dvb_ringbuffer_avail(src);
+ todo = ret;
+
+ split = (src->pread + ret > src->size) ?
+ src->size - src->pread :
+ 0;
+
+ /*
+ * In DVR PULL mode, write might block.
+ * Lock on DVR buffer is released before calling to
+ * write, if DVR was released meanwhile, dvr_in_exit is
+ * prompted. Lock is aquired when updating the read pointer
+ * again to preserve read/write pointers consistancy
+ */
+ if (split > 0) {
+ spin_unlock(&dmxdev->dvr_in_lock);
+ dmxdev->demux->write(dmxdev->demux,
+ src->data + src->pread,
+ split);
+
+ if (dmxdev->dvr_in_exit)
+ break;
+
+ spin_lock(&dmxdev->dvr_in_lock);
+
+ todo -= split;
+ DVB_RINGBUFFER_SKIP(src, split);
+ }
+
+ spin_unlock(&dmxdev->dvr_in_lock);
+ dmxdev->demux->write(dmxdev->demux,
+ src->data + src->pread, todo);
+
+ if (dmxdev->dvr_in_exit)
+ break;
+
+ spin_lock(&dmxdev->dvr_in_lock);
+
+ DVB_RINGBUFFER_SKIP(src, todo);
+ dmxdev->dvr_processing_input = 0;
+ spin_unlock(&dmxdev->dvr_in_lock);
+
+ wake_up_all(&src->queue);
+ }
+
+ return 0;
+}
+
+
static int dvb_dvr_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
@@ -542,6 +626,17 @@
dmxdev->demux->dvr_input.priv_handle = NULL;
dmxdev->demux->dvr_input.ringbuff = &dmxdev->dvr_input_buffer;
dvbdev->writers--;
+
+ dmxdev->dvr_input_thread =
+ kthread_run(
+ dvr_input_thread_entry,
+ (void *)dmxdev,
+ "dvr_input");
+
+ if (IS_ERR(dmxdev->dvr_input_thread)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENOMEM;
+ }
}
dvbdev->users++;
@@ -601,11 +696,11 @@
dmxdev->demux->write_cancel(dmxdev->demux);
/*
- * Now flush dvr-in workqueue so that no one
+ * Now stop dvr-input thread so that no one
* would process data from dvr input buffer any more
* before it gets freed.
*/
- flush_workqueue(dmxdev->dvr_input_workqueue);
+ kthread_stop(dmxdev->dvr_input_thread);
dvbdev->writers++;
dmxdev->demux->disconnect_frontend(dmxdev->demux);
@@ -773,12 +868,7 @@
buf += ret;
mutex_unlock(&dmxdev->mutex);
-
wake_up_all(&src->queue);
-
- if (!work_pending(&dmxdev->dvr_input_work))
- queue_work(dmxdev->dvr_input_workqueue,
- &dmxdev->dvr_input_work);
}
return (count - todo) ? (count - todo) : ret;
@@ -827,87 +917,6 @@
return res;
}
-static void dvr_input_work_func(struct work_struct *worker)
-{
- struct dmxdev *dmxdev =
- container_of(worker, struct dmxdev, dvr_input_work);
- struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
- int ret;
- size_t todo;
- size_t split;
-
- while (1) {
- /* wait for input */
- ret = wait_event_interruptible(src->queue,
- (!src->data) ||
- (dvb_ringbuffer_avail(src)) ||
- (src->error != 0) ||
- (dmxdev->dvr_in_exit));
-
- if (ret < 0)
- break;
-
- spin_lock(&dmxdev->dvr_in_lock);
-
- if (!src->data || dmxdev->exit || dmxdev->dvr_in_exit) {
- spin_unlock(&dmxdev->dvr_in_lock);
- break;
- }
-
- if (src->error) {
- spin_unlock(&dmxdev->dvr_in_lock);
- wake_up_all(&src->queue);
- break;
- }
-
- dmxdev->dvr_processing_input = 1;
-
- ret = dvb_ringbuffer_avail(src);
- todo = ret;
-
- split = (src->pread + ret > src->size) ?
- src->size - src->pread :
- 0;
-
- /*
- * In DVR PULL mode, write might block.
- * Lock on DVR buffer is released before calling to
- * write, if DVR was released meanwhile, dvr_in_exit is
- * prompted. Lock is aquired when updating the read pointer
- * again to preserve read/write pointers consistancy
- */
- if (split > 0) {
- spin_unlock(&dmxdev->dvr_in_lock);
- dmxdev->demux->write(dmxdev->demux,
- src->data + src->pread,
- split);
-
- if (dmxdev->dvr_in_exit)
- break;
-
- spin_lock(&dmxdev->dvr_in_lock);
-
- todo -= split;
- DVB_RINGBUFFER_SKIP(src, split);
- }
-
- spin_unlock(&dmxdev->dvr_in_lock);
- dmxdev->demux->write(dmxdev->demux,
- src->data + src->pread, todo);
-
- if (dmxdev->dvr_in_exit)
- break;
-
- spin_lock(&dmxdev->dvr_in_lock);
-
- DVB_RINGBUFFER_SKIP(src, todo);
- dmxdev->dvr_processing_input = 0;
- spin_unlock(&dmxdev->dvr_in_lock);
-
- wake_up_all(&src->queue);
- }
-}
-
static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
unsigned int f_flags,
unsigned long size)
@@ -1205,10 +1214,6 @@
wake_up_all(&buffer->queue);
- if (!work_pending(&dmxdev->dvr_input_work))
- queue_work(dmxdev->dvr_input_workqueue,
- &dmxdev->dvr_input_work);
-
return 0;
}
@@ -3260,14 +3265,6 @@
if (!dmxdev->filter)
return -ENOMEM;
- dmxdev->dvr_input_workqueue =
- create_singlethread_workqueue("dvr_workqueue");
-
- if (dmxdev->dvr_input_workqueue == NULL) {
- vfree(dmxdev->filter);
- return -ENOMEM;
- }
-
dmxdev->playback_mode = DMX_PB_MODE_PUSH;
mutex_init(&dmxdev->mutex);
@@ -3288,9 +3285,6 @@
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, NULL, 8192);
- INIT_WORK(&dmxdev->dvr_input_work,
- dvr_input_work_func);
-
if (dmxdev->demux->debugfs_demux_dir)
debugfs_create_file("filters", S_IRUGO,
dmxdev->demux->debugfs_demux_dir, dmxdev,
@@ -3313,9 +3307,6 @@
dmxdev->dvr_dvbdev->users==1);
}
- flush_workqueue(dmxdev->dvr_input_workqueue);
- destroy_workqueue(dmxdev->dvr_input_workqueue);
-
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 6c02111..d1c1cc3 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -34,7 +34,7 @@
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/dvb/dmx.h>
#include "dvbdev.h"
@@ -133,8 +133,6 @@
};
struct dmxdev {
- struct work_struct dvr_input_work;
-
struct dvb_device *dvbdev;
struct dvb_device *dvr_dvbdev;
@@ -167,7 +165,7 @@
struct dvb_ringbuffer dvr_input_buffer;
enum dmx_buffer_mode dvr_input_buffer_mode;
- struct workqueue_struct *dvr_input_workqueue;
+ struct task_struct *dvr_input_thread;
#define DVR_BUFFER_SIZE (10*188*1024)
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index b2a7f71..f61b74f 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -473,16 +473,15 @@
kfree(ctrlcmd);
free_qcmd(rcmd);
D("%s: rc %d\n", __func__, rc);
- /* rc is the time elapsed. */
- if (rc >= 0) {
- /* TODO: Refactor msm_ctrl_cmd::status field */
- if (out->status == 0)
- rc = -1;
- else if (out->status == 1 || out->status == 4)
- rc = 0;
- else
- rc = -EINVAL;
- }
+ /* rc is the time elapsed.
+ * This means that the communication with the daemon itself was
+ * successful(irrespective of the handling of the ctrlcmd).
+ * So, just reset the rc to 0 to indicate success.
+ * Its upto the caller to parse the ctrlcmd to check the status. We
+ * dont need to parse it here. */
+ if (rc >= 0)
+ rc = 0;
+
return rc;
ctrlcmd_alloc_fail:
@@ -846,9 +845,9 @@
rc = -EINVAL;
goto end;
}
-
+ tmp_cmd.status = cmd_ptr->status = ctrlcmd.status;
if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
- (void *)&tmp_cmd, cmd_len)) {
+ (void *)cmd_ptr, cmd_len)) {
pr_err("%s: copy_to_user failed in cpy, size=%d\n",
__func__, cmd_len);
rc = -EINVAL;
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index a95a296..c281f9c 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -631,10 +631,7 @@
}
inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
if (inst->prop.fps) {
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
}
exit:
return rc;
@@ -881,11 +878,7 @@
"Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Performance might be impacted\n");
- }
-
+ msm_comm_scale_clocks_and_bus(inst);
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
dprintk(VIDC_ERR,
@@ -976,10 +969,7 @@
rc = -EINVAL;
break;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Power might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
if (rc)
dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index d01841d..f4c973f 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -639,10 +639,7 @@
dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Performance might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
@@ -718,10 +715,7 @@
rc = -EINVAL;
break;
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks. Power might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
if (rc)
dprintk(VIDC_ERR,
@@ -1371,10 +1365,7 @@
dprintk(VIDC_WARN,
"Failed to set frame rate %d\n", rc);
}
- if (msm_comm_scale_clocks(inst->core, inst->session_type)) {
- dprintk(VIDC_WARN,
- "Failed to scale clocks\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
}
exit:
return rc;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index cda0ea8..87f53ac 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -64,7 +64,6 @@
};
static const u32 bus_table[] = {
- 0,
36000,
110400,
244800,
@@ -77,12 +76,11 @@
{
int num_rows = sizeof(bus_table)/(sizeof(u32));
int i;
- if (!load)
- return 0;
for (i = 0; i < num_rows; i++) {
if (load <= bus_table[i])
break;
}
+ i++;
dprintk(VIDC_DBG, "Required bus = %d\n", i);
return i;
}
@@ -122,37 +120,60 @@
break;
ret = table[i].freq;
}
- dprintk(VIDC_INFO, "Required clock rate = %lu\n", ret);
+ dprintk(VIDC_DBG, "Required clock rate = %lu\n", ret);
return ret;
}
-int msm_comm_scale_bus(struct msm_vidc_core *core, enum session_type type)
+static int msm_comm_scale_bus(struct msm_vidc_core *core,
+ enum session_type type, enum mem_type mtype)
{
int load;
int rc = 0;
+ u32 handle = 0;
if (!core || type >= MSM_VIDC_MAX_DEVICES) {
dprintk(VIDC_ERR, "Invalid args: %p, %d\n", core, type);
return -EINVAL;
}
load = msm_comm_get_load(core, type);
- rc = msm_bus_scale_client_update_request(
- core->resources.bus_info.ddr_handle[type],
- get_bus_vector(load));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
- goto fail_scale_bus;
+ if (mtype & DDR_MEM)
+ handle = core->resources.bus_info.ddr_handle[type];
+ if (mtype & OCMEM_MEM)
+ handle = core->resources.bus_info.ocmem_handle[type];
+ if (handle) {
+ rc = msm_bus_scale_client_update_request(
+ handle, get_bus_vector(load));
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+ } else {
+ dprintk(VIDC_ERR, "Failed to scale bus, mtype: %d\n",
+ mtype);
+ rc = -EINVAL;
}
- rc = msm_bus_scale_client_update_request(
- core->resources.bus_info.ocmem_handle[type],
- get_bus_vector(load));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
- goto fail_scale_bus;
- }
-fail_scale_bus:
return rc;
}
+static void msm_comm_unvote_buses(struct msm_vidc_core *core,
+ enum mem_type mtype)
+{
+ int i;
+ for (i = 0; i < MSM_VIDC_MAX_DEVICES; i++) {
+ if ((mtype & DDR_MEM) &&
+ msm_bus_scale_client_update_request(
+ core->resources.bus_info.ddr_handle[i],
+ 0)) {
+ dprintk(VIDC_WARN,
+ "Failed to unvote for DDR accesses\n");
+ }
+ if ((mtype & OCMEM_MEM) &&
+ msm_bus_scale_client_update_request(
+ core->resources.bus_info.ocmem_handle[i],
+ 0)) {
+ dprintk(VIDC_WARN,
+ "Failed to unvote for OCMEM accesses\n");
+ }
+ }
+}
+
static int protect_cp_mem(struct msm_vidc_core *core)
{
struct tzbsp_memprot memprot;
@@ -589,33 +610,28 @@
struct v4l2_event dqevent;
unsigned long flags;
if (response) {
- inst = (struct msm_vidc_inst *)response->session_id;
- dprintk(VIDC_WARN,
- "Sys error received for session %p\n", inst);
- if (inst) {
- core = inst->core;
- if (core) {
- spin_lock_irqsave(&core->lock, flags);
- core->state = VIDC_CORE_INVALID;
- spin_unlock_irqrestore(&core->lock, flags);
- dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
- dqevent.id = 0;
- list_for_each_entry(inst, &core->instances,
+ core = get_vidc_core(response->device_id);
+ dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
+ if (core) {
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INVALID;
+ spin_unlock_irqrestore(&core->lock, flags);
+ dqevent.type = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+ dqevent.id = 0;
+ list_for_each_entry(inst, &core->instances,
list) {
- if (inst) {
- v4l2_event_queue_fh(
- &inst->event_handler,
- &dqevent);
- spin_lock_irqsave(&inst->lock,
- flags);
- inst->state =
- MSM_VIDC_CORE_INVALID;
- spin_unlock_irqrestore(
- &inst->lock, flags);
- }
- }
- wake_up(&inst->kernel_event_queue);
+ v4l2_event_queue_fh(&inst->event_handler,
+ &dqevent);
+
+ spin_lock_irqsave(&inst->lock, flags);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ spin_unlock_irqrestore(&inst->lock, flags);
+
+ wake_up(&inst->kernel_event_queue);
}
+ } else {
+ dprintk(VIDC_ERR,
+ "Got SYS_ERR but unable to identify core");
}
} else {
dprintk(VIDC_ERR,
@@ -882,7 +898,7 @@
}
}
-int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type)
+static int msm_comm_scale_clocks(struct msm_vidc_core *core)
{
int num_mbs_per_sec;
int rc = 0;
@@ -896,14 +912,8 @@
rc = clk_set_rate(core->resources.clock[VCODEC_CLK].clk,
get_clock_rate(&core->resources.clock[VCODEC_CLK],
num_mbs_per_sec));
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
- goto fail_clk_set_rate;
- }
- rc = msm_comm_scale_bus(core, type);
if (rc)
- dprintk(VIDC_ERR, "Failed to scale bus bandwidth\n");
-fail_clk_set_rate:
+ dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
return rc;
}
@@ -949,6 +959,28 @@
}
}
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core = inst->core;
+ if (!inst) {
+ dprintk(VIDC_WARN, "Invalid params\n");
+ return;
+ }
+ if (msm_comm_scale_clocks(core)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale clocks. Performance might be impacted\n");
+ }
+ if (msm_comm_scale_bus(core, inst->session_type, DDR_MEM)) {
+ dprintk(VIDC_WARN,
+ "Failed to scale DDR bus. Performance might be impacted\n");
+ }
+ if (core->resources.ocmem.buf) {
+ if (msm_comm_scale_bus(core, inst->session_type, OCMEM_MEM))
+ dprintk(VIDC_WARN,
+ "Failed to scale OCMEM bus. Performance might be impacted\n");
+ }
+}
+
static int msm_comm_load_fw(struct msm_vidc_core *core)
{
int rc = 0;
@@ -956,25 +988,28 @@
dprintk(VIDC_ERR, "Invalid paramter: %p\n", core);
return -EINVAL;
}
-
if (!core->resources.fw.cookie)
core->resources.fw.cookie = subsystem_get("venus");
if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
dprintk(VIDC_ERR, "Failed to download firmware\n");
rc = -ENOMEM;
- goto fail_subsystem_get;
+ goto fail_load_fw;
}
+ /*Clocks can be enabled only after pil_get since
+ * gdsc is turned-on in pil_get*/
rc = msm_comm_enable_clks(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
goto fail_enable_clks;
}
+
rc = protect_cp_mem(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to protect memory\n");
goto fail_iommu_attach;
}
+
rc = msm_comm_iommu_attach(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to attach iommu");
@@ -986,7 +1021,7 @@
fail_enable_clks:
subsystem_put(core->resources.fw.cookie);
core->resources.fw.cookie = NULL;
-fail_subsystem_get:
+fail_load_fw:
return rc;
}
@@ -1189,16 +1224,23 @@
core->id, core->state);
goto core_already_inited;
}
- rc = msm_comm_scale_clocks(core, inst->session_type);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
- goto fail_load_fw;
- }
+
rc = msm_comm_load_fw(core);
if (rc) {
dprintk(VIDC_ERR, "Failed to load video firmware\n");
goto fail_load_fw;
}
+ rc = msm_comm_scale_clocks(core);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale clocks: %d\n", rc);
+ goto fail_core_init;
+ }
+
+ rc = msm_comm_scale_bus(core, inst->session_type, DDR_MEM);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to scale DDR bus: %d\n", rc);
+ goto fail_core_init;
+ }
init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
rc = vidc_hal_core_init(core->device,
core->resources.io_map[NS_MAP].domain);
@@ -1215,6 +1257,7 @@
return rc;
fail_core_init:
msm_comm_unload_fw(core);
+ msm_comm_unvote_buses(core, DDR_MEM);
fail_load_fw:
mutex_unlock(&core->sync_lock);
return rc;
@@ -1231,10 +1274,7 @@
core->id, core->state);
goto core_already_uninited;
}
- if (msm_comm_scale_clocks(core, inst->session_type)) {
- dprintk(VIDC_WARN, "Failed to scale clocks while closing\n");
- dprintk(VIDC_INFO, "Power might be impacted\n");
- }
+ msm_comm_scale_clocks_and_bus(inst);
if (list_empty(&core->instances)) {
msm_comm_unset_ocmem(core);
msm_comm_free_ocmem(core);
@@ -1249,6 +1289,7 @@
core->state = VIDC_CORE_UNINIT;
spin_unlock_irqrestore(&core->lock, flags);
msm_comm_unload_fw(core);
+ msm_comm_unvote_buses(core, DDR_MEM|OCMEM_MEM);
}
core_already_uninited:
change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
@@ -1367,11 +1408,18 @@
goto exit;
}
ocmem_sz = get_ocmem_requirement(inst->prop.height, inst->prop.width);
- rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
- if (rc)
- dprintk(VIDC_WARN,
+ rc = msm_comm_scale_bus(inst->core, inst->session_type, OCMEM_MEM);
+ if (!rc) {
+ rc = msm_comm_alloc_ocmem(inst->core, ocmem_sz);
+ if (rc) {
+ dprintk(VIDC_WARN,
"Failed to allocate OCMEM. Performance will be impacted\n");
-
+ msm_comm_unvote_buses(inst->core, OCMEM_MEM);
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "Failed to vote for OCMEM BW. Performance will be impacted\n");
+ }
rc = vidc_hal_session_load_res((void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 28bec97..916a3ca 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -32,7 +32,7 @@
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
-int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index e9295a6..b274d13 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -134,6 +134,11 @@
u32 freq;
};
+enum mem_type {
+ DDR_MEM = 0x1,
+ OCMEM_MEM = 0x2,
+};
+
struct core_clock {
char name[MAX_NAME_LENGTH];
struct clk *clk;
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 200f5d3..8231bd4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
+++ b/drivers/media/video/msm_vidc/vidc_hal_interrupt_handler.c
@@ -154,11 +154,14 @@
cmd_done.device_id = device->device_id;
device->callback(SYS_ERROR, &cmd_done);
}
-static void hal_process_session_error(struct hal_device *device)
+static void hal_process_session_error(struct hal_device *device,
+ struct hfi_msg_event_notify_packet *pkt)
{
struct msm_vidc_cb_cmd_done cmd_done;
memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
cmd_done.device_id = device->device_id;
+ cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+ session_id;
device->callback(SESSION_ERROR, &cmd_done);
}
static void hal_process_event_notify(struct hal_device *device,
@@ -179,7 +182,7 @@
break;
case HFI_EVENT_SESSION_ERROR:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
- hal_process_session_error(device);
+ hal_process_session_error(device, pkt);
break;
case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED");
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index c9fb721..3715417 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1566,18 +1566,18 @@
if (ret)
return -EIO;
- *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
- if (!(*handle)) {
- pr_err("failed to allocate memory for kernel client handle\n");
- return -ENOMEM;
- }
-
app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
memcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(app_ireq);
if (ret < 0)
return -EINVAL;
+ *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
+ if (!(*handle)) {
+ pr_err("failed to allocate memory for kernel client handle\n");
+ return -ENOMEM;
+ }
+
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
pr_err("kmalloc failed\n");
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 3b678c5..f310524 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -327,10 +327,15 @@
int data_inverse;
int sync_inverse;
int enable_inverse;
+ u32 tsif_irq;
/* debugfs */
struct dentry *dent_tsif;
struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
+ u32 stat_rx;
+ u32 stat_overflow;
+ u32 stat_lost_sync;
+ u32 stat_timeout;
};
enum tspp_buf_state {
@@ -480,6 +485,49 @@
dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
+
+ /*
+ * Before returning IRQ_HANDLED to the generic interrupt handling
+ * framework need to make sure all operations including clearing of
+ * interrupt status registers in the hardware is performed.
+ * Thus a barrier after clearing the interrupt status register
+ * is required to guarantee that the interrupt status register has
+ * really been cleared by the time we return from this handler.
+ */
+ wmb();
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tsif_isr(int irq, void *dev)
+{
+ struct tspp_tsif_device *tsif_device = dev;
+ u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
+
+ if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
+ TSIF_STS_CTL_OVERFLOW |
+ TSIF_STS_CTL_LOST_SYNC |
+ TSIF_STS_CTL_TIMEOUT)))
+ return IRQ_NONE;
+
+ if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
+ tsif_device->stat_overflow++;
+
+ if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
+ tsif_device->stat_lost_sync++;
+
+ if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
+ tsif_device->stat_timeout++;
+
+ iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
+
+ /*
+ * Before returning IRQ_HANDLED to the generic interrupt handling
+ * framework need to make sure all operations including clearing of
+ * interrupt status registers in the hardware is performed.
+ * Thus a barrier after clearing the interrupt status register
+ * is required to guarantee that the interrupt status register has
+ * really been cleared by the time we return from this handler.
+ */
wmb();
return IRQ_HANDLED;
}
@@ -527,6 +575,11 @@
channel->waiting->filled = iovec.size;
channel->waiting->read_index = 0;
+ if (channel->src == TSPP_SOURCE_TSIF0)
+ device->tsif[0].stat_rx++;
+ else if (channel->src == TSPP_SOURCE_TSIF1)
+ device->tsif[1].stat_rx++;
+
/* update the pointers */
channel->waiting = channel->waiting->next;
}
@@ -2326,6 +2379,31 @@
base + debugfs_tsif_regs[i].offset,
&fops_iomem_x32);
}
+
+ debugfs_create_u32(
+ "stat_rx_chunks",
+ S_IRUGO|S_IWUGO,
+ tsif_device->dent_tsif,
+ &tsif_device->stat_rx);
+
+ debugfs_create_u32(
+ "stat_overflow",
+ S_IRUGO|S_IWUGO,
+ tsif_device->dent_tsif,
+ &tsif_device->stat_overflow);
+
+ debugfs_create_u32(
+ "stat_lost_sync",
+ S_IRUGO|S_IWUGO,
+ tsif_device->dent_tsif,
+ &tsif_device->stat_lost_sync);
+
+ debugfs_create_u32(
+ "stat_timeout",
+ S_IRUGO|S_IWUGO,
+ tsif_device->dent_tsif,
+ &tsif_device->stat_timeout);
+
}
}
@@ -2504,6 +2582,21 @@
goto err_irq;
}
+ /* map TSIF IRQs */
+ device->tsif[0].tsif_irq = TSIF1_IRQ;
+ device->tsif[1].tsif_irq = TSIF2_IRQ;
+
+ for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
+ rc = request_irq(device->tsif[i].tsif_irq,
+ tsif_isr, IRQF_SHARED,
+ dev_name(&pdev->dev), &device->tsif[i]);
+ if (rc) {
+ dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
+ i, rc);
+ device->tsif[i].tsif_irq = 0;
+ }
+ }
+
/* BAM IRQ */
device->bam_irq = TSIF_BAM_IRQ;
@@ -2635,8 +2728,11 @@
sps_deregister_bam_device(device->bam_handle);
- for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+ for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
tsif_debugfs_exit(&device->tsif[i]);
+ if (device->tsif[i].tsif_irq)
+ free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
+ }
wake_lock_destroy(&device->wake_lock);
free_irq(device->tspp_irq, device);
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 33f0600..a1bea00 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -80,6 +80,7 @@
config MMC_BLOCK_TEST
tristate "MMC block test"
depends on MMC_BLOCK && IOSCHED_TEST
+ default y
help
MMC block test can be used with test iosched to test the MMC block
device.
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 35bb4ac..610a822 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -1702,6 +1702,12 @@
(bkops_stat->suspend == 0) &&
(bkops_stat->hpi == 1))
goto exit;
+ /* this might happen due to timing issues */
+ else if
+ ((bkops_stat->bkops_level[BKOPS_SEVERITY_1_INDEX] == 0) &&
+ (bkops_stat->suspend == 0) &&
+ (bkops_stat->hpi == 0))
+ goto ignore;
else
goto fail;
break;
@@ -1735,6 +1741,9 @@
exit:
return 0;
+ignore:
+ test_iosched_set_ignore_round(true);
+ return 0;
fail:
if (td->fs_wr_reqs_during_test) {
test_pr_info("%s: wr reqs during test, cancel the round",
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 81a4ba0..fd18560 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -964,10 +964,12 @@
mmc_claim_host(host);
/* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
+ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
+ sdio_reset(host);
+ mmc_go_idle(host);
err = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host));
- else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+ } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
if (err > 0) {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4f7d4c3..96234fc 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1864,9 +1864,10 @@
*/
wake_lock(&host->sdio_wlock);
} else {
- if (mmc->card && !mmc_card_sdio(mmc->card)) {
- WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
- mmc_hostname(mmc));
+ if (!mmc->card || (mmc->card &&
+ !mmc_card_sdio(mmc->card))) {
+ pr_warning("%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
+ mmc_hostname(mmc));
ret = 1;
break;
}
@@ -1898,9 +1899,10 @@
#endif
if (status & MCI_SDIOINTROPE) {
- if (mmc->card && !mmc_card_sdio(mmc->card)) {
- WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
- mmc_hostname(mmc));
+ if (!mmc->card || (mmc->card &&
+ !mmc_card_sdio(mmc->card))) {
+ pr_warning("%s: SDIO interrupt (SDIOINTROPE) received for non-SDIO card\n",
+ mmc_hostname(mmc));
ret = 1;
break;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index b92d34a..71a9860 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -566,8 +566,6 @@
void __iomem *pmu_spare_reg;
u32 reg = 0;
unsigned long flags;
- struct clk *cxo = clk_get(&penv->pdev->dev, "cxo");
- int rc = 0;
if (!enable_wcnss_suspend_notify)
return;
@@ -576,18 +574,12 @@
return;
/* For Riva */
- rc = clk_prepare_enable(cxo);
- if (rc) {
- pr_err("cxo enable failed\n");
- return;
- }
pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
spin_lock_irqsave(®_spinlock, flags);
reg = readl_relaxed(pmu_spare_reg);
reg |= RIVA_SUSPEND_BIT;
writel_relaxed(reg, pmu_spare_reg);
spin_unlock_irqrestore(®_spinlock, flags);
- clk_disable_unprepare(cxo);
}
EXPORT_SYMBOL(wcnss_suspend_notify);
@@ -596,8 +588,6 @@
void __iomem *pmu_spare_reg;
u32 reg = 0;
unsigned long flags;
- struct clk *cxo = clk_get(&penv->pdev->dev, "cxo");
- int rc = 0;
if (!enable_wcnss_suspend_notify)
return;
@@ -608,17 +598,11 @@
/* For Riva */
pmu_spare_reg = penv->msm_wcnss_base + RIVA_SPARE_OFFSET;
- rc = clk_prepare_enable(cxo);
- if (rc) {
- pr_err("cxo enable failed\n");
- return;
- }
spin_lock_irqsave(®_spinlock, flags);
reg = readl_relaxed(pmu_spare_reg);
reg &= ~RIVA_SUSPEND_BIT;
writel_relaxed(reg, pmu_spare_reg);
spin_unlock_irqrestore(®_spinlock, flags);
- clk_disable_unprepare(cxo);
}
EXPORT_SYMBOL(wcnss_resume_notify);
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index f671ece..a3bbb73 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -1005,6 +1005,8 @@
no_queue = ((options & SPS_O_NO_Q));
ack_xfers = ((options & SPS_O_ACK_TRANSFERS));
+ pipe->hybrid = options & SPS_O_HYBRID;
+
/* Create interrupt source mask */
mask = 0;
for (n = 0; n < ARRAY_SIZE(opt_event_table); n++) {
@@ -1773,7 +1775,7 @@
}
/* If pipe is polled and queue is enabled, perform polling operation */
- if (pipe->polled && !pipe->sys.no_queue)
+ if ((pipe->polled || pipe->hybrid) && !pipe->sys.no_queue)
pipe_handler_eot(dev, pipe);
/* Is there a completed descriptor? */
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 6004b75..84d2b97 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_bam.h
@@ -170,6 +170,7 @@
u32 pipe_index_mask;
u32 irq_mask;
int polled;
+ int hybrid;
u32 irq_gen_addr;
enum sps_mode mode;
u32 num_descs; /* Size (number of elements) of descriptor FIFO */
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index a2b4730..b193810 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -2690,7 +2690,9 @@
int ret = 0;
struct pm8921_soc_params raw;
+ mutex_lock(&the_chip->bms_output_lock);
read_soc_params_raw(the_chip, &raw);
+ mutex_unlock(&the_chip->bms_output_lock);
*val = 0;
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 1955ff4..3b813d8 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -1950,6 +1950,18 @@
goto error_read;
}
+ rc = qpnp_vadc_is_ready();
+ if (rc) {
+ pr_info("vadc not ready: %d, deferring probe\n", rc);
+ goto error_read;
+ }
+
+ rc = qpnp_iadc_is_ready();
+ if (rc) {
+ pr_info("iadc not ready: %d, deferring probe\n", rc);
+ goto error_read;
+ }
+
rc = set_battery_data(chip);
if (rc) {
pr_err("Bad battery data %d\n", rc);
@@ -1996,7 +2008,7 @@
vbatt = 0;
get_battery_voltage(&vbatt);
- pr_info("OK battery_capacity_at_boot=%d vbatt = %d\n",
+ pr_debug("OK battery_capacity_at_boot=%d vbatt = %d\n",
get_prop_bms_capacity(chip),
vbatt);
pr_info("probe success\n");
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index e6f5bf5..5e7ab9f 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -848,8 +848,7 @@
},
};
-#define UART_NR ARRAY_SIZE(msm_uart_ports)
-
+#define UART_NR 256
static inline struct uart_port * get_port_from_line(unsigned int line)
{
return &msm_uart_ports[line].uart;
@@ -1002,9 +1001,7 @@
struct resource *resource;
struct uart_port *port;
int irq;
-#ifdef CONFIG_SERIAL_MSM_RX_WAKEUP
struct msm_serial_platform_data *pdata = pdev->dev.platform_data;
-#endif
if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
return -ENXIO;
@@ -1057,6 +1054,8 @@
#endif
pm_runtime_enable(port->dev);
+ if (pdata != NULL && pdata->userid && pdata->userid <= UART_NR)
+ port->line = pdata->userid;
return uart_add_one_port(&msm_uart_driver, port);
}
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 8f68234..aca2af3 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
#include <mach/usbdiag.h>
@@ -427,6 +428,7 @@
struct diag_context *ctxt = ch->priv_usb;
unsigned long flags;
struct usb_request *req;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!ctxt)
return -ENODEV;
@@ -456,7 +458,9 @@
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->read_pool);
spin_unlock_irqrestore(&ctxt->lock, flags);
- ERROR(ctxt->cdev, "%s: cannot queue"
+ /* 1 error message for every 10 sec */
+ if (__ratelimit(&rl))
+ ERROR(ctxt->cdev, "%s: cannot queue"
" read request\n", __func__);
return -EIO;
}
@@ -483,6 +487,7 @@
struct diag_context *ctxt = ch->priv_usb;
unsigned long flags;
struct usb_request *req = NULL;
+ static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
if (!ctxt)
return -ENODEV;
@@ -512,7 +517,9 @@
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->write_pool);
spin_unlock_irqrestore(&ctxt->lock, flags);
- ERROR(ctxt->cdev, "%s: cannot queue"
+ /* 1 error message for every 10 sec */
+ if (__ratelimit(&rl))
+ ERROR(ctxt->cdev, "%s: cannot queue"
" read request\n", __func__);
return -EIO;
}
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index c6ffaf2..0411baa 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1407,30 +1407,37 @@
struct hdmi_disp_mode_list_type *disp_mode_list,
uint32 video_format)
{
- const struct hdmi_disp_mode_timing_type *timing =
- hdmi_common_get_supported_mode(video_format);
- boolean supported = timing != NULL;
+ const struct hdmi_disp_mode_timing_type *timing;
+ boolean supported = false;
+ boolean mhl_supported = true;
if (video_format >= HDMI_VFRMT_MAX)
return;
+ timing = hdmi_common_get_supported_mode(video_format);
+ supported = timing != NULL;
DEV_DBG("EDID: format: %d [%s], %s\n",
video_format, video_format_2string(video_format),
supported ? "Supported" : "Not-Supported");
- if (supported) {
- if (mhl_is_enabled()) {
- const struct hdmi_disp_mode_timing_type *mhl_timing =
- hdmi_mhl_get_supported_mode(video_format);
- boolean mhl_supported = mhl_timing != NULL;
- DEV_DBG("EDID: format: %d [%s], %s by MHL\n",
+
+ if (mhl_is_enabled()) {
+ const struct hdmi_disp_mode_timing_type *mhl_timing =
+ hdmi_mhl_get_supported_mode(video_format);
+ mhl_supported = mhl_timing != NULL;
+ DEV_DBG("EDID: format: %d [%s], %s by MHL\n",
video_format, video_format_2string(video_format),
- mhl_supported ? "Supported" : "Not-Supported");
- if (mhl_supported)
- disp_mode_list->disp_mode_list[
+ mhl_supported ? "Supported" : "Not-Supported");
+ }
+
+ if (supported && mhl_supported) {
+ disp_mode_list->disp_mode_list[
disp_mode_list->num_of_elements++] = video_format;
- } else
- disp_mode_list->disp_mode_list[
- disp_mode_list->num_of_elements++] = video_format;
+ if (video_format == external_common_state->video_resolution) {
+ DEV_DBG("%s: Default resolution %d [%s] supported\n",
+ __func__, video_format,
+ video_format_2string(video_format));
+ external_common_state->default_res_supported = true;
+ }
}
}
@@ -1866,6 +1873,7 @@
memset(&external_common_state->disp_mode_list, 0,
sizeof(external_common_state->disp_mode_list));
memset(edid_buf, 0, sizeof(edid_buf));
+ external_common_state->default_res_supported = false;
status = hdmi_common_read_edid_block(0, edid_buf);
if (status || !check_edid_header(edid_buf)) {
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index 768e550..70a99ee 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -210,6 +210,7 @@
boolean hpd_state;
struct kobject *uevent_kobj;
uint32 video_resolution;
+ boolean default_res_supported;
struct device *dev;
struct switch_dev sdev;
struct switch_dev audio_sdev;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 9efb898..516c92c 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -785,8 +785,8 @@
/* Build EDID table */
hdmi_msm_read_edid();
switch_set_state(&external_common_state->sdev, 1);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
+ DEV_INFO("%s: hdmi state switched to %d\n", __func__,
+ external_common_state->sdev.state);
DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE);
@@ -800,8 +800,8 @@
}
} else {
switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("hdmi: Hdmi state switch to %d: %s\n",
- external_common_state->sdev.state, __func__);
+ DEV_INFO("%s: hdmi state switch to %d\n", __func__,
+ external_common_state->sdev.state);
DEV_INFO("hdmi: HDMI HPD: sense DISCONNECTED: send OFFLINE\n");
kobject_uevent(external_common_state->uevent_kobj,
KOBJ_OFFLINE);
@@ -929,10 +929,6 @@
DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
link_status);
if (hdmi_msm_state->full_auth_done) {
- switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
-
SWITCH_SET_HDMI_AUDIO(0, 0);
envp[0] = "HDCP_STATE=FAIL";
@@ -3016,9 +3012,6 @@
SWITCH_SET_HDMI_AUDIO(1, 0);
}
- switch_set_state(&external_common_state->sdev, 1);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
return;
error:
@@ -3038,9 +3031,6 @@
mutex_lock(&hdmi_msm_state_mutex);
hdmi_msm_state->hdcp_activating = FALSE;
mutex_unlock(&hdmi_msm_state_mutex);
- switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
}
static void hdmi_msm_video_setup(int video_format)
@@ -4345,32 +4335,40 @@
DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres,
mfd->var_pixclock);
+ /* Only start transmission with supported resolution */
changed = hdmi_common_get_video_format_from_drv_data(mfd);
- hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE);
+ if (changed || external_common_state->default_res_supported) {
+ hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE);
+ mutex_lock(&external_common_state_hpd_mutex);
+ hdmi_msm_state->panel_power_on = TRUE;
+ if (external_common_state->hpd_state &&
+ hdmi_msm_is_power_on()) {
+ DEV_DBG("%s: Turning HDMI on\n", __func__);
+ mutex_unlock(&external_common_state_hpd_mutex);
+ hdmi_msm_turn_on();
- mutex_lock(&external_common_state_hpd_mutex);
- hdmi_msm_state->panel_power_on = TRUE;
- if (external_common_state->hpd_state && hdmi_msm_is_power_on()) {
- DEV_DBG("%s: Turning HDMI on\n", __func__);
- mutex_unlock(&external_common_state_hpd_mutex);
- hdmi_msm_turn_on();
-
- if (hdmi_msm_state->hdcp_enable) {
- /* Kick off HDCP Authentication */
- mutex_lock(&hdcp_auth_state_mutex);
- hdmi_msm_state->reauth = FALSE;
- hdmi_msm_state->full_auth_done = FALSE;
- mutex_unlock(&hdcp_auth_state_mutex);
- mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
+ if (hdmi_msm_state->hdcp_enable) {
+ /* Kick off HDCP Authentication */
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->reauth = FALSE;
+ hdmi_msm_state->full_auth_done = FALSE;
+ mutex_unlock(&hdcp_auth_state_mutex);
+ mod_timer(&hdmi_msm_state->hdcp_timer,
+ jiffies + HZ/2);
+ }
+ } else {
+ mutex_unlock(&external_common_state_hpd_mutex);
}
- } else
- mutex_unlock(&external_common_state_hpd_mutex);
- hdmi_msm_dump_regs("HDMI-ON: ");
-
- DEV_INFO("power=%s DVI= %s\n",
- hdmi_msm_is_power_on() ? "ON" : "OFF" ,
- hdmi_msm_is_dvi_mode() ? "ON" : "OFF");
+ hdmi_msm_dump_regs("HDMI-ON: ");
+ DEV_INFO("power=%s DVI= %s\n",
+ hdmi_msm_is_power_on() ? "ON" : "OFF" ,
+ hdmi_msm_is_dvi_mode() ? "ON" : "OFF");
+ } else {
+ DEV_ERR("%s: Video fmt %d not supp. Returning\n",
+ __func__,
+ external_common_state->video_resolution);
+ }
/* Enable HPD interrupt and listen to disconnect interrupts */
hdmi_msm_hpd_polarity_setup(HPD_DISCONNECT_POLARITY,
@@ -4383,9 +4381,6 @@
char *envp[2];
/* Simulating a HPD event based on MHL event */
- switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
if (on) {
hdmi_msm_read_edid();
hdmi_msm_state->reauth = FALSE ;
@@ -4403,8 +4398,8 @@
kobject_uevent_env(external_common_state->uevent_kobj,
KOBJ_CHANGE, envp);
switch_set_state(&external_common_state->sdev, 1);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
+ DEV_INFO("%s: hdmi state switched to %d\n",
+ __func__, external_common_state->sdev.state);
} else {
hdmi_msm_hdcp_enable();
}
@@ -4413,8 +4408,8 @@
kobject_uevent(external_common_state->uevent_kobj,
KOBJ_OFFLINE);
switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
+ DEV_INFO("%s: hdmi state switched to %d\n", __func__,
+ external_common_state->sdev.state);
}
}
EXPORT_SYMBOL(mhl_connect_api);
@@ -4741,6 +4736,8 @@
/* Set HDMI switch node to 0 on HPD feature disable */
switch_set_state(&external_common_state->sdev, 0);
+ DEV_INFO("%s: hdmi state switched to %d\n", __func__,
+ external_common_state->sdev.state);
}
return rc;
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 6edc9f2..ee2405e 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -28,6 +28,8 @@
extern char *mmss_cc_base; /* mutimedia sub system clock control */
extern spinlock_t dsi_clk_lock;
extern u32 mdp_max_clk;
+extern u32 dbg_force_ov0_blt;
+extern u32 dbg_force_ov1_blt;
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 59565c1..05344fc 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2895,8 +2895,9 @@
perf_req->mdp_bw);
perf_cur->mdp_bw = perf_req->mdp_bw;
}
- if (mfd->panel_info.pdest == DISPLAY_1 &&
- perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_1 &&
+ perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) ||
+ dbg_force_ov0_blt) {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
mdp4_lcdc_overlay_blt_start(mfd);
@@ -2906,17 +2907,18 @@
mdp4_dsi_cmd_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
mdp4_mddi_blt_start(mfd);
- pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer0 start blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov0_blt,
perf_req->use_ov0_blt);
perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
}
- if (mfd->panel_info.pdest == DISPLAY_2 &&
- perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_2 &&
+ perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) ||
+ dbg_force_ov1_blt) {
mdp4_dtv_overlay_blt_start(mfd);
- pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer1 start blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov1_blt,
@@ -2945,8 +2947,9 @@
perf_req->mdp_bw);
perf_cur->mdp_bw = perf_req->mdp_bw;
}
- if (mfd->panel_info.pdest == DISPLAY_1 &&
- !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_1 &&
+ !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) ||
+ dbg_force_ov0_blt) {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
mdp4_lcdc_overlay_blt_stop(mfd);
@@ -2956,17 +2959,18 @@
mdp4_dsi_cmd_blt_stop(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
mdp4_mddi_blt_stop(mfd);
- pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer0 stop blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov0_blt,
perf_req->use_ov0_blt);
perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
}
- if (mfd->panel_info.pdest == DISPLAY_2 &&
- !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+ if ((mfd->panel_info.pdest == DISPLAY_2 &&
+ !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) ||
+ dbg_force_ov1_blt) {
mdp4_dtv_overlay_blt_stop(mfd);
- pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+ pr_debug("%s mixer1 stop blt [%d] from %d to %d.\n",
__func__,
flag,
perf_cur->use_ov1_blt,
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 54f5ef5..767375d 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -1029,6 +1029,135 @@
.write = dbg_reg_write,
};
+u32 dbg_force_ov0_blt;
+u32 dbg_force_ov1_blt;
+
+static ssize_t dbg_force_ov0_blt_read(
+ struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos) {
+ int len;
+
+ if (*ppos)
+ return 0;
+
+ len = snprintf(debug_buf, sizeof(debug_buf),
+ "%d\n", dbg_force_ov0_blt);
+
+ if (len < 0)
+ return 0;
+
+ if (copy_to_user(buff, debug_buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+
+ return len;
+}
+
+static ssize_t dbg_force_ov0_blt_write(
+ struct file *file,
+ const char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ u32 cnt;
+
+ if (count >= sizeof(debug_buf))
+ return -EFAULT;
+
+ if (copy_from_user(debug_buf, buff, count))
+ return -EFAULT;
+
+ debug_buf[count] = 0; /* end of string */
+
+ cnt = sscanf(debug_buf, "%x", &dbg_force_ov0_blt);
+
+ pr_info("%s: dbg_force_ov0_blt = %x\n",
+ __func__, dbg_force_ov0_blt);
+
+ if ((dbg_force_ov0_blt & 0x0f) > 2)
+ pr_err("%s: invalid dbg_force_ov0_blt = %d\n",
+ __func__, dbg_force_ov0_blt);
+
+ if ((dbg_force_ov0_blt >> 4) > 2)
+ pr_err("%s: invalid dbg_force_ov0_blt = %d\n",
+ __func__, dbg_force_ov0_blt);
+
+ return count;
+}
+
+static const struct file_operations dbg_force_ov0_blt_fops = {
+ .open = dbg_open,
+ .release = dbg_release,
+ .read = dbg_force_ov0_blt_read,
+ .write = dbg_force_ov0_blt_write,
+};
+
+static ssize_t dbg_force_ov1_blt_read(
+ struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos) {
+ int len;
+
+ if (*ppos)
+ return 0;
+
+ len = snprintf(debug_buf, sizeof(debug_buf),
+ "%x\n", dbg_force_ov1_blt);
+
+ if (len < 0)
+ return 0;
+
+ if (copy_to_user(buff, debug_buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+
+ return len;
+}
+
+static ssize_t dbg_force_ov1_blt_write(
+ struct file *file,
+ const char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ u32 cnt;
+
+ if (count >= sizeof(debug_buf))
+ return -EFAULT;
+
+ if (copy_from_user(debug_buf, buff, count))
+ return -EFAULT;
+
+ debug_buf[count] = 0; /* end of string */
+
+ cnt = sscanf(debug_buf, "%x", &dbg_force_ov1_blt);
+
+ pr_info("%s: dbg_force_ov1_blt = %x\n",
+ __func__, dbg_force_ov1_blt);
+
+ if ((dbg_force_ov1_blt & 0x0f) > 2)
+ pr_err("%s: invalid dbg_force_ov1_blt = %x\n",
+ __func__, dbg_force_ov1_blt);
+
+ if ((dbg_force_ov1_blt >> 4) > 2)
+ pr_err("%s: invalid dbg_force_ov1_blt = %d\n",
+ __func__, dbg_force_ov1_blt);
+
+ return count;
+}
+
+static const struct file_operations dbg_force_ov1_blt_fops = {
+ .open = dbg_open,
+ .release = dbg_release,
+ .read = dbg_force_ov1_blt_read,
+ .write = dbg_force_ov1_blt_write,
+};
+
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
static uint32 hdmi_offset;
static uint32 hdmi_count;
@@ -1249,6 +1378,22 @@
}
#endif
+ if (debugfs_create_file("force_ov0_blt", 0644, dent, 0,
+ &dbg_force_ov0_blt_fops)
+ == NULL) {
+ pr_err("%s(%d): debugfs_create_file: debug fail\n",
+ __FILE__, __LINE__);
+ return -EFAULT;
+ }
+
+ if (debugfs_create_file("force_ov1_blt", 0644, dent, 0,
+ &dbg_force_ov1_blt_fops)
+ == NULL) {
+ pr_err("%s(%d): debugfs_create_file: debug fail\n",
+ __FILE__, __LINE__);
+ return -EFAULT;
+ }
+
dent = debugfs_create_dir("mddi", NULL);
if (IS_ERR(dent)) {
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 98cce5b..29546b7 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -445,4 +445,5 @@
header-y += genlock.h
header-y += msm_audio_amrwb.h
header-y += coresight-stm.h
-header-y += ci-bridge-spi.h
\ No newline at end of file
+header-y += ci-bridge-spi.h
+header-y += msm_audio_amrwbplus.h
diff --git a/include/linux/msm_audio_amrwbplus.h b/include/linux/msm_audio_amrwbplus.h
new file mode 100644
index 0000000..aa17117
--- /dev/null
+++ b/include/linux/msm_audio_amrwbplus.h
@@ -0,0 +1,18 @@
+#ifndef __MSM_AUDIO_AMR_WB_PLUS_H
+#define __MSM_AUDIO_AMR_WB_PLUS_H
+
+#define AUDIO_GET_AMRWBPLUS_CONFIG_V2 _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+2), struct msm_audio_amrwbplus_config_v2)
+#define AUDIO_SET_AMRWBPLUS_CONFIG_V2 _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+3), struct msm_audio_amrwbplus_config_v2)
+
+struct msm_audio_amrwbplus_config_v2 {
+ unsigned int size_bytes;
+ unsigned int version;
+ unsigned int num_channels;
+ unsigned int amr_band_mode;
+ unsigned int amr_dtx_mode;
+ unsigned int amr_frame_fmt;
+ unsigned int amr_lsf_idx;
+};
+#endif /* __MSM_AUDIO_AMR_WB_PLUS_H */
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 077ccfc..fc34b22 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -402,8 +402,11 @@
};
/**
- * enum qpnp_adc_meas_timer - Selects the measurement interval time.
+ * enum qpnp_adc_meas_timer_1 - Selects the measurement interval time.
* If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * The timer period is used by the USB_ID. Do not set a polling rate
+ * greater than 1 second on PMIC 2.0. The max polling rate on the PMIC 2.0
+ * appears to be limited to 1 second.
* %ADC_MEAS_INTERVAL_0MS : 0ms
* %ADC_MEAS_INTERVAL_1P0MS : 1ms
* %ADC_MEAS_INTERVAL_2P0MS : 2ms
@@ -421,24 +424,126 @@
* %ADC_MEAS_INTERVAL_8S : 8seconds
* %ADC_MEAS_INTERVAL_16S: 16seconds
*/
-enum qpnp_adc_meas_timer {
- ADC_MEAS_INTERVAL_0MS = 0,
- ADC_MEAS_INTERVAL_1P0MS,
- ADC_MEAS_INTERVAL_2P0MS,
- ADC_MEAS_INTERVAL_3P9MS,
- ADC_MEAS_INTERVAL_7P8MS,
- ADC_MEAS_INTERVAL_15P6MS,
- ADC_MEAS_INTERVAL_31P3MS,
- ADC_MEAS_INTERVAL_62P5MS,
- ADC_MEAS_INTERVAL_125MS,
- ADC_MEAS_INTERVAL_250MS,
- ADC_MEAS_INTERVAL_500MS,
- ADC_MEAS_INTERVAL_1S,
- ADC_MEAS_INTERVAL_2S,
- ADC_MEAS_INTERVAL_4S,
- ADC_MEAS_INTERVAL_8S,
- ADC_MEAS_INTERVAL_16S,
- ADC_MEAS_INTERVAL_NONE,
+enum qpnp_adc_meas_timer_1 {
+ ADC_MEAS1_INTERVAL_0MS = 0,
+ ADC_MEAS1_INTERVAL_1P0MS,
+ ADC_MEAS1_INTERVAL_2P0MS,
+ ADC_MEAS1_INTERVAL_3P9MS,
+ ADC_MEAS1_INTERVAL_7P8MS,
+ ADC_MEAS1_INTERVAL_15P6MS,
+ ADC_MEAS1_INTERVAL_31P3MS,
+ ADC_MEAS1_INTERVAL_62P5MS,
+ ADC_MEAS1_INTERVAL_125MS,
+ ADC_MEAS1_INTERVAL_250MS,
+ ADC_MEAS1_INTERVAL_500MS,
+ ADC_MEAS1_INTERVAL_1S,
+ ADC_MEAS1_INTERVAL_2S,
+ ADC_MEAS1_INTERVAL_4S,
+ ADC_MEAS1_INTERVAL_8S,
+ ADC_MEAS1_INTERVAL_16S,
+ ADC_MEAS1_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_2 - Selects the measurement interval time.
+ * If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * The timer period is used by the batt_therm. Do not set a polling rate
+ * greater than 1 second on PMIC 2.0. The max polling rate on the PMIC 2.0
+ * appears to be limited to 1 second.
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_100MS : 100ms
+ * %ADC_MEAS_INTERVAL_200MS : 200ms
+ * %ADC_MEAS_INTERVAL_300MS : 300ms
+ * %ADC_MEAS_INTERVAL_400MS : 400ms
+ * %ADC_MEAS_INTERVAL_500MS : 500ms
+ * %ADC_MEAS_INTERVAL_600MS : 600ms
+ * %ADC_MEAS_INTERVAL_700MS : 700ms
+ * %ADC_MEAS_INTERVAL_800MS : 800ms
+ * %ADC_MEAS_INTERVAL_900MS : 900ms
+ * %ADC_MEAS_INTERVAL_1S: 1seconds
+ * %ADC_MEAS_INTERVAL_1P1S: 1.1seconds
+ * %ADC_MEAS_INTERVAL_1P2S: 1.2seconds
+ * %ADC_MEAS_INTERVAL_1P3S: 1.3seconds
+ * %ADC_MEAS_INTERVAL_1P4S: 1.4seconds
+ * %ADC_MEAS_INTERVAL_1P5S: 1.5seconds
+ */
+enum qpnp_adc_meas_timer_2 {
+ ADC_MEAS2_INTERVAL_0MS = 0,
+ ADC_MEAS2_INTERVAL_100MS,
+ ADC_MEAS2_INTERVAL_200MS,
+ ADC_MEAS2_INTERVAL_300MS,
+ ADC_MEAS2_INTERVAL_400MS,
+ ADC_MEAS2_INTERVAL_500MS,
+ ADC_MEAS2_INTERVAL_600MS,
+ ADC_MEAS2_INTERVAL_700MS,
+ ADC_MEAS2_INTERVAL_800MS,
+ ADC_MEAS2_INTERVAL_900MS,
+ ADC_MEAS2_INTERVAL_1S,
+ ADC_MEAS2_INTERVAL_1P1S,
+ ADC_MEAS2_INTERVAL_1P2S,
+ ADC_MEAS2_INTERVAL_1P3S,
+ ADC_MEAS2_INTERVAL_1P4S,
+ ADC_MEAS2_INTERVAL_1P5S,
+ ADC_MEAS2_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_3 - Selects the measurement interval time.
+ * If value = 0, use 0ms else use 2^(value + 4)/ 32768).
+ * Do not set a polling rate greater than 1 second on PMIC 2.0.
+ * The max polling rate on the PMIC 2.0 appears to be limited to 1 second.
+ * %ADC_MEAS_INTERVAL_0MS : 0ms
+ * %ADC_MEAS_INTERVAL_1S : 1seconds
+ * %ADC_MEAS_INTERVAL_2S : 2seconds
+ * %ADC_MEAS_INTERVAL_3S : 3seconds
+ * %ADC_MEAS_INTERVAL_4S : 4seconds
+ * %ADC_MEAS_INTERVAL_5S : 5seconds
+ * %ADC_MEAS_INTERVAL_6S: 6seconds
+ * %ADC_MEAS_INTERVAL_7S : 7seconds
+ * %ADC_MEAS_INTERVAL_8S : 8seconds
+ * %ADC_MEAS_INTERVAL_9S : 9seconds
+ * %ADC_MEAS_INTERVAL_10S : 10seconds
+ * %ADC_MEAS_INTERVAL_11S : 11seconds
+ * %ADC_MEAS_INTERVAL_12S : 12seconds
+ * %ADC_MEAS_INTERVAL_13S : 13seconds
+ * %ADC_MEAS_INTERVAL_14S : 14seconds
+ * %ADC_MEAS_INTERVAL_15S : 15seconds
+ */
+enum qpnp_adc_meas_timer_3 {
+ ADC_MEAS3_INTERVAL_0S = 0,
+ ADC_MEAS3_INTERVAL_1S,
+ ADC_MEAS3_INTERVAL_2S,
+ ADC_MEAS3_INTERVAL_3S,
+ ADC_MEAS3_INTERVAL_4S,
+ ADC_MEAS3_INTERVAL_5S,
+ ADC_MEAS3_INTERVAL_6S,
+ ADC_MEAS3_INTERVAL_7S,
+ ADC_MEAS3_INTERVAL_8S,
+ ADC_MEAS3_INTERVAL_9S,
+ ADC_MEAS3_INTERVAL_10S,
+ ADC_MEAS3_INTERVAL_11S,
+ ADC_MEAS3_INTERVAL_12S,
+ ADC_MEAS3_INTERVAL_13S,
+ ADC_MEAS3_INTERVAL_14S,
+ ADC_MEAS3_INTERVAL_15S,
+ ADC_MEAS3_INTERVAL_NONE,
+};
+
+/**
+ * enum qpnp_adc_meas_timer_select - Selects the timer for which
+ * the appropriate polling frequency is set.
+ * %ADC_MEAS_TIMER_SELECT1 - Select this timer if the client is USB_ID.
+ * %ADC_MEAS_TIMER_SELECT2 - Select this timer if the client is batt_therm.
+ * %ADC_MEAS_TIMER_SELECT3 - The timer is added only for completion. It is
+ * not used by kernel space clients and user space clients cannot set
+ * the polling frequency. The driver will set a appropriate polling
+ * frequency to measure the user space clients from qpnp_adc_meas_timer_3.
+ */
+enum qpnp_adc_meas_timer_select {
+ ADC_MEAS_TIMER_SELECT1 = 0,
+ ADC_MEAS_TIMER_SELECT2,
+ ADC_MEAS_TIMER_SELECT3,
+ ADC_MEAS_TIMER_NUM,
};
/**
@@ -455,6 +560,134 @@
};
/**
+ * Channel selection registers for each of the 5 configurable measurements
+ * Channels allotment is fixed for the given channels below.
+ * The USB_ID and BATT_THERM channels are used only by the kernel space
+ * USB and Battery drivers.
+ * The other 3 channels are configurable for use by userspace clients.
+ * USB_ID uses QPNP_ADC_TM_M0_ADC_CH_SEL_CTL
+ * BATT_TEMP uses QPNP_ADC_TM_M1_ADC_CH_SEL_CTL
+ * PA_THERM1 uses QPNP_ADC_TM_M2_ADC_CH_SEL_CTL
+ * PA_THERM2 uses QPNP_ADC_TM_M3_ADC_CH_SEL_CTL
+ * EMMC_THERM uses QPNP_ADC_TM_M4_ADC_CH_SEL_CTL
+ */
+enum qpnp_adc_tm_channel_select {
+ QPNP_ADC_TM_M0_ADC_CH_SEL_CTL = 0x48,
+ QPNP_ADC_TM_M1_ADC_CH_SEL_CTL = 0x68,
+ QPNP_ADC_TM_M2_ADC_CH_SEL_CTL = 0x70,
+ QPNP_ADC_TM_M3_ADC_CH_SEL_CTL = 0x78,
+ QPNP_ADC_TM_M4_ADC_CH_SEL_CTL = 0x80,
+ QPNP_ADC_TM_CH_SELECT_NONE
+};
+
+/**
+ * struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
+ * @channel: ADC channel for which thermal monitoring is requested.
+ * @adc_code: The pre-calibrated digital output of a given ADC releative to the
+ * ADC reference.
+ * @high_thr_temp: Temperature at which high threshold notification is required.
+ * @low_thr_temp: Temperature at which low threshold notification is required.
+ * @low_thr_voltage : Low threshold voltage ADC code used for reverse
+ * calibration.
+ * @high_thr_voltage: High threshold voltage ADC code used for reverse
+ * calibration.
+ */
+struct qpnp_adc_tm_config {
+ int channel;
+ int adc_code;
+ int high_thr_temp;
+ int low_thr_temp;
+ int64_t high_thr_voltage;
+ int64_t low_thr_voltage;
+};
+
+/**
+ * enum qpnp_adc_tm_trip_type - Type for setting high/low temperature/voltage.
+ * %ADC_TM_TRIP_HIGH_WARM: Setting high temperature. Note that high temperature
+ * corresponds to low voltage. Driver handles this case
+ * appropriately to set high/low thresholds for voltage.
+ * threshold.
+ * %ADC_TM_TRIP_LOW_COOL: Setting low temperature.
+ */
+enum qpnp_adc_tm_trip_type {
+ ADC_TM_TRIP_HIGH_WARM = 0,
+ ADC_TM_TRIP_LOW_COOL,
+ ADC_TM_TRIP_NUM,
+};
+
+/**
+ * enum qpnp_tm_state - This lets the client know whether the threshold
+ * that was crossed was high/low.
+ * %ADC_TM_HIGH_STATE: Client is notified of crossing the requested high
+ * threshold.
+ * %ADC_TM_LOW_STATE: Client is notified of crossing the requested low
+ * threshold.
+ */
+enum qpnp_tm_state {
+ ADC_TM_HIGH_STATE = 0,
+ ADC_TM_LOW_STATE,
+ ADC_TM_STATE_NUM,
+};
+
+/**
+ * enum qpnp_state_request - Request to enable/disable the corresponding
+ * high/low voltage/temperature thresholds.
+ * %ADC_TM_HIGH_THR_ENABLE: Enable high voltage/temperature threshold.
+ * %ADC_TM_LOW_THR_ENABLE: Enable low voltage/temperature threshold.
+ * %ADC_TM_HIGH_LOW_THR_ENABLE: Enable high and low voltage/temperature
+ * threshold.
+ * %ADC_TM_HIGH_THR_DISABLE: Disable high voltage/temperature threshold.
+ * %ADC_TM_LOW_THR_DISABLE: Disable low voltage/temperature threshold.
+ * %ADC_TM_HIGH_THR_DISABLE: Disable high and low voltage/temperature
+ * threshold.
+ */
+enum qpnp_state_request {
+ ADC_TM_HIGH_THR_ENABLE = 0,
+ ADC_TM_LOW_THR_ENABLE,
+ ADC_TM_HIGH_LOW_THR_ENABLE,
+ ADC_TM_HIGH_THR_DISABLE,
+ ADC_TM_LOW_THR_DISABLE,
+ ADC_TM_HIGH_LOW_THR_DISABLE,
+ ADC_TM_THR_NUM,
+};
+
+/**
+ * struct qpnp_adc_tm_usbid_param - Represent USB_ID threshold
+ * monitoring configuration.
+ * @high_thr: High voltage threshold for which notification is requested.
+ * @low_thr: Low voltage threshold for which notification is requested.
+ * @state_request: Enable/disable the corresponding high and low voltage
+ * thresholds.
+ * @timer_interval: Select polling rate from qpnp_adc_meas_timer_1 type.
+ * @threshold_notification: Notification callback once threshold are crossed.
+ */
+struct qpnp_adc_tm_usbid_param {
+ int32_t high_thr;
+ int32_t low_thr;
+ enum qpnp_state_request state_request;
+ enum qpnp_adc_meas_timer_1 timer_interval;
+ void (*threshold_notification) (enum qpnp_tm_state state);
+};
+
+/**
+ * struct qpnp_adc_tm_btm_param - Represent Battery temperature threshold
+ * monitoring configuration.
+ * @high_temp: High temperature threshold for which notification is requested.
+ * @low_temp: Low temperature threshold for which notification is requested.
+ * @state_request: Enable/disable the corresponding high and low temperature
+ * thresholds.
+ * @timer_interval: Select polling rate from qpnp_adc_meas_timer_2 type.
+ * @threshold_notification: Notification callback once threshold are crossed.
+ */
+struct qpnp_adc_tm_btm_param {
+ int32_t high_temp;
+ int32_t low_temp;
+ enum qpnp_state_request state_request;
+ enum qpnp_adc_meas_timer_2 timer_interval;
+ void (*threshold_notification) (enum qpnp_tm_state state);
+};
+
+/**
* struct qpnp_vadc_linear_graph - Represent ADC characteristics.
* @dy: Numerator slope to calculate the gain.
* @dx: Denominator slope to calculate the gain.
@@ -541,7 +774,7 @@
};
/**
- * struct qpnp_adc_amux - AMUX properties for individual channel
+ * struct qpnp_vadc_amux - AMUX properties for individual channel
* @name: Channel string name.
* @channel_num: Channel in integer used from qpnp_adc_channels.
* @chan_path_prescaling: Channel scaling performed on the input signal.
@@ -624,7 +857,7 @@
* @adc_prop - ADC properties specific to the ADC peripheral.
* @amux_prop - AMUX properties representing the ADC peripheral.
* @adc_channels - ADC channel properties for the ADC peripheral.
- * @adc_irq - IRQ number that is mapped to the ADC peripheral.
+ * @adc_irq_eoc - End of Conversion IRQ.
* @adc_lock - ADC lock for access to the peripheral.
* @adc_rslt_completion - ADC result notification after interrupt
* is received.
@@ -637,7 +870,7 @@
struct qpnp_adc_properties *adc_prop;
struct qpnp_adc_amux_properties *amux_prop;
struct qpnp_vadc_amux *adc_channels;
- int adc_irq;
+ int adc_irq_eoc;
struct mutex adc_lock;
struct completion adc_rslt_completion;
struct qpnp_iadc_calib calib;
@@ -828,6 +1061,70 @@
* has not occured.
*/
int32_t qpnp_vadc_is_ready(void);
+/**
+ * qpnp_adc_tm_scaler() - Performs reverse calibration.
+ * @config: Thermal monitoring configuration.
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution and
+ * reference voltage.
+ * @chan_prop: Individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ */
+static inline int32_t qpnp_adc_tm_scaler(struct qpnp_adc_tm_config *tm_config,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop)
+{ return -ENXIO; }
+/**
+ * qpnp_get_vadc_gain_and_offset() - Obtains the VADC gain and offset
+ * for absolute and ratiometric calibration.
+ * @param: The result in which the ADC offset and gain values are stored.
+ * @type: The calibration type whether client needs the absolute or
+ * ratiometric gain and offset values.
+ */
+int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_linear_graph *param,
+ enum qpnp_adc_calib_type calib_type);
+/**
+ * qpnp_adc_btm_scaler() - Performs reverse calibration on the low/high
+ * temperature threshold values passed by the client.
+ * The function maps the temperature to voltage and applies
+ * ratiometric calibration on the voltage values.
+ * @param: The input parameters that contain the low/high temperature
+ * values.
+ * @low_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ * @high_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ */
+int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold);
+/**
+ * qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
+ * and convert given temperature to voltage on supported
+ * thermistor channels using 100k pull-up.
+ * @param: The input temperature values.
+ */
+int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param);
+/**
+ * qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
+ * and converts the given ADC code to temperature for
+ * thermistor channels using 100k pull-up.
+ * @reg: The input ADC code.
+ * @result: The physical measurement temperature on the thermistor.
+ */
+int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result);
+/**
+ * qpnp_adc_usb_scaler() - Performs reverse calibration on the low/high
+ * voltage threshold values passed by the client.
+ * The function applies ratiometric calibration on the
+ * voltage values.
+ * @param: The input parameters that contain the low/high voltage
+ * threshold values.
+ * @low_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ * @high_threshold: The low threshold value that needs to be updated with
+ * the above calibrated voltage value.
+ */
+int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold);
#else
static inline int32_t qpnp_vadc_read(uint32_t channel,
struct qpnp_vadc_result *result)
@@ -874,6 +1171,29 @@
{ return -ENXIO; }
static inline int32_t qpnp_vadc_is_ready(void)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_default(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_adc_chan_properties *chan_prop,
+ struct qpnp_adc_chan_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_get_vadc_gain_and_offset(
+ struct qpnp_vadc_linear_graph *param,
+ enum qpnp_adc_calib_type calib_type)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_usb_scaler(
+ struct qpnp_adc_tm_usbid_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_btm_scaler(
+ struct qpnp_adc_tm_btm_param *param,
+ uint32_t *low_threshold, uint32_t *high_threshold)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_scale_therm_voltage_pu2(
+ struct qpnp_adc_tm_config *param)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2(
+ uint32_t reg, int64_t *result)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4376ece..3dd0ccd 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -712,8 +712,8 @@
#define AFE_PORT_ID_PRIMARY_MI2S_TX 0x1001
#define AFE_PORT_ID_SECONDARY_MI2S_RX 0x1002
#define AFE_PORT_ID_SECONDARY_MI2S_TX 0x1003
-#define AFE_PORT_IDERTIARY_MI2S_RX 0x1004
-#define AFE_PORT_IDERTIARY_MI2S_TX 0x1005
+#define AFE_PORT_ID_TERTIARY_MI2S_RX 0x1004
+#define AFE_PORT_ID_TERTIARY_MI2S_TX 0x1005
#define AFE_PORT_ID_QUATERNARY_MI2S_RX 0x1006
#define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007
#define AUDIO_PORT_ID_I2S_RX 0x1008
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 6c60318..4ecd435 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -20,10 +20,11 @@
#define MSM_MI2S_SD3 (1 << 3)
#define MSM_MI2S_CAP_RX 0
#define MSM_MI2S_CAP_TX 1
+
#define MSM_PRIM_MI2S 0
#define MSM_SEC_MI2S 1
#define MSM_TERT_MI2S 2
-#define MSM_QUAD_MI2S 3
+#define MSM_QUAT_MI2S 3
struct msm_dai_auxpcm_pdata {
const char *clk;
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index cb2f3d7..9c43d09 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -16,13 +16,13 @@
#define ADM_PATH_PLAYBACK 0x1
#define ADM_PATH_LIVE_REC 0x2
#define ADM_PATH_NONLIVE_REC 0x3
+#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
-#define Q6_AFE_MAX_PORTS 32
/* multiple copp per stream. */
struct route_payload {
- unsigned int copp_ids[Q6_AFE_MAX_PORTS];
+ unsigned int copp_ids[AFE_MAX_PORTS];
unsigned short num_copps;
unsigned int session_id;
};
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 1324f8a..444b432 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -71,6 +71,8 @@
IDX_INT_FM_TX = 29,
IDX_RT_PROXY_PORT_001_RX = 30,
IDX_RT_PROXY_PORT_001_TX = 31,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX = 32,
+ IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX = 33,
AFE_MAX_PORTS
};
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 9c1aef2..e11b985 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -3035,7 +3035,7 @@
msecs_to_jiffies(300));
}
/* apply the digital gain after the decimator is enabled*/
- if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+ if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
snd_soc_write(codec,
tx_digital_gain_reg[w->shift + offset],
snd_soc_read(codec,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index a27dc48..5ffb60a 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -2247,7 +2247,7 @@
msecs_to_jiffies(300));
}
/* apply the digital gain after the decimator is enabled*/
- if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+ if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
snd_soc_write(codec,
tx_digital_gain_reg[w->shift + offset],
snd_soc_read(codec,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index cde5b02..1dfa605 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1765,6 +1765,9 @@
case FORMAT_AMRWB:
open.write_format = AMRWB_FS;
break;
+ case FORMAT_AMR_WB_PLUS:
+ open.write_format = AMR_WB_PLUS;
+ break;
case FORMAT_V13K:
open.write_format = V13K_FS;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 621d24b..a307bcc 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1310,6 +1310,16 @@
switch (mi2s_id) {
case MSM_PRIM_MI2S:
*port_id = MI2S_RX;
+ break;
+ case MSM_SEC_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
+ break;
+ case MSM_TERT_MI2S:
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_RX;
+ break;
+ case MSM_QUAT_MI2S:
+ *port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ break;
break;
default:
ret = -1;
@@ -1320,7 +1330,16 @@
switch (mi2s_id) {
case MSM_PRIM_MI2S:
*port_id = MI2S_TX;
- break;
+ break;
+ case MSM_SEC_MI2S:
+ *port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
+ break;
+ case MSM_TERT_MI2S:
+ *port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ break;
+ case MSM_QUAT_MI2S:
+ *port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ break;
default:
ret = -1;
break;
@@ -1330,7 +1349,7 @@
ret = -1;
break;
}
- pr_debug("%s: port_id = %x\n", __func__, *port_id);
+ pr_debug("%s: port_id = %#x\n", __func__, *port_id);
return ret;
}
@@ -1346,15 +1365,17 @@
u16 port_id = 0;
int rc = 0;
- dev_dbg(dai->dev, "%s: device name %s dai id %x,port id = %x\n",
- __func__, dai->name, dai->id, port_id);
-
if (msm_mi2s_get_port_id(dai->id, substream->stream,
&port_id) != 0) {
- dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+ dev_err(dai->dev, "%s: Invalid Port ID %#x\n",
+ __func__, port_id);
return -EINVAL;
}
+ dev_dbg(dai->dev, "%s: dai id %d, afe port id = %x\n"
+ "dai_data->channels = %u sample_rate = %u\n", __func__,
+ dai->id, port_id, dai_data->channels, dai_data->rate);
+
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
/* PORT START should be set if prepare called
* in active state.
@@ -1382,6 +1403,8 @@
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
+ struct afe_param_id_i2s_cfg *i2s = &dai_data->port_config.i2s;
+
dai_data->channels = params_channels(params);
switch (dai_data->channels) {
@@ -1451,13 +1474,19 @@
mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
}
- pr_debug("%s: dai_data->channels = %d, line = %d\n"
- ",mono_stereo =%x sample rate = %x\n", __func__,
- dai_data->channels, dai_data->port_config.i2s.channel_mode,
- dai_data->port_config.i2s.mono_stereo, dai_data->rate);
+ dev_dbg(dai->dev, "%s: dai id %d dai_data->channels = %d\n"
+ "sample_rate = %u i2s_cfg_minor_version = %#x\n"
+ "bit_width = %hu channel_mode = %#x mono_stereo = %#x\n"
+ "ws_src = %#x sample_rate = %u data_format = %#x\n"
+ "reserved = %u\n", __func__, dai->id, dai_data->channels,
+ dai_data->rate, i2s->i2s_cfg_minor_version, i2s->bit_width,
+ i2s->channel_mode, i2s->mono_stereo, i2s->ws_src,
+ i2s->sample_rate, i2s->data_format, i2s->reserved);
+
return 0;
+
error_invalid_data:
- pr_debug("%s: dai_data->channels = %d, line = %d\n", __func__,
+ pr_debug("%s: dai_data->channels = %d channel_mode = %d\n", __func__,
dai_data->channels, dai_data->port_config.i2s.channel_mode);
return -EINVAL;
}
@@ -1507,11 +1536,12 @@
if (msm_mi2s_get_port_id(dai->id, substream->stream,
&port_id) != 0) {
- dev_err(dai->dev, "%s: Invalid Port ID\n", __func__);
+ dev_err(dai->dev, "%s: Invalid Port ID %#x\n",
+ __func__, port_id);
}
- dev_dbg(dai->dev, "%s: device name %s port id = %x\n",
- __func__, dai->name, port_id);
+ dev_dbg(dai->dev, "%s: closing afe port id = %x\n",
+ __func__, port_id);
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
rc = afe_close(port_id);
@@ -1714,20 +1744,21 @@
if (rc) {
dev_err(&pdev->dev,
"%s: missing %x in dt node\n", __func__, mi2s_intf);
- return rc;
+ return rc;
}
- if (mi2s_intf > MSM_QUAD_MI2S) {
- dev_err(&pdev->dev, "%s: Invalid MI2S ID from Device Tree\n",
- __func__);
- return -EINVAL;
+ dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
+ mi2s_intf);
+
+ if (mi2s_intf < MSM_PRIM_MI2S || mi2s_intf > MSM_QUAT_MI2S) {
+ dev_err(&pdev->dev,
+ "%s: Invalid MI2S ID %u from Device Tree\n",
+ __func__, mi2s_intf);
+ return -ENXIO;
}
- if (mi2s_intf == MSM_PRIM_MI2S) {
- dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s",
- MSM_PRIM_MI2S);
- pdev->id = MSM_PRIM_MI2S;
- }
+ dev_set_name(&pdev->dev, "%s.%d", "msm-dai-q6-mi2s", mi2s_intf);
+ pdev->id = mi2s_intf;
mi2s_pdata = kzalloc(sizeof(struct msm_mi2s_pdata), GFP_KERNEL);
if (!mi2s_pdata) {
@@ -1736,9 +1767,6 @@
goto rtn;
}
- dev_dbg(&pdev->dev, "dev name %s dev id %x\n", dev_name(&pdev->dev),
- pdev->id);
-
rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-mi2s-rx-lines",
&rx_line);
if (rc) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 2e0c229..17c18dd 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -142,6 +142,8 @@
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+ { AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, 0, 0, 0},
+ { AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, 0, 0, 0},
};
@@ -943,6 +945,21 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX ,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1043,6 +1060,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1623,8 +1643,13 @@
SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
+ 0, 0, 0, 0),
+
SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MI2S_TX", "MI2S Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback",
0, 0, 0 , 0),
@@ -1684,6 +1709,9 @@
hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ quaternary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -1827,9 +1855,16 @@
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
+
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -2006,8 +2041,11 @@
{"BE_OUT", NULL, "SLIMBUS_4_RX"},
{"BE_OUT", NULL, "HDMI"},
{"BE_OUT", NULL, "MI2S_RX"},
+ {"BE_OUT", NULL, "QUAT_MI2S_RX"},
+
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
+ {"QUAT_MI2S_TX", NULL, "BE_IN"},
{"SLIMBUS_0_TX", NULL, "BE_IN" },
{"SLIMBUS_1_TX", NULL, "BE_IN" },
{"SLIMBUS_3_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 261c359..be646ed 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -33,6 +33,8 @@
#define LPASS_BE_MI2S_RX "MI2S_RX"
#define LPASS_BE_MI2S_TX "MI2S_TX"
+#define LPASS_BE_QUAT_MI2S_RX "QUAT_MI2S_RX"
+#define LPASS_BE_QUAT_MI2S_TX "QUAT_MI2S_TX"
#define LPASS_BE_STUB_RX "STUB_RX"
#define LPASS_BE_STUB_TX "STUB_TX"
#define LPASS_BE_SLIMBUS_1_RX "SLIMBUS_1_RX"
@@ -95,6 +97,8 @@
MSM_BACKEND_DAI_EXTPROC_RX,
MSM_BACKEND_DAI_EXTPROC_TX,
MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index cc69123..7267a82 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -34,11 +34,11 @@
struct adm_ctl {
void *apr;
- atomic_t copp_id[Q6_AFE_MAX_PORTS];
- atomic_t copp_cnt[Q6_AFE_MAX_PORTS];
- atomic_t copp_stat[Q6_AFE_MAX_PORTS];
- u32 mem_map_handle[Q6_AFE_MAX_PORTS];
- wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
+ atomic_t copp_id[AFE_MAX_PORTS];
+ atomic_t copp_cnt[AFE_MAX_PORTS];
+ atomic_t copp_stat[AFE_MAX_PORTS];
+ u32 mem_map_handle[AFE_MAX_PORTS];
+ wait_queue_head_t wait[AFE_MAX_PORTS];
};
static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
@@ -81,7 +81,7 @@
this_adm.apr);
if (this_adm.apr) {
apr_reset(this_adm.apr);
- for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i],
RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
@@ -107,7 +107,7 @@
adm_callback_debug_print(data);
if (data->payload_size) {
index = q6audio_get_port_index(data->token);
- if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: invalid port idx %d token %d\n",
__func__, index, data->token);
return 0;
@@ -219,15 +219,15 @@
struct adm_cmd_set_pp_params_v5 adm_params;
int index = afe_get_port_index(port_id);
if (index < 0 || index >= AFE_MAX_PORTS) {
- pr_err("%s: invalid port idx %d portid %d\n",
+ pr_err("%s: invalid port idx %d portid %#x\n",
__func__, index, port_id);
return 0;
}
- pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+ pr_debug("%s: Port id %#x, index %d\n", __func__, port_id, index);
if (!aud_cal || aud_cal->cal_size == 0) {
- pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+ pr_debug("%s: No ADM cal to send for port_id = %#x!\n",
__func__, port_id);
result = -EINVAL;
goto done;
@@ -257,7 +257,7 @@
adm_params.payload_size);
result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
if (result < 0) {
- pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+ pr_err("%s: Set params failed port = %#x payload = 0x%x\n",
__func__, port_id, aud_cal->cal_paddr);
result = -EINVAL;
goto done;
@@ -267,7 +267,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!result) {
- pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+ pr_err("%s: Set params timed out port = %#x, payload = 0x%x\n",
__func__, port_id, aud_cal->cal_paddr);
result = -EINVAL;
goto done;
@@ -317,10 +317,10 @@
}
if (!send_adm_cal_block(port_id, &aud_cal))
- pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+ pr_debug("%s: Audproc cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
- pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+ pr_debug("%s: Audproc cal not sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
pr_debug("%s: Sending audvol cal\n", __func__);
@@ -351,10 +351,10 @@
}
if (!send_adm_cal_block(port_id, &aud_cal))
- pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+ pr_debug("%s: Audvol cal sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
else
- pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+ pr_debug("%s: Audvol cal not sent for port id: %#x, path %d\n",
__func__, port_id, acdb_path);
}
@@ -384,7 +384,7 @@
rtac_set_adm_handle(this_adm.apr);
}
index = afe_get_port_index(port_id);
- pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+ pr_debug("%s: Port ID %#x, index %d\n", __func__, port_id, index);
cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -405,7 +405,7 @@
atomic_set(&this_adm.copp_stat[index], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
if (ret < 0) {
- pr_err("%s:ADM enable for port %d failed\n",
+ pr_err("%s:ADM enable for port %#x failed\n",
__func__, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -415,7 +415,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+ pr_err("%s ADM connect AFE failed for port %#x\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -435,18 +435,18 @@
int index;
int tmp_port = q6audio_get_port_id(port_id);
- pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+ pr_debug("%s: port %#x path:%d rate:%d mode:%d\n", __func__,
port_id, path, rate, channel_mode);
port_id = q6audio_convert_virtual_to_portid(port_id);
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+ pr_err("%s port idi[%#x] is invalid\n", __func__, port_id);
return -ENODEV;
}
index = q6audio_get_port_index(port_id);
- pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+ pr_debug("%s: Port ID %#x, index %d\n", __func__, port_id, index);
if (this_adm.apr == NULL) {
this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
@@ -543,15 +543,15 @@
return -EINVAL;
}
- pr_debug("%s: port_id=%d rate=%d"
- "topology_id=0x%X\n", __func__, open.endpoint_id_1, \
- open.sample_rate, open.topology_id);
+ pr_debug("%s: port_id=%#x rate=%d topology_id=0x%X\n",
+ __func__, open.endpoint_id_1, open.sample_rate,
+ open.topology_id);
atomic_set(&this_adm.copp_stat[index], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
if (ret < 0) {
- pr_err("%s:ADM enable for port %d for[%d] failed\n",
+ pr_err("%s:ADM enable for port %#x for[%d] failed\n",
__func__, tmp_port, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -561,7 +561,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s ADM open failed for port %d"
+ pr_err("%s ADM open failed for port %#x"
"for [%d]\n", __func__, tmp_port, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -599,7 +599,7 @@
/* Assumes port_ids have already been validated during adm_open */
int index = q6audio_get_port_index(copp_id);
- if (index < 0 || index >= Q6_AFE_MAX_PORTS) {
+ if (index < 0 || index >= AFE_MAX_PORTS) {
pr_err("%s: invalid port idx %d token %d\n",
__func__, index, copp_id);
return 0;
@@ -615,7 +615,7 @@
}
route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map;
- pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0] :%d coppid[%d]\n",
+ pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%#x coppid[%d]\n",
__func__, session_id, path, num_copps, port_id[0], copp_id);
route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -658,10 +658,10 @@
tmp = q6audio_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < Q6_AFE_MAX_PORTS)
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS)
copps_list[i] =
atomic_read(&this_adm.copp_id[tmp]);
- pr_debug("%s: port_id[%d]: %d, index: %d act coppid[0x%x]\n",
+ pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
__func__, i, port_id[i], tmp,
atomic_read(&this_adm.copp_id[tmp]));
}
@@ -669,7 +669,7 @@
ret = apr_send_pkt(this_adm.apr, (uint32_t *)matrix_map);
if (ret < 0) {
- pr_err("%s: ADM routing for port %d failed\n",
+ pr_err("%s: ADM routing for port %#x failed\n",
__func__, port_id[0]);
ret = -EINVAL;
goto fail_cmd;
@@ -678,7 +678,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s: ADM cmd Route failed for port %d\n",
+ pr_err("%s: ADM cmd Route failed for port %#x\n",
__func__, port_id[0]);
ret = -EINVAL;
goto fail_cmd;
@@ -724,7 +724,7 @@
port_id = q6audio_convert_virtual_to_portid(port_id);
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s port id[%d] is invalid\n", __func__, port_id);
+ pr_err("%s port id[%#x] is invalid\n", __func__, port_id);
return -ENODEV;
}
@@ -864,10 +864,10 @@
if (q6audio_validate_port(port_id) < 0)
return -EINVAL;
- pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
+ pr_debug("%s port_id=%#x index %d\n", __func__, port_id, index);
if (!(atomic_read(&this_adm.copp_cnt[index]))) {
- pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+ pr_err("%s: copp count for port[%#x]is 0\n", __func__, port_id);
goto fail_cmd;
}
@@ -890,7 +890,7 @@
atomic_set(&this_adm.copp_stat[index], 0);
- pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+ pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
atomic_read(&this_adm.copp_id[index]),
port_id, index,
@@ -907,7 +907,7 @@
atomic_read(&this_adm.copp_stat[index]),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- pr_err("%s: ADM cmd Route failed for port %d\n",
+ pr_err("%s: ADM cmd Route failed for port %#x\n",
__func__, port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -925,7 +925,7 @@
int i = 0;
this_adm.apr = NULL;
- for (i = 0; i < Q6_AFE_MAX_PORTS; i++) {
+ for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
atomic_set(&this_adm.copp_stat[i], 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 8d8ff5d..de9841a 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -165,6 +165,7 @@
case INT_FM_RX:
case VOICE_PLAYBACK_TX:
case RT_PROXY_PORT_001_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
ret = MSM_AFE_PORT_TYPE_RX;
break;
@@ -183,12 +184,13 @@
case VOICE_RECORD_RX:
case INT_BT_SCO_TX:
case RT_PROXY_PORT_001_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
ret = MSM_AFE_PORT_TYPE_TX;
break;
default:
WARN_ON(1);
- pr_err("%s: invalid port id %d\n", __func__, port_id);
+ pr_err("%s: invalid port id %#x\n", __func__, port_id);
ret = -EINVAL;
}
@@ -283,10 +285,10 @@
(port_id == RT_PROXY_DAI_001_TX))
port_id = VIRTUAL_ID_TO_PORTID(port_id);
- pr_debug("%s: port id: %d\n", __func__, port_id);
+ pr_debug("%s: port id: %#x\n", __func__, port_id);
index = q6audio_get_port_index(port_id);
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s: port id: %d\n", __func__, port_id);
+ pr_err("%s: port id: %#x\n", __func__, port_id);
return -EINVAL;
}
@@ -295,7 +297,7 @@
return ret;
if (q6audio_validate_port(port_id) < 0) {
- pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+ pr_err("%s: Failed : Invalid Port id = %#x\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -321,6 +323,12 @@
case SECONDARY_I2S_TX:
case MI2S_RX:
case MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
case HDMI_RX:
@@ -370,7 +378,7 @@
atomic_set(&this_afe.status, 0);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
if (ret < 0) {
- pr_err("%s: AFE enable for port %d failed\n", __func__,
+ pr_err("%s: AFE enable for port %#x failed\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -407,7 +415,7 @@
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
if (IS_ERR_VALUE(ret)) {
- pr_err("%s: AFE enable for port %d failed\n", __func__,
+ pr_err("%s: AFE enable for port %#x failed\n", __func__,
port_id);
ret = -EINVAL;
goto fail_cmd;
@@ -468,7 +476,10 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
-
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
default: return -EINVAL;
}
}
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 8c524fa..033cb8e 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -48,7 +48,10 @@
case INT_FM_TX: return IDX_INT_FM_TX;
case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
-
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_QUATERNARY_MI2S_TX;
default: return -EINVAL;
}
}
@@ -82,6 +85,10 @@
case INT_FM_TX: return AFE_PORT_ID_INTERNAL_FM_TX;
case RT_PROXY_PORT_001_RX: return AFE_PORT_ID_RT_PROXY_PORT_001_RX;
case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_RX;
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ return AFE_PORT_ID_QUATERNARY_MI2S_TX;
default: return -EINVAL;
}
@@ -138,6 +145,8 @@
case INT_FM_TX:
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_RX:
+ case AFE_PORT_ID_QUATERNARY_MI2S_TX:
{
ret = 0;
break;