Merge "msm: camera: Add some error checks" into msm-3.0
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
new file mode 100644
index 0000000..11af7a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -0,0 +1,15 @@
+* Qualcomm MSM VIDC
+
+Required properties:
+- compatible : one of:
+ - "qcom,msm-vidc"
+- reg : offset and length of the register set for the device.
+- interrupts : should contain the vidc interrupt.
+
+Example:
+
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0xfdc00000 0xff000>;
+ interrupts = <0 44 0>;
+ };
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 393d48b..48d5720 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -358,4 +358,36 @@
};
};
};
+
+ krait0_vreg: regulator@f9088000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait0";
+ reg = <0xf9088000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait1_vreg: regulator@f9098000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait1";
+ reg = <0xf9098000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait2_vreg: regulator@f90a8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait2";
+ reg = <0xf90a8000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait3_vreg: regulator@f90b8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait3";
+ reg = <0xf90b8000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index db44d13..89a726e 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -44,6 +44,12 @@
clock-frequency = <19200000>;
};
+ qcom,vidc@fdc00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0xfdc00000 0xff000>;
+ interrupts = <0 44 0>;
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -265,4 +271,8 @@
qcom,firmware-name = "wcnss";
};
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm_ocmem";
+ };
};
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 64451eb..eb2c2c8 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -44,6 +44,7 @@
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_LPASS_QDSP6V5=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_OCMEM=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index c39b301..fb5cff7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -311,6 +311,7 @@
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index dedef45..5c01299 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -320,6 +320,7 @@
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index e6b7b79..ac9f465 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -240,6 +240,7 @@
CONFIG_MMC_EMBEDDED_SDIO=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_CLKGATE=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c294d59..4ecc3a4 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -302,6 +302,18 @@
select MULTI_IRQ_HANDLER
select ARM_TICKET_LOCKS
select MSM_RUN_QUEUE_STATS
+
+config ARCH_MSM9625
+ bool "MSM9625"
+ select ARM_GIC
+ select GIC_SECURE
+ select ARCH_MSM_CORTEX_A5
+ select SMP
+ select MSM_SMP
+ select CPU_V7
+ select MULTI_IRQ_HANDLER
+ select MSM_V2_TLMM
+
endmenu
choice
@@ -869,6 +881,7 @@
default "0x80200000" if ARCH_MSM8930
default "0x20200000" if ARCH_MSMCOPPER
default "0x10000000" if ARCH_FSM9XXX
+ default "0x20200000" if ARCH_MSM9625
default "0x00200000" if !MSM_STACKED_MEMORY
default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
default "0x20000000" if ARCH_QSD8X50
@@ -2224,6 +2237,12 @@
instead of pmem. Selecting this may also involve userspace
dependencies as well.
+config MSM_OCMEM
+ bool "MSM On-Chip memory driver (OCMEM)"
+ help
+ Enable support for On-Chip Memory available on certain MSM chipsets.
+ OCMEM is a low latency, high performance pool shared by subsystems.
+
config MSM_RTB
bool "Register tracing"
help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 000cf43..d633aa7 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -318,6 +318,7 @@
ifdef CONFIG_VCM
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index be539d0..ed17cc4 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -427,6 +427,7 @@
apq8064_fmem_pdata.size = 0;
apq8064_fmem_pdata.reserved_size_low = 0;
apq8064_fmem_pdata.reserved_size_high = 0;
+ apq8064_fmem_pdata.align = PAGE_SIZE;
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
@@ -2252,6 +2253,11 @@
},
};
+static struct platform_device rc_input_loopback_pdev = {
+ .name = "rc-user-input",
+ .id = -1,
+};
+
static struct platform_device *mpq_devices[] __initdata = {
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
@@ -2268,6 +2274,7 @@
#ifdef CONFIG_MSM_VCAP
&msm8064_device_vcap,
#endif
+ &rc_input_loopback_pdev,
};
static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index ecebfa9..9171749 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -284,6 +284,10 @@
#endif
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
/* SDC3: External card slot */
+ if (!machine_is_msm8930_cdp()) {
+ msm8960_sdc3_data.wpswitch_gpio = 0;
+ msm8960_sdc3_data.wpswitch_polarity = 0;
+ }
msm_add_sdcc(3, &msm8960_sdc3_data);
#endif
}
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 28499dd..1c4251c 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -488,6 +488,7 @@
msm8930_fmem_pdata.size = 0;
msm8930_fmem_pdata.reserved_size_low = 0;
msm8930_fmem_pdata.reserved_size_high = 0;
+ msm8930_fmem_pdata.align = PAGE_SIZE;
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c9a5f77..ea1ab58 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -471,7 +471,7 @@
{
.name = "led:blue",
.flags = PM8XXX_ID_LED_2,
- .default_trigger = "dc-online",
+ .default_trigger = "notification",
},
};
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index a8602d3..da9ce67 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -310,7 +310,7 @@
.name = "tabla-slave",
.e_addr = {0, 0, 0x60, 0, 0x17, 2},
},
- .irq = 85,
+ .irq = MSM_GPIO_TO_INT(85),
.irq_base = TABLA_INTERRUPT_BASE,
.num_irqs = NR_WCD9XXX_IRQS,
.reset_gpio = 84,
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index eff5490..14efac4 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -409,6 +409,7 @@
*/
void __init msm_copper_add_drivers(void)
{
+ msm_smd_init();
msm_spm_device_init();
regulator_stub_init();
}
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 49945d0..bfd9379 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -241,7 +241,7 @@
/* T6 Object */
0, 0, 0, 0, 0, 0,
/* T38 Object */
- 16, 0, 0, 0, 0, 0, 0, 0,
+ 16, 1, 0, 0, 0, 0, 0, 0,
/* T7 Object */
32, 16, 50,
/* T8 Object */
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 93a430b..43937b8 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -152,7 +152,6 @@
{
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evb()
- || machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7())
gpio_sdc1_hw_det = 42;
@@ -257,7 +256,6 @@
if (machine_is_msm7627a_qrd1() ||
machine_is_msm7627a_evb() ||
machine_is_msm8625_evb() ||
- machine_is_msm8625_evt() ||
machine_is_msm7627a_qrd3() ||
machine_is_msm8625_qrd7())
status = !gpio_get_value(gpio_sdc1_hw_det);
@@ -384,7 +382,14 @@
gpio_sdc1_config();
if (mmc_regulator_init(1, "mmc", 2850000))
return;
- sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ /* 8x25 EVT do not use hw detector */
+ if (!(machine_is_msm8625_evt()))
+ sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
+ if (machine_is_msm8625_evt())
+ sdc1_plat_data.status = NULL;
+#endif
+
msm_add_sdcc(1, &sdc1_plat_data);
#endif
/* SDIO WLAN slot */
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index df4ca83..803550a 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -883,6 +883,7 @@
android_pmem_audio_pdata.size = pmem_audio_size;
fmem_pdata.size = 0;
+ fmem_pdata.align = PAGE_SIZE;
/* Find pmem devices that should use FMEM (reusable) memory.
*/
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 4860d42..3a0b87e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -49,6 +49,7 @@
#define CE3_CORE_CLK_CTL_REG REG(0x36CC)
#define CE3_CLK_SRC_NS_REG REG(0x36C0)
#define DMA_BAM_HCLK_CTL REG(0x25C0)
+#define CLK_HALT_AFAB_SFAB_STATEA_REG REG(0x2FC0)
#define CLK_HALT_AFAB_SFAB_STATEB_REG REG(0x2FC4)
#define CLK_HALT_CFPB_STATEA_REG REG(0x2FCC)
#define CLK_HALT_CFPB_STATEB_REG REG(0x2FD0)
@@ -142,7 +143,9 @@
#define USB_HSIC_XCVR_FS_CLK_NS_REG REG(0x2928)
#define USB_PHY0_RESET_REG REG(0x2E20)
#define PCIE_ALT_REF_CLK_NS_REG REG(0x3860)
+#define PCIE_ACLK_CTL_REG REG(0x22C0)
#define PCIE_HCLK_CTL_REG REG(0x22CC)
+#define PCIE_PCLK_CTL_REG REG(0x22D0)
#define GPLL1_MODE_REG REG(0x3160)
#define GPLL1_L_VAL_REG REG(0x3164)
#define GPLL1_M_VAL_REG REG(0x3168)
@@ -1952,6 +1955,34 @@
},
};
+static struct branch_clk pcie_phy_ref_clk = {
+ .b = {
+ .ctl_reg = PCIE_PCLK_CTL_REG,
+ .en_mask = BIT(4),
+ .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+ .halt_bit = 29,
+ },
+ .c = {
+ .dbg_name = "pcie_phy_ref_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(pcie_phy_ref_clk.c),
+ },
+};
+
+static struct branch_clk pcie_a_clk = {
+ .b = {
+ .ctl_reg = PCIE_ACLK_CTL_REG,
+ .en_mask = BIT(4),
+ .halt_reg = CLK_HALT_AFAB_SFAB_STATEA_REG,
+ .halt_bit = 13,
+ },
+ .c = {
+ .dbg_name = "pcie_a_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(pcie_a_clk.c),
+ },
+};
+
static struct branch_clk dma_bam_p_clk = {
.b = {
.ctl_reg = DMA_BAM_HCLK_CTL,
@@ -4575,6 +4606,8 @@
{ TEST_PER_HS(0x26), &q6sw_clk },
{ TEST_PER_HS(0x27), &q6fw_clk },
{ TEST_PER_HS(0x2A), &adm0_clk.c },
+ { TEST_PER_HS(0x2D), &pcie_phy_ref_clk.c },
+ { TEST_PER_HS(0x32), &pcie_a_clk.c },
{ TEST_PER_HS(0x34), &ebi1_clk.c },
{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
@@ -4960,6 +4993,8 @@
CLK_LOOKUP("iface_clk", sdc3_p_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", sdc4_p_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", pcie_p_clk.c, ""),
+ CLK_LOOKUP("ref_clk", pcie_phy_ref_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pcie_a_clk.c, ""),
CLK_LOOKUP("core_clk", adm0_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", adm0_p_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", pmic_arb0_p_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 7123ffa..03667d7 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -102,6 +102,7 @@
#define MMSS_DEBUG_CLK_CTL_REG 0x0900
#define LPASS_DEBUG_CLK_CTL_REG 0x29000
#define LPASS_LPA_PLL_VOTE_APPS_REG 0x2000
+#define MSS_DEBUG_CLK_CTL_REG 0x0078
#define USB30_MASTER_CMD_RCGR 0x03D4
#define USB30_MOCK_UTMI_CMD_RCGR 0x03E8
@@ -230,6 +231,7 @@
#define BLSP2_UART5_BCR 0x0BC0
#define BLSP2_QUP6_BCR 0x0C00
#define BLSP2_UART6_BCR 0x0C40
+#define BOOT_ROM_BCR 0x0E00
#define PDM_BCR 0x0CC0
#define PRNG_BCR 0x0D00
#define BAM_DMA_BCR 0x0D40
@@ -280,6 +282,8 @@
#define OXILICX_AXI_CBCR 0x4038
#define OXILI_BCR 0x4020
#define OXILICX_BCR 0x4030
+#define LPASS_Q6SS_BCR 0x6000
+#define MSS_Q6SS_BCR 0x1068
#define OCMEM_SYS_NOC_AXI_CBCR 0x0244
#define OCMEM_NOC_CFG_AHB_CBCR 0x0248
@@ -327,6 +331,7 @@
#define BLSP1_UART6_APPS_CBCR 0x0904
#define BLSP1_UART6_SIM_CBCR 0x0908
#define BLSP2_AHB_CBCR 0x0944
+#define BOOT_ROM_AHB_CBCR 0x0E04
#define BLSP2_QUP1_SPI_APPS_CBCR 0x0984
#define BLSP2_QUP1_I2C_APPS_CBCR 0x0988
#define BLSP2_UART1_APPS_CBCR 0x09C4
@@ -469,6 +474,11 @@
#define MMSS_MISC_AHB_CBCR 0x502C
#define MMSS_S0_AXI_CBCR 0x5064
#define OCMEMNOC_CBCR 0x50B4
+#define LPASS_Q6SS_AHB_LFABIF_CBCR 0x22000
+#define LPASS_Q6SS_XO_CBCR 0x26000
+#define MSS_XO_Q6_CBCR 0x108C
+#define MSS_BUS_Q6_CBCR 0x10A4
+#define MSS_CFG_AHB_CBCR 0x0280
#define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
#define APCS_CLOCK_SLEEP_ENA_VOTE 0x1488
@@ -1625,6 +1635,19 @@
},
};
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .bcr_reg = BOOT_ROM_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
static struct local_vote_clk gcc_blsp2_ahb_clk = {
.cbcr_reg = BLSP2_AHB_CBCR,
.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
@@ -2225,6 +2248,17 @@
},
};
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
static struct clk_freq_tbl ftbl_mmss_ahb_clk[] = {
F_MM(19200000, cxo, 1, 0, 0),
F_MM(40000000, gpll0, 15, 0, 0),
@@ -4291,6 +4325,55 @@
},
};
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+ .cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahb_lfabif_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahb_lfabif_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_xo_clk = {
+ .cbcr_reg = LPASS_Q6SS_XO_CBCR,
+ .bcr_reg = LPASS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_xo_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_xo_clk.c),
+ },
+};
+
+static struct branch_clk mss_xo_q6_clk = {
+ .cbcr_reg = MSS_XO_Q6_CBCR,
+ .bcr_reg = MSS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MSS_BASE],
+ .c = {
+ .dbg_name = "mss_xo_q6_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mss_xo_q6_clk.c),
+ .depends = &gcc_mss_cfg_ahb_clk.c,
+ },
+};
+
+static struct branch_clk mss_bus_q6_clk = {
+ .cbcr_reg = MSS_BUS_Q6_CBCR,
+ .bcr_reg = MSS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MSS_BASE],
+ .c = {
+ .dbg_name = "mss_bus_q6_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mss_bus_q6_clk.c),
+ .depends = &gcc_mss_cfg_ahb_clk.c,
+ },
+};
+
#ifdef CONFIG_DEBUG_FS
struct measure_mux_entry {
@@ -4339,6 +4422,8 @@
{&gcc_blsp2_uart4_apps_clk.c, GCC_BASE, 0x00c2},
{&gcc_blsp2_uart5_apps_clk.c, GCC_BASE, 0x00c6},
{&gcc_blsp2_uart6_apps_clk.c, GCC_BASE, 0x00cb},
+ {&gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x0100},
+ {&gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
{&gcc_ce1_clk.c, GCC_BASE, 0x0140},
{&gcc_ce2_clk.c, GCC_BASE, 0x0148},
{&gcc_pdm2_clk.c, GCC_BASE, 0x00da},
@@ -4438,6 +4523,11 @@
{&audio_core_lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
{&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
{&audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e},
+ {&q6ss_xo_clk.c, LPASS_BASE, 0x002b},
+ {&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
+ {&mss_bus_q6_clk.c, MSS_BASE, 0x003c},
+ {&mss_xo_q6_clk.c, MSS_BASE, 0x0007},
+
{&dummy_clk, N_BASES, 0x0000},
};
@@ -4465,6 +4555,7 @@
clk->sample_ticks = 0x10000;
clk->multiplier = 1;
+ writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
@@ -4495,6 +4586,12 @@
writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
break;
+ case MSS_BASE:
+ clk_sel = 0x32;
+ regval = BVAL(5, 0, measure_mux[i].debug_mux);
+ writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+ break;
+
default:
return -EINVAL;
}
@@ -4807,6 +4904,13 @@
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
+ CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, ""),
+ CLK_LOOKUP("core_clk", q6ss_xo_clk.c, ""),
+ CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, ""),
+ CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+
/* TODO: Remove dummy clocks as soon as they become unnecessary */
CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
@@ -5048,6 +5152,9 @@
#define LPASS_CC_PHYS 0xFE000000
#define LPASS_CC_SIZE SZ_256K
+#define MSS_CC_PHYS 0xFC980000
+#define MSS_CC_SIZE SZ_16K
+
static void __init msmcopper_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5062,6 +5169,10 @@
if (!virt_bases[LPASS_BASE])
panic("clock-copper: Unable to ioremap LPASS_CC memory!");
+ virt_bases[MSS_BASE] = ioremap(MSS_CC_PHYS, MSS_CC_SIZE);
+ if (!virt_bases[MSS_BASE])
+ panic("clock-copper: Unable to ioremap MSS_CC memory!");
+
clk_ops_local_pll.enable = copper_pll_clk_enable;
reg_init();
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index f8cb345..4ad73f9 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -686,6 +686,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
.memtype = ION_CP_MM_HEAP_ID,
.enable_ion = 1,
+ .cp_enabled = 1,
#else
.memtype = MEMTYPE_EBI1,
.enable_ion = 0,
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
new file mode 100644
index 0000000..91b4d07
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_9625_H
+#define __ASM_ARCH_MSM_IRQS_9625_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15: STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+: SPI (shared peripheral interrupts)
+ */
+
+
+#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 16)
+#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 208)
+
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 88
+#define NR_BOARD_IRQS 0
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index e3904b4..bf766f4 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -62,6 +62,8 @@
#include "irqs-copper.h"
#elif defined(CONFIG_ARCH_MSM9615)
#include "irqs-9615.h"
+#elif defined(CONFIG_ARCH_MSM9625)
+#include "irqs-9625.h"
#elif defined(CONFIG_ARCH_MSM7X30)
#include "irqs-7x30.h"
#elif defined(CONFIG_ARCH_QSD8X50)
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2966509..dc633fb 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -295,6 +295,14 @@
* -EINVAL - NULL parameter or non-packet based channel provided
*/
int smd_is_pkt_avail(smd_channel_t *ch);
+
+/*
+ * SMD initialization function that registers for a SMD platform driver.
+ *
+ * returns success on successful driver registration.
+ */
+int __init msm_smd_init(void);
+
#else
static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -411,6 +419,11 @@
{
return -ENODEV;
}
+
+static inline int __init msm_smd_init(void)
+{
+ return 0;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
new file mode 100644
index 0000000..bf7c338
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_H
+
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#define OCMEM_MIN_ALLOC SZ_64K
+#define OCMEM_MIN_ALIGN SZ_64K
+
+/* Maximum number of slots in DM */
+#define OCMEM_MAX_CHUNKS 32
+#define MIN_CHUNK_SIZE (SZ_1K/8)
+
+struct ocmem_buf {
+ unsigned long addr;
+ unsigned long len;
+};
+
+struct ocmem_buf_attr {
+ unsigned long paddr;
+ unsigned long len;
+};
+
+struct ocmem_chunk {
+ bool ro;
+ unsigned long ddr_paddr;
+ unsigned long size;
+};
+
+struct ocmem_map_list {
+ int num_chunks;
+ struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
+};
+
+/* List of clients that allocate/interact with OCMEM */
+/* Must be in sync with client_names */
+enum ocmem_client {
+ /* GMEM clients */
+ OCMEM_GRAPHICS = 0x0,
+ /* TCMEM clients */
+ OCMEM_VIDEO,
+ OCMEM_CAMERA,
+ /* Dummy Clients */
+ OCMEM_HP_AUDIO,
+ OCMEM_VOICE,
+ /* IMEM Clients */
+ OCMEM_LP_AUDIO,
+ OCMEM_SENSORS,
+ OCMEM_BLAST,
+ OCMEM_CLIENT_MAX,
+};
+
+/**
+ * List of OCMEM notification events which will be broadcasted
+ * to clients that optionally register for these notifications
+ * on a per allocation basis.
+ **/
+enum ocmem_notif_type {
+ OCMEM_MAP_DONE = 1,
+ OCMEM_MAP_FAIL,
+ OCMEM_UNMAP_DONE,
+ OCMEM_UNMAP_FAIL,
+ OCMEM_ALLOC_GROW,
+ OCMEM_ALLOC_SHRINK,
+ OCMEM_NOTIF_TYPE_COUNT,
+};
+
+/* APIS */
+/* Notification APIs */
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb);
+
+int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+
+/* Allocation APIs */
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+ unsigned long goal, unsigned long step);
+
+/* Free APIs */
+int ocmem_free(int client_id, struct ocmem_buf *buf);
+
+/* Dynamic Resize APIs */
+int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+int ocmem_expand(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+/* Priority Enforcement APIs */
+int ocmem_evict(int client_id);
+
+int ocmem_restore(int client_id);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
new file mode 100644
index 0000000..32d46b4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+
+/** All interfaces in this header should only be used by OCMEM driver
+ * Client drivers should use wrappers available in ocmem.h
+ **/
+
+#include "ocmem.h"
+#include <mach/msm_iomap.h>
+#include <asm/io.h>
+
+#define OCMEM_PHYS_BASE 0xFEC00000
+#define OCMEM_PHYS_SIZE 0x180000
+
+struct ocmem_zone;
+
+struct ocmem_zone_ops {
+ unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+ int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
+};
+
+struct ocmem_zone {
+ int owner;
+ int active_regions;
+ int max_regions;
+ struct list_head region_list;
+ unsigned long z_start;
+ unsigned long z_end;
+ unsigned long z_head;
+ unsigned long z_tail;
+ unsigned long z_free;
+ struct gen_pool *z_pool;
+ struct ocmem_zone_ops *z_ops;
+};
+
+struct ocmem_req {
+ struct rw_semaphore rw_sem;
+ /* Chain in sched queue */
+ struct list_head sched_list;
+ /* Chain in zone list */
+ struct list_head zone_list;
+ int owner;
+ int prio;
+ uint32_t req_id;
+ unsigned long req_min;
+ unsigned long req_max;
+ unsigned long req_step;
+ /* reverse pointers */
+ struct ocmem_zone *zone;
+ struct ocmem_buf *buffer;
+ unsigned long state;
+ /* Request assignments */
+ unsigned long req_start;
+ unsigned long req_end;
+ unsigned long req_sz;
+};
+
+struct ocmem_handle {
+ struct ocmem_buf buffer;
+ struct mutex handle_mutex;
+ struct ocmem_req *req;
+};
+
+struct ocmem_zone *get_zone(unsigned);
+#endif
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 0652f3b..49a3e6f 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -49,9 +49,11 @@
#define MSM_IOMMU_ATTR_CACHED_WT 0x3
-static inline void clean_pte(unsigned long *start, unsigned long *end)
+static inline void clean_pte(unsigned long *start, unsigned long *end,
+ int redirect)
{
- dmac_flush_range(start, end);
+ if (!redirect)
+ dmac_flush_range(start, end);
}
static int msm_iommu_tex_class[4];
@@ -292,6 +294,9 @@
memset(priv->pgtable, 0, SZ_16K);
domain->priv = priv;
+
+ clean_pte(priv->pgtable, priv->pgtable + NUM_FL_PTE, priv->redirect);
+
return 0;
fail_nomem:
@@ -518,8 +523,7 @@
for (i = 0; i < 16; i++)
*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
| FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 16);
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
@@ -530,8 +534,7 @@
*fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
| pgprot;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
/* Need a 2nd level table */
@@ -548,12 +551,12 @@
goto fail;
}
memset(sl, 0, SZ_4K);
+ clean_pte(sl, sl + NUM_SL_PTE, priv->redirect);
*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
FL_TYPE_TABLE);
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
if (!(*fl_pte & FL_TYPE_TABLE)) {
@@ -574,8 +577,7 @@
*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
| SL_TYPE_SMALL | pgprot;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 1);
+ clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_64K) {
@@ -591,8 +593,7 @@
*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
| SL_SHARED | SL_TYPE_LARGE | pgprot;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 16);
+ clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
ret = __flush_iotlb_va(domain, va);
@@ -652,15 +653,13 @@
for (i = 0; i < 16; i++)
*(fl_pte+i) = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 16);
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
@@ -671,15 +670,13 @@
for (i = 0; i < 16; i++)
*(sl_pte+i) = 0;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 16);
+ clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
if (len == SZ_4K) {
*sl_pte = 0;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 1);
+ clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_4K || len == SZ_64K) {
@@ -692,8 +689,7 @@
free_page((unsigned long)sl_table);
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
}
@@ -773,10 +769,12 @@
}
memset(sl_table, 0, SZ_4K);
+ clean_pte(sl_table, sl_table + NUM_SL_PTE,
+ priv->redirect);
+
*fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
FL_TYPE_TABLE);
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
} else
sl_table = (unsigned long *)
__va(((*fl_pte) & FL_BASE_MASK));
@@ -809,8 +807,8 @@
}
}
- if (!priv->redirect)
- clean_pte(sl_table + sl_start, sl_table + sl_offset);
+ clean_pte(sl_table + sl_start, sl_table + sl_offset,
+ priv->redirect);
fl_pte++;
sl_offset = 0;
@@ -854,8 +852,8 @@
sl_end = NUM_SL_PTE;
memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
- if (!priv->redirect)
- clean_pte(sl_table + sl_start, sl_table + sl_end);
+ clean_pte(sl_table + sl_start, sl_table + sl_end,
+ priv->redirect);
offset += (sl_end - sl_start) * SZ_4K;
@@ -879,8 +877,7 @@
free_page((unsigned long)sl_table);
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
sl_start = 0;
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 6e8c99e..085b87a 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -21,6 +21,10 @@
#include <linux/gfp.h>
#include <linux/msm_ipc.h>
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+#include <linux/android_aid.h>
+#endif
+
#include <asm/string.h>
#include <asm/atomic.h>
@@ -39,6 +43,21 @@
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+static inline int check_permissions(void)
+{
+ int rc = 0;
+ if (!current_euid() || in_egroup_p(AID_NET_RAW))
+ rc = 1;
+ return rc;
+}
+# else
+static inline int check_permissions(void)
+{
+ return 1;
+}
+#endif
+
static void msm_ipc_router_unload_modem(void *pil)
{
if (pil)
@@ -214,6 +233,11 @@
struct msm_ipc_port *port_ptr;
void *pil;
+ if (!check_permissions()) {
+ pr_err("%s: Do not have permissions\n", __func__);
+ return -EPERM;
+ }
+
if (unlikely(protocol != 0)) {
pr_err("%s: Protocol not supported\n", __func__);
return -EPROTONOSUPPORT;
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index 7775740..c58b0e1 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -31,6 +31,7 @@
#define SCM_Q6_NMI_CMD 0x1
#define MODULE_NAME "lpass_8960"
+#define MAX_BUF_SIZE 0x51
/* Subsystem restart: QDSP6 data, functions */
static void lpass_fatal_fn(struct work_struct *);
@@ -86,10 +87,39 @@
.notifier_call = modem_notifier_cb,
};
+static void lpass_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[MAX_BUF_SIZE];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
+ MODULE_NAME);
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("%s: subsystem failure reason: (unknown, init value found)",
+ MODULE_NAME);
+ return;
+ }
+
+ size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
static void lpass_fatal_fn(struct work_struct *work)
{
pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
__func__);
+ lpass_log_failure_reason();
panic(MODULE_NAME ": Resetting the SoC");
}
@@ -104,6 +134,7 @@
pr_err("%s: LPASS SMSM state changed to SMSM_RESET,"
" new_state = 0x%x, old_state = 0x%x\n", __func__,
new_state, old_state);
+ lpass_log_failure_reason();
panic(MODULE_NAME ": Resetting the SoC");
}
}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 404c8f0..b21412f 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -26,7 +26,7 @@
#include <mach/memory.h>
#include <mach/msm_iomap.h>
-#define L2C_IMEM_ADDR 0x2a03f014
+#define L2_DUMP_OFFSET 0x14
static unsigned long msm_cache_dump_addr;
@@ -43,6 +43,11 @@
unsigned long event, void *ptr)
{
#ifdef CONFIG_MSM_CACHE_DUMP_ON_PANIC
+ /*
+ * Clear the bootloader magic so the dumps aren't overwritten
+ */
+ __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
+
scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 2);
scm_call_atomic1(L1C_SERVICE_ID, CACHE_BUFFER_DUMP_COMMAND_ID, 1);
#endif
@@ -66,9 +71,6 @@
unsigned long buf;
unsigned long size;
} l1_cache_data;
-#ifndef CONFIG_MSM_CACHE_DUMP_ON_PANIC
- unsigned int *imem_loc;
-#endif
void *temp;
unsigned long total_size = d->l1_size + d->l2_size;
@@ -104,11 +106,9 @@
if (ret)
pr_err("%s: could not register L2 buffer ret = %d.\n",
__func__, ret);
-#else
- imem_loc = ioremap(L2C_IMEM_ADDR, SZ_4K);
- __raw_writel(msm_cache_dump_addr + d->l1_size, imem_loc);
- iounmap(imem_loc);
#endif
+ __raw_writel(msm_cache_dump_addr + d->l1_size,
+ MSM_IMEM_BASE + L2_DUMP_OFFSET);
atomic_notifier_chain_register(&panic_notifier_list,
&msm_cache_dump_blk);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
new file mode 100644
index 0000000..af39dc3
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem.c
@@ -0,0 +1,304 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <mach/ocmem_priv.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+struct ocmem_partition {
+ const char *name;
+ int id;
+ unsigned long p_start;
+ unsigned long p_size;
+ unsigned long p_min;
+};
+
+struct ocmem_plat_data {
+ void __iomem *vbase;
+ unsigned long size;
+ unsigned long base;
+ struct ocmem_partition *parts;
+ int nr_parts;
+};
+
+struct ocmem_zone zones[OCMEM_CLIENT_MAX];
+
+struct ocmem_zone *get_zone(unsigned id)
+{
+ if (id < OCMEM_GRAPHICS || id >= OCMEM_CLIENT_MAX)
+ return NULL;
+ else
+ return &zones[id];
+}
+
+static struct ocmem_plat_data *ocmem_pdata;
+
+#define CLIENT_NAME_MAX 10
+/* Must be in sync with enum ocmem_client */
+static const char *client_names[OCMEM_CLIENT_MAX] = {
+ "graphics",
+ "video",
+ "camera",
+ "hp_audio",
+ "voice",
+ "lp_audio",
+ "sensors",
+ "blast",
+};
+
+struct ocmem_quota_table {
+ const char *name;
+ int id;
+ unsigned long start;
+ unsigned long size;
+ unsigned long min;
+};
+
+/* This static table will go away with device tree support */
+static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
+ /* name, id, start, size, min */
+ { "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000},
+ { "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000},
+ { "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0},
+ { "voice", OCMEM_VOICE, 0x0, 0x0, 0x0 },
+ { "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0},
+ { "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000},
+ { "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000},
+ { "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000},
+};
+
+static inline int get_id(const char *name)
+{
+ int i = 0;
+ for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
+ if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
+ return i;
+ }
+ return -EINVAL;
+}
+
+static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
+{
+ struct ocmem_plat_data *pdata = NULL;
+ struct ocmem_partition *parts = NULL;
+ struct device *dev = &pdev->dev;
+ int nr_parts;
+ int i;
+ int j;
+
+ pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+ GFP_KERNEL);
+
+ if (!pdata) {
+ dev_err(dev, "Unable to allocate memory for"
+ " platform data\n");
+ return NULL;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(qt); i++)
+ if (qt[i].size != 0x0)
+ nr_parts++;
+
+ if (nr_parts == 0x0) {
+ dev_err(dev, "No valid ocmem partitions\n");
+ return NULL;
+ } else
+ dev_info(dev, "Total partitions = %d\n", nr_parts);
+
+ parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
+ GFP_KERNEL);
+
+ if (!parts) {
+ dev_err(dev, "Unable to allocate memory for"
+ " partition data\n");
+ return NULL;
+ }
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
+ if (qt[i].size == 0x0) {
+ dev_dbg(dev, "Skipping creation of pool for %s\n",
+ qt[i].name);
+ continue;
+ }
+ parts[j].id = qt[i].id;
+ parts[j].p_size = qt[i].size;
+ parts[j].p_start = qt[i].start;
+ parts[j].p_min = qt[i].min;
+ j++;
+ }
+ BUG_ON(j != nr_parts);
+ pdata->nr_parts = nr_parts;
+ pdata->parts = parts;
+ pdata->base = OCMEM_PHYS_BASE;
+ pdata->size = OCMEM_PHYS_SIZE;
+ return pdata;
+}
+
+static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
+{
+ return NULL;
+}
+
+static int ocmem_zone_init(struct platform_device *pdev)
+{
+
+ int ret = -1;
+ int i = 0;
+ unsigned active_zones = 0;
+
+ struct ocmem_zone *zone = NULL;
+ struct ocmem_zone_ops *z_ops = NULL;
+ struct device *dev = &pdev->dev;
+ unsigned long start;
+ struct ocmem_plat_data *pdata = NULL;
+
+ pdata = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->nr_parts; i++) {
+ struct ocmem_partition *part = &pdata->parts[i];
+ zone = get_zone(part->id);
+
+ dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
+ i, part->p_start, part->p_size,
+ client_names[part->id]);
+
+ if (part->p_size > pdata->size) {
+ dev_alert(dev, "Quota > ocmem_size for id:%d\n",
+ part->id);
+ continue;
+ }
+
+ zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
+
+ if (!zone->z_pool) {
+ dev_alert(dev, "Creating pool failed for id:%d\n",
+ part->id);
+ return -EBUSY;
+ }
+
+ start = pdata->base + part->p_start;
+ ret = gen_pool_add(zone->z_pool, start,
+ part->p_size, -1);
+
+ if (ret < 0) {
+ gen_pool_destroy(zone->z_pool);
+ dev_alert(dev, "Unable to back pool %d with "
+ "buffer:%lx\n", part->id, part->p_size);
+ return -EBUSY;
+ }
+
+ /* Initialize zone allocators */
+ z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
+ GFP_KERNEL);
+ if (!z_ops) {
+ pr_alert("ocmem: Unable to allocate memory for"
+ "zone ops:%d\n", i);
+ return -EBUSY;
+ }
+
+ /* Initialize zone parameters */
+ zone->z_start = start;
+ zone->z_head = zone->z_start;
+ zone->z_end = start + part->p_size;
+ zone->z_tail = zone->z_end;
+ zone->z_free = part->p_size;
+ zone->owner = part->id;
+ zone->active_regions = 0;
+ zone->max_regions = 0;
+ INIT_LIST_HEAD(&zone->region_list);
+ zone->z_ops = z_ops;
+ active_zones++;
+
+ if (active_zones == 1)
+ pr_info("Physical OCMEM zone layout:\n");
+
+ pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
+ client_names[part->id], zone->z_start,
+ zone->z_end, part->p_size/SZ_1K);
+ }
+
+ dev_info(dev, "Total active zones = %d\n", active_zones);
+ return 0;
+}
+
+static int __devinit msm_ocmem_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!pdev->dev.of_node->child) {
+ dev_info(dev, "Missing Configuration in Device Tree\n");
+ ocmem_pdata = parse_static_config(pdev);
+ } else {
+ ocmem_pdata = parse_dt_config(pdev);
+ }
+
+ /* Check if we have some configuration data to start */
+ if (!ocmem_pdata)
+ return -ENODEV;
+
+ /* Sanity Checks */
+ BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
+ BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
+
+ platform_set_drvdata(pdev, ocmem_pdata);
+
+ if (ocmem_zone_init(pdev))
+ return -EBUSY;
+
+ dev_info(dev, "initialized successfully\n");
+ return 0;
+}
+
+static int __devexit msm_ocmem_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id msm_ocmem_dt_match[] = {
+ { .compatible = "qcom,msm_ocmem",
+ },
+ {}
+};
+
+static struct platform_driver msm_ocmem_driver = {
+ .probe = msm_ocmem_probe,
+ .remove = __devexit_p(msm_ocmem_remove),
+ .driver = {
+ .name = "msm_ocmem",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_ocmem_dt_match,
+ },
+};
+
+static int __init ocmem_init(void)
+{
+ return platform_driver_register(&msm_ocmem_driver);
+}
+subsys_initcall(ocmem_init);
+
+static void __exit ocmem_exit(void)
+{
+ platform_driver_unregister(&msm_ocmem_driver);
+}
+module_exit(ocmem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index 8dfba0b..a7c2543 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -552,7 +552,9 @@
struct audpcm_buffer_node *buf_node;
struct list_head *ptr, *next;
union msm_audio_event_payload payload;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
MM_DBG("\n"); /* Macro prints the file name and function */
list_for_each_safe(ptr, next, &audio->out_queue) {
buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
@@ -565,6 +567,7 @@
audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
audio->out_needed = 0;
atomic_set(&audio->out_bytes, 0);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_ioport_reset(struct audio *audio)
{
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index 5abdf85..7f72e25 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -836,7 +836,9 @@
struct audmp3_buffer_node *buf_node;
struct list_head *ptr, *next;
union msm_audio_event_payload payload;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
MM_DBG("\n"); /* Macro prints the file name and function */
list_for_each_safe(ptr, next, &audio->out_queue) {
buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
@@ -849,6 +851,7 @@
audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
audio->out_needed = 0;
atomic_set(&audio->out_bytes, 0);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_flush(struct audio *audio)
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 60b5c20..733b7a1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* sbc/pcm audio input driver
* Based on the pcm input driver in arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -41,7 +41,6 @@
#include <mach/iommu_domains.h>
#include <mach/msm_adsp.h>
#include <mach/msm_memtypes.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -108,7 +107,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *msm_map;
+ void *msm_map;
int opened;
int enabled;
@@ -849,7 +848,7 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->msm_map);
+ iounmap(audio->msm_map);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -871,9 +870,7 @@
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->msm_map = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->msm_map = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->msm_map)) {
MM_ERR("could not map the phys address to kernel"
"space\n");
@@ -881,7 +878,7 @@
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = (u8 *)audio->msm_map->vaddr;
+ audio->data = (u8 *)audio->msm_map;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac.c b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
index 9069426..32053bf 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -38,7 +38,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -142,8 +141,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1629,9 +1628,9 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audaac_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
@@ -1821,10 +1820,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
audio->map_v_write =
- msm_subsystem_map_buffer(audio->phys,
- pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ ioremap(audio->phys,
+ pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, \
freeing instance 0x%08x\n",
@@ -1835,7 +1832,7 @@
kfree(audio);
goto done;
}
- audio->data = (u8 *)audio->map_v_write->vaddr;
+ audio->data = (u8 *)audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1857,28 +1854,26 @@
MM_ERR("could not allocate read buffers, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
goto done;
}
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->read_phys,
- PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->read_phys,
+ PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read phys address, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
free_contiguous_memory_by_paddr(audio->read_phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
goto done;
}
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->read_phys, (int)audio->read_data);
@@ -2000,9 +1995,9 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
index 010fd90..d2b4407 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -32,7 +32,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/iommu_domains.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -97,8 +96,8 @@
wait_queue_head_t write_wait;
int32_t out_phys; /* physical address of write buffer */
char *out_data;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int wflush; /*write flush */
@@ -1292,12 +1291,12 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
if (audio->out_data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1320,16 +1319,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
@@ -1398,16 +1395,15 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
@@ -1434,7 +1430,7 @@
aac_in_listener, (void *) audio);
if (rc) {
MM_ERR("failed to register device event listener\n");
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
index 90373f9..89957a4 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,7 +28,6 @@
#include <mach/dal.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/audpp.h>
#include <mach/socinfo.h>
@@ -111,7 +110,7 @@
u16 *pbe_enable_flag;
u32 fluence_extbuff;
u8 *fluence_extbuff_virt;
- struct msm_mapped_buffer *map_v_fluence;
+ void *map_v_fluence;
struct acdb_pbe_block *pbe_blk;
@@ -130,7 +129,7 @@
/* pmem for get acdb blk */
unsigned long get_blk_paddr;
u8 *get_blk_kvaddr;
- struct msm_mapped_buffer *map_v_get_blk;
+ void *map_v_get_blk;
char *build_id;
};
@@ -140,7 +139,7 @@
u32 node_status;
s32 stream_id;
u32 phys_addr_acdb_values;
- struct msm_mapped_buffer *map_v_addr;
+ void *map_v_addr;
u8 *virt_addr_acdb_values;
struct auddev_evt_audcal_info device_info;
};
@@ -237,7 +236,7 @@
struct rtc_acdb_pmem {
u8 *viraddr;
int32_t phys;
- struct msm_mapped_buffer *map_v_rtc;
+ void *map_v_rtc;
};
struct rtc_acdb_data {
@@ -1087,11 +1086,11 @@
rtc_acdb.valid_abid = false;
if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_read->map_v_rtc);
+ iounmap(rtc_read->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_read->phys);
}
if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_write->map_v_rtc);
+ iounmap(rtc_write->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_write->phys);
}
}
@@ -1141,17 +1140,15 @@
result = -ENOMEM;
goto error;
}
- rtc_read->map_v_rtc = msm_subsystem_map_buffer(
- rtc_read->phys,
- PMEM_RTC_ACDB_QUERY_MEM,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ rtc_read->map_v_rtc = ioremap(rtc_read->phys,
+ PMEM_RTC_ACDB_QUERY_MEM);
if (IS_ERR(rtc_read->map_v_rtc)) {
MM_ERR("ACDB Could not map physical address\n");
result = -ENOMEM;
goto error;
}
- rtc_read->viraddr = rtc_read->map_v_rtc->vaddr;
+ rtc_read->viraddr = rtc_read->map_v_rtc;
memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
@@ -1162,16 +1159,15 @@
result = -ENOMEM;
goto error;
}
- rtc_write->map_v_rtc = msm_subsystem_map_buffer(
- rtc_write->phys, PMEM_RTC_ACDB_QUERY_MEM,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ rtc_write->map_v_rtc = ioremap(rtc_write->phys,
+ PMEM_RTC_ACDB_QUERY_MEM);
if (IS_ERR(rtc_write->map_v_rtc)) {
MM_ERR("ACDB Could not map physical address\n");
result = -ENOMEM;
goto error;
}
- rtc_write->viraddr = rtc_write->map_v_rtc->vaddr;
+ rtc_write->viraddr = rtc_write->map_v_rtc;
memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
init_waitqueue_head(&rtc_acdb.wait);
return true;
@@ -1187,11 +1183,11 @@
debugfs_remove(get_set_abid_data_dentry);
}
if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_read->map_v_rtc);
+ iounmap(rtc_read->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_read->phys);
}
if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_write->map_v_rtc);
+ iounmap(rtc_write->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_write->phys);
}
return false;
@@ -2544,11 +2540,9 @@
result = -ENOMEM;
goto error;
}
- acdb_cache_tx[i].map_v_addr =
- msm_subsystem_map_buffer(
+ acdb_cache_tx[i].map_v_addr = ioremap(
acdb_cache_tx[i].phys_addr_acdb_values,
- ACDB_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ ACDB_BUF_SIZE);
if (IS_ERR(acdb_cache_tx[i].map_v_addr)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
@@ -2557,15 +2551,14 @@
goto error;
}
acdb_cache_tx[i].virt_addr_acdb_values =
- acdb_cache_tx[i].map_v_addr->vaddr;
+ acdb_cache_tx[i].map_v_addr;
memset(acdb_cache_tx[i].virt_addr_acdb_values, 0,
ACDB_BUF_SIZE);
}
return result;
error:
for (err = 0; err < i; err++) {
- msm_subsystem_unmap_buffer(
- acdb_cache_tx[err].map_v_addr);
+ iounmap(acdb_cache_tx[err].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[err].phys_addr_acdb_values);
}
@@ -2590,11 +2583,8 @@
goto error;
}
acdb_cache_rx[i].map_v_addr =
- msm_subsystem_map_buffer(
- acdb_cache_rx[i].phys_addr_acdb_values,
- ACDB_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ ioremap(acdb_cache_rx[i].phys_addr_acdb_values,
+ ACDB_BUF_SIZE);
if (IS_ERR(acdb_cache_rx[i].map_v_addr)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
@@ -2603,15 +2593,14 @@
goto error;
}
acdb_cache_rx[i].virt_addr_acdb_values =
- acdb_cache_rx[i].map_v_addr->vaddr;
+ acdb_cache_rx[i].map_v_addr;
memset(acdb_cache_rx[i].virt_addr_acdb_values, 0,
ACDB_BUF_SIZE);
}
return result;
error:
for (err = 0; err < i; err++) {
- msm_subsystem_unmap_buffer(
- acdb_cache_rx[err].map_v_addr);
+ iounmap(acdb_cache_rx[err].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[err].phys_addr_acdb_values);
}
@@ -2628,10 +2617,8 @@
result = -ENOMEM;
goto error;
}
- acdb_data.map_v_get_blk = msm_subsystem_map_buffer(
- acdb_data.get_blk_paddr,
- ACDB_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
+ ACDB_BUF_SIZE);
if (IS_ERR(acdb_data.map_v_get_blk)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
@@ -2639,7 +2626,7 @@
acdb_data.get_blk_paddr);
goto error;
}
- acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk->vaddr;
+ acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
error:
return result;
@@ -2650,7 +2637,7 @@
u32 i = 0;
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
- msm_subsystem_unmap_buffer(acdb_cache_rx[i].map_v_addr);
+ iounmap(acdb_cache_rx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
}
@@ -2661,7 +2648,7 @@
u32 i = 0;
for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
- msm_subsystem_unmap_buffer(acdb_cache_tx[i].map_v_addr);
+ iounmap(acdb_cache_tx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
}
@@ -2669,7 +2656,7 @@
static void free_memory_acdb_get_blk(void)
{
- msm_subsystem_unmap_buffer(acdb_data.map_v_get_blk);
+ iounmap(acdb_data.map_v_get_blk);
free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
}
@@ -2827,11 +2814,9 @@
result = -ENOMEM;
goto done;
}
- acdb_data.map_v_fluence =
- msm_subsystem_map_buffer(
+ acdb_data.map_v_fluence = ioremap(
acdb_data.fluence_extbuff,
- FLUENCE_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ FLUENCE_BUF_SIZE);
if (IS_ERR(acdb_data.map_v_fluence)) {
MM_ERR("ACDB=> Could not map physical address\n");
free_memory_acdb_get_blk();
@@ -2852,7 +2837,7 @@
goto done;
} else
acdb_data.fluence_extbuff_virt =
- acdb_data.map_v_fluence->vaddr;
+ acdb_data.map_v_fluence;
done:
return result;
}
@@ -3431,11 +3416,11 @@
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
if (i < MAX_AUDREC_SESSIONS) {
- msm_subsystem_unmap_buffer(acdb_cache_tx[i].map_v_addr);
+ iounmap(acdb_cache_tx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
}
- msm_subsystem_unmap_buffer(acdb_cache_rx[i].map_v_addr);
+ iounmap(acdb_cache_rx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
}
@@ -3446,7 +3431,7 @@
kfree(acdb_data.preproc_iir);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.pbe_extbuff);
- msm_subsystem_unmap_buffer(acdb_data.map_v_fluence);
+ iounmap(acdb_data.map_v_fluence);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.fluence_extbuff);
mutex_destroy(&acdb_data.acdb_mutex);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
index 4b8b7a6..a53128d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
@@ -43,7 +43,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -139,8 +138,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
int wflush; /* Write flush */
@@ -1023,12 +1022,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("read buf map fail\n");
rc = -ENOMEM;
@@ -1038,7 +1035,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1420,10 +1417,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audadpcm_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1615,10 +1612,7 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, \
freeing instance 0x%08x\n",
@@ -1629,7 +1623,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1729,7 +1723,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
index a09b71b..5f288dd 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
@@ -44,7 +44,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -993,12 +992,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read phys address\n");
rc = -ENOMEM;
@@ -1007,7 +1004,7 @@
} else {
uint8_t index;
uint32_t offset = 0;
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1317,10 +1314,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrnb_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1512,9 +1509,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, freeing \
instance 0x%08x\n", (int)audio);
@@ -1525,7 +1520,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
}
@@ -1610,7 +1605,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index bdb5bb1..790c510 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -32,7 +32,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/msm_adsp.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
@@ -99,7 +98,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
+ void *map_v_read;
int opened;
int enabled;
@@ -767,7 +766,7 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -788,16 +787,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
index 48e9a9f..b74c054 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
@@ -45,7 +45,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -136,8 +135,8 @@
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1003,12 +1002,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("Error could not map read"
" phys address\n");
@@ -1018,7 +1015,7 @@
} else {
uint8_t index;
uint32_t offset = 0;
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
audio->pcm_feedback = 1;
audio->buf_refresh = 0;
audio->pcm_buf_count =
@@ -1401,10 +1398,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrwb_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1591,9 +1588,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys buffers, freeing \
instance 0x%08x\n", (int)audio);
@@ -1603,7 +1598,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1692,7 +1687,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
index 9b5694d..8818cbd 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
@@ -40,7 +40,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -982,12 +981,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read"
" phy address\n");
@@ -998,7 +995,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1311,10 +1308,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audevrc_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1505,9 +1502,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("failed to map write physical address, freeing \
instance 0x%08x\n", (int)audio);
@@ -1517,7 +1512,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1604,7 +1599,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index 50621c9..150e476 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -33,7 +33,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -131,8 +130,8 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
int running;
@@ -1319,12 +1318,12 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
if (audio->out_data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1346,17 +1345,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read physical address\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
@@ -1425,17 +1421,14 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could map write buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
@@ -1461,7 +1454,7 @@
evrc_in_listener, (void *) audio);
if (rc) {
MM_ERR("failed to register device event listener\n");
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
index c639833..a4fc3e3 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
@@ -37,7 +37,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -198,8 +197,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
uint32_t drv_status;
int mfield; /* meta field embedded in data */
@@ -1609,12 +1608,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buffer"
" physical address\n");
@@ -1625,7 +1622,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -2145,11 +2142,11 @@
wake_up(&audio->event_wait);
audmp3_reset_event_queue(audio);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -2353,10 +2350,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("failed to map write physical"
" address , freeing instance"
@@ -2368,7 +2363,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr\
0x%08x\n", audio->phys,\
(int)audio->data);
@@ -2485,7 +2480,7 @@
msm_adsp_put(audio->audplay);
err:
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
index dc41bf4..fae2401 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -276,7 +276,7 @@
struct audio_mvs_dl_reply {
struct rpc_reply_hdr reply_hdr;
- uint32_t voc_pkt[MVS_MAX_VOC_PKT_SIZE/4];
+ uint32_t voc_pkt[Q5V2_MVS_MAX_VOC_PKT_SIZE/4];
uint32_t valid_frame_info_ptr;
uint32_t frame_mode;
@@ -288,7 +288,7 @@
struct audio_mvs_buf_node {
struct list_head list;
- struct msm_audio_mvs_frame frame;
+ struct q5v2_msm_audio_mvs_frame frame;
};
/* Each buffer is 20 ms, queue holds 200 ms of data. */
@@ -933,10 +933,15 @@
pr_debug("%s: UL AMR frame_type %d\n",
__func__, be32_to_cpu(*args));
- } else if ((frame_mode == MVS_FRAME_MODE_PCM_UL) ||
- (frame_mode == MVS_FRAME_MODE_VOC_TX)) {
- /* PCM and EVRC don't have frame_type */
+ } else if (frame_mode == MVS_FRAME_MODE_PCM_UL) {
+ /* PCM don't have frame_type */
buf_node->frame.frame_type = 0;
+ } else if (frame_mode == MVS_FRAME_MODE_VOC_TX) {
+ /* Extracting EVRC current buffer frame rate*/
+ buf_node->frame.frame_type = be32_to_cpu(*args);
+
+ pr_debug("%s: UL EVRC frame_type %d\n",
+ __func__, be32_to_cpu(*args));
} else if (frame_mode == MVS_FRAME_MODE_G711_UL) {
/* Extract G711 frame type. */
buf_node->frame.frame_type = be32_to_cpu(*args);
@@ -1065,7 +1070,7 @@
cpu_to_be32(AUDIO_MVS_PKT_NORMAL);
} else if (frame_mode == MVS_FRAME_MODE_VOC_RX) {
dl_reply.cdc_param.gnr_arg.param1 =
- cpu_to_be32(audio->rate_type);
+ cpu_to_be32(buf_node->frame.frame_type);
dl_reply.cdc_param.gnr_arg.param2 = 0;
dl_reply.cdc_param.\
gnr_arg.valid_pkt_status_ptr =
@@ -1427,7 +1432,7 @@
if ((audio->state == AUDIO_MVS_STARTED) &&
(!list_empty(&audio->out_queue))) {
- if (count >= sizeof(struct msm_audio_mvs_frame)) {
+ if (count >= sizeof(struct q5v2_msm_audio_mvs_frame)) {
buf_node = list_first_entry(&audio->out_queue,
struct audio_mvs_buf_node,
list);
@@ -1435,7 +1440,8 @@
rc = copy_to_user(buf,
&buf_node->frame,
- sizeof(struct msm_audio_mvs_frame));
+ sizeof(struct q5v2_msm_audio_mvs_frame)
+ );
if (rc == 0) {
rc = buf_node->frame.len +
@@ -1453,7 +1459,7 @@
} else {
pr_err("%s: Read count %d < sizeof(frame) %d",
__func__, count,
- sizeof(struct msm_audio_mvs_frame));
+ sizeof(struct q5v2_msm_audio_mvs_frame));
rc = -ENOMEM;
}
@@ -1491,7 +1497,7 @@
mutex_lock(&audio->in_lock);
if (audio->state == AUDIO_MVS_STARTED) {
- if (count <= sizeof(struct msm_audio_mvs_frame)) {
+ if (count <= sizeof(struct q5v2_msm_audio_mvs_frame)) {
if (!list_empty(&audio->free_in_queue)) {
buf_node =
list_first_entry(&audio->free_in_queue,
@@ -1511,7 +1517,7 @@
} else {
pr_err("%s: Write count %d < sizeof(frame) %d",
__func__, count,
- sizeof(struct msm_audio_mvs_frame));
+ sizeof(struct q5v2_msm_audio_mvs_frame));
rc = -ENOMEM;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
index 9a93185..930de03 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -36,7 +36,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppcmdi.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
@@ -86,7 +85,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_write;
int teos; /* valid only if tunnel mode & no data left for decoder */
int opened;
int enabled;
@@ -704,16 +703,13 @@
{
the_audio.phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (the_audio.phys) {
- the_audio.map_v_write = msm_subsystem_map_buffer(
- the_audio.phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ the_audio.map_v_write = ioremap(the_audio.phys, DMASZ);
if (IS_ERR(the_audio.map_v_write)) {
MM_ERR("could not map physical buffers\n");
free_contiguous_memory_by_paddr(the_audio.phys);
return -ENOMEM;
}
- the_audio.data = the_audio.map_v_write->vaddr;
+ the_audio.data = the_audio.map_v_write;
} else {
MM_ERR("could not allocate physical buffers\n");
return -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
index b22820b..613ee57 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
@@ -40,7 +40,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppcmdi.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -172,7 +171,7 @@
/* data allocated for various buffers */
char *data;
int32_t phys;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_write;
uint32_t drv_status;
int wflush; /* Write flush */
int opened;
@@ -1382,7 +1381,7 @@
wake_up(&audio->event_wait);
audpcm_reset_event_queue(audio);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
mutex_unlock(&audio->lock);
@@ -1560,10 +1559,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys\
address freeing instance \
@@ -1575,7 +1572,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x \
kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
@@ -1679,7 +1676,7 @@
msm_adsp_put(audio->audplay);
err:
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index a5a9bd2..ce67ebb 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -33,7 +33,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/msm_adsp.h>
#include <mach/socinfo.h>
@@ -113,7 +112,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
+ void *map_v_read;
int opened;
int enabled;
@@ -843,7 +842,7 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -864,16 +863,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read phys buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate read buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
index ce5d421..c4851d9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
@@ -41,7 +41,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -128,8 +127,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -984,12 +983,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
rc = -ENOMEM;
@@ -999,7 +996,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1313,10 +1310,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audqcelp_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1505,9 +1502,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, freeing \
instance 0x%08x\n", (int)audio);
@@ -1517,7 +1512,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1604,7 +1599,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index d34499d..7041bde 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -33,7 +33,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -133,8 +132,8 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
@@ -1325,12 +1324,12 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
if (audio->out_data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1352,16 +1351,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
@@ -1431,16 +1428,14 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
@@ -1466,7 +1461,7 @@
qcelp_in_listener, (void *) audio);
if (rc) {
MM_ERR("failed to register device event listener\n");
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index f29b078..79439e1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -45,7 +45,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -141,8 +140,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1062,12 +1061,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("read buf alloc fail\n");
rc = -ENOMEM;
@@ -1077,7 +1074,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1458,10 +1455,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwma_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1652,10 +1649,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not allocate write buffers, \
freeing instance 0x%08x\n",
@@ -1666,7 +1660,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1772,7 +1766,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
index cf25359..6672ca0 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
@@ -44,7 +44,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -141,8 +140,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1074,12 +1073,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("read buf map fail\n");
rc = -ENOMEM;
@@ -1089,7 +1086,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->pcm_feedback = 1;
audio->buf_refresh = 0;
audio->pcm_buf_count =
@@ -1471,10 +1468,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwmapro_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1665,10 +1662,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, \
freeing instance 0x%08x\n",
@@ -1679,7 +1673,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1790,7 +1784,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
index 1d8195e..1fa0876 100644
--- a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
+++ b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
@@ -27,7 +27,6 @@
#include "../proc_comm.h"
#include <mach/debug_mm.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp6v2/dsp_debug.h>
static wait_queue_head_t dsp_wait;
@@ -72,8 +71,7 @@
{
char cmd[32];
void __iomem *ptr;
- unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
- struct msm_mapped_buffer *mem_buffer;
+ void *mem_buffer;
if (count >= sizeof(cmd))
return -EINVAL;
@@ -96,21 +94,19 @@
}
}
/* assert DSP NMI */
- mem_buffer = msm_subsystem_map_buffer(DSP_NMI_ADDR, 0x16, flags,
- NULL, 0);
+ mem_buffer = ioremap(DSP_NMI_ADDR, 0x16);
if (IS_ERR((void *)mem_buffer)) {
pr_err("%s:map_buffer failed, error = %ld\n", __func__,
PTR_ERR((void *)mem_buffer));
return -ENOMEM;
}
- ptr = mem_buffer->vaddr;
+ ptr = mem_buffer;
if (!ptr) {
pr_err("Unable to map DSP NMI\n");
return -EFAULT;
}
writel(0x1, (void *)ptr);
- if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
- pr_err("%s:unmap buffer failed\n", __func__);
+ iounmap(mem_buffer);
} else if (!strcmp(cmd, "boom")) {
q6audio_dsp_not_responding();
} else if (!strcmp(cmd, "continue-crash")) {
@@ -135,8 +131,7 @@
size_t mapsize = PAGE_SIZE;
unsigned addr;
void __iomem *ptr;
- unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
- struct msm_mapped_buffer *mem_buffer;
+ void *mem_buffer;
if ((dsp_ram_base == 0) || (dsp_ram_size == 0)) {
pr_err("[%s:%s] Memory Invalid or not initialized, Base = 0x%x,"
@@ -158,29 +153,26 @@
mapsize *= 2;
while (count >= PAGE_SIZE) {
- mem_buffer = msm_subsystem_map_buffer(addr, mapsize, flags,
- NULL, 0);
+ mem_buffer = ioremap(addr, mapsize);
if (IS_ERR((void *)mem_buffer)) {
pr_err("%s:map_buffer failed, error = %ld\n",
__func__, PTR_ERR((void *)mem_buffer));
return -ENOMEM;
}
- ptr = mem_buffer->vaddr;
+ ptr = mem_buffer;
if (!ptr) {
pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
__func__, addr);
return -EFAULT;
}
if (copy_to_user(buf, ptr, PAGE_SIZE)) {
- if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
- pr_err("%s: unmap buffer failed\n", __func__);
+ iounmap(mem_buffer);
pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
__func__, buf);
return -EFAULT;
}
copy_ok_count += PAGE_SIZE;
- if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
- pr_err("%s: unmap buffer failed\n", __func__);
+ iounmap(mem_buffer);
addr += PAGE_SIZE;
buf += PAGE_SIZE;
actual += PAGE_SIZE;
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index b14c968..221ffca 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,10 @@
#define SCM_FLAG_WARMBOOT_CPU2 0x10
#define SCM_FLAG_WARMBOOT_CPU3 0x40
+#ifdef CONFIG_MSM_SCM
int scm_set_boot_addr(void *addr, int flags);
+#else
+static inline int scm_set_boot_addr(void *addr, int flags) { return 0; }
+#endif
#endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index dac0a37..ddc3a8d 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3483,8 +3483,14 @@
},
};
-static int __init msm_smd_init(void)
+int __init msm_smd_init(void)
{
+ static bool registered;
+
+ if (registered)
+ return 0;
+
+ registered = true;
return platform_driver_register(&msm_smd_driver);
}
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index b457a00..81a9fa7 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -393,6 +393,8 @@
case MDP_RGB_565:
case MDP_BGR_565:
case MDP_YCRYCB_H2V1:
+ case MDP_YCBCR_H1V1:
+ case MDP_YCRCB_H1V1:
p->num_planes = 1;
p->plane_size[0] = w * h * get_bpp(format);
break;
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index bd7729b..9597d18 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1493,21 +1493,28 @@
mutex_unlock(&client->lock);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
+ if (data.fd < 0)
+ return data.fd;
break;
}
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
+ int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
data.handle = ion_import_fd(client, data.fd);
- if (IS_ERR(data.handle))
+ if (IS_ERR(data.handle)) {
+ ret = PTR_ERR(data.handle);
data.handle = NULL;
+ }
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
+ if (ret < 0)
+ return ret;
break;
}
case ION_IOC_CUSTOM:
@@ -1561,6 +1568,8 @@
if (!data.handle)
ion_free(client, handle);
+ if (ret < 0)
+ return ret;
break;
}
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 15c0ec5..c8bfce3 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -213,6 +213,45 @@
}
}
+static int is_heap_overlapping(const struct ion_platform_heap *heap1,
+ const struct ion_platform_heap *heap2)
+{
+ unsigned long heap1_base = heap1->base;
+ unsigned long heap2_base = heap2->base;
+ unsigned long heap1_end = heap1->base + heap1->size - 1;
+ unsigned long heap2_end = heap2->base + heap2->size - 1;
+
+ if (heap1_base == heap2_base)
+ return 1;
+ if (heap1_base < heap2_base && heap1_end >= heap2_base)
+ return 1;
+ if (heap2_base < heap1_base && heap2_end >= heap1_base)
+ return 1;
+ return 0;
+}
+
+static void check_for_heap_overlap(const struct ion_platform_heap heap_list[],
+ unsigned long nheaps)
+{
+ unsigned long i;
+ unsigned long j;
+
+ for (i = 0; i < nheaps; ++i) {
+ const struct ion_platform_heap *heap1 = &heap_list[i];
+ if (!heap1->base)
+ continue;
+ for (j = i + 1; j < nheaps; ++j) {
+ const struct ion_platform_heap *heap2 = &heap_list[j];
+ if (!heap2->base)
+ continue;
+ if (is_heap_overlapping(heap1, heap2)) {
+ panic("Memory in heap %s overlaps with heap %s\n",
+ heap1->name, heap2->name);
+ }
+ }
+ }
+}
+
static int msm_ion_probe(struct platform_device *pdev)
{
struct ion_platform_data *pdata = pdev->dev.platform_data;
@@ -258,6 +297,8 @@
ion_device_add_heap(idev, heaps[i]);
}
+
+ check_for_heap_overlap(pdata->heaps, num_heaps);
platform_set_drvdata(pdev, idev);
return 0;
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 9479302..96390ac 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -69,10 +69,9 @@
static struct adreno_device device_3d0 = {
.dev = {
+ KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
.name = DEVICE_3D0_NAME,
.id = KGSL_DEVICE_3D0,
- .ver_major = DRIVER_VERSION_MAJOR,
- .ver_minor = DRIVER_VERSION_MINOR,
.mh = {
.mharb = ADRENO_CFG_MHARB,
/* Remove 1k boundary check in z470 to avoid a GPU
@@ -92,9 +91,6 @@
.pwrctrl = {
.irq_name = KGSL_3D0_IRQ,
},
- .mutex = __MUTEX_INITIALIZER(device_3d0.dev.mutex),
- .state = KGSL_STATE_INIT,
- .active_cnt = 0,
.iomemname = KGSL_3D0_REG_MEMORY,
.ftbl = &adreno_functable,
#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -280,7 +276,7 @@
/* set page table base */
*cmds++ = cp_type0_packet(MH_MMU_PT_BASE, 1);
- *cmds++ = kgsl_pt_get_base_addr(
+ *cmds++ = kgsl_mmu_pt_get_base_addr(
device->mmu.hwpagetable);
sizedwords += 4;
}
@@ -482,8 +478,6 @@
adreno_dev = ADRENO_DEVICE(device);
device->parentdev = &pdev->dev;
- init_completion(&device->recovery_gate);
-
status = adreno_ringbuffer_init(device);
if (status != 0)
goto error;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2ce2f2b..adf2772 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -25,6 +25,8 @@
#include <linux/ashmem.h>
#include <linux/major.h>
#include <linux/ion.h>
+#include <linux/io.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -385,7 +387,7 @@
idr_remove(&dev_priv->device->context_idr, id);
}
-static void kgsl_timestamp_expired(struct work_struct *work)
+void kgsl_timestamp_expired(struct work_struct *work)
{
struct kgsl_device *device = container_of(work, struct kgsl_device,
ts_expired_ws);
@@ -415,6 +417,7 @@
mutex_unlock(&device->mutex);
}
+EXPORT_SYMBOL(kgsl_timestamp_expired);
static void kgsl_check_idle_locked(struct kgsl_device *device)
{
@@ -2334,7 +2337,7 @@
};
EXPORT_SYMBOL(kgsl_driver);
-void kgsl_unregister_device(struct kgsl_device *device)
+static void _unregister_device(struct kgsl_device *device)
{
int minor;
@@ -2343,43 +2346,15 @@
if (device == kgsl_driver.devp[minor])
break;
}
-
- mutex_unlock(&kgsl_driver.devlock);
-
- if (minor == KGSL_DEVICE_MAX)
- return;
-
- kgsl_device_snapshot_close(device);
-
- kgsl_cffdump_close(device->id);
- kgsl_pwrctrl_uninit_sysfs(device);
-
- wake_lock_destroy(&device->idle_wakelock);
- pm_qos_remove_request(&device->pm_qos_req_dma);
-
- idr_destroy(&device->context_idr);
-
- if (device->memstore.hostptr)
- kgsl_sharedmem_free(&device->memstore);
-
- kgsl_mmu_close(device);
-
- if (device->work_queue) {
- destroy_workqueue(device->work_queue);
- device->work_queue = NULL;
+ if (minor != KGSL_DEVICE_MAX) {
+ device_destroy(kgsl_driver.class,
+ MKDEV(MAJOR(kgsl_driver.major), minor));
+ kgsl_driver.devp[minor] = NULL;
}
-
- device_destroy(kgsl_driver.class,
- MKDEV(MAJOR(kgsl_driver.major), minor));
-
- mutex_lock(&kgsl_driver.devlock);
- kgsl_driver.devp[minor] = NULL;
mutex_unlock(&kgsl_driver.devlock);
}
-EXPORT_SYMBOL(kgsl_unregister_device);
-int
-kgsl_register_device(struct kgsl_device *device)
+static int _register_device(struct kgsl_device *device)
{
int minor, ret;
dev_t dev;
@@ -2393,7 +2368,6 @@
break;
}
}
-
mutex_unlock(&kgsl_driver.devlock);
if (minor == KGSL_DEVICE_MAX) {
@@ -2409,75 +2383,17 @@
device->name);
if (IS_ERR(device->dev)) {
+ mutex_lock(&kgsl_driver.devlock);
+ kgsl_driver.devp[minor] = NULL;
+ mutex_unlock(&kgsl_driver.devlock);
ret = PTR_ERR(device->dev);
KGSL_CORE_ERR("device_create(%s): %d\n", device->name, ret);
- goto err_devlist;
+ return ret;
}
dev_set_drvdata(device->parentdev, device);
-
- /* Generic device initialization */
- init_waitqueue_head(&device->wait_queue);
-
- kgsl_cffdump_open(device->id);
-
- init_completion(&device->hwaccess_gate);
- init_completion(&device->suspend_gate);
-
- ATOMIC_INIT_NOTIFIER_HEAD(&device->ts_notifier_list);
-
- setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
- ret = kgsl_create_device_workqueue(device);
- if (ret)
- goto err_devlist;
-
- INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
- INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
-
- INIT_LIST_HEAD(&device->events);
-
- device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
-
- ret = kgsl_mmu_init(device);
- if (ret != 0)
- goto err_dest_work_q;
-
- ret = kgsl_allocate_contiguous(&device->memstore, KGSL_MEMSTORE_SIZE);
- if (ret != 0)
- goto err_close_mmu;
-
- wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
- pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
- idr_init(&device->context_idr);
-
- /* Initalize the snapshot engine */
- kgsl_device_snapshot_init(device);
-
- /* sysfs and debugfs initalization - failure here is non fatal */
-
- /* Initialize logging */
- kgsl_device_debugfs_init(device);
-
- /* Initialize common sysfs entries */
- kgsl_pwrctrl_init_sysfs(device);
-
return 0;
-
-err_close_mmu:
- kgsl_mmu_close(device);
-err_dest_work_q:
- destroy_workqueue(device->work_queue);
- device->work_queue = NULL;
-err_devlist:
- mutex_lock(&kgsl_driver.devlock);
- kgsl_driver.devp[minor] = NULL;
- mutex_unlock(&kgsl_driver.devlock);
-
- return ret;
}
-EXPORT_SYMBOL(kgsl_register_device);
int kgsl_device_platform_probe(struct kgsl_device *device)
{
@@ -2487,7 +2403,12 @@
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
- pm_runtime_enable(device->parentdev);
+ status = _register_device(device);
+ if (status)
+ return status;
+
+ /* Initialize logging first, so that failures below actually print. */
+ kgsl_device_debugfs_init(device);
status = kgsl_pwrctrl_init(device);
if (status)
@@ -2512,29 +2433,40 @@
device->reg_phys = res->start;
device->reg_len = resource_size(res);
- if (!request_mem_region(device->reg_phys, device->reg_len,
- device->name)) {
+ if (!devm_request_mem_region(device->dev, device->reg_phys,
+ device->reg_len, device->name)) {
KGSL_DRV_ERR(device, "request_mem_region failed\n");
status = -ENODEV;
goto error_pwrctrl_close;
}
- device->reg_virt = ioremap(device->reg_phys, device->reg_len);
+ device->reg_virt = devm_ioremap(device->dev, device->reg_phys,
+ device->reg_len);
if (device->reg_virt == NULL) {
KGSL_DRV_ERR(device, "ioremap failed\n");
status = -ENODEV;
- goto error_release_mem;
+ goto error_pwrctrl_close;
+ }
+ /*acquire interrupt */
+ device->pwrctrl.interrupt_num =
+ platform_get_irq_byname(pdev, device->pwrctrl.irq_name);
+
+ if (device->pwrctrl.interrupt_num <= 0) {
+ KGSL_DRV_ERR(device, "platform_get_irq_byname failed: %d\n",
+ device->pwrctrl.interrupt_num);
+ status = -EINVAL;
+ goto error_pwrctrl_close;
}
- status = request_irq(device->pwrctrl.interrupt_num, kgsl_irq_handler,
- IRQF_TRIGGER_HIGH, device->name, device);
+ status = devm_request_irq(device->dev, device->pwrctrl.interrupt_num,
+ kgsl_irq_handler, IRQF_TRIGGER_HIGH,
+ device->name, device);
if (status) {
KGSL_DRV_ERR(device, "request_irq(%d) failed: %d\n",
device->pwrctrl.interrupt_num, status);
- goto error_iounmap;
+ goto error_pwrctrl_close;
}
- device->pwrctrl.have_irq = 1;
disable_irq(device->pwrctrl.interrupt_num);
KGSL_DRV_INFO(device,
@@ -2544,38 +2476,78 @@
result = kgsl_drm_init(pdev);
if (result)
- goto error_iounmap;
+ goto error_pwrctrl_close;
- status = kgsl_register_device(device);
- if (!status)
- return status;
+ kgsl_cffdump_open(device->id);
- free_irq(device->pwrctrl.interrupt_num, NULL);
- device->pwrctrl.have_irq = 0;
-error_iounmap:
- iounmap(device->reg_virt);
- device->reg_virt = NULL;
-error_release_mem:
- release_mem_region(device->reg_phys, device->reg_len);
+ setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+ status = kgsl_create_device_workqueue(device);
+ if (status)
+ goto error_pwrctrl_close;
+
+ status = kgsl_mmu_init(device);
+ if (status != 0) {
+ KGSL_DRV_ERR(device, "kgsl_mmu_init failed %d\n", status);
+ goto error_dest_work_q;
+ }
+
+ status = kgsl_allocate_contiguous(&device->memstore,
+ sizeof(struct kgsl_devmemstore));
+
+ if (status != 0) {
+ KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
+ status);
+ goto error_close_mmu;
+ }
+
+ wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
+ pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ /* Initalize the snapshot engine */
+ kgsl_device_snapshot_init(device);
+
+ /* Initialize common sysfs entries */
+ kgsl_pwrctrl_init_sysfs(device);
+
+ return 0;
+
+error_close_mmu:
+ kgsl_mmu_close(device);
+error_dest_work_q:
+ destroy_workqueue(device->work_queue);
+ device->work_queue = NULL;
error_pwrctrl_close:
kgsl_pwrctrl_close(device);
error:
+ _unregister_device(device);
return status;
}
EXPORT_SYMBOL(kgsl_device_platform_probe);
void kgsl_device_platform_remove(struct kgsl_device *device)
{
- kgsl_unregister_device(device);
+ kgsl_device_snapshot_close(device);
- if (device->reg_virt != NULL) {
- iounmap(device->reg_virt);
- device->reg_virt = NULL;
- release_mem_region(device->reg_phys, device->reg_len);
+ kgsl_cffdump_close(device->id);
+ kgsl_pwrctrl_uninit_sysfs(device);
+
+ wake_lock_destroy(&device->idle_wakelock);
+ pm_qos_remove_request(&device->pm_qos_req_dma);
+
+ idr_destroy(&device->context_idr);
+
+ kgsl_sharedmem_free(&device->memstore);
+
+ kgsl_mmu_close(device);
+
+ if (device->work_queue) {
+ destroy_workqueue(device->work_queue);
+ device->work_queue = NULL;
}
kgsl_pwrctrl_close(device);
- pm_runtime_disable(device->parentdev);
+ _unregister_device(device);
}
EXPORT_SYMBOL(kgsl_device_platform_remove);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b42e606..0964458 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -199,6 +199,26 @@
s64 on_time;
};
+void kgsl_timestamp_expired(struct work_struct *work);
+
+#define KGSL_DEVICE_COMMON_INIT(_dev) \
+ .hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
+ .suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
+ .recovery_gate = COMPLETION_INITIALIZER((_dev).recovery_gate),\
+ .ts_notifier_list = ATOMIC_NOTIFIER_INIT((_dev).ts_notifier_list),\
+ .idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
+ kgsl_idle_check),\
+ .ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
+ kgsl_timestamp_expired),\
+ .context_idr = IDR_INIT((_dev).context_idr),\
+ .events = LIST_HEAD_INIT((_dev).events),\
+ .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\
+ .mutex = __MUTEX_INITIALIZER((_dev).mutex),\
+ .state = KGSL_STATE_INIT,\
+ .ver_major = DRIVER_VERSION_MAJOR,\
+ .ver_minor = DRIVER_VERSION_MINOR,\
+ .last_expired_ctxt_id = KGSL_CONTEXT_INVALID
+
struct kgsl_context {
uint32_t id;
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 880fde1..ab47f40 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -708,6 +708,13 @@
return ptbase;
}
+static unsigned int
+kgsl_gpummu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
+ return gpummu_pt->base.gpuaddr;
+}
+
struct kgsl_mmu_ops gpummu_ops = {
.mmu_init = kgsl_gpummu_init,
.mmu_close = kgsl_gpummu_close,
@@ -719,6 +726,9 @@
.mmu_get_current_ptbase = kgsl_gpummu_get_current_ptbase,
.mmu_enable_clk = NULL,
.mmu_disable_clk = NULL,
+ .mmu_get_hwpagetable_asid = NULL,
+ .mmu_get_pt_lsb = NULL,
+ .mmu_get_reg_map_desc = NULL,
};
struct kgsl_mmu_pt_ops gpummu_pt_ops = {
@@ -727,4 +737,5 @@
.mmu_create_pagetable = kgsl_gpummu_create_pagetable,
.mmu_destroy_pagetable = kgsl_gpummu_destroy_pagetable,
.mmu_pt_equal = kgsl_gpummu_pt_equal,
+ .mmu_pt_get_base_addr = kgsl_gpummu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_gpummu.h b/drivers/gpu/msm/kgsl_gpummu.h
index c61a8b2..caa5df1 100644
--- a/drivers/gpu/msm/kgsl_gpummu.h
+++ b/drivers/gpu/msm/kgsl_gpummu.h
@@ -75,9 +75,4 @@
void *kgsl_gpummu_ptpool_init(int entries);
void kgsl_gpummu_ptpool_destroy(void *ptpool);
-static inline unsigned int kgsl_pt_get_base_addr(struct kgsl_pagetable *pt)
-{
- struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
- return gpummu_pt->base.gpuaddr;
-}
#endif /* __KGSL_GPUMMU_H */
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 4f27e6c..2f83a40 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -96,27 +96,77 @@
return ret;
}
+/*
+ * kgsl_iommu_pt_equal - Check if pagetables are equal
+ * @pt - Pointer to pagetable
+ * @pt_base - Address of a pagetable that the IOMMU register is
+ * programmed with
+ *
+ * Checks whether the pt_base is equal to the base address of
+ * the pagetable which is contained in the pt structure
+ * Return - Non-zero if the pagetable addresses are equal else 0
+ */
static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
unsigned int pt_base)
{
- struct iommu_domain *domain = pt ? pt->priv : NULL;
- return domain && pt_base && ((unsigned int)domain == pt_base);
+ struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
+ unsigned int domain_ptbase = iommu_pt ?
+ iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+ /* Only compare the valid address bits of the pt_base */
+ domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT);
+ pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT);
+ return domain_ptbase && pt_base &&
+ (domain_ptbase == pt_base);
}
+/*
+ * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
+ * @mmu_specific_pt - Pointer to pagetable which is to be freed
+ *
+ * Return - void
+ */
static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
{
- struct iommu_domain *domain = mmu_specific_pt;
- if (domain)
- iommu_domain_free(domain);
+ struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ if (iommu_pt->domain)
+ iommu_domain_free(iommu_pt->domain);
+ if (iommu_pt->iommu) {
+ if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
+ iommu_pt->iommu->asid_reuse)
+ iommu_pt->iommu->asid_reuse--;
+ if (!iommu_pt->iommu->asid_reuse ||
+ (KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
+ clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
+ }
+ kfree(iommu_pt);
}
+/*
+ * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
+ *
+ * Allocate memory to hold a pagetable and allocate the IOMMU
+ * domain which is the actual IOMMU pagetable
+ * Return - void
+ */
void *kgsl_iommu_create_pagetable(void)
{
- struct iommu_domain *domain = iommu_domain_alloc(0);
- if (!domain)
- KGSL_CORE_ERR("Failed to create iommu domain\n");
+ struct kgsl_iommu_pt *iommu_pt;
- return domain;
+ iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
+ if (!iommu_pt) {
+ KGSL_CORE_ERR("kzalloc(%d) failed\n",
+ sizeof(struct kgsl_iommu_pt));
+ return NULL;
+ }
+ iommu_pt->domain = iommu_domain_alloc(0);
+ if (!iommu_pt->domain) {
+ KGSL_CORE_ERR("Failed to create iommu domain\n");
+ kfree(iommu_pt);
+ return NULL;
+ }
+ return iommu_pt;
}
/*
@@ -133,25 +183,25 @@
*/
static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
{
- struct iommu_domain *domain;
+ struct kgsl_iommu_pt *iommu_pt;
struct kgsl_iommu *iommu = mmu->priv;
int i, j;
BUG_ON(mmu->hwpagetable == NULL);
BUG_ON(mmu->hwpagetable->priv == NULL);
- domain = mmu->hwpagetable->priv;
+ iommu_pt = mmu->hwpagetable->priv;
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
if (iommu_unit->dev[j].attached) {
- iommu_detach_device(domain,
+ iommu_detach_device(iommu_pt->domain,
iommu_unit->dev[j].dev);
iommu_unit->dev[j].attached = false;
KGSL_MEM_INFO(mmu->device, "iommu %p detached "
"from user dev of MMU: %p\n",
- domain, mmu);
+ iommu_pt->domain, mmu);
}
}
}
@@ -172,14 +222,14 @@
*/
static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
{
- struct iommu_domain *domain;
+ struct kgsl_iommu_pt *iommu_pt;
struct kgsl_iommu *iommu = mmu->priv;
int i, j, ret = 0;
BUG_ON(mmu->hwpagetable == NULL);
BUG_ON(mmu->hwpagetable->priv == NULL);
- domain = mmu->hwpagetable->priv;
+ iommu_pt = mmu->hwpagetable->priv;
/*
* Loop through all the iommu devcies under all iommu units and
@@ -189,7 +239,7 @@
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
if (!iommu_unit->dev[j].attached) {
- ret = iommu_attach_device(domain,
+ ret = iommu_attach_device(iommu_pt->domain,
iommu_unit->dev[j].dev);
if (ret) {
KGSL_MEM_ERR(mmu->device,
@@ -200,8 +250,8 @@
iommu_unit->dev[j].attached = true;
KGSL_MEM_INFO(mmu->device,
"iommu pt %p attached to dev %p, ctx_id %d\n",
- domain, iommu_unit->dev[j].dev,
- iommu_unit->dev[j].ctx_id);
+ iommu_pt->domain, iommu_unit->dev[j].dev,
+ iommu_unit->dev[j].ctx_id);
}
}
}
@@ -352,19 +402,66 @@
return ret;
}
+/*
+ * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * IOMMU ttbr0 register is programmed with
+ * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
+ *
+ * Return - actual pagetable address that the ttbr0 register is programmed
+ * with
+ */
+static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
+ return iommu_get_pt_base_addr(iommu_pt->domain);
+}
+
+/*
+ * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
+ * @mmu - Pointer to mmu structure
+ * @hostptr - Pointer to the IOMMU register map. This is used to match
+ * the iommu device whose lsb value is to be returned
+ * @ctx_id - The context bank whose lsb valus is to be returned
+ * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
+ * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
+ * are only programmed once in the beginning when a domain is attached
+ * does not change.
+ */
+static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
+ unsigned int unit_id,
+ enum kgsl_iommu_context_id ctx_id)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i, j;
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++)
+ if (unit_id == i &&
+ ctx_id == iommu_unit->dev[j].ctx_id)
+ return iommu_unit->dev[j].pt_lsb;
+ }
+ return 0;
+}
+
static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable)
{
if (mmu->flags & KGSL_FLAGS_STARTED) {
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
/* page table not current, then setup mmu to use new
* specified page table
*/
if (mmu->hwpagetable != pagetable) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
- kgsl_detach_pagetable_iommu_domain(mmu);
+ unsigned int flags = 0;
mmu->hwpagetable = pagetable;
- if (mmu->hwpagetable)
- kgsl_attach_pagetable_iommu_domain(mmu);
+ /* force tlb flush if asid is reused */
+ if (iommu->asid_reuse &&
+ (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
+ flags |= KGSL_MMUFLAGS_TLBFLUSH;
+ flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
+ mmu->device->id);
+ kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
}
}
}
@@ -385,6 +482,14 @@
sizeof(struct kgsl_iommu));
return -ENOMEM;
}
+ iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!iommu->asids) {
+ KGSL_CORE_ERR("kzalloc(%d) failed\n",
+ sizeof(struct kgsl_iommu));
+ status = -ENOMEM;
+ goto done;
+ }
mmu->priv = iommu;
status = kgsl_get_iommu_ctxt(mmu);
@@ -398,6 +503,7 @@
__func__);
done:
if (status) {
+ kfree(iommu->asids);
kfree(iommu);
mmu->priv = NULL;
}
@@ -418,6 +524,7 @@
int status = 0;
int i = 0;
struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt;
mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
/* Return error if the default pagetable doesn't exist */
@@ -437,6 +544,14 @@
goto err;
}
}
+ /*
+ * The dafault pagetable always has asid 0 assigned by the iommu driver
+ * and asid 1 is assigned to the private context.
+ */
+ iommu_pt = mmu->defaultpagetable->priv;
+ iommu_pt->asid = 0;
+ set_bit(0, iommu->asids);
+ set_bit(1, iommu->asids);
return status;
err:
for (i--; i >= 0; i--) {
@@ -454,6 +569,8 @@
static int kgsl_iommu_start(struct kgsl_mmu *mmu)
{
int status;
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i, j;
if (mmu->flags & KGSL_FLAGS_STARTED)
return 0;
@@ -474,7 +591,42 @@
kgsl_detach_pagetable_iommu_domain(mmu);
mmu->hwpagetable = NULL;
}
+ status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+ if (status) {
+ KGSL_CORE_ERR("clk enable failed\n");
+ goto done;
+ }
+ status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
+ if (status) {
+ KGSL_CORE_ERR("clk enable failed\n");
+ goto done;
+ }
+ /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
+ * that value should not change when we change pagetables, so while
+ * changing pagetables we can use this lsb value of the pagetable w/o
+ * having to read it again
+ */
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++)
+ iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
+ KGSL_IOMMU_GET_IOMMU_REG(
+ iommu_unit->reg_map.hostptr,
+ iommu_unit->dev[j].ctx_id,
+ TTBR0));
+ }
+ iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[0].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER,
+ CONTEXTIDR);
+ kgsl_iommu_disable_clk(mmu);
+
+done:
+ if (status) {
+ kgsl_iommu_disable_clk(mmu);
+ kgsl_detach_pagetable_iommu_domain(mmu);
+ }
return status;
}
@@ -484,8 +636,7 @@
{
int ret;
unsigned int range = memdesc->size;
- struct iommu_domain *domain = (struct iommu_domain *)
- mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
/* All GPU addresses as assigned are page aligned, but some
functions purturb the gpuaddr with an offset, so apply the
@@ -496,10 +647,10 @@
if (range == 0 || gpuaddr == 0)
return 0;
- ret = iommu_unmap_range(domain, gpuaddr, range);
+ ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
if (ret)
KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
- "with err: %d\n", domain, gpuaddr,
+ "with err: %d\n", iommu_pt->domain, gpuaddr,
range, ret);
return 0;
@@ -513,20 +664,20 @@
{
int ret;
unsigned int iommu_virt_addr;
- struct iommu_domain *domain = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
- BUG_ON(NULL == domain);
+ BUG_ON(NULL == iommu_pt);
iommu_virt_addr = memdesc->gpuaddr;
- ret = iommu_map_range(domain, iommu_virt_addr, memdesc->sg,
+ ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
memdesc->size, (IOMMU_READ | IOMMU_WRITE));
if (ret) {
KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
- "failed with err: %d\n", domain,
+ "failed with err: %d\n", iommu_pt->domain,
iommu_virt_addr, memdesc->sg, memdesc->size,
- 0, ret);
+ (IOMMU_READ | IOMMU_WRITE), ret);
return ret;
}
@@ -573,6 +724,8 @@
}
if (mmu->defaultpagetable)
kgsl_mmu_putpagetable(mmu->defaultpagetable);
+ kfree(iommu->asids);
+ kfree(iommu);
return 0;
}
@@ -592,17 +745,168 @@
KGSL_IOMMU_TTBR0_PA_SHIFT);
}
+/*
+ * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
+ * pagetable
+ * @mmu - Pointer to mmu structure
+ *
+ * Allocates an asid to a IOMMU domain if it does not already have one. asid's
+ * are unique identifiers for pagetable that can be used to selectively flush
+ * tlb entries of the IOMMU unit.
+ * Return - asid to be used with the IOMMU domain
+ */
+static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
+
+ /*
+ * If the iommu pagetable does not have any asid assigned and is not the
+ * default pagetable then assign asid.
+ */
+ if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
+ iommu_pt->asid = find_first_zero_bit(iommu->asids,
+ KGSL_IOMMU_MAX_ASIDS);
+ /* No free bits means reuse asid */
+ if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
+ iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
+ iommu->asid_reuse++;
+ }
+ set_bit(iommu_pt->asid, iommu->asids);
+ /*
+ * Store pointer to asids list so that during pagetable destroy
+ * the asid assigned to this pagetable may be cleared
+ */
+ iommu_pt->iommu = iommu;
+ }
+ /* Return the asid + the constant part of asid that never changes */
+ return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
+ KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
+ (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
+ KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
+}
+
+/*
+ * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
+ * of the primary context bank
+ * @mmu - Pointer to mmu structure
+ * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
+ * flushed or both
+ *
+ * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
+ * do both by doing direct register writes to the IOMMu registers through the
+ * cpu
+ * Return - void
+ */
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+ uint32_t flags)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int temp;
+ int i;
+ unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
+ mmu->hwpagetable);
+ unsigned int pt_val;
+
+ if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
+ KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+ return;
+ }
+ /* Mask off the lsb of the pt base address since lsb will not change */
+ pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
+ if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+ kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ for (i = 0; i < iommu->unit_count; i++) {
+ /* get the lsb value which should not change when
+ * changing ttbr0 */
+ pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
+ KGSL_IOMMU_CONTEXT_USER);
+ pt_val += pt_base;
+
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+
+ mb();
+ temp = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, TTBR0);
+ /* Set asid */
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
+ kgsl_iommu_get_hwpagetable_asid(mmu));
+ mb();
+ temp = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
+ }
+ }
+ /* Flush tlb */
+ if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+ for (i = 0; i < iommu->unit_count; i++) {
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
+ kgsl_iommu_get_hwpagetable_asid(mmu));
+ mb();
+ }
+ }
+ /* Disable smmu clock */
+ kgsl_iommu_disable_clk(mmu);
+}
+
+/*
+ * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
+ * the address of memory descriptors which map the IOMMU registers
+ * @mmu - Pointer to mmu structure
+ * @reg_map_desc - Out parameter in which the address of the array containing
+ * pointers to register map descriptors is returned. The caller is supposed
+ * to free this array
+ *
+ * Return - The number of iommu units which is also the number of register
+ * mapped descriptor arrays which the out parameter will have
+ */
+static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
+ void **reg_map_desc)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ void **reg_desc_ptr;
+ int i;
+
+ /*
+ * Alocate array of pointers that will hold address of the register map
+ * descriptors
+ */
+ reg_desc_ptr = kmalloc(iommu->unit_count *
+ sizeof(struct kgsl_memdesc *), GFP_KERNEL);
+ if (!reg_desc_ptr) {
+ KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
+ iommu->unit_count * sizeof(struct kgsl_memdesc *));
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < iommu->unit_count; i++)
+ reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
+
+ *reg_map_desc = reg_desc_ptr;
+ return i;
+}
+
struct kgsl_mmu_ops iommu_ops = {
.mmu_init = kgsl_iommu_init,
.mmu_close = kgsl_iommu_close,
.mmu_start = kgsl_iommu_start,
.mmu_stop = kgsl_iommu_stop,
.mmu_setstate = kgsl_iommu_setstate,
- .mmu_device_setstate = NULL,
+ .mmu_device_setstate = kgsl_iommu_default_setstate,
.mmu_pagefault = NULL,
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk = kgsl_iommu_disable_clk,
+ .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
+ .mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
+ .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
};
struct kgsl_mmu_pt_ops iommu_pt_ops = {
@@ -611,4 +915,5 @@
.mmu_create_pagetable = kgsl_iommu_create_pagetable,
.mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
.mmu_pt_equal = kgsl_iommu_pt_equal,
+ .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 5a92f513..c2e84a6 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -26,6 +26,10 @@
#define KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT 0
#define KGSL_IOMMU_CTX_TLBIASID 0x804
#define KGSL_IOMMU_CTX_SHIFT 12
+
+#define KGSL_IOMMU_MAX_ASIDS 256
+#define KGSL_IOMMU_ASID_REUSE 2
+
/*
* Max number of iommu units that the gpu core can have
* On APQ8064, KGSL can control a maximum of 2 IOMMU units.
@@ -35,6 +39,22 @@
/* Max number of iommu contexts per IOMMU unit */
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
+/* Macros to read/write IOMMU registers */
+#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val) \
+ writel_relaxed(val, base_addr + \
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ KGSL_IOMMU_##REG)
+
+#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG) \
+ readl_relaxed(base_addr + \
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ KGSL_IOMMU_##REG)
+
+/* Gets the lsb value of pagetable */
+#define KGSL_IOMMMU_PT_LSB(pt_val) \
+ (pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK << \
+ KGSL_IOMMU_TTBR0_PA_SHIFT))
+
/*
* struct kgsl_iommu_device - Structure holding data about iommu contexts
* @dev: Device pointer to iommu context
@@ -81,6 +101,7 @@
* @asids: A bit structure indicating which id's are presently used
* @asid: Contains the initial value of IOMMU_CONTEXTIDR when a domain
* is first attached
+ * asid_reuse: Holds the number of times the reuse asid is reused
*/
struct kgsl_iommu {
struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
@@ -89,7 +110,19 @@
struct kgsl_device *device;
unsigned long *asids;
unsigned int asid;
- unsigned int active_ctx;
+ unsigned int asid_reuse;
+};
+
+/*
+ * struct kgsl_iommu_pt - Iommu pagetable structure private to kgsl driver
+ * @domain: Pointer to the iommu domain that contains the iommu pagetable
+ * @iommu: Pointer to iommu structure
+ * @asid: The asid assigned to this domain
+ */
+struct kgsl_iommu_pt {
+ struct iommu_domain *domain;
+ struct kgsl_iommu *iommu;
+ unsigned int asid;
};
#endif
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 5fdc182..606d861 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -521,11 +521,8 @@
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return (void *)(-1);
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
- if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
- name = KGSL_MMU_GLOBAL_PT;
-#else
- name = KGSL_MMU_GLOBAL_PT;
+#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+ name = KGSL_MMU_GLOBAL_PT;
#endif
pt = kgsl_get_pagetable(name);
@@ -546,7 +543,8 @@
struct kgsl_device *device = mmu->device;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return;
- else if (device->ftbl->setstate)
+ else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
+ kgsl_mmu_type))
device->ftbl->setstate(device, flags);
else if (mmu->mmu_ops->mmu_device_setstate)
mmu->mmu_ops->mmu_device_setstate(mmu, flags);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index fc64629..df4a64b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -134,6 +134,12 @@
(struct kgsl_mmu *mmu);
int (*mmu_enable_clk)
(struct kgsl_mmu *mmu, int ctx_id);
+ int (*mmu_get_hwpagetable_asid)(struct kgsl_mmu *mmu);
+ int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
+ unsigned int unit_id,
+ enum kgsl_iommu_context_id ctx_id);
+ int (*mmu_get_reg_map_desc)(struct kgsl_mmu *mmu,
+ void **reg_map_desc);
};
struct kgsl_mmu_pt_ops {
@@ -147,6 +153,8 @@
void (*mmu_destroy_pagetable) (void *pt);
int (*mmu_pt_equal) (struct kgsl_pagetable *pt,
unsigned int pt_base);
+ unsigned int (*mmu_pt_get_base_addr)
+ (struct kgsl_pagetable *pt);
};
struct kgsl_mmu {
@@ -236,4 +244,21 @@
return pt->pt_ops->mmu_pt_equal(pt, pt_base);
}
+static inline unsigned int kgsl_mmu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+ return 0;
+ else
+ return pt->pt_ops->mmu_pt_get_base_addr(pt);
+}
+
+static inline int kgsl_mmu_get_reg_map_desc(struct kgsl_mmu *mmu,
+ void **reg_map_desc)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_map_desc)
+ return mmu->mmu_ops->mmu_get_reg_map_desc(mmu, reg_map_desc);
+ else
+ return 0;
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 9365772..3a29d71 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
@@ -552,17 +553,8 @@
}
}
- /*acquire interrupt */
- pwr->interrupt_num =
- platform_get_irq_byname(pdev, pwr->irq_name);
- if (pwr->interrupt_num <= 0) {
- KGSL_PWR_ERR(device, "platform_get_irq_byname failed: %d\n",
- pwr->interrupt_num);
- result = -EINVAL;
- goto done;
- }
-
+ pm_runtime_enable(device->parentdev);
register_early_suspend(&device->display_off);
return result;
@@ -582,16 +574,9 @@
KGSL_PWR_INFO(device, "close device %d\n", device->id);
+ pm_runtime_disable(device->parentdev);
unregister_early_suspend(&device->display_off);
- if (pwr->interrupt_num > 0) {
- if (pwr->have_irq) {
- free_irq(pwr->interrupt_num, NULL);
- pwr->have_irq = 0;
- }
- pwr->interrupt_num = 0;
- }
-
clk_put(pwr->ebi1_clk);
if (pwr->pcl)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 6325b66..1e5c21c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -39,7 +39,6 @@
struct kgsl_pwrctrl {
int interrupt_num;
- int have_irq;
struct clk *ebi1_clk;
struct clk *grp_clks[KGSL_MAX_CLKS];
unsigned long power_flags;
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 240de9a..846a9a1 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -132,10 +132,9 @@
static struct z180_device device_2d0 = {
.dev = {
+ KGSL_DEVICE_COMMON_INIT(device_2d0.dev),
.name = DEVICE_2D0_NAME,
.id = KGSL_DEVICE_2D0,
- .ver_major = DRIVER_VERSION_MAJOR,
- .ver_minor = DRIVER_VERSION_MINOR,
.mh = {
.mharb = Z180_CFG_MHARB,
.mh_intf_cfg1 = 0x00032f07,
@@ -152,20 +151,17 @@
.pwrctrl = {
.irq_name = KGSL_2D0_IRQ,
},
- .mutex = __MUTEX_INITIALIZER(device_2d0.dev.mutex),
- .state = KGSL_STATE_INIT,
- .active_cnt = 0,
.iomemname = KGSL_2D0_REG_MEMORY,
.ftbl = &z180_functable,
},
+ .cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
};
static struct z180_device device_2d1 = {
.dev = {
+ KGSL_DEVICE_COMMON_INIT(device_2d1.dev),
.name = DEVICE_2D1_NAME,
.id = KGSL_DEVICE_2D1,
- .ver_major = DRIVER_VERSION_MAJOR,
- .ver_minor = DRIVER_VERSION_MINOR,
.mh = {
.mharb = Z180_CFG_MHARB,
.mh_intf_cfg1 = 0x00032f07,
@@ -182,12 +178,10 @@
.pwrctrl = {
.irq_name = KGSL_2D1_IRQ,
},
- .mutex = __MUTEX_INITIALIZER(device_2d1.dev.mutex),
- .state = KGSL_STATE_INIT,
- .active_cnt = 0,
.iomemname = KGSL_2D1_REG_MEMORY,
.ftbl = &z180_functable,
},
+ .cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
};
static irqreturn_t z180_irq_handler(struct kgsl_device *device)
@@ -524,7 +518,6 @@
device->parentdev = &pdev->dev;
z180_dev = Z180_DEVICE(device);
- spin_lock_init(&z180_dev->cmdwin_lock);
status = z180_ringbuffer_init(device);
if (status != 0)
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 5508c3d..c07bdc4 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -24,6 +24,17 @@
LIRC daemon handles protocol decoding for IR reception and
encoding for IR transmitting (aka "blasting").
+config USER_RC_INPUT
+ tristate "User Space Input device wrapper for Remote Control"
+ depends on RC_CORE
+
+ ---help---
+ Say Y if you want to report remote control input events
+ from userspace.
+
+ To compile this driver as a module, choose M here: the module will
+ be called user-rc-input.
+
source "drivers/media/rc/keymaps/Kconfig"
config IR_NEC_DECODER
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 523fcd0..b9c1e21 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -11,6 +11,7 @@
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
+obj-$(CONFIG_USER_RC_INPUT) += user-rc-input.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/rc/user-rc-input.c b/drivers/media/rc/user-rc-input.c
new file mode 100644
index 0000000..f1a9334
--- /dev/null
+++ b/drivers/media/rc/user-rc-input.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <media/rc-core.h>
+#include <media/user-rc-input.h>
+
+#define MAX_RC_DEVICES 1
+#define USER_RC_INPUT_DEV_NAME "user-rc-input"
+#define USER_RC_INPUT_DRV_NAME "rc-user-input"
+
+struct user_rc_input_dev {
+ struct cdev rc_input_cdev;
+ struct class *rc_input_class;
+ struct device *rc_input_dev;
+ struct rc_dev *rcdev;
+ dev_t rc_input_base_dev;
+ struct device *dev;
+ int in_use;
+};
+
+static int user_rc_input_open(struct inode *inode, struct file *file)
+{
+ struct cdev *input_cdev = inode->i_cdev;
+ struct user_rc_input_dev *input_dev =
+ container_of(input_cdev, struct user_rc_input_dev, rc_input_cdev);
+
+ if (input_dev->in_use) {
+ dev_err(input_dev->dev,
+ "Device is already open..only one instance is allowed\n");
+ return -EBUSY;
+ }
+ input_dev->in_use++;
+ file->private_data = input_dev;
+
+ return 0;
+}
+
+static int user_rc_input_release(struct inode *inode, struct file *file)
+{
+ struct user_rc_input_dev *input_dev = file->private_data;
+
+ input_dev->in_use--;
+
+ return 0;
+}
+
+static ssize_t user_rc_input_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ struct user_rc_input_dev *input_dev = file->private_data;
+ __u8 *buf;
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf) {
+ dev_err(input_dev->dev,
+ "kmalloc failed...Insufficient memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ dev_err(input_dev->dev, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ switch (buf[0]) {
+ case USER_CONTROL_PRESSED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " pressed 0x%x\n", buf[1]);
+ rc_keydown(input_dev->rcdev, buf[1], 0);
+ break;
+ case USER_CONTROL_REPEATED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " repeated 0x%x\n", buf[1]);
+ rc_repeat(input_dev->rcdev);
+ break;
+ case USER_CONTROL_RELEASED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " released 0x%x\n", buf[1]);
+ rc_keyup(input_dev->rcdev);
+ break;
+ }
+
+out_free:
+ kfree(buf);
+out:
+ return ret;
+}
+
+const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = user_rc_input_open,
+ .write = user_rc_input_write,
+ .release = user_rc_input_release,
+};
+
+static int __devinit user_rc_input_probe(struct platform_device *pdev)
+{
+ struct user_rc_input_dev *user_rc_dev;
+ struct rc_dev *rcdev;
+ int retval;
+
+ user_rc_dev = kzalloc(sizeof(struct user_rc_input_dev), GFP_KERNEL);
+ if (!user_rc_dev)
+ return -ENOMEM;
+
+ user_rc_dev->rc_input_class = class_create(THIS_MODULE,
+ "user-rc-input-loopback");
+
+ if (IS_ERR(user_rc_dev->rc_input_class)) {
+ retval = PTR_ERR(user_rc_dev->rc_input_class);
+ goto err;
+ }
+
+ retval = alloc_chrdev_region(&user_rc_dev->rc_input_base_dev, 0,
+ MAX_RC_DEVICES, USER_RC_INPUT_DEV_NAME);
+
+ if (retval) {
+ dev_err(&pdev->dev,
+ "alloc_chrdev_region failed\n");
+ goto alloc_chrdev_err;
+ }
+
+ dev_info(&pdev->dev, "User space report key event input "
+ "loopback driver registered, "
+ "major %d\n", MAJOR(user_rc_dev->rc_input_base_dev));
+
+ cdev_init(&user_rc_dev->rc_input_cdev, &fops);
+ retval = cdev_add(&user_rc_dev->rc_input_cdev,
+ user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+ if (retval) {
+ dev_err(&pdev->dev, "cdev_add failed\n");
+ goto cdev_add_err;
+ }
+ user_rc_dev->rc_input_dev =
+ device_create(user_rc_dev->rc_input_class,
+ NULL,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev),
+ 0), NULL, "user-rc-input-dev%d", 0);
+
+ if (IS_ERR(user_rc_dev->rc_input_dev)) {
+ retval = PTR_ERR(user_rc_dev->rc_input_dev);
+ dev_err(&pdev->dev, "device_create failed\n");
+ goto device_create_err;
+ }
+
+ rcdev = rc_allocate_device();
+ if (!rcdev) {
+ dev_err(&pdev->dev, "failed to allocate rc device");
+ retval = -ENOMEM;
+ goto err_allocate_device;
+ }
+
+ rcdev->driver_type = RC_DRIVER_SCANCODE;
+ rcdev->allowed_protos = RC_TYPE_OTHER;
+ rcdev->input_name = USER_RC_INPUT_DEV_NAME;
+ rcdev->input_id.bustype = BUS_HOST;
+ rcdev->driver_name = USER_RC_INPUT_DRV_NAME;
+ rcdev->map_name = RC_MAP_UE_RF4CE;
+
+ retval = rc_register_device(rcdev);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "failed to register rc device\n");
+ goto rc_register_err;
+ }
+ user_rc_dev->rcdev = rcdev;
+ user_rc_dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, user_rc_dev);
+ user_rc_dev->in_use = 0;
+
+ return 0;
+
+rc_register_err:
+ rc_free_device(rcdev);
+err_allocate_device:
+ device_destroy(user_rc_dev->rc_input_class,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+cdev_add_err:
+ unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+device_create_err:
+ cdev_del(&user_rc_dev->rc_input_cdev);
+alloc_chrdev_err:
+ class_destroy(user_rc_dev->rc_input_class);
+err:
+ kfree(user_rc_dev);
+ return retval;
+}
+
+static int __devexit user_rc_input_remove(struct platform_device *pdev)
+{
+ struct user_rc_input_dev *user_rc_dev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ rc_free_device(user_rc_dev->rcdev);
+ device_destroy(user_rc_dev->rc_input_class,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+ unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+ cdev_del(&user_rc_dev->rc_input_cdev);
+ class_destroy(user_rc_dev->rc_input_class);
+ kfree(user_rc_dev);
+
+ return 0;
+}
+
+static struct platform_driver user_rc_input_driver = {
+ .probe = user_rc_input_probe,
+ .remove = __devexit_p(user_rc_input_remove),
+ .driver = {
+ .name = USER_RC_INPUT_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init user_rc_input_init(void)
+{
+ return platform_driver_register(&user_rc_input_driver);
+}
+module_init(user_rc_input_init);
+
+static void __exit user_rc_input_exit(void)
+{
+ platform_driver_unregister(&user_rc_input_driver);
+}
+module_exit(user_rc_input_exit);
+
+MODULE_DESCRIPTION("User RC Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index a86e5c4..0d17e13 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -307,13 +307,13 @@
#endif
rc = gpio_request(external->led_en, "sc628a");
if (!rc) {
- gpio_direction_output(external->led_en, 1);
+ gpio_direction_output(external->led_en, 0);
} else {
goto err1;
}
rc = gpio_request(external->led_flash_en, "sc628a");
if (!rc) {
- gpio_direction_output(external->led_flash_en, 1);
+ gpio_direction_output(external->led_flash_en, 0);
break;
}
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index b7376dc..71c10ad 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -50,10 +50,12 @@
/* enable the frame irq, bit 0 = Display list 0 ROI done */
msm_camera_io_w_mb(1, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
msm_camera_io_dump(vpe_ctrl->vpebase, 0x120);
+ msm_camera_io_dump(vpe_ctrl->vpebase + 0x00400, 0x18);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x10000, 0x250);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x30000, 0x20);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x50000, 0x30);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x50400, 0x10);
+
/* this triggers the operation. */
msm_camera_io_w(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET);
wmb();
@@ -756,7 +758,7 @@
}
rc = request_irq(vpe_ctrl->vpeirq->start, vpe_parse_irq,
- IRQF_TRIGGER_RISING, "vfe", 0);
+ IRQF_TRIGGER_RISING, "vpe", 0);
if (rc < 0) {
release_mem_region(vpe_ctrl->vpemem->start,
resource_size(vpe_ctrl->vpemem));
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 553ee4f..0d14626 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -60,7 +60,8 @@
#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400
#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404
-#define VPE_AXI_ARB_2_OFFSET 0x004C
+#define VPE_AXI_ARB_1_OFFSET 0x00408
+#define VPE_AXI_ARB_2_OFFSET 0x0040C
#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n))
#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n))
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
new file mode 100644
index 0000000..25b5c5c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -0,0 +1,244 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include "msm_smem.h"
+
+struct smem_client {
+ int mem_type;
+ void *clnt;
+};
+
+static int ion_user_to_kernel(struct smem_client *client,
+ int fd, u32 offset, struct msm_smem *mem)
+{
+ struct ion_handle *hndl;
+ unsigned long ionflag;
+ size_t len;
+ int rc = 0;
+ hndl = ion_import_fd(client->clnt, fd);
+ if (IS_ERR_OR_NULL(hndl)) {
+ pr_err("Failed to get handle: %p, %d, %d, %p\n",
+ client, fd, offset, hndl);
+ rc = -ENOMEM;
+ goto fail_import_fd;
+ }
+ rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
+ if (rc) {
+ pr_err("Failed to get ion flags: %d", rc);
+ goto fail_map;
+ }
+ rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
+ if (rc) {
+ pr_err("Failed to get physical address\n");
+ goto fail_map;
+ }
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
+ if (!mem->kvaddr) {
+ pr_err("Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+
+ mem->kvaddr += offset;
+ mem->paddr += offset;
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ mem->device_addr = mem->paddr;
+ mem->size = len;
+ return rc;
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_import_fd:
+ return rc;
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size,
+ u32 align, u32 flags, struct msm_smem *mem)
+{
+ struct ion_handle *hndl;
+ size_t len;
+ int rc = 0;
+ flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+ hndl = ion_alloc(client->clnt, size, align, flags);
+ if (IS_ERR_OR_NULL(hndl)) {
+ pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
+ client, size, align, flags);
+ rc = -ENOMEM;
+ goto fail_shared_mem_alloc;
+ }
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
+ pr_err("Failed to get physical address\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ mem->device_addr = mem->paddr;
+ mem->size = size;
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+ if (!mem->kvaddr) {
+ pr_err("Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ return rc;
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+ return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+ ion_unmap_kernel(client->clnt, mem->smem_priv);
+ ion_free(client->clnt, mem->smem_priv);
+}
+
+static void *ion_new_client(void)
+{
+ struct ion_client *client = NULL;
+ client = msm_ion_client_create(-1, "video_client");
+ if (!client)
+ pr_err("Failed to create smem client\n");
+ return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+ ion_client_destroy(client->clnt);
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
+{
+ struct smem_client *client = clt;
+ int rc = 0;
+ struct msm_smem *mem;
+ if (fd < 0) {
+ pr_err("Invalid fd: %d\n", fd);
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ pr_err("Failed to allocte shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = ion_user_to_kernel(clt, fd, offset, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void *msm_smem_new_client(enum smem_type mtype)
+{
+ struct smem_client *client = NULL;
+ void *clnt = NULL;
+ switch (mtype) {
+ case SMEM_ION:
+ clnt = ion_new_client();
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ if (clnt) {
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client) {
+ client->mem_type = mtype;
+ client->clnt = clnt;
+ }
+ } else {
+ pr_err("Failed to create new client: mtype = %d\n", mtype);
+ }
+ return client;
+};
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
+{
+ struct smem_client *client;
+ int rc = 0;
+ struct msm_smem *mem;
+
+ client = clt;
+ if (!client) {
+ pr_err("Invalid client passed\n");
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ pr_err("Failed to allocate shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = alloc_ion_mem(client, size, align, flags, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+ struct smem_client *client = clt;
+ if (!client || !mem) {
+ pr_err("Invalid client/handle passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ free_ion_mem(client, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+ struct smem_client *client = clt;
+ if (!client) {
+ pr_err("Invalid client passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ ion_delete_client(client);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ kfree(client);
+}
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
new file mode 100644
index 0000000..84d12cc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_SMEM_H_
+#define _MSM_SMEM_H_
+
+#include <linux/types.h>
+#include <linux/ion.h>
+
+enum smem_type {
+ SMEM_ION,
+};
+
+struct msm_smem {
+ int mem_type;
+ size_t size;
+ void *kvaddr;
+ unsigned long paddr;
+ unsigned long device_addr;
+ /*Device address and others to follow*/
+ void *smem_priv;
+};
+
+void *msm_smem_new_client(enum smem_type mtype);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset);
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
new file mode 100644
index 0000000..f125cdc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -0,0 +1,505 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_drv *vidc_driver;
+
+struct buffer_info {
+ struct list_head list;
+ int type;
+ int fd;
+ int buff_off;
+ int size;
+ u32 uvaddr;
+ struct msm_smem *handle;
+};
+
+struct msm_v4l2_vid_inst {
+ void *vidc_inst;
+ void *mem_client;
+ struct list_head registered_bufs;
+};
+
+struct buffer_info *get_registered_buf(struct list_head *list,
+ int fd, u32 buff_off, u32 size)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ if (!list || fd < 0) {
+ pr_err("%s Invalid input\n", __func__);
+ goto err_invalid_input;
+ }
+ if (!list_empty(list)) {
+ list_for_each_entry(temp, list, list) {
+ if (temp && temp->fd == fd &&
+ (CONTAINS(temp->buff_off, temp->size, buff_off)
+ || CONTAINS(buff_off, size, temp->buff_off)
+ || OVERLAPS(buff_off, size,
+ temp->buff_off, temp->size))) {
+ pr_err("This memory region is already mapped\n");
+ ret = temp;
+ break;
+ }
+ }
+ }
+err_invalid_input:
+ return ret;
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+ int rc = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct msm_video_device *vid_dev =
+ container_of(vdev, struct msm_video_device, vdev);
+ struct msm_vidc_core *core = video_drvdata(filp);
+ void *inst;
+ struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
+ GFP_KERNEL);
+ if (!v4l2_inst) {
+ pr_err("Failed to allocate memory for this instance\n");
+ rc = -ENOMEM;
+ goto fail_nomem;
+ }
+ v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
+ if (!v4l2_inst->mem_client) {
+ pr_err("Failed to create memory client\n");
+ rc = -ENOMEM;
+ goto fail_mem_client;
+ }
+ inst = msm_vidc_open(core->id, vid_dev->type);
+ if (!inst) {
+ pr_err("Failed to create video instance, core: %d, type = %d\n",
+ core->id, vid_dev->type);
+ rc = -ENOMEM;
+ goto fail_open;
+ }
+ INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
+ v4l2_inst->vidc_inst = inst;
+ filp->private_data = v4l2_inst;
+ return rc;
+fail_open:
+ msm_smem_delete_client(v4l2_inst->mem_client);
+fail_mem_client:
+ kfree(v4l2_inst);
+fail_nomem:
+ return rc;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+ int rc;
+ struct list_head *ptr, *next;
+ struct buffer_info *binfo;
+ struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+ rc = msm_vidc_close(v4l2_inst->vidc_inst);
+ list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+ binfo = list_entry(ptr, struct buffer_info, list);
+ list_del(&binfo->list);
+ msm_smem_free(v4l2_inst->mem_client, binfo->handle);
+ kfree(binfo);
+ }
+ msm_smem_delete_client(v4l2_inst->mem_client);
+ kfree(v4l2_inst);
+ return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+ return msm_vidc_querycap(v4l2_inst->vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_enum_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_s_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_g_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_s_ctrl(v4l2_inst->vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_g_ctrl(v4l2_inst->vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_reqbufs(v4l2_inst->vidc_inst, b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ struct msm_smem *handle;
+ struct buffer_info *binfo;
+ int rc = 0;
+ int i;
+ if (!v4l2_inst->mem_client) {
+ pr_err("Failed to get memory client\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ for (i = 0; i < b->length; ++i) {
+ binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ if (binfo) {
+ pr_err("This memory region has already been prepared\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1]);
+ if (!handle) {
+ pr_err("Failed to get device buffer address\n");
+ kfree(binfo);
+ goto exit;
+ }
+ binfo->type = b->type;
+ binfo->fd = b->m.planes[i].reserved[0];
+ binfo->buff_off = b->m.planes[i].reserved[1];
+ binfo->size = b->m.planes[i].length;
+ binfo->uvaddr = b->m.planes[i].m.userptr;
+ binfo->handle = handle;
+ pr_debug("Registering buffer: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
+ b->m.planes[i].m.userptr = handle->device_addr;
+ }
+ rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
+exit:
+ return rc;
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ struct buffer_info *binfo;
+ int rc = 0;
+ int i;
+ for (i = 0; i < b->length; ++i) {
+ binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ if (!binfo) {
+ pr_err("This buffer is not registered: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ rc = -EINVAL;
+ goto err_invalid_buff;
+ }
+ b->m.planes[i].m.userptr = binfo->handle->device_addr;
+ pr_debug("Queueing device address = %ld\n",
+ binfo->handle->device_addr);
+ }
+ rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
+err_invalid_buff:
+ return rc;
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_dqbuf(v4l2_inst->vidc_inst, b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_streamon(v4l2_inst->vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_streamoff(v4l2_inst->vidc_inst, i);
+}
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+ .vidioc_querycap = msm_v4l2_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+ .vidioc_reqbufs = msm_v4l2_reqbufs,
+ .vidioc_prepare_buf = msm_v4l2_prepare_buf,
+ .vidioc_qbuf = msm_v4l2_qbuf,
+ .vidioc_dqbuf = msm_v4l2_dqbuf,
+ .vidioc_streamon = msm_v4l2_streamon,
+ .vidioc_streamoff = msm_v4l2_streamoff,
+ .vidioc_s_ctrl = msm_v4l2_s_ctrl,
+ .vidioc_g_ctrl = msm_v4l2_g_ctrl,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+ struct poll_table_struct *pt)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+ return msm_vidc_poll(v4l2_inst->vidc_inst, filp, pt);
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_v4l2_open,
+ .release = msm_v4l2_close,
+ .ioctl = video_ioctl2,
+ .poll = msm_v4l2_poll,
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+ struct msm_vidc_core *core)
+{
+ struct resource *res;
+ int i = 0;
+ if (!core)
+ return -EINVAL;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("Failed to get IORESOURCE_MEM\n");
+ return -ENODEV;
+ }
+ core->register_base = res->start;
+ core->register_size = resource_size(res);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("Failed to get IORESOURCE_IRQ\n");
+ return -ENODEV;
+ }
+ core->irq = res->start;
+ INIT_LIST_HEAD(&core->instances);
+ mutex_init(&core->sync_lock);
+ spin_lock_init(&core->lock);
+ core->base_addr = 0x34f00000;
+ core->state = VIDC_CORE_UNINIT;
+ for (i = SYS_MSG_INDEX(SYS_MSG_START);
+ i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+ init_completion(&core->completions[i]);
+ }
+ return 0;
+}
+
+static int __devinit msm_vidc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+ unsigned long flags;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core || !vidc_driver) {
+ pr_err("Failed to allocate memory for device core\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ rc = msm_vidc_initialize_core(pdev, core);
+ if (rc) {
+ pr_err("Failed to init core\n");
+ goto err_v4l2_register;
+ }
+ rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+ if (rc) {
+ pr_err("Failed to register v4l2 device\n");
+ goto err_v4l2_register;
+ }
+ core->vdev[MSM_VIDC_DECODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+ rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+ VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER);
+ if (rc) {
+ pr_err("Failed to register video decoder device");
+ goto err_dec_register;
+ }
+ video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+
+ core->vdev[MSM_VIDC_ENCODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+ rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+ VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER + 1);
+ if (rc) {
+ pr_err("Failed to register video encoder device");
+ goto err_enc_register;
+ }
+ video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+ core->device = vidc_hal_add_device(core->id, core->base_addr,
+ core->register_base, core->register_size, core->irq,
+ &handle_cmd_response);
+ if (!core->device) {
+ pr_err("Failed to create interrupt handler");
+ goto err_cores_exceeded;
+ }
+
+ spin_lock_irqsave(&vidc_driver->lock, flags);
+ if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) {
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ pr_err("Maximum cores already exist, core_no = %d\n",
+ vidc_driver->num_cores);
+ goto err_cores_exceeded;
+ }
+
+ core->id = vidc_driver->num_cores++;
+ list_add_tail(&core->list, &vidc_driver->cores);
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+ core->debugfs_root = debugfs_create_dir(debugfs_name,
+ vidc_driver->debugfs_root);
+ pdev->dev.platform_data = core;
+ return rc;
+
+err_cores_exceeded:
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+ v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+ kfree(core);
+err_no_mem:
+ return rc;
+}
+
+static int __devexit msm_vidc_remove(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = pdev->dev.platform_data;
+ vidc_hal_delete_device(core->device);
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+ v4l2_device_unregister(&core->v4l2_dev);
+ kfree(core);
+ return rc;
+}
+static const struct of_device_id msm_vidc_dt_match[] = {
+ {.compatible = "qcom,msm-vidc"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+ .probe = msm_vidc_probe,
+ .remove = msm_vidc_remove,
+ .driver = {
+ .name = "msm_vidc",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_vidc_dt_match,
+ },
+};
+
+static int __init msm_vidc_init(void)
+{
+ int rc = 0;
+ vidc_driver = kzalloc(sizeof(*vidc_driver),
+ GFP_KERNEL);
+ if (!vidc_driver) {
+ pr_err("Failed to allocate memroy for msm_vidc_drv\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&vidc_driver->cores);
+ spin_lock_init(&vidc_driver->lock);
+ vidc_driver->debugfs_root = debugfs_create_dir("msm_vidc", NULL);
+ if (!vidc_driver->debugfs_root)
+ pr_err("Failed to create debugfs for msm_vidc\n");
+
+ rc = platform_driver_register(&msm_vidc_driver);
+ if (rc) {
+ pr_err("Failed to register platform driver\n");
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+ platform_driver_unregister(&msm_vidc_driver);
+ debugfs_remove_recursive(vidc_driver->debugfs_root);
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
new file mode 100644
index 0000000..879d324
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -0,0 +1,872 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MAX_PLANES 1
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 6
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+ "DIVX Format 4",
+ "DIVX Format 5",
+ "DIVX Format 6",
+ NULL
+};
+static const char *mpeg_video_stream_format[] = {
+ "NAL Format Start Codes",
+ "NAL Format One NAL Per Buffer",
+ "NAL Format One Byte Length",
+ "NAL Format Two Byte Length",
+ "NAL Format Four Byte Length",
+ NULL
+};
+static const char *const mpeg_video_output_order[] = {
+ "Display Order",
+ "Decode Order",
+ NULL
+};
+static const struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+ .name = "NAL Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+ ),
+ .qmenu = mpeg_video_stream_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+ .name = "Output Order",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+ ),
+ .qmenu = mpeg_video_output_order,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
+ .name = "Picture Type Decoding",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 15,
+ .default_value = 15,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+ .name = "Keep Aspect Ratio",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+ .name = "Deblocker Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+ .name = "Divx Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+ ),
+ .qmenu = mpeg_video_vidc_divx_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+ .name = "MB Error Map Reporting",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+ .name = "control",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static u32 get_frame_size_nv12(int plane,
+ u32 height, u32 width)
+{
+ int stride = (width + 31) & (~31);
+ return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane,
+ u32 height, u32 width)
+{
+ return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane,
+ u32 height, u32 width)
+{
+ return 0x500000;
+}
+
+static const struct msm_vidc_format vdec_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg2",
+ .description = "Mpeg2 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = CAPTURE_PORT,
+ },
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamon\n");
+ rc = vb2_streamon(q, i);
+ if (rc)
+ pr_err("streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ unsigned long flags;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct extradata_buf *ebuf;
+
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ ebuf = list_entry(ptr, struct extradata_buf, list);
+ list_del(&ebuf->list);
+ msm_smem_free(inst->mem_client, ebuf->handle);
+ kfree(ebuf);
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+
+ pr_debug("Calling streamoff\n");
+ rc = vb2_streamoff(q, i);
+ if (rc)
+ pr_err("streamoff failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ struct extradata_buf *binfo;
+ for (i = 0; i < b->length; i++) {
+ pr_err("device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Failed to allocate shared mem\n");
+ return -ENOMEM;
+ }
+ binfo->device_addr = b->m.planes[i].m.userptr;
+ rc = msm_comm_allocate_extradata_buffers(inst, binfo);
+ if (rc) {
+ pr_err("msm_comm_allocate_extradata_buffers failed");
+ break;
+ }
+ buffer_info.extradata_size = binfo->handle->size;
+ buffer_info.extradata_addr = binfo->handle->device_addr;
+ rc = vidc_hal_session_set_buffers((void *)inst->session,
+ &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_qbuf(q, b);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_dqbuf(q, b, true);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ rc = vb2_reqbufs(q, b);
+ if (rc)
+ pr_err("Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+
+ if (fmt) {
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.height = inst->height;
+ f->fmt.pix_mp.width = inst->width;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, inst->height, inst->width);
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ inst->width = f->fmt.pix_mp.width;
+ inst->height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (fmt && fmt->type != CAPTURE_PORT) {
+ pr_err("Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (fmt && fmt->type != OUTPUT_PORT) {
+ pr_err("Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ }
+
+ if (fmt) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ inst->fmts[fmt->type] = fmt;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ goto err_invalid_fmt;
+ }
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+err_invalid_fmt:
+ return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ pr_err("No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_frame_size frame_sz;
+ unsigned long flags;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ *num_planes = 1;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ pr_debug("Getting bufreqs on capture plane\n");
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->width;
+ frame_sz.height = inst->height;
+ pr_debug("width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set hal property for framesize\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+ *num_planes = 1;
+ spin_lock_irqsave(&inst->lock, flags);
+ *num_buffers = inst->buff_req.buffer[1].buffer_count_actual;
+ spin_unlock_irqrestore(&inst->lock, flags);
+ pr_debug("size = %d, alignment = %d\n",
+ inst->buff_req.buffer[1].buffer_size,
+ inst->buff_req.buffer[1].buffer_alignment);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+
+ break;
+ default:
+ pr_err("Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+ struct v4l2_control control;
+ struct hal_nal_stream_format_supported stream_format;
+ struct hal_enable_picture enable_picture;
+ struct hal_enable hal_property;
+ struct hal_enable prop;
+ u32 control_idx = 0;
+ enum hal_property property_id = 0;
+ u32 property_val = 0;
+ void *pdata;
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ for (; control_idx < NUM_CTRLS; control_idx++) {
+ control.id = msm_vdec_ctrls[control_idx].id;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc) {
+ pr_err("Failed to get control value for ID=%d\n",
+ msm_vdec_ctrls[control_idx].id);
+ } else {
+ property_id = 0;
+ switch (control.id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ property_id =
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+ stream_format.nal_stream_format_supported =
+ (0x00000001 << control.value);
+ pdata = &stream_format;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+ property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
+ property_id =
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ enable_picture.picture_type = control.value;
+ pdata = &enable_picture;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+ property_id =
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+ property_id =
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+ property_id = HAL_PARAM_DIVX_FORMAT;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+ property_id =
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+ property_id =
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ default:
+ break;
+ }
+ if (property_id) {
+ pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ property_id,
+ msm_vdec_ctrls[control_idx].id,
+ control.value);
+ rc = vidc_hal_session_set_property((void *)
+ inst->session, property_id,
+ pdata);
+ }
+ if (rc)
+ pr_err("Failed to set hal property for framesize\n");
+ }
+ }
+
+ prop.enable = 1;
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, &prop);
+ if (rc)
+ pr_err("Failed to set smooth streaming\n");
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto fail_start;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ pr_err("Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_vdec_start_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc)
+ pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+ .queue_setup = msm_vdec_queue_setup,
+ .start_streaming = msm_vdec_start_streaming,
+ .buf_queue = msm_vdec_buf_queue,
+ .stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+ return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ pr_err("Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
+ inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
+ inst->height = DEFAULT_HEIGHT;
+ inst->width = DEFAULT_WIDTH;
+ return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+ .s_ctrl = msm_vdec_op_s_ctrl,
+ .g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+ return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_s_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+ int idx = 0;
+ struct v4l2_ctrl_config ctrl_cfg;
+ int ret_val = 0;
+
+ ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+
+ if (ret_val) {
+ pr_err("CTRL ERR: Control handler init failed, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ for (; idx < NUM_CTRLS; idx++) {
+ if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
+ /*add private control*/
+ ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
+ ctrl_cfg.flags = 0;
+ ctrl_cfg.id = msm_vdec_ctrls[idx].id;
+ /*ctrl_cfg.is_private =
+ * msm_vdec_ctrls[idx].is_private;
+ * ctrl_cfg.is_volatile =
+ * msm_vdec_ctrls[idx].is_volatile;*/
+ ctrl_cfg.max = msm_vdec_ctrls[idx].maximum;
+ ctrl_cfg.min = msm_vdec_ctrls[idx].minimum;
+ ctrl_cfg.menu_skip_mask =
+ msm_vdec_ctrls[idx].menu_skip_mask;
+ ctrl_cfg.name = msm_vdec_ctrls[idx].name;
+ ctrl_cfg.ops = &msm_vdec_ctrl_ops;
+ ctrl_cfg.step = msm_vdec_ctrls[idx].step;
+ ctrl_cfg.type = msm_vdec_ctrls[idx].type;
+ ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
+
+ v4l2_ctrl_new_custom(&inst->ctrl_handler,
+ &ctrl_cfg, NULL);
+ } else {
+ if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].menu_skip_mask,
+ msm_vdec_ctrls[idx].default_value);
+ } else {
+ v4l2_ctrl_new_std(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].minimum,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].step,
+ msm_vdec_ctrls[idx].default_value);
+ }
+ }
+ }
+ ret_val = inst->ctrl_handler.error;
+ if (ret_val)
+ pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
new file mode 100644
index 0000000..6529065
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
new file mode 100644
index 0000000..cae2d6f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 8
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+ int stride = (width + 31) & (~31);
+ return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+ return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+ return width * height / 2;
+}
+
+static const struct msm_vidc_format venc_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = OUTPUT_PORT,
+ },
+};
+
+static int msm_venc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_frame_size frame_sz;
+ unsigned long flags;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ *num_planes = 1;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->width;
+ frame_sz.height = inst->height;
+ pr_debug("width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set hal property for framesize\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+ *num_planes = 1;
+ spin_lock_irqsave(&inst->lock, flags);
+ *num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
+ spin_unlock_irqrestore(&inst->lock, flags);
+ pr_debug("size = %d, alignment = %d, count = %d\n",
+ inst->buff_req.buffer[0].buffer_size,
+ inst->buff_req.buffer[0].buffer_alignment,
+ inst->buff_req.buffer[0].buffer_count_actual);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+
+ break;
+ default:
+ pr_err("Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto fail_start;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ pr_err("Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_venc_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc)
+ pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+ .queue_setup = msm_venc_queue_setup,
+ .start_streaming = msm_venc_start_streaming,
+ .buf_queue = msm_venc_buf_queue,
+ .stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+ return &msm_venc_vb2q_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ pr_err("Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[CAPTURE_PORT] = &venc_formats[1];
+ inst->fmts[OUTPUT_PORT] = &venc_formats[0];
+ inst->height = DEFAULT_HEIGHT;
+ inst->width = DEFAULT_WIDTH;
+ return rc;
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ pr_err("No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (fmt && fmt->type != CAPTURE_PORT) {
+ pr_err("Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->width = f->fmt.pix_mp.width;
+ inst->height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (fmt && fmt->type != OUTPUT_PORT) {
+ pr_err("Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (fmt) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ inst->fmts[fmt->type] = fmt;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ goto exit;
+ }
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+
+ if (fmt) {
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.height = inst->height;
+ f->fmt.pix_mp.width = inst->width;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, inst->height, inst->width);
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ rc = vb2_reqbufs(q, b);
+ if (rc)
+ pr_err("Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ for (i = 0; i < b->length; i++) {
+ pr_err("device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ rc = vidc_hal_session_set_buffers((void *)inst->session,
+ &buffer_info);
+ if (rc)
+ pr_err("vidc_hal_session_set_buffers failed");
+ }
+ break;
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_qbuf(q, b);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_dqbuf(q, b, true);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamon\n");
+ rc = vb2_streamon(q, i);
+ if (rc)
+ pr_err("streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamoff\n");
+ rc = vb2_streamoff(q, i);
+ if (rc)
+ pr_err("streamoff failed on port: %d\n", i);
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
new file mode 100644
index 0000000..4a156dd
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
new file mode 100644
index 0000000..4725f5f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -0,0 +1,339 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include "msm_smem.h"
+
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *wait)
+{
+ int rc = 0;
+ struct msm_vidc_inst *inst = instance;
+ struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
+ struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+ struct vb2_buffer *out_vb = NULL;
+ struct vb2_buffer *cap_vb = NULL;
+ unsigned long flags;
+ if (!outq->streaming && !capq->streaming) {
+ pr_err("Returning POLLERR from here: %d, %d\n",
+ outq->streaming, capq->streaming);
+ return POLLERR;
+ }
+ poll_wait(filp, &capq->done_wq, wait);
+ poll_wait(filp, &outq->done_wq, wait);
+ spin_lock_irqsave(&capq->done_lock, flags);
+ if (!list_empty(&capq->done_list))
+ cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+ done_entry);
+ if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+ || cap_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&capq->done_lock, flags);
+ spin_lock_irqsave(&outq->done_lock, flags);
+ if (!list_empty(&outq->done_list))
+ out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+ done_entry);
+ if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+ || out_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&outq->done_lock, flags);
+ return rc;
+}
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_querycap(instance, cap);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_querycap(instance, cap);
+ return -EINVAL;
+}
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_enum_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_enum_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_fmt(instance, f);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_g_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_ctrl(instance, control);
+ return -EINVAL;
+}
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_ctrl(instance, control);
+ return -EINVAL;
+}
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_reqbufs(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_reqbufs(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_prepare_buf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_prepare_buf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_dqbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_dqbuf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamon(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamon(instance, i);
+ return -EINVAL;
+}
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamoff(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamoff(instance, i);
+ return -EINVAL;
+}
+
+void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ return NULL;
+}
+
+void vidc_put_userptr(void *buf_priv)
+{
+}
+
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+ .get_userptr = vidc_get_userptr,
+ .put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+ enum v4l2_buf_type type, enum session_type sess)
+{
+ struct vb2_queue *q = NULL;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q = &inst->vb2_bufq[CAPTURE_PORT];
+ } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q = &inst->vb2_bufq[OUTPUT_PORT];
+ } else {
+ pr_err("buf_type = %d not recognised\n", type);
+ return -EINVAL;
+ }
+ q->type = type;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_flags = 0;
+ if (sess == MSM_VIDC_DECODER)
+ q->ops = msm_vdec_get_vb2q_ops();
+ else if (sess == MSM_VIDC_ENCODER)
+ q->ops = msm_venc_get_vb2q_ops();
+ q->mem_ops = &msm_vidc_vb2_mem_ops;
+ q->drv_priv = inst;
+ return vb2_queue_init(q);
+}
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+ struct msm_vidc_inst *inst = NULL;
+ struct msm_vidc_core *core = NULL;
+ unsigned long flags;
+ int rc = 0;
+ int i = 0;
+ if (core_id >= MSM_VIDC_CORES_MAX ||
+ session_type >= MSM_VIDC_MAX_DEVICES) {
+ pr_err("Invalid input, core_id = %d, session = %d\n",
+ core_id, session_type);
+ goto err_invalid_core;
+ }
+ core = get_vidc_core(core_id);
+ if (!core) {
+ pr_err("Failed to find core for core_id = %d\n", core_id);
+ goto err_invalid_core;
+ }
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst) {
+ pr_err("Unable to allocate video instance\n");
+ goto err_no_mem;
+ }
+ mutex_init(&inst->sync_lock);
+ spin_lock_init(&inst->lock);
+ inst->session_type = session_type;
+ INIT_LIST_HEAD(&inst->pendingq);
+ INIT_LIST_HEAD(&inst->internalbufs);
+ INIT_LIST_HEAD(&inst->extradatabufs);
+ inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+ inst->core = core;
+ for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+ i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+ init_completion(&inst->completions[i]);
+ }
+ inst->mem_client = msm_smem_new_client(SMEM_ION);
+ if (!inst->mem_client) {
+ pr_err("Failed to create memory client\n");
+ goto fail_mem_client;
+ }
+ if (session_type == MSM_VIDC_DECODER) {
+ msm_vdec_inst_init(inst);
+ msm_vdec_ctrl_init(inst);
+ } else if (session_type == MSM_VIDC_ENCODER) {
+ msm_venc_inst_init(inst);
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ session_type);
+ if (rc) {
+ pr_err("Failed to initialize vb2 queue on capture port\n");
+ goto fail_init;
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ session_type);
+ if (rc) {
+ pr_err("Failed to initialize vb2 queue on capture port\n");
+ goto fail_init;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
+ if (rc) {
+ pr_err("Failed to move video instance to init state\n");
+ goto fail_init;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ list_add_tail(&inst->list, &core->instances);
+ spin_unlock_irqrestore(&core->lock, flags);
+ return inst;
+fail_init:
+ msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+ kfree(inst);
+ inst = NULL;
+err_no_mem:
+err_invalid_core:
+ return inst;
+}
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+ unsigned long flags;
+ struct list_head *ptr, *next;
+ struct vb2_buf_entry *entry;
+ struct internal_buf *buf;
+ struct extradata_buf *ebuf;
+ if (inst) {
+ spin_lock_irqsave(&inst->lock, flags);
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ entry = list_entry(ptr, struct vb2_buf_entry, list);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ ebuf = list_entry(ptr, struct extradata_buf, list);
+ list_del(&ebuf->list);
+ msm_smem_free(inst->mem_client, ebuf->handle);
+ kfree(ebuf);
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ msm_smem_delete_client(inst->mem_client);
+ }
+}
+
+int msm_vidc_close(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_inst *temp;
+ struct msm_vidc_core *core;
+ struct list_head *ptr, *next;
+ int rc = 0;
+ core = inst->core;
+ mutex_lock(&core->sync_lock);
+ list_for_each_safe(ptr, next, &core->instances) {
+ temp = list_entry(ptr, struct msm_vidc_inst, list);
+ if (temp == inst) {
+ list_del(&inst->list);
+ kfree(inst);
+ }
+ }
+ mutex_unlock(&core->sync_lock);
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+ if (rc)
+ pr_err("Failed to move video instance to init state\n");
+ cleanup_instance(inst);
+ pr_debug("Closed the instance\n");
+ return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
new file mode 100644
index 0000000..e889b1c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -0,0 +1,929 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define HW_RESPONSE_TIMEOUT 5000
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+ int __rc = (__p >= __d);\
+ __rc; \
+})
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+ struct msm_vidc_core *core;
+ int found = 0;
+ unsigned long flags;
+ if (core_id > MSM_VIDC_CORES_MAX) {
+ pr_err("Core id = %d is greater than max = %d\n",
+ core_id, MSM_VIDC_CORES_MAX);
+ return NULL;
+ }
+ spin_lock_irqsave(&vidc_driver->lock, flags);
+ list_for_each_entry(core, &vidc_driver->cores, list) {
+ if (core && core->id == core_id)
+ found = 1;
+ break;
+ }
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ if (found)
+ return core;
+ return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+ int i, k = 0;
+ if (!fmt || index < 0) {
+ pr_err("Invalid inputs, fmt = %p, index = %d\n",
+ fmt, index);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].type != fmt_type)
+ continue;
+ if (k == index)
+ break;
+ k++;
+ }
+ if (i == size) {
+ pr_err("Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+ int i;
+ if (!fmt) {
+ pr_err("Invalid inputs, fmt = %p\n", fmt);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].fourcc == fourcc)
+ break;
+ }
+ if (i == size) {
+ pr_err("Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+
+struct vb2_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return &inst->vb2_bufq[CAPTURE_PORT];
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return &inst->vb2_bufq[OUTPUT_PORT];
+ return NULL;
+}
+
+static void handle_sys_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_core *core;
+ struct vidc_hal_sys_init_done *sys_init_msg;
+ int index = SYS_MSG_INDEX(cmd);
+ if (!response) {
+ pr_err("Failed to get valid response for sys init\n");
+ return;
+ }
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ pr_err("Wrong device_id received\n");
+ return;
+ }
+ pr_debug("index = %d\n", index);
+ pr_debug("ptr = %p\n", &(core->completions[index]));
+ complete(&(core->completions[index]));
+ sys_init_msg = response->data;
+ if (!sys_init_msg) {
+ pr_err("sys_init_done message not proper\n");
+ return;
+ }
+}
+
+static inline void change_inst_state(struct msm_vidc_inst *inst,
+ enum instance_state state)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ pr_debug("Moved inst: %p from state: %d to state: %d\n",
+ inst, inst->state, state);
+ inst->state = state;
+ spin_unlock_irqrestore(&inst->lock, flags);
+}
+
+static int signal_session_msg_receipt(enum command_response cmd,
+ struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ pr_err("Invalid(%p) instance id\n", inst);
+ return -EINVAL;
+ }
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+ return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+ enum command_response cmd)
+{
+ int rc = 0;
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(cmd)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+ enum instance_state flipped_state,
+ enum instance_state desired_state,
+ enum command_response hal_cmd)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto err_same_state;
+ }
+ pr_debug("Waiting for hal_cmd: %d\n", hal_cmd);
+ rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+ if (!rc)
+ change_inst_state(inst, desired_state);
+err_same_state:
+ return rc;
+}
+
+static void handle_session_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ return;
+ } else {
+ pr_err("Failed to get valid response for session init\n");
+ }
+}
+
+static void handle_session_prop_info(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ unsigned long flags;
+ if (!response || !response->data) {
+ pr_err("Failed to get valid response for prop info\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ spin_lock_irqsave(&inst->lock, flags);
+ memcpy(&inst->buff_req, response->data,
+ sizeof(struct buffer_requirements));
+ spin_unlock_irqrestore(&inst->lock, flags);
+ signal_session_msg_receipt(cmd, inst);
+}
+
+static void handle_load_resource_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response)
+ inst = (struct msm_vidc_inst *)response->session_id;
+ else
+ pr_err("Failed to get valid response for load resource\n");
+}
+
+static void handle_start_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for start done\n");
+ }
+}
+
+static void handle_stop_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for stop done\n");
+ }
+}
+
+static void handle_release_res_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for release"
+ " resource done\n");
+ }
+}
+
+static void handle_session_close(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for session close\n");
+ }
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q,
+ u32 dev_addr)
+{
+ struct vb2_buffer *vb = NULL;
+ int found = 0;
+ if (!q) {
+ pr_err("Invalid parameter\n");
+ return NULL;
+ }
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->v4l2_planes[0].m.userptr == dev_addr) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("Failed to find the buffer in queued list: %d, %d\n",
+ dev_addr, q->type);
+ vb = NULL;
+ }
+ return vb;
+}
+
+static void handle_ebd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct vb2_buffer *vb;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ vb = response->clnt_data;
+ if (vb)
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
+static void handle_fbd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct vb2_buffer *vb;
+ struct vidc_hal_fbd *fill_buf_done;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+ vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+ (u32)fill_buf_done->packet_buffer1);
+ if (vb) {
+ vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ pr_err("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+}
+
+void handle_cmd_response(enum command_response cmd, void *data)
+{
+ pr_debug("Command response = %d\n", cmd);
+ switch (cmd) {
+ case SYS_INIT_DONE:
+ handle_sys_init_done(cmd, data);
+ break;
+ case SESSION_INIT_DONE:
+ handle_session_init_done(cmd, data);
+ break;
+ case SESSION_PROPERTY_INFO:
+ handle_session_prop_info(cmd, data);
+ break;
+ case SESSION_LOAD_RESOURCE_DONE:
+ handle_load_resource_done(cmd, data);
+ break;
+ case SESSION_START_DONE:
+ handle_start_done(cmd, data);
+ break;
+ case SESSION_ETB_DONE:
+ handle_ebd(cmd, data);
+ break;
+ case SESSION_FTB_DONE:
+ handle_fbd(cmd, data);
+ break;
+ case SESSION_STOP_DONE:
+ handle_stop_done(cmd, data);
+ break;
+ case SESSION_RELEASE_RESOURCE_DONE:
+ handle_release_res_done(cmd, data);
+ break;
+ case SESSION_END_DONE:
+ handle_session_close(cmd, data);
+ break;
+ default:
+ pr_err("response unhandled\n");
+ break;
+ }
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ int rc = 0;
+ mutex_lock(&core->sync_lock);
+ if (core->state >= VIDC_CORE_INIT_DONE) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+ pr_debug("Waiting for SYS_INIT_DONE\n");
+ rc = wait_for_completion_timeout(
+ &core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ goto exit;
+ } else {
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INIT_DONE;
+ spin_unlock_irqrestore(&core->lock, flags);
+ }
+ pr_debug("SYS_INIT_DONE!!!\n");
+core_already_inited:
+ change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+ rc = 0;
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ mutex_lock(&core->sync_lock);
+ if (core->state >= VIDC_CORE_INIT) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+ init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
+ rc = vidc_hal_core_init(core->device);
+ if (rc) {
+ pr_err("Failed to init core, id = %d\n", core->id);
+ goto exit;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INIT;
+ spin_unlock_irqrestore(&core->lock, flags);
+core_already_inited:
+ change_inst_state(inst, MSM_VIDC_CORE_INIT);
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ mutex_lock(&core->sync_lock);
+ if (core->state == VIDC_CORE_UNINIT) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_uninited;
+ }
+ if (list_empty(&core->instances)) {
+ pr_debug("Calling vidc_hal_core_release\n");
+ rc = vidc_hal_core_release(core->device);
+ if (rc) {
+ pr_err("Failed to release core, id = %d\n", core->id);
+ goto exit;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_UNINIT;
+ spin_unlock_irqrestore(&core->lock, flags);
+ }
+core_already_uninited:
+ change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static enum hal_domain get_hal_domain(int session_type)
+{
+ enum hal_domain domain;
+ switch (session_type) {
+ case MSM_VIDC_ENCODER:
+ domain = HAL_VIDEO_DOMAIN_ENCODER;
+ break;
+ case MSM_VIDC_DECODER:
+ domain = HAL_VIDEO_DOMAIN_DECODER;
+ break;
+ default:
+ pr_err("Wrong domain\n");
+ domain = HAL_UNUSED_DOMAIN;
+ break;
+ }
+ return domain;
+}
+
+static enum hal_video_codec get_hal_codec_type(int fourcc)
+{
+ enum hal_video_codec codec;
+ pr_debug("codec in %s is 0x%x", __func__, fourcc);
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_H264_NO_SC:
+ codec = HAL_VIDEO_CODEC_H264;
+ break;
+ case V4L2_PIX_FMT_H263:
+ codec = HAL_VIDEO_CODEC_H263;
+ break;
+ case V4L2_PIX_FMT_MPEG1:
+ codec = HAL_VIDEO_CODEC_MPEG1;
+ break;
+ case V4L2_PIX_FMT_MPEG2:
+ codec = HAL_VIDEO_CODEC_MPEG2;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ codec = HAL_VIDEO_CODEC_MPEG4;
+ break;
+ case V4L2_PIX_FMT_VC1_ANNEX_G:
+ case V4L2_PIX_FMT_VC1_ANNEX_L:
+ codec = HAL_VIDEO_CODEC_VC1;
+ break;
+ /*HAL_VIDEO_CODEC_MVC
+ HAL_VIDEO_CODEC_DIVX_311
+ HAL_VIDEO_CODEC_DIVX
+ HAL_VIDEO_CODEC_SPARK
+ HAL_VIDEO_CODEC_VP6
+ HAL_VIDEO_CODEC_VP7
+ HAL_VIDEO_CODEC_VP8*/
+ default:
+ pr_err("Wrong codec: %d\n", fourcc);
+ codec = HAL_UNUSED_CODEC;
+ }
+ return codec;
+}
+
+static int msm_comm_session_init(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ int fourcc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ fourcc = inst->fmts[OUTPUT_PORT]->fourcc;
+ } else if (inst->session_type == MSM_VIDC_ENCODER) {
+ fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
+ } else {
+ pr_err("Invalid session\n");
+ return -EINVAL;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
+ inst->session = vidc_hal_session_init(inst->core->device, (u32) inst,
+ get_hal_domain(inst->session_type),
+ get_hal_codec_type(fourcc));
+ if (!inst->session) {
+ pr_err("Failed to call session init for: %d, %d, %d, %d\n",
+ (int)inst->core->device, (int)inst,
+ inst->session_type, fourcc);
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ rc = vidc_hal_session_load_res((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
+ rc = vidc_hal_session_start((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_START);
+exit:
+ return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send Stop to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
+ rc = vidc_hal_session_stop((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send stop\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+ return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send release res to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
+ rc = vidc_hal_session_release_res((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_comm_session_close(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send session close to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
+ rc = vidc_hal_session_end((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+ int rc = 0;
+ int flipped_state;
+ if (!inst) {
+ pr_err("Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ pr_debug("Trying to move inst: %p from: 0x%x to 0x%x\n",
+ inst, inst->state, state);
+ mutex_lock(&inst->sync_lock);
+ flipped_state = inst->state;
+ if (flipped_state < MSM_VIDC_STOP
+ && state > MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ } else if (flipped_state > MSM_VIDC_STOP
+ && state < MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP -
+ (flipped_state - MSM_VIDC_STOP + 1);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ }
+ pr_debug("flipped_state = 0x%x\n", flipped_state);
+ switch (flipped_state) {
+ case MSM_VIDC_CORE_UNINIT_DONE:
+ case MSM_VIDC_CORE_INIT:
+ rc = msm_comm_init_core(inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CORE_INIT_DONE:
+ rc = msm_comm_init_core_done(inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_OPEN:
+ rc = msm_comm_session_init(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_OPEN_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+ SESSION_INIT_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_LOAD_RESOURCES:
+ rc = msm_vidc_load_resources(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_LOAD_RESOURCES_DONE:
+ case MSM_VIDC_START:
+ rc = msm_vidc_start(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_START_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+ SESSION_START_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_STOP:
+ rc = msm_vidc_stop(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_STOP_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+ SESSION_STOP_DONE);
+ if (rc || state <= inst->state)
+ break;
+ pr_debug("Moving to Stop Done state\n");
+ case MSM_VIDC_RELEASE_RESOURCES:
+ rc = msm_vidc_release_res(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_RELEASE_RESOURCES_DONE:
+ rc = wait_for_state(inst, flipped_state,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ SESSION_RELEASE_RESOURCE_DONE);
+ if (rc || state <= inst->state)
+ break;
+ pr_debug("Moving to release resources done state\n");
+ case MSM_VIDC_CLOSE:
+ rc = msm_comm_session_close(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CLOSE_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+ SESSION_END_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CORE_UNINIT:
+ pr_debug("***************Sending core uninit\n");
+ rc = msm_vidc_deinit_core(inst);
+ if (rc || state == inst->state)
+ break;
+ default:
+ pr_err("State not recognized\n");
+ rc = -EINVAL;
+ break;
+ }
+ mutex_unlock(&inst->sync_lock);
+ if (rc)
+ pr_err("Failed to move from state: %d to %d\n",
+ inst->state, state);
+ return rc;
+}
+
+int msm_comm_qbuf(struct vb2_buffer *vb)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ struct msm_vidc_inst *inst;
+ unsigned long flags;
+ struct vb2_buf_entry *entry;
+ struct vidc_frame_data frame_data;
+ q = vb->vb2_queue;
+ inst = q->drv_priv;
+
+ if (!inst || !vb) {
+ pr_err("Invalid input: %p, %p\n", inst, vb);
+ return -EINVAL;
+ }
+ if (inst->state != MSM_VIDC_START_DONE) {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_err("Out of memory\n");
+ goto err_no_mem;
+ }
+ entry->vb = vb;
+ pr_debug("Queueing buffer in pendingq\n");
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&entry->list, &inst->pendingq);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ } else {
+ memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
+ frame_data.alloc_len = vb->v4l2_planes[0].length;
+ frame_data.filled_len = vb->v4l2_planes[0].bytesused;
+ frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
+ frame_data.clnt_data = (u32)vb;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ frame_data.buffer_type = HAL_BUFFER_INPUT;
+ if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
+ frame_data.flags = HAL_BUFFERFLAG_EOS;
+ pr_debug("Received EOS on output capability\n");
+ }
+ pr_debug("Sending etb to hal: Alloc: %d :filled: %d\n",
+ frame_data.alloc_len, frame_data.filled_len);
+ rc = vidc_hal_session_etb((void *) inst->session,
+ &frame_data);
+ pr_debug("Sent etb to HAL\n");
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct extradata_buf *addr;
+ struct list_head *ptr, *next;
+ frame_data.filled_len = 0;
+ frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_data.extradata_addr = 0;
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ addr = list_entry(ptr,
+ struct extradata_buf, list);
+ if (addr->device_addr ==
+ frame_data.device_addr) {
+ frame_data.extradata_addr =
+ addr->handle->device_addr;
+ break;
+ }
+ }
+ pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
+ " extradata_addr: %d\n", frame_data.alloc_len,
+ frame_data.filled_len,
+ frame_data.extradata_addr);
+ rc = vidc_hal_session_ftb((void *) inst->session,
+ &frame_data);
+ } else {
+ pr_err("This capability is not supported: %d\n",
+ q->type);
+ rc = -EINVAL;
+ }
+ }
+ if (rc)
+ pr_err("Failed to queue buffer\n");
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ mutex_lock(&inst->sync_lock);
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
+ rc = vidc_hal_session_get_buf_req((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to get property\n");
+ goto exit;
+ }
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ goto exit;
+ }
+ rc = 0;
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+ struct extradata_buf *binfo)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct msm_smem *handle;
+ pr_debug("Extradata: num = %d, size = %d, align = %d\n",
+ inst->buff_req.buffer[4].buffer_count_actual,
+ inst->buff_req.buffer[4].buffer_size,
+ inst->buff_req.buffer[4].buffer_alignment);
+ if (!inst->buff_req.buffer[4].buffer_size) {
+ pr_err("invalid size: %d",
+ inst->buff_req.buffer[4].buffer_size);
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ handle = msm_smem_alloc(inst->mem_client,
+ inst->buff_req.buffer[4].buffer_size,
+ inst->buff_req.buffer[4].buffer_alignment, 0);
+ if (!handle) {
+ pr_err("Failed to allocate Extradata memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo->handle = handle;
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->extradatabufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info;
+ unsigned long flags;
+ int i;
+ pr_debug("scratch: num = %d, size = %d\n",
+ inst->buff_req.buffer[6].buffer_count_actual,
+ inst->buff_req.buffer[6].buffer_size);
+ for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
+ i++) {
+ handle = msm_smem_alloc(inst->mem_client,
+ inst->buff_req.buffer[6].buffer_size, 1, 0);
+ if (!handle) {
+ pr_err("Failed to allocate scratch memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo->handle = handle;
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->internalbufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ buffer_info.buffer_size =
+ inst->buff_req.buffer[6].buffer_size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_set_buffers((void *) inst->session,
+ &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ break;
+ }
+ }
+err_no_mem:
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
new file mode 100644
index 0000000..45bfa7b
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+ struct list_head list;
+ struct vb2_buffer *vb;
+};
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct vb2_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+ struct extradata_buf *binfo);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct vb2_buffer *vb);
+#define IS_PRIV_CTRL(idx) (\
+ (V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
+ V4L2_CTRL_DRIVER_PRIV(idx))
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
new file mode 100644
index 0000000..dce2dee
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -0,0 +1,166 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/msm_vidc.h>
+
+#include "vidc_hal_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+
+#define SYS_MSG_START VIDC_EVENT_CHANGE
+#define SYS_MSG_END SYS_DEBUG
+#define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
+#define SESSION_MSG_END SESSION_PROPERTY_INFO
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+enum vidc_ports {
+ OUTPUT_PORT,
+ CAPTURE_PORT,
+ MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+ VIDC_CORE_UNINIT = 0,
+ VIDC_CORE_INIT,
+ VIDC_CORE_INIT_DONE,
+};
+
+/*Donot change the enum values unless
+ * you know what you are doing*/
+enum instance_state {
+ MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+ MSM_VIDC_CORE_INIT,
+ MSM_VIDC_CORE_INIT_DONE,
+ MSM_VIDC_OPEN,
+ MSM_VIDC_OPEN_DONE,
+ MSM_VIDC_LOAD_RESOURCES,
+ MSM_VIDC_LOAD_RESOURCES_DONE,
+ MSM_VIDC_START,
+ MSM_VIDC_START_DONE,
+ MSM_VIDC_STOP,
+ MSM_VIDC_STOP_DONE,
+ MSM_VIDC_RELEASE_RESOURCES,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ MSM_VIDC_CLOSE,
+ MSM_VIDC_CLOSE_DONE,
+ MSM_VIDC_CORE_UNINIT,
+};
+
+struct buf_info {
+ struct list_head list;
+ struct vb2_buffer *buf;
+};
+
+struct internal_buf {
+ struct list_head list;
+ struct msm_smem *handle;
+};
+
+struct extradata_buf {
+ struct list_head list;
+ struct msm_smem *handle;
+ u32 device_addr;
+};
+
+struct msm_vidc_format {
+ char name[64];
+ u8 description[32];
+ u32 fourcc;
+ int num_planes;
+ int type;
+ u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+ spinlock_t lock;
+ struct list_head cores;
+ int num_cores;
+ struct dentry *debugfs_root;
+};
+
+struct msm_video_device {
+ int type;
+ struct video_device vdev;
+};
+
+struct msm_vidc_core {
+ struct list_head list;
+ struct mutex sync_lock;
+ int id;
+ void *device;
+ struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+ struct v4l2_device v4l2_dev;
+ spinlock_t lock;
+ struct list_head instances;
+ struct dentry *debugfs_root;
+ u32 base_addr;
+ u32 register_base;
+ u32 register_size;
+ u32 irq;
+ enum vidc_core_state state;
+ struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+};
+
+struct msm_vidc_inst {
+ struct list_head list;
+ struct mutex sync_lock;
+ struct msm_vidc_core *core;
+ int session_type;
+ void *session;
+ u32 width;
+ u32 height;
+ int state;
+ const struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct vb2_queue vb2_bufq[MAX_PORT_NUM];
+ spinlock_t lock;
+ struct list_head pendingq;
+ struct list_head internalbufs;
+ struct list_head extradatabufs;
+ struct buffer_requirements buff_req;
+ void *mem_client;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl {
+ u32 id;
+ char name[64];
+ enum v4l2_ctrl_type type;
+ s32 minimum;
+ s32 maximum;
+ s32 default_value;
+ u32 step;
+ u32 menu_skip_mask;
+ const char * const *qmenu;
+};
+
+void handle_cmd_response(enum command_response cmd, void *data);
+#endif
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 92990b9..f9999c5 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -29,6 +29,18 @@
#define SDIO_DEVICE_ID_MSM_WCN1314 0x2881
#endif
+#ifndef SDIO_VENDOR_ID_MSM_QCA
+#define SDIO_VENDOR_ID_MSM_QCA 0x271
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6003_1
+#define SDIO_DEVICE_ID_MSM_QCA_AR6003_1 0x300
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6003_2
+#define SDIO_DEVICE_ID_MSM_QCA_AR6003_2 0x301
+#endif
+
/*
* This hook just adds a quirk for all sdio devices
*/
@@ -51,6 +63,12 @@
SDIO_FIXUP(SDIO_VENDOR_ID_MSM, SDIO_DEVICE_ID_MSM_WCN1314,
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_1,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 39e6ce3..13fe3e6 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -707,7 +707,7 @@
}
if (!err && host->sdio_irqs)
- mmc_signal_sdio_irq(host);
+ wake_up_process(host->sdio_irq_thread);
mmc_release_host(host);
/*
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index d489233..c442907 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -27,18 +27,20 @@
#include "sdio_ops.h"
-static int process_sdio_pending_irqs(struct mmc_card *card)
+static int process_sdio_pending_irqs(struct mmc_host *host)
{
+ struct mmc_card *card = host->card;
int i, ret, count;
unsigned char pending;
struct sdio_func *func;
/*
* Optimization, if there is only 1 function interrupt registered
- * call irq handler directly
+ * and we know an IRQ was signaled then call irq handler directly.
+ * Otherwise do the full probe.
*/
func = card->sdio_single_irq;
- if (func) {
+ if (func && host->sdio_irq_pending) {
func->irq_handler(func);
return 1;
}
@@ -115,7 +117,8 @@
ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
if (ret)
break;
- ret = process_sdio_pending_irqs(host->card);
+ ret = process_sdio_pending_irqs(host);
+ host->sdio_irq_pending = false;
mmc_release_host(host);
/*
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index de5e741..e7797b1 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1863,6 +1863,8 @@
chip->ext_charging = false;
chip->ext_charge_done = false;
bms_notify_check(chip);
+ /* Update battery charging LEDs and user space battery info */
+ power_supply_changed(&chip->batt_psy);
}
static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
@@ -1917,6 +1919,8 @@
/* Start BMS */
schedule_delayed_work(&chip->eoc_work, delay);
wake_lock(&chip->eoc_wake_lock);
+ /* Update battery charging LEDs and user space battery info */
+ power_supply_changed(&chip->batt_psy);
}
static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index d754a88..b612a0b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3273,15 +3273,6 @@
udc->gadget.dev.parent = dev;
udc->gadget.dev.release = udc_release;
- retval = hw_device_init(regs);
- if (retval < 0)
- goto free_udc;
-
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
- INIT_LIST_HEAD(&mEp->ep.ep_list);
- }
-
udc->transceiver = otg_get_transceiver();
if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
@@ -3291,6 +3282,15 @@
}
}
+ retval = hw_device_init(regs);
+ if (retval < 0)
+ goto put_transceiver;
+
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+ INIT_LIST_HEAD(&mEp->ep.ep_list);
+ }
+
if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
retval = hw_device_reset(udc);
if (retval)
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index fcbc75c..f7230fe 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -525,7 +525,7 @@
}
dev->notify->driver_data = dev;
- if (!dev->port.in->driver_data) {
+ if (!dev->port.in->desc || !dev->port.out->desc) {
if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
dev->port.in->desc = NULL;
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 35ea497..863ddcd 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -2301,13 +2301,14 @@
static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
{
struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+ struct msm_otg *otg = to_msm_otg(ui->xceiv);
unsigned long flags;
-
atomic_set(&ui->softconnect, is_active);
spin_lock_irqsave(&ui->lock, flags);
- if (ui->usb_state == USB_STATE_NOTATTACHED || ui->driver == NULL) {
+ if (ui->usb_state == USB_STATE_NOTATTACHED || ui->driver == NULL ||
+ atomic_read(&otg->chg_type) == USB_CHG_TYPE__WALLCHARGER) {
spin_unlock_irqrestore(&ui->lock, flags);
return 0;
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 4dd6aff..deb4064 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -697,6 +697,9 @@
/* Remote wakeup or resume */
set_bit(A_BUS_REQ, &motg->inputs);
otg->state = OTG_STATE_A_HOST;
+
+ /* ensure hardware is not in low power mode */
+ pm_runtime_resume(otg->dev);
break;
default:
break;
@@ -2511,7 +2514,10 @@
pr_debug("OTG IRQ: in LPM\n");
disable_irq_nosync(irq);
motg->async_int = 1;
- pm_request_resume(otg->dev);
+ if (atomic_read(&motg->pm_suspended))
+ motg->sm_work_pending = true;
+ else
+ pm_request_resume(otg->dev);
return IRQ_HANDLED;
}
@@ -2676,7 +2682,10 @@
return;
}
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (atomic_read(&motg->pm_suspended))
+ motg->sm_work_pending = true;
+ else
+ queue_work(system_nrt_wq, &motg->sm_work);
}
static irqreturn_t msm_pmic_id_irq(int irq, void *data)
@@ -2695,8 +2704,12 @@
set_bit(A_BUS_REQ, &motg->inputs);
}
- if (motg->otg.state != OTG_STATE_UNDEFINED)
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (motg->otg.state != OTG_STATE_UNDEFINED) {
+ if (atomic_read(&motg->pm_suspended))
+ motg->sm_work_pending = true;
+ else
+ queue_work(system_nrt_wq, &motg->sm_work);
+ }
return IRQ_HANDLED;
}
@@ -3533,28 +3546,42 @@
#ifdef CONFIG_PM_SLEEP
static int msm_otg_pm_suspend(struct device *dev)
{
+ int ret = 0;
struct msm_otg *motg = dev_get_drvdata(dev);
dev_dbg(dev, "OTG PM suspend\n");
- return msm_otg_suspend(motg);
+
+ atomic_set(&motg->pm_suspended, 1);
+ ret = msm_otg_suspend(motg);
+ if (ret)
+ atomic_set(&motg->pm_suspended, 0);
+
+ return ret;
}
static int msm_otg_pm_resume(struct device *dev)
{
+ int ret = 0;
struct msm_otg *motg = dev_get_drvdata(dev);
- int ret;
dev_dbg(dev, "OTG PM resume\n");
- ret = msm_otg_resume(motg);
- if (ret)
- return ret;
- /* Update runtime PM status */
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ atomic_set(&motg->pm_suspended, 0);
+ if (motg->sm_work_pending) {
+ motg->sm_work_pending = false;
- return 0;
+ pm_runtime_get_noresume(dev);
+ ret = msm_otg_resume(motg);
+
+ /* Update runtime PM status */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ queue_work(system_nrt_wq, &motg->sm_work);
+ }
+
+ return ret;
}
#endif
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
index fe71dc1..5fa9b09 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
@@ -290,6 +290,8 @@
decoder->client_output_buf_req.actual_count
&& decoder->progressive_only)
need_reconfig = false;
+ if (input_vcd_frm->flags & VCD_FRAME_FLAG_EOS)
+ need_reconfig = false;
if ((input_vcd_frm->data_len <= seq_hdr_info.dec_frm_size ||
(input_vcd_frm->flags & VCD_FRAME_FLAG_CODECCONFIG)) &&
(!need_reconfig ||
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index a2ee306..c9a17de 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -317,6 +317,7 @@
unsigned int sdio_irqs;
struct task_struct *sdio_irq_thread;
+ bool sdio_irq_pending;
atomic_t sdio_irq_thread_abort;
mmc_pm_flag_t pm_flags; /* requested pm features */
@@ -411,6 +412,7 @@
static inline void mmc_signal_sdio_irq(struct mmc_host *host)
{
host->ops->enable_sdio_irq(host, 0);
+ host->sdio_irq_pending = true;
wake_up_process(host->sdio_irq_thread);
}
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 8ec9796..1807cb0 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -133,4 +133,12 @@
};
+#define Q5V2_MVS_MAX_VOC_PKT_SIZE 320
+
+struct q5v2_msm_audio_mvs_frame {
+ uint32_t frame_type;
+ uint32_t len;
+ uint8_t voc_pkt[Q5V2_MVS_MAX_VOC_PKT_SIZE];
+
+};
#endif /* __MSM_AUDIO_MVS_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index b53d9dd..6e96f85 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -293,6 +293,8 @@
#define B_BUS_REQ 16
unsigned long inputs;
struct work_struct sm_work;
+ bool sm_work_pending;
+ atomic_t pm_suspended;
atomic_t in_lpm;
int async_int;
unsigned cur_power;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 147b068..a3b45c9 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -656,6 +656,7 @@
/* Cache handling flags */
#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800
#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000
+#define V4L2_BUF_FLAG_EOS 0x2000
/*
* O V E R L A Y P R E V I E W
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
new file mode 100644
index 0000000..b883ffa
--- /dev/null
+++ b/include/media/msm_vidc.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_H_
+#define _MSM_VIDC_H_
+
+#include <linux/videodev2.h>
+#include <linux/poll.h>
+
+enum core_id {
+ MSM_VIDC_CORE_0 = 0,
+ MSM_VIDC_CORES_MAX,
+};
+
+enum session_type {
+ MSM_VIDC_ENCODER = 0,
+ MSM_VIDC_DECODER,
+ MSM_VIDC_MAX_DEVICES,
+};
+
+void *msm_vidc_open(int core_id, int session_type);
+int msm_vidc_close(void *instance);
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *pt);
+#endif
diff --git a/include/media/user-rc-input.h b/include/media/user-rc-input.h
new file mode 100644
index 0000000..e58e40f
--- /dev/null
+++ b/include/media/user-rc-input.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __USER_RC_INPUT_H__
+#define __USER_RC_INPUT_H__
+
+#define USER_CONTROL_PRESSED 0x01
+#define USER_CONTROL_REPEATED 0x02
+#define USER_CONTROL_RELEASED 0x03
+
+#endif /* __USER_RC_INPUT_H__ */
+
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 968d46e..54a9187 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -13,7 +13,6 @@
#define __Q6_ASM_H__
#include <mach/qdsp6v2/apr.h>
-#include <mach/msm_subsystem_map.h>
#include <sound/apr_audio.h>
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#include <linux/ion.h>
@@ -110,7 +109,7 @@
struct ion_handle *handle;
struct ion_client *client;
#else
- struct msm_mapped_buffer *mem_buffer;
+ void *mem_buffer;
#endif
};
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index a2c6f5f..3f7e399 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -13,7 +13,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/mfd/pm8xxx/spk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -36,6 +36,8 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+#define SPK_AMP_POS 0x1
+#define SPK_AMP_NEG 0x2
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -45,6 +47,7 @@
static int msm8930_slim_0_rx_ch = 1;
static int msm8930_slim_0_tx_ch = 1;
+static int msm8930_ext_spk_pamp;
static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
static int msm8930_btsco_ch = 1;
@@ -111,11 +114,81 @@
return 1;
}
+static void msm8960_ext_spk_power_amp_on(u32 spk)
+{
+ if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+ if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+ (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+ pr_debug("%s() External Bottom Speaker Ampl already "
+ "turned on. spk = 0x%08x\n", __func__, spk);
+ return;
+ }
+
+ msm8930_ext_spk_pamp |= spk;
+
+ if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+ (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+ pm8xxx_spk_enable(MSM8930_SPK_ON);
+ pr_debug("%s: slepping 4 ms after turning on external "
+ " Left Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+ }
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void msm8960_ext_spk_power_amp_off(u32 spk)
+{
+ if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+ if (!msm8930_ext_spk_pamp)
+ return;
+
+ pm8xxx_spk_enable(MSM8930_SPK_OFF);
+ msm8930_ext_spk_pamp = 0;
+ pr_debug("%s: slepping 4 ms after turning on external "
+ " Left Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
- /* TODO: add external speaker power amps support */
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+ msm8960_ext_spk_power_amp_on(SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+ msm8960_ext_spk_power_amp_on(SPK_AMP_NEG);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+ msm8960_ext_spk_power_amp_off(SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+ msm8960_ext_spk_power_amp_off(SPK_AMP_NEG);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -174,7 +247,7 @@
msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk Left Neg", msm8930_spkramp_event),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Digital Mic1", NULL),
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index ba5c79d..fc08febf 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -38,7 +38,6 @@
#include <mach/peripheral-loader.h>
#include <mach/qdsp6v2/audio_acdb.h>
#include <mach/qdsp6v2/rtac.h>
-#include <mach/msm_subsystem_map.h>
#include <sound/apr_audio.h>
#include <sound/q6asm.h>
@@ -258,7 +257,7 @@
"%ld\n", __func__,
PTR_ERR((void *)port->buf[cnt].mem_buffer));
else {
- if (msm_subsystem_unmap_buffer(
+ if (iounmap(
port->buf[cnt].mem_buffer) < 0)
pr_err("%s: unmap buffer"
" failed\n", __func__);
@@ -328,7 +327,7 @@
"%ld\n", __func__,
PTR_ERR((void *)port->buf[0].mem_buffer));
else {
- if (msm_subsystem_unmap_buffer(
+ if (iounmap(
port->buf[0].mem_buffer) < 0)
pr_err("%s: unmap buffer"
" failed\n", __func__);
@@ -574,11 +573,8 @@
mutex_unlock(&ac->cmd_lock);
goto fail;
}
- flags = MSM_SUBSYSTEM_MAP_KADDR |
- MSM_SUBSYSTEM_MAP_CACHED;
buf[cnt].mem_buffer =
- msm_subsystem_map_buffer(buf[cnt].phys,
- bufsz, flags, NULL, 0);
+ ioremap(buf[cnt].phys, bufsz);
if (IS_ERR(
(void *)buf[cnt].mem_buffer)) {
pr_err("%s:map_buffer failed,"
@@ -588,7 +584,7 @@
goto fail;
}
buf[cnt].data =
- buf[cnt].mem_buffer->vaddr;
+ buf[cnt].mem_buffer;
if (!buf[cnt].data) {
pr_err("%s:invalid vaddr,"
" iomap failed\n", __func__);
@@ -700,9 +696,7 @@
goto fail;
}
- flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
- buf[0].mem_buffer = msm_subsystem_map_buffer(buf[0].phys,
- bufsz * bufcnt, flags, NULL, 0);
+ buf[0].mem_buffer = ioremap(buf[0].phys, bufsz * bufcnt);
if (IS_ERR((void *)buf[cnt].mem_buffer)) {
pr_err("%s:map_buffer failed,"
"error = %ld\n",
@@ -711,7 +705,7 @@
mutex_unlock(&ac->cmd_lock);
goto fail;
}
- buf[0].data = buf[0].mem_buffer->vaddr;
+ buf[0].data = buf[0].mem_buffer;
#endif
if (!buf[0].data) {
pr_err("%s:invalid vaddr,"