Merge "msm: mdss: fix mdp suspend/resume sequence"
diff --git a/Documentation/devicetree/bindings/cache/msm_cache_dump.txt b/Documentation/devicetree/bindings/cache/msm_cache_dump.txt
new file mode 100644
index 0000000..b7a68b5
--- /dev/null
+++ b/Documentation/devicetree/bindings/cache/msm_cache_dump.txt
@@ -0,0 +1,24 @@
+* Qualcomm Krait L1 / L2 cache dumping device
+This is a virtual device that dumps the contents of L1 and L2 caches in the
+event of a kernel panic or a watchdog trigger.
+
+Required properties:
+- compatible: Should be "qcom,cache_dump"
+- qcom,l1-dump-size: Amount of memory needed for L1 dump(s), in bytes
+- qcom,l2-dump-size: Amount of memory needed for L2 dump, in bytes
+- qcom,memory-reservation-size: Combined reserved memory for the dump buffers
+- qcom,memory-reservation-type: Type of memory to be reserved
+
+Optional properties:
+- qcom,use-imem-dump-offset: If specified, store cache dump buffer addresses
+ in IMEM rather than using the memory dump reservation table.
+
+Example:
+ qcom,cache_dump {
+ compatible = "qcom,cache_dump";
+ qcom,l1-dump-size = <0x100000>;
+ qcom,l2-dump-size = <0x400000>;
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x500000>;
+ };
+
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 82e76fc..26bddd9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -14,7 +14,7 @@
- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. Default value is 24(rgb888).
18 = for rgb666
16 = for rgb565
-- qcom,panel-phy-regulatorSettings: An array of length 8 that specifies the PHY
+- qcom,panel-phy-regulatorSettings: An array of length 7 that specifies the PHY
regulator settings for the panel.
- qcom,panel-phy-timingSettings: An array of length 12 that specifies the PHY
timing settings for the panel.
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
new file mode 100644
index 0000000..1d3c2db
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -0,0 +1,80 @@
+Qualcomm's QPNP PMIC Battery Management System driver
+
+QPNP PMIC BMS provides interface to clients to read properties related
+to the battery. It's main function is to calculate the State of Charge (SOC),
+a 0-100 percentage representing the amount of charge left in the battery.
+
+BMS node
+
+Required properties:
+- compatible : should be "qcom,qpnp-bms" for the BM driver.
+- reg : offset and length of the PMIC BMS register map.
+- interrupts : the interrupt mappings for bms.
+ The format should be
+ <slave-id peripheral-id interrupt-number>.
+- interrupt-names : names for the mapped bms interrupt
+ The following interrupts are required:
+ 0 : vsense_for_r
+ 1 : vsense_avg
+ 2 : sw_cc_thr
+ 3 : ocv_thr
+ 4 : charge_begin
+ 5 : good_ocv
+ 6 : ocv_for_r
+ 7 : cc_thr
+- qcom,bms-r-sense-mohm : sensor resistance in in milli-ohms.
+- qcom,bms-v-cutoff-uv : cutoff voltage where the battery is considered dead in
+ micro-volts.
+- qcom,bms-max-voltage-uv : maximum voltage for the battery in micro-volts.
+- qcom,bms-r-conn-mohm : connector resistance in milli-ohms.
+- qcom,bms-shutdown-soc-valid-limit : If the ocv upon restart is within this
+ distance of the shutdown ocv, the BMS will try to force
+ the new SoC to the old one to provide charge continuity.
+ That is to say,
+ if (abs(shutdown-soc - current-soc) < limit)
+ then use old SoC.
+- qcom,bms-adjust-soc-low-threshold : The low threshold for the "flat portion"
+ of the charging curve. The BMS will not adjust SoC
+ based on voltage during this time.
+- qcom,bms-adjust-soc-high-threshold : The high threshold for the "flat
+ portion" of the charging curve. The BMS will not
+ adjust SoC based on voltage during this time.
+- qcom,bms-chg-term-ua : current in micro-amps when charging is considered done.
+ As soon as current passes this point, charging is
+ stopped.
+
+Example:
+ bms@4000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "qcom,qpnp-bms";
+ reg = <0x4000 0x100>;
+
+ interrupts = <0x0 0x40 0x0>,
+ <0x0 0x40 0x1>,
+ <0x0 0x40 0x2>,
+ <0x0 0x40 0x3>,
+ <0x0 0x40 0x4>,
+ <0x0 0x40 0x5>,
+ <0x0 0x40 0x6>,
+ <0x0 0x40 0x7>;
+
+ interrupt-names = "vsense_for_r",
+ "vsense_avg",
+ "sw_cc_thr",
+ "ocv_thr",
+ "charge_begin",
+ "good_ocv",
+ "ocv_for_r",
+ "cc_thr";
+
+ qcom,bms-r-sense-mohm = <10>;
+ qcom,bms-v-cutoff-uv = <3400000>;
+ qcom,bms-max-voltage-uv = <4200000>;
+ qcom,bms-r-conn-mohm = <18>;
+ qcom,bms-shutdown-soc-valid-limit = <20>;
+ qcom,bms-adjust-soc-low-threshold = <25>;
+ qcom,bms-adjust-soc-high-threshold = <45>;
+ qcom,bms-chg-term-ua = <100000>;
+ };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index fe60c83..ffd4518 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -860,6 +860,14 @@
interrupt-names = "l1_irq", "l2_irq";
};
+ qcom,cache_dump {
+ compatible = "qcom,cache_dump";
+ qcom,l1-dump-size = <0x100000>;
+ qcom,l2-dump-size = <0x500000>;
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x600000>; /* 6M EBI1 buffer */
+ };
+
tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
reg = <0xfc4a8000 0x2000>,
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 10d2f4d..7e3aad7 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -287,6 +287,7 @@
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MSM_WFD=y
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index bc1eded..c79f82f 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -396,11 +396,13 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 883e04d..eb00f34 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -392,11 +392,13 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 792eea4..9bb6e09 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -474,16 +474,19 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
+ .csiphy_core = 2,
.csid_core = 2,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 7a1e2ff..b5f214b 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -139,12 +139,14 @@
struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
{
+ .csiphy_core = 1,
.csid_core = 1,
.ioclk = {
.vfe_clk_rate = 192000000,
},
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.ioclk = {
.vfe_clk_rate = 266667000,
@@ -154,12 +156,14 @@
struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.ioclk = {
.vfe_clk_rate = 192000000,
},
},
{
+ .csiphy_core = 0,
.csid_core = 0,
.ioclk = {
.vfe_clk_rate = 266667000,
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index f16751d..b3ce01c 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -884,6 +884,7 @@
#ifdef CONFIG_MSM_CAMERA_V4L2
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.ioclk = {
@@ -891,6 +892,7 @@
},
},
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.ioclk = {
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index acd7f74..7e5f022 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -360,6 +360,7 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
+ .csiphy_core = 0,
.csid_core = 0,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
@@ -368,6 +369,7 @@
},
},
{
+ .csiphy_core = 1,
.csid_core = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 6ddb462..f6b1332 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5330,6 +5330,7 @@
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-0048"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-006c"),
+ CLK_LOOKUP("cam_clk", cam2_clk.c, ""),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
CLK_LOOKUP("csi_src_clk", csi1_src_clk.c, "msm_csid.1"),
CLK_LOOKUP("csi_src_clk", csi2_src_clk.c, "msm_csid.2"),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 4ad5580..0f106f5 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2316,8 +2316,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device apq8064_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 292f58d..ad89a86 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -530,8 +530,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device msm8930_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 33782ab..b6926a2 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -3668,8 +3668,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device msm8960_rpm_stat_device = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index b65bd1f..acf577e 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -365,25 +365,25 @@
static struct msm_iommu_dev gfx3d_iommu = {
.name = "gfx3d",
.ncb = 3,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev gfx3d1_iommu = {
.name = "gfx3d1",
.ncb = 3,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev gfx2d0_iommu = {
.name = "gfx2d0",
.ncb = 2,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev gfx2d1_iommu = {
.name = "gfx2d1",
.ncb = 2,
- .ttbr_split = 2,
+ .ttbr_split = 1,
};
static struct msm_iommu_dev vcap_iommu = {
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 5b8729a..433fee3 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -63,6 +63,7 @@
uint8_t csid_core;
uint8_t is_vpe;
struct msm_bus_scale_pdata *cam_bus_scale_table;
+ uint8_t csiphy_core;
};
#ifdef CONFIG_SENSORS_MT9T013
@@ -177,7 +178,6 @@
struct msm_camera_csi_lane_params {
uint16_t csi_lane_assign;
uint16_t csi_lane_mask;
- uint8_t csi_phy_sel;
};
struct msm_camera_gpio_conf {
diff --git a/arch/arm/mach-msm/include/mach/msm_memory_dump.h b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
index 5e686bf..729a077 100644
--- a/arch/arm/mach-msm/include/mach/msm_memory_dump.h
+++ b/arch/arm/mach-msm/include/mach/msm_memory_dump.h
@@ -17,7 +17,8 @@
enum dump_client_type {
MSM_CPU_CTXT = 0,
- MSM_CACHE,
+ MSM_L1_CACHE,
+ MSM_L2_CACHE,
MSM_OCMEM,
MSM_TMC_ETFETB,
MSM_ETM0_REG,
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 9759d5a..8b4978f 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -21,10 +21,13 @@
#include <linux/pm.h>
#include <linux/memory_alloc.h>
#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <mach/scm.h>
#include <mach/msm_cache_dump.h>
#include <mach/memory.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_memory_dump.h>
#define L2_DUMP_OFFSET 0x14
@@ -37,6 +40,7 @@
*/
static struct l1_cache_dump *l1_dump;
static struct l2_cache_dump *l2_dump;
+static int use_imem_dump_offset;
static int msm_cache_dump_panic(struct notifier_block *this,
unsigned long event, void *ptr)
@@ -45,7 +49,8 @@
/*
* Clear the bootloader magic so the dumps aren't overwritten
*/
- __raw_writel(0, MSM_IMEM_BASE + L2_DUMP_OFFSET);
+ if (use_imem_dump_offset)
+ __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);
@@ -65,14 +70,38 @@
static int msm_cache_dump_probe(struct platform_device *pdev)
{
struct msm_cache_dump_platform_data *d = pdev->dev.platform_data;
+ struct msm_client_dump l1_dump_entry, l2_dump_entry;
int ret;
struct {
unsigned long buf;
unsigned long size;
} l1_cache_data;
void *temp;
- unsigned long total_size = d->l1_size + d->l2_size;
+ u32 l1_size, l2_size;
+ unsigned long total_size;
+ if (pdev->dev.of_node) {
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,l1-dump-size", &l1_size);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,l2-dump-size", &l2_size);
+ if (ret)
+ return ret;
+
+ use_imem_dump_offset = of_property_read_bool(pdev->dev.of_node,
+ "qcom,use-imem-dump-offset");
+ } else {
+ l1_size = d->l1_size;
+ l2_size = d->l2_size;
+
+ /* Non-DT targets assume the IMEM dump offset shall be used */
+ use_imem_dump_offset = 1;
+ };
+
+ total_size = l1_size + l2_size;
msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
if (!msm_cache_dump_addr) {
@@ -86,7 +115,7 @@
iounmap(temp);
l1_cache_data.buf = msm_cache_dump_addr;
- l1_cache_data.size = d->l1_size;
+ l1_cache_data.size = l1_size;
ret = scm_call(L1C_SERVICE_ID, L1C_BUFFER_SET_COMMAND_ID,
&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
@@ -96,10 +125,11 @@
__func__, ret);
l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
+ l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
- l1_cache_data.buf = msm_cache_dump_addr + d->l1_size;
- l1_cache_data.size = d->l2_size;
+ l1_cache_data.buf = msm_cache_dump_addr + l1_size;
+ l1_cache_data.size = l2_size;
ret = scm_call(L1C_SERVICE_ID, L2C_BUFFER_SET_COMMAND_ID,
&l1_cache_data, sizeof(l1_cache_data), NULL, 0);
@@ -108,11 +138,27 @@
pr_err("%s: could not register L2 buffer ret = %d.\n",
__func__, ret);
#endif
- __raw_writel(msm_cache_dump_addr + d->l1_size,
+
+ if (use_imem_dump_offset)
+ __raw_writel(msm_cache_dump_addr + l1_size,
MSM_IMEM_BASE + L2_DUMP_OFFSET);
+ else {
+ l1_dump_entry.id = MSM_L1_CACHE;
+ l1_dump_entry.start_addr = msm_cache_dump_addr;
+ l1_dump_entry.end_addr = l1_dump_entry.start_addr + l1_size - 1;
+ l2_dump_entry.id = MSM_L2_CACHE;
+ l2_dump_entry.start_addr = msm_cache_dump_addr + l1_size;
+ l2_dump_entry.end_addr = l2_dump_entry.start_addr + l2_size - 1;
- l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + d->l1_size);
+ ret = msm_dump_table_register(&l1_dump_entry);
+ if (ret)
+ pr_err("Could not register L1 dump area: %d\n", ret);
+
+ ret = msm_dump_table_register(&l2_dump_entry);
+ if (ret)
+ pr_err("Could not register L2 dump area: %d\n", ret);
+ }
atomic_notifier_chain_register(&panic_notifier_list,
&msm_cache_dump_blk);
@@ -126,11 +172,18 @@
return 0;
}
+static struct of_device_id cache_dump_match_table[] = {
+ { .compatible = "qcom,cache_dump", },
+ {}
+};
+EXPORT_COMPAT("qcom,cache_dump");
+
static struct platform_driver msm_cache_dump_driver = {
.remove = __devexit_p(msm_cache_dump_remove),
.driver = {
.name = "msm_cache_dump",
- .owner = THIS_MODULE
+ .owner = THIS_MODULE,
+ .of_match_table = cache_dump_match_table,
},
};
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a190342..a9d1ed8 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -289,9 +289,10 @@
if (!handle)
return;
- for (i = 0; i < handle->write_idx; i++)
+ for (i = 0; i < handle->num_elements; i++)
kfree(handle->kvp[i].value);
kfree(handle->kvp);
+ kfree(handle->buf);
kfree(handle);
}
EXPORT_SYMBOL(msm_rpm_free_request);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index b8fca38..7bf928f 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2706,62 +2706,100 @@
return val;
}
+struct a3xx_vbif_data {
+ unsigned int reg;
+ unsigned int val;
+};
+
+/* VBIF registers start after 0x3000 so use 0x0 as end of list marker */
+static struct a3xx_vbif_data a305_vbif[] = {
+ /* Set up 16 deep read/write request queues */
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010 },
+ /* Enable WR-REQ */
+ { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF },
+ /* Set up round robin arbitration between both AXI ports */
+ { A3XX_VBIF_ARB_CTL, 0x00000030 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C },
+ {0, 0},
+};
+
+static struct a3xx_vbif_data a320_vbif[] = {
+ /* Set up 16 deep read/write request queues */
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010 },
+ { A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010 },
+ /* Enable WR-REQ */
+ { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF },
+ /* Set up round robin arbitration between both AXI ports */
+ { A3XX_VBIF_ARB_CTL, 0x00000030 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C },
+ /* Enable 1K sort */
+ { A3XX_VBIF_ABIT_SORT, 0x000000FF },
+ { A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
+ {0, 0},
+};
+
+static struct a3xx_vbif_data a330_vbif[] = {
+ /* Set up 16 deep read/write request queues */
+ { A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818 },
+ { A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303 },
+ { A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818 },
+ { A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818 },
+ /* Enable WR-REQ */
+ { A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F },
+ /* Set up round robin arbitration between both AXI ports */
+ { A3XX_VBIF_ARB_CTL, 0x00000030 },
+ /* Set up VBIF_ROUND_ROBIN_QOS_ARB */
+ { A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001 },
+ /* Set up AOOO */
+ { A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF },
+ { A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF },
+ /* Enable 1K sort */
+ { A3XX_VBIF_ABIT_SORT, 0x1FFFF },
+ { A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4 },
+ /* Disable VBIF clock gating. This is to enable AXI running
+ * higher frequency than GPU.
+ */
+ { A3XX_VBIF_CLKON, 1 },
+ {0, 0},
+};
+
static void a3xx_start(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = &adreno_dev->dev;
+ struct a3xx_vbif_data *vbif = NULL;
- /* Set up 16 deep read/write request queues */
- if (adreno_is_a330(adreno_dev)) {
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818);
- /* Enable WR-REQ */
- adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
+ if (adreno_is_a305(adreno_dev))
+ vbif = a305_vbif;
+ else if (adreno_is_a320(adreno_dev))
+ vbif = a320_vbif;
+ else if (adreno_is_a330(adreno_dev))
+ vbif = a330_vbif;
- /* Set up round robin arbitration between both AXI ports */
- adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
- /* Set up VBIF_ROUND_ROBIN_QOS_ARB */
- adreno_regwrite(device, A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
+ BUG_ON(vbif == NULL);
- /* Set up AOOO */
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF);
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF);
-
- /* Enable 1K sort */
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x1FFFF);
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
-
- /* Diable VBIF clock gating. This is to enable AXI running
- * higher frequency than GPU.
- */
- adreno_regwrite(device, A3XX_VBIF_CLKON, 1);
- } else {
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010);
- /* Enable WR-REQ */
- adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
-
- /* Set up round robin arbitration between both AXI ports */
- adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
- /* Set up AOOO */
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003C);
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x003C003C);
+ while (vbif->reg != 0) {
+ adreno_regwrite(device, vbif->reg, vbif->val);
+ vbif++;
}
- if (cpu_is_apq8064()) {
- /* Enable 1K sort */
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x000000FF);
- adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
- }
/* Make all blocks contribute to the GPU BUSY perf counter */
adreno_regwrite(device, A3XX_RBBM_GPU_BUSY_MASKED, 0xFFFFFFFF);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index dee889d..0e1e100 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -320,7 +320,7 @@
if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
return CONFIG_MSM_KGSL_PAGE_TABLE_SIZE;
else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
- return SZ_2G;
+ return SZ_2G - KGSL_PAGETABLE_BASE;
else
return 0;
}
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ae020e8..0d2d91c 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1262,3 +1262,4 @@
endif # V4L_MEM2MEM_DRIVERS
source "drivers/media/video/msm_vidc/Kconfig"
+source "drivers/media/video/msm_wfd/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 082ee3d..fd736c3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -215,7 +215,7 @@
obj-$(CONFIG_MSM_CAMERA) += msm/
obj-$(CONFIG_ARCH_OMAP) += omap/
obj-$(CONFIG_MSM_VIDC_V4L2) += msm_vidc/
-obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += msm_wfd/
+obj-$(CONFIG_MSM_WFD) += msm_wfd/
ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/video/msm/csi/msm_csi2_register.c b/drivers/media/video/msm/csi/msm_csi2_register.c
index aa539ff..5f2183b 100644
--- a/drivers/media/video/msm/csi/msm_csi2_register.c
+++ b/drivers/media/video/msm/csi/msm_csi2_register.c
@@ -16,18 +16,21 @@
#include "msm_csi_register.h"
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index, struct msm_cam_server_dev *server_dev)
+ uint8_t csiphy_code_index, uint8_t csid_core_index,
+ struct msm_cam_server_dev *server_dev)
{
int rc = -ENODEV;
+ CDBG("%s csiphy sel %d csid sel %d\n", __func__, csiphy_code_index,
+ csid_core_index);
/* register csiphy subdev */
- p_mctl->csiphy_sdev = server_dev->csiphy_device[core_index];
+ p_mctl->csiphy_sdev = server_dev->csiphy_device[csiphy_code_index];
if (!p_mctl->csiphy_sdev)
goto out;
v4l2_set_subdev_hostdata(p_mctl->csiphy_sdev, p_mctl);
/* register csid subdev */
- p_mctl->csid_sdev = server_dev->csid_device[core_index];
+ p_mctl->csid_sdev = server_dev->csid_device[csid_core_index];
if (!p_mctl->csid_sdev)
goto out;
v4l2_set_subdev_hostdata(p_mctl->csid_sdev, p_mctl);
diff --git a/drivers/media/video/msm/csi/msm_csi_register.h b/drivers/media/video/msm/csi/msm_csi_register.h
index ebb001c..4214feb 100644
--- a/drivers/media/video/msm/csi/msm_csi_register.h
+++ b/drivers/media/video/msm/csi/msm_csi_register.h
@@ -12,5 +12,5 @@
*/
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index,
+ uint8_t csiphy_code_index, uint8_t csid_core_index,
struct msm_cam_server_dev *server_dev);
diff --git a/drivers/media/video/msm/csi/msm_csic_register.c b/drivers/media/video/msm/csi/msm_csic_register.c
index dc3641a..af50101 100644
--- a/drivers/media/video/msm/csi/msm_csic_register.c
+++ b/drivers/media/video/msm/csi/msm_csic_register.c
@@ -16,11 +16,12 @@
#include "msm_csi_register.h"
int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index, struct msm_cam_server_dev *server_dev)
+ uint8_t csiphy_code_index, uint8_t csid_core_index,
+ struct msm_cam_server_dev *server_dev)
{
int rc = -ENODEV;
- p_mctl->csic_sdev = server_dev->csic_device[core_index];
+ p_mctl->csic_sdev = server_dev->csic_device[csid_core_index];
if (!p_mctl->csic_sdev)
goto out;
v4l2_set_subdev_hostdata(p_mctl->csic_sdev, p_mctl);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index cb59d68..2d9296c 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -720,7 +720,7 @@
int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
struct msm_cam_subdev_info *sd_info);
int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index);
+ uint8_t csiphy_core_index, uint8_t csid_core_index);
int msm_server_open_client(int *p_qidx);
int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
int msm_server_close_client(int idx);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index c94da2a..482e569 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -529,7 +529,8 @@
wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
- rc = msm_mctl_find_sensor_subdevs(p_mctl, csid_core);
+ rc = msm_mctl_find_sensor_subdevs(p_mctl, camdev->csiphy_core,
+ csid_core);
if (rc < 0) {
pr_err("%s: msm_mctl_find_sensor_subdevs failed:%d\n",
__func__, rc);
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 999783e..f5c9a73 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -402,7 +402,8 @@
csi_lane_assign;
sensor_output_info->csi_lane_mask = csi_lane_params->
csi_lane_mask;
- sensor_output_info->csi_phy_sel = csi_lane_params->csi_phy_sel;
+ sensor_output_info->csi_phy_sel =
+ s_ctrl->sensordata->pdata->csiphy_core;
}
sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
for (index = 0; index < sensor_output_info->csi_if; index++)
@@ -1184,8 +1185,7 @@
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR3;
}
- pinfo->csi_lane_params->csi_phy_sel = val;
-
+ sensordata->pdata->csiphy_core = val;
kfree(val_array);
return rc;
ERROR3:
@@ -1762,6 +1762,8 @@
s_ctrl->sensor_i2c_addr >> 1;
s_ctrl->sensor_i2c_client->cci_client->retries = 3;
s_ctrl->sensor_i2c_client->cci_client->id_map = 0;
+ if (!s_ctrl->wait_num_frames)
+ s_ctrl->wait_num_frames = 1 * Q10;
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
@@ -1777,6 +1779,8 @@
if (rc < 0)
goto probe_fail;
+ pr_err("%s %s probe succeeded\n", __func__,
+ s_ctrl->sensordata->sensor_name);
v4l2_subdev_init(&s_ctrl->sensor_v4l2_subdev,
s_ctrl->sensor_v4l2_subdev_ops);
snprintf(s_ctrl->sensor_v4l2_subdev.name,
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index b78e20d..74dd3f2 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1801,13 +1801,14 @@
}
int msm_mctl_find_sensor_subdevs(struct msm_cam_media_controller *p_mctl,
- int core_index)
+ uint8_t csiphy_core_index, uint8_t csid_core_index)
{
int rc = -ENODEV;
v4l2_set_subdev_hostdata(p_mctl->sensor_sdev, p_mctl);
- rc = msm_csi_register_subdevs(p_mctl, core_index, &g_server_dev);
+ rc = msm_csi_register_subdevs(p_mctl, csiphy_core_index,
+ csid_core_index, &g_server_dev);
if (rc < 0)
pr_err("%s: Could not find sensor subdevs\n", __func__);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index a4c4b83..7fa4f26 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -561,22 +561,69 @@
fail_nomem:
return rc;
}
+static int msm_v4l2_release_output_buffers(struct msm_v4l2_vid_inst *v4l2_inst)
+{
+ struct list_head *ptr, *next;
+ struct buffer_info *bi;
+ struct v4l2_buffer buffer_info;
+ struct v4l2_plane plane;
+ int rc = 0;
+ list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buffer_info.type = bi->type;
+ plane.reserved[0] = bi->fd;
+ plane.reserved[1] = bi->buff_off;
+ plane.length = bi->size;
+ plane.m.userptr = bi->device_addr;
+ buffer_info.m.planes = &plane;
+ buffer_info.length = 1;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+ &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed Release buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ list_del(&bi->list);
+ if (bi->handle)
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle);
+ kfree(bi);
+ }
+ }
+ return rc;
+}
static int msm_v4l2_close(struct file *filp)
{
- int rc;
+ int rc = 0;
struct list_head *ptr, *next;
- struct buffer_info *binfo;
+ struct buffer_info *bi;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
vidc_inst = get_vidc_inst(filp, NULL);
v4l2_inst = get_v4l2_inst(filp, NULL);
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
rc = msm_vidc_close(vidc_inst);
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- binfo = list_entry(ptr, struct buffer_info, list);
- list_del(&binfo->list);
- msm_smem_free(v4l2_inst->mem_client, binfo->handle);
- kfree(binfo);
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ list_del(&bi->list);
+ if (bi->handle)
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle);
+ kfree(bi);
+ }
}
msm_smem_delete_client(v4l2_inst->mem_client);
kfree(v4l2_inst);
@@ -630,38 +677,13 @@
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
struct msm_v4l2_vid_inst *v4l2_inst;
- struct list_head *ptr, *next;
- int rc;
- struct buffer_info *bi;
- struct v4l2_buffer buffer_info;
- struct v4l2_plane plane;
+ int rc = 0;
v4l2_inst = get_v4l2_inst(file, NULL);
- if (b->count == 0) {
- list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- buffer_info.type = bi->type;
- plane.reserved[0] = bi->fd;
- plane.reserved[1] = bi->buff_off;
- plane.length = bi->size;
- plane.m.userptr = bi->device_addr;
- buffer_info.m.planes = &plane;
- buffer_info.length = 1;
- dprintk(VIDC_DBG,
- "Releasing buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
- rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
- &buffer_info);
- list_del(&bi->list);
- if (bi->handle)
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle);
- kfree(bi);
- }
- }
- }
+ if (b->count == 0)
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
return msm_vidc_reqbufs((void *)vidc_inst, b);
}
@@ -824,7 +846,15 @@
static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dec)
{
+ struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ int rc = 0;
+ v4l2_inst = get_v4l2_inst(file, NULL);
+ if (dec->cmd == V4L2_DEC_CMD_STOP)
+ rc = msm_v4l2_release_output_buffers(v4l2_inst);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for release output buffers\n", __func__);
return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index be2e848..ead118d 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -747,6 +747,16 @@
return rc;
}
+static inline int stop_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to move inst: %p to start done state\n", inst);
+ return rc;
+}
+
static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct msm_vidc_inst *inst;
@@ -788,13 +798,11 @@
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
- rc = msm_comm_try_state(inst,
- MSM_VIDC_RELEASE_RESOURCES_DONE);
+ rc = stop_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
- rc = msm_comm_try_state(inst,
- MSM_VIDC_RELEASE_RESOURCES_DONE);
+ rc = stop_streaming(inst);
break;
default:
dprintk(VIDC_ERR,
@@ -830,6 +838,12 @@
rc = msm_comm_flush(inst, dec->flags);
break;
case V4L2_DEC_CMD_STOP:
+ rc = msm_comm_release_scratch_buffers(inst);
+ if (rc)
+ pr_err("Failed to release scratch buffers: %d\n", rc);
+ rc = msm_comm_release_persist_buffers(inst);
+ if (rc)
+ pr_err("Failed to release persist buffers: %d\n", rc);
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
break;
default:
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 7f3096a..2aed0b7 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -1566,6 +1566,68 @@
return rc;
}
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->internalbufs)) {
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->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_release_buffers(
+ (void *) inst->session, &buffer_info);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+}
+
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
+{
+ struct msm_smem *handle;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct vidc_buffer_addr_info buffer_info;
+ int rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->persistbufs)) {
+ list_for_each_safe(ptr, next, &inst->persistbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ handle = buf->handle;
+ buffer_info.buffer_size = handle->size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_release_buffers(
+ (void *) inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in %s for buffer %ld\n",
+ __func__, handle->device_addr);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+}
+
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -1586,6 +1648,17 @@
list_for_each_safe(ptr, next, &inst->internalbufs) {
binfo = list_entry(ptr, struct internal_buf,
list);
+ handle = binfo->handle;
+ buffer_info.buffer_size = handle->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_release_buffers(
+ (void *) inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed in release %s for buffer %ld\n",
+ __func__, handle->device_addr);
list_del(&binfo->list);
msm_smem_free(inst->mem_client, binfo->handle);
kfree(binfo);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 69aa53a..1301e5c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -32,6 +32,8 @@
int msm_comm_qbuf(struct vb2_buffer *vb);
int msm_comm_scale_clocks(struct msm_vidc_core *core, enum session_type type);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
diff --git a/drivers/media/video/msm_wfd/Kconfig b/drivers/media/video/msm_wfd/Kconfig
new file mode 100644
index 0000000..6050d73
--- /dev/null
+++ b/drivers/media/video/msm_wfd/Kconfig
@@ -0,0 +1,6 @@
+menuconfig MSM_WFD
+ bool "Qualcomm MSM Wifi Display Driver"
+ depends on (MSM_VIDC_1080P || MSM_VIDC_V4L2)
+ ---help---
+ Enables the Wifi Display driver.
+
diff --git a/drivers/media/video/msm_wfd/Makefile b/drivers/media/video/msm_wfd/Makefile
index 5decaca..813bc64 100644
--- a/drivers/media/video/msm_wfd/Makefile
+++ b/drivers/media/video/msm_wfd/Makefile
@@ -1,5 +1,14 @@
-obj-y += mdp-subdev.o
-obj-y += enc-subdev.o
-obj-y += vsg-subdev.o
-obj-y += wfd-ioctl.o
-obj-y += wfd-util.o
+ifeq ($(CONFIG_MSM_WFD),y)
+ obj-y += wfd-ioctl.o
+ obj-y += wfd-util.o
+ obj-y += vsg-subdev.o
+ ifeq ($(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL),y)
+ obj-y += mdp-4-subdev.o
+ else ifeq ($(CONFIG_FB_MSM_MDSS_WRITEBACK),y)
+ obj-y += mdp-5-subdev.o
+ else
+ obj-y += mdp-dummy-subdev.o
+ endif
+ obj-$(CONFIG_MSM_VIDC_1080P) += enc-mfc-subdev.o
+ obj-$(CONFIG_MSM_VIDC_V4L2) += enc-venus-subdev.o
+endif
diff --git a/drivers/media/video/msm_wfd/enc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
similarity index 96%
rename from drivers/media/video/msm_wfd/enc-subdev.c
rename to drivers/media/video/msm_wfd/enc-mfc-subdev.c
index e1cabf9..5997345 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -227,7 +227,7 @@
BUFFER_TYPE_OUTPUT, pmem_fd,
kvaddr, buffer_index, &ion_handle);
else
- WFD_MSG_ERR("Got an output buffer that we "
+ WFD_MSG_ERR("Got an output buffer that we " \
"couldn't recognize!\n");
if (msm_ion_do_cache_op(client_ctx->user_ion_client,
@@ -547,8 +547,8 @@
if (vcd_property_level.level < VCD_LEVEL_MPEG4_0
|| vcd_property_level.level > VCD_LEVEL_MPEG4_X) {
- WFD_MSG_ERR("Level (%d) out of range"
- "for codec (%d)\n", level, codec);
+ WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
+ level, codec);
rc = -EINVAL;
goto err;
@@ -558,8 +558,8 @@
if (vcd_property_level.level < VCD_LEVEL_H264_1
|| vcd_property_level.level > VCD_LEVEL_H264_5p1) {
- WFD_MSG_ERR("Level (%d) out of range"
- "for codec (%d)\n", level, codec);
+ WFD_MSG_ERR("Level (%d) out of range for codec (%d)\n",
+ level, codec);
rc = -EINVAL;
goto err;
@@ -678,9 +678,9 @@
vcd_property_profile.profile = VCD_PROFILE_MPEG4_ASP;
break;
default:
- WFD_MSG_ERR("Profile %d not supported,"
- "defaulting to simple (%d)",
- profile, VCD_PROFILE_MPEG4_SP);
+ WFD_MSG_ERR("Profile %d not supported, defaulting " \
+ "to simple (%d)", profile,
+ VCD_PROFILE_MPEG4_SP);
vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
break;
}
@@ -697,17 +697,16 @@
vcd_property_profile.profile = VCD_PROFILE_H264_HIGH;
break;
default:
- WFD_MSG_ERR("Profile %d not supported,"
- "defaulting to baseline (%d)",
- profile, VCD_PROFILE_H264_BASELINE);
+ WFD_MSG_ERR("Profile %d not supported, defaulting " \
+ "to baseline (%d)", profile,
+ VCD_PROFILE_H264_BASELINE);
vcd_property_profile.profile =
VCD_PROFILE_H264_BASELINE;
break;
}
} else {
- WFD_MSG_ERR("Codec (%d) not supported,"
- "not setting profile (%d)",
- codec, profile);
+ WFD_MSG_ERR("Codec (%d) not supported, not "\
+ "setting profile (%d)", codec, profile);
rc = -ENOTSUPP;
goto err_set_profile;
}
@@ -2312,6 +2311,73 @@
return rc;
}
+long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ unsigned long rc = 0, size = 0;
+ void *paddr = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mmap || !mmap->mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ if (inst->secure) {
+ rc = ion_phys(mmap->ion_client, mregion->ion_handle,
+ (unsigned long *)&paddr,
+ (size_t *)&size);
+ } else {
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
+ 0, (unsigned long *)&paddr,
+ &size, 0, 0);
+ }
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get physical addr\n");
+ paddr = NULL;
+ } else if (size < mregion->size) {
+ WFD_MSG_ERR("Failed to map enough memory\n");
+ rc = -ENOMEM;
+ }
+
+ mregion->paddr = paddr;
+ return rc;
+}
+
+long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = sd->dev_priv;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ mregion = mmap->mregion;
+ if (!inst->secure) {
+ ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ }
+
+ return 0;
+}
+
long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
long rc = 0;
@@ -2375,6 +2441,12 @@
case ENCODE_FLUSH:
rc = venc_flush_buffers(sd, arg);
break;
+ case ENC_MMAP:
+ rc = venc_mmap(sd, arg);
+ break;
+ case ENC_MUNMAP:
+ rc = venc_munmap(sd, arg);
+ break;
default:
rc = -1;
break;
diff --git a/drivers/media/video/msm_wfd/enc-subdev.h b/drivers/media/video/msm_wfd/enc-subdev.h
index 00eb6da..c6c854e 100644
--- a/drivers/media/video/msm_wfd/enc-subdev.h
+++ b/drivers/media/video/msm_wfd/enc-subdev.h
@@ -14,6 +14,7 @@
#ifndef _WFD_ENC_SUBDEV_
#define _WFD_ENC_SUBDEV_
+#include <linux/list.h>
#include <linux/msm_ion.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
@@ -29,6 +30,15 @@
u32 cookie;
struct ion_handle *ion_handle;
};
+
+/* FIXME: need to come with a less stupid name */
+struct mem_region_map {
+ struct mem_region *mregion;
+ struct ion_client *ion_client;
+ uint32_t flags;
+ void *cookie;
+};
+
struct bufreq {
u32 count;
u32 height;
@@ -44,13 +54,27 @@
struct venc_msg_ops {
void *cookie;
void *cbdata;
- int secure;
+ bool secure;
void (*op_buffer_done)(void *cookie, u32 status,
struct vb2_buffer *buf);
void (*ip_buffer_done)(void *cookie, u32 status,
struct mem_region *mregion);
};
+static inline bool mem_region_equals(struct mem_region *a,
+ struct mem_region *b)
+{
+ if (a == b)
+ return true;
+ else if (a->fd || b->fd)
+ return (a->fd == b->fd) &&
+ (a->offset == b->offset);
+ else if (a->kvaddr || b->kvaddr)
+ return a->kvaddr == b->kvaddr;
+ else
+ return false;
+}
+
#define OPEN _IOR('V', 1, void *)
#define CLOSE _IO('V', 2)
#define ENCODE_START _IO('V', 3)
@@ -75,6 +99,8 @@
#define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
#define FREE_RECON_BUFFERS _IO('V', 23)
#define ENCODE_FLUSH _IO('V', 24)
+#define ENC_MMAP _IOWR('V', 25, struct mem_region_map *)
+#define ENC_MUNMAP _IOWR('V', 26, struct mem_region_map *)
extern int venc_init(struct v4l2_subdev *sd, u32 val);
extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
new file mode 100644
index 0000000..04e42f5
--- /dev/null
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -0,0 +1,1218 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* 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/bitmap.h>
+#include <linux/completion.h>
+#include <linux/ion.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <mach/iommu_domains.h>
+#include <media/msm_vidc.h>
+#include <media/v4l2-subdev.h>
+#include "enc-subdev.h"
+#include "wfd-util.h"
+
+#define BUF_TYPE_OUTPUT V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
+#define BUF_TYPE_INPUT V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
+
+static struct ion_client *venc_ion_client;
+
+struct index_bitmap {
+ unsigned long *bitmap;
+ int size;
+ int size_bits; /*Size in bits, not necessarily size/8 */
+};
+
+struct venc_inst {
+ void *vidc_context;
+ struct mutex lock;
+ struct venc_msg_ops vmops;
+ struct mem_region registered_input_bufs, registered_output_bufs;
+ struct index_bitmap free_input_indices, free_output_indices;
+ int num_output_planes, num_input_planes;
+ struct task_struct *callback_thread;
+ bool callback_thread_running;
+ struct completion dq_complete, cmd_complete;
+ bool secure;
+ int domain;
+};
+
+int venc_load_fw(struct v4l2_subdev *sd)
+{
+ /*No need to explicitly load the fw */
+ return 0;
+}
+
+int venc_init(struct v4l2_subdev *sd, u32 val)
+{
+ if (!venc_ion_client)
+ venc_ion_client = msm_ion_client_create(-1, "wfd_enc_subdev");
+
+ return venc_ion_client ? 0 : -ENOMEM;
+}
+
+static int next_free_index(struct index_bitmap *index_bitmap)
+{
+ int index = find_first_zero_bit(index_bitmap->bitmap,
+ index_bitmap->size_bits);
+
+ return (index >= index_bitmap->size_bits) ?
+ -1 : index;
+}
+
+static int mark_index_busy(struct index_bitmap *index_bitmap, int index)
+{
+ if (index > index_bitmap->size_bits) {
+ WFD_MSG_WARN("Marking unknown index as busy\n");
+ return -EINVAL;
+ }
+ set_bit(index, index_bitmap->bitmap);
+ return 0;
+}
+
+static int mark_index_free(struct index_bitmap *index_bitmap, int index)
+{
+ if (index > index_bitmap->size_bits) {
+ WFD_MSG_WARN("Marking unknown index as free\n");
+ return -EINVAL;
+ }
+ clear_bit(index, index_bitmap->bitmap);
+ return 0;
+}
+
+static int get_list_len(struct mem_region *list)
+{
+ struct mem_region *curr = NULL;
+ int index = 0;
+ list_for_each_entry(curr, &list->list, list) {
+ ++index;
+ }
+
+ return index;
+}
+
+static struct mem_region *get_registered_mregion(struct mem_region *list,
+ struct mem_region *mregion)
+{
+ struct mem_region *curr = NULL;
+ list_for_each_entry(curr, &list->list, list) {
+ if (unlikely(mem_region_equals(curr, mregion)))
+ return curr;
+ }
+
+ return NULL;
+}
+
+static int venc_vidc_callback_thread(void *data)
+{
+ struct venc_inst *inst = data;
+ WFD_MSG_DBG("Starting callback thread\n");
+ while (!kthread_should_stop()) {
+ bool dequeue_buf = false;
+ struct v4l2_buffer buffer = {0};
+ struct v4l2_event event = {0};
+ int num_planes = 0;
+ int flags = msm_vidc_wait(inst->vidc_context);
+
+ if (flags & POLLERR) {
+ WFD_MSG_ERR("Encoder reported error\n");
+ break;
+ }
+
+ if (flags & POLLPRI) {
+ bool bail_out = false;
+
+ msm_vidc_dqevent(inst->vidc_context, &event);
+ if (event.type == V4L2_EVENT_MSM_VIDC_CLOSE_DONE) {
+ WFD_MSG_ERR("enc callback thread shutting " \
+ "down normally\n");
+ bail_out = true;
+ } else {
+ WFD_MSG_ERR("Got unknown event %d, ignoring\n",
+ event.id);
+ }
+
+ complete_all(&inst->cmd_complete);
+ if (bail_out)
+ break;
+ }
+
+ if (flags & POLLIN || flags & POLLRDNORM) {
+ buffer.type = BUF_TYPE_OUTPUT;
+ dequeue_buf = true;
+ num_planes = inst->num_output_planes;
+ WFD_MSG_DBG("Output buffer ready!\n");
+ }
+
+ if (flags & POLLOUT || flags & POLLWRNORM) {
+ buffer.type = BUF_TYPE_INPUT;
+ dequeue_buf = true;
+ num_planes = inst->num_input_planes;
+ WFD_MSG_DBG("Input buffer ready!\n");
+ }
+
+ if (dequeue_buf) {
+ int rc = 0;
+ struct v4l2_plane *planes = NULL;
+ struct mem_region *curr = NULL, *mregion = NULL;
+ struct list_head *reg_bufs = NULL;
+ struct index_bitmap *bitmap = NULL;
+
+ planes = kzalloc(sizeof(*planes) * num_planes,
+ GFP_KERNEL);
+ buffer.m.planes = planes;
+ buffer.length = 1;
+ buffer.memory = V4L2_MEMORY_USERPTR;
+ rc = msm_vidc_dqbuf(inst->vidc_context, &buffer);
+
+ if (rc) {
+ WFD_MSG_ERR("Error dequeuing buffer" \
+ "from vidc: %d", rc);
+ goto abort_dequeue;
+ }
+
+ reg_bufs = buffer.type == BUF_TYPE_OUTPUT ?
+ &inst->registered_output_bufs.list :
+ &inst->registered_input_bufs.list;
+
+ bitmap = buffer.type == BUF_TYPE_OUTPUT ?
+ &inst->free_output_indices :
+ &inst->free_input_indices;
+
+ list_for_each_entry(curr, reg_bufs, list) {
+ if ((u32)curr->paddr ==
+ buffer.m.planes[0].m.userptr) {
+ mregion = curr;
+ break;
+ }
+ }
+
+ if (!mregion) {
+ WFD_MSG_ERR("Got done msg for unknown buf\n");
+ goto abort_dequeue;
+ }
+
+ if (buffer.type == BUF_TYPE_OUTPUT &&
+ inst->vmops.op_buffer_done) {
+ struct vb2_buffer *vb =
+ (struct vb2_buffer *)mregion->cookie;
+
+ vb->v4l2_buf.flags = buffer.flags;
+ vb->v4l2_buf.timestamp = buffer.timestamp;
+ vb->v4l2_planes[0].bytesused =
+ buffer.m.planes[0].bytesused;
+
+ inst->vmops.op_buffer_done(
+ inst->vmops.cbdata, 0, vb);
+ } else if (buffer.type == BUF_TYPE_INPUT &&
+ inst->vmops.ip_buffer_done) {
+ inst->vmops.ip_buffer_done(
+ inst->vmops.cbdata,
+ 0, mregion);
+ }
+
+ complete_all(&inst->dq_complete);
+ mutex_lock(&inst->lock);
+ mark_index_free(bitmap, buffer.index);
+ mutex_unlock(&inst->lock);
+abort_dequeue:
+ kfree(planes);
+ }
+ }
+
+
+ WFD_MSG_DBG("Exiting callback thread\n");
+ mutex_lock(&inst->lock);
+ inst->callback_thread_running = false;
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
+static long venc_open(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct venc_msg_ops *vmops = arg;
+ struct v4l2_event_subscription event = {0};
+ struct msm_vidc_iommu_info maps[MAX_MAP];
+ int rc = 0;
+
+ if (!vmops) {
+ WFD_MSG_ERR("Callbacks required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_open_fail;
+ } else if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_open_fail;
+ }
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst) {
+ WFD_MSG_ERR("Failed to allocate memory\n");
+ rc = -EINVAL;
+ goto venc_open_fail;
+ }
+
+ inst->secure = false;
+ inst->vmops = *vmops;
+ INIT_LIST_HEAD(&inst->registered_output_bufs.list);
+ INIT_LIST_HEAD(&inst->registered_input_bufs.list);
+ init_completion(&inst->dq_complete);
+ init_completion(&inst->cmd_complete);
+ mutex_init(&inst->lock);
+ inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
+ if (!inst->vidc_context) {
+ WFD_MSG_ERR("Failed to create vidc context\n");
+ rc = -ENXIO;
+ goto vidc_open_fail;
+ }
+
+ event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ WFD_MSG_ERR("Failed to subscribe to CLOSE_DONE event\n");
+ goto vidc_subscribe_fail;
+ }
+
+ event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ rc = msm_vidc_subscribe_event(inst->vidc_context, &event);
+ if (rc) {
+ WFD_MSG_ERR("Failed to subscribe to FLUSH_DONE event\n");
+ goto vidc_subscribe_fail;
+ }
+
+ rc = msm_vidc_get_iommu_maps(inst->vidc_context, maps);
+ if (rc) {
+ WFD_MSG_ERR("Failed to retreive domain mappings\n");
+ rc = -ENODATA;
+ goto vidc_subscribe_fail;
+ }
+
+ inst->domain = maps[inst->secure ? CP_MAP : NS_MAP].domain;
+
+ inst->callback_thread = kthread_run(venc_vidc_callback_thread, inst,
+ "venc_vidc_callback_thread");
+ if (IS_ERR(inst->callback_thread)) {
+ WFD_MSG_ERR("Failed to create callback thread\n");
+ rc = PTR_ERR(inst->callback_thread);
+ inst->callback_thread = NULL;
+ goto vidc_kthread_create_fail;
+ }
+ inst->callback_thread_running = true;
+
+ sd->dev_priv = inst;
+ vmops->cookie = inst;
+ return 0;
+vidc_kthread_create_fail:
+ event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+
+ event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+vidc_subscribe_fail:
+ msm_vidc_close(inst->vidc_context);
+vidc_open_fail:
+ kfree(inst);
+venc_open_fail:
+ return rc;
+}
+
+static long venc_close(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_event_subscription event = {0};
+ struct v4l2_encoder_cmd enc_cmd = {0};
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_close_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ enc_cmd.cmd = V4L2_ENC_CMD_STOP;
+ msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
+
+ wait_for_completion(&inst->cmd_complete);
+
+ if (inst->callback_thread && inst->callback_thread_running)
+ kthread_stop(inst->callback_thread);
+
+ event.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ if (rc)
+ WFD_MSG_WARN("Failed to unsubscribe close event\n");
+
+ event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ rc = msm_vidc_unsubscribe_event(inst->vidc_context, &event);
+ if (rc)
+ WFD_MSG_WARN("Failed to unsubscribe flush event\n");
+
+ rc = msm_vidc_close(inst->vidc_context);
+ if (rc)
+ WFD_MSG_WARN("Failed to close vidc context\n");
+
+ kfree(inst);
+ sd->dev_priv = inst = NULL;
+venc_close_fail:
+ return rc;
+}
+
+static long venc_get_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct bufreq *bufreq = arg;
+ struct v4l2_requestbuffers v4l2_bufreq = {0};
+ struct v4l2_format v4l2_format = {0};
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid buffer requirements\n");
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ /* Get buffer count */
+ v4l2_bufreq = (struct v4l2_requestbuffers) {
+ .count = bufreq->count,
+ .type = BUF_TYPE_OUTPUT,
+ .memory = V4L2_MEMORY_USERPTR,
+ };
+
+ rc = msm_vidc_reqbufs(inst->vidc_context, &v4l2_bufreq);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting buffer requirements\n");
+ goto venc_buf_req_fail;
+ }
+
+ /* Get buffer size */
+ v4l2_format.type = BUF_TYPE_OUTPUT;
+ rc = msm_vidc_g_fmt(inst->vidc_context, &v4l2_format);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting OP buffer size\n");
+ goto venc_buf_req_fail;
+ }
+
+ bufreq->count = v4l2_bufreq.count;
+ bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ inst->free_output_indices.size_bits = bufreq->count;
+ inst->free_output_indices.size = roundup(bufreq->count,
+ sizeof(unsigned long)) / sizeof(unsigned long);
+ inst->free_output_indices.bitmap = kzalloc(inst->free_output_indices.
+ size, GFP_KERNEL);
+venc_buf_req_fail:
+ return rc;
+}
+
+static long venc_set_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct bufreq *bufreq = arg;
+ struct v4l2_requestbuffers v4l2_bufreq = {0};
+ struct v4l2_format v4l2_format = {0};
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid buffer requirements\n");
+ rc = -EINVAL;
+ goto venc_buf_req_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ /* Attempt to set buffer count */
+ v4l2_bufreq = (struct v4l2_requestbuffers) {
+ .count = bufreq->count,
+ .type = BUF_TYPE_INPUT,
+ .memory = V4L2_MEMORY_USERPTR,
+ };
+
+ rc = msm_vidc_reqbufs(inst->vidc_context, &v4l2_bufreq);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting buffer requirements");
+ goto venc_buf_req_fail;
+ }
+
+ /* Get buffer size */
+ v4l2_format.type = BUF_TYPE_INPUT;
+ rc = msm_vidc_g_fmt(inst->vidc_context, &v4l2_format);
+ if (rc) {
+ WFD_MSG_ERR("Failed getting OP buffer size\n");
+ goto venc_buf_req_fail;
+ }
+
+ bufreq->count = v4l2_bufreq.count;
+ bufreq->size = v4l2_format.fmt.pix_mp.plane_fmt[0].sizeimage;
+
+ inst->free_input_indices.size_bits = bufreq->count;
+ inst->free_input_indices.size = roundup(bufreq->count,
+ sizeof(unsigned long)) / sizeof(unsigned long);
+ inst->free_input_indices.bitmap = kzalloc(inst->free_input_indices.
+ size, GFP_KERNEL);
+venc_buf_req_fail:
+ return rc;
+}
+
+static long venc_start(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = NULL;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_start_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_OUTPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamon vidc's output port");
+ goto venc_start_fail;
+ }
+
+ rc = msm_vidc_streamon(inst->vidc_context, BUF_TYPE_INPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamon vidc's input port");
+ goto venc_start_fail;
+ }
+
+venc_start_fail:
+ return rc;
+}
+
+static long venc_stop(struct v4l2_subdev *sd)
+{
+ struct venc_inst *inst = NULL;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_stop_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamoff vidc's input port");
+ goto venc_stop_fail;
+ }
+
+ rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_OUTPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to streamoff vidc's output port");
+ goto venc_stop_fail;
+ }
+
+venc_stop_fail:
+ return rc;
+}
+
+static long venc_set_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct v4l2_buffer buf = {0};
+ struct v4l2_plane plane = {0};
+ struct mem_region *mregion = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto set_input_buffer_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid input buffer\n");
+ rc = -EINVAL;
+ goto set_input_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ if (get_registered_mregion(&inst->registered_input_bufs, mregion)) {
+ WFD_MSG_ERR("Duplicate input buffer\n");
+ rc = -EEXIST;
+ goto set_input_buffer_fail;
+ }
+
+ mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+ *mregion = *(struct mem_region *)arg;
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ };
+
+ buf = (struct v4l2_buffer) {
+ .index = get_list_len(&inst->registered_input_bufs),
+ .type = BUF_TYPE_INPUT,
+ .bytesused = 0,
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Prepare %p with index, %d",
+ (void *)buf.m.planes[0].m.userptr, buf.index);
+ rc = msm_vidc_prepare_buf(inst->vidc_context, &buf);
+ if (rc) {
+ WFD_MSG_ERR("Failed to prepare input buffer\n");
+ goto set_input_buffer_fail;
+ }
+
+ list_add_tail(&mregion->list, &inst->registered_input_bufs.list);
+ return 0;
+set_input_buffer_fail:
+ kfree(mregion);
+ return rc;
+}
+
+static int venc_map_user_to_kernel(struct venc_inst *inst,
+ struct mem_region *mregion)
+{
+ int rc = 0;
+ unsigned long flags = 0, size = 0;
+ if (!mregion) {
+ rc = -EINVAL;
+ goto venc_map_fail;
+ }
+
+ mregion->ion_handle = ion_import_dma_buf(venc_ion_client, mregion->fd);
+ if (IS_ERR_OR_NULL(mregion->ion_handle)) {
+ rc = PTR_ERR(mregion->ion_handle);
+ WFD_MSG_ERR("Failed to get handle: %p, %d, %d, %d\n",
+ venc_ion_client, mregion->fd, mregion->offset, rc);
+ mregion->ion_handle = NULL;
+ goto venc_map_fail;
+ }
+
+ rc = ion_handle_get_flags(venc_ion_client, mregion->ion_handle, &flags);
+ if (rc) {
+ WFD_MSG_ERR("Failed to get ion flags %d\n", rc);
+ goto venc_map_fail;
+ }
+
+ mregion->kvaddr = ion_map_kernel(venc_ion_client,
+ mregion->ion_handle, flags);
+
+ if (IS_ERR_OR_NULL(mregion->kvaddr)) {
+ WFD_MSG_ERR("Failed to map buffer into kernel\n");
+ rc = PTR_ERR(mregion->kvaddr);
+ mregion->kvaddr = NULL;
+ goto venc_map_fail;
+ }
+
+ rc = ion_map_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0, SZ_4K, 0,
+ (unsigned long *)&mregion->paddr, &size, flags, 0);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to map into iommu\n");
+ goto venc_map_iommu_map_fail;
+ } else if (size < mregion->size) {
+ WFD_MSG_ERR("Failed to iommu map the correct size\n");
+ goto venc_map_iommu_size_fail;
+ }
+
+ return 0;
+venc_map_iommu_size_fail:
+ ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0);
+venc_map_iommu_map_fail:
+ ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+venc_map_fail:
+ return rc;
+}
+
+static int venc_unmap_user_to_kernel(struct venc_inst *inst,
+ struct mem_region *mregion)
+{
+ if (!mregion || !mregion->ion_handle)
+ return 0;
+
+ if (mregion->paddr) {
+ ion_unmap_iommu(venc_ion_client, mregion->ion_handle,
+ inst->domain, 0);
+ mregion->paddr = NULL;
+ }
+
+ if (mregion->kvaddr) {
+ ion_unmap_kernel(venc_ion_client, mregion->ion_handle);
+ mregion->kvaddr = NULL;
+ }
+
+
+ return 0;
+}
+
+static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+ struct v4l2_buffer buf = {0};
+ struct v4l2_plane plane = {0};
+ struct mem_region *mregion = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_set_output_buffer_fail;
+ } else if (!mregion) {
+ WFD_MSG_ERR("Invalid output buffer\n");
+ rc = -EINVAL;
+ goto venc_set_output_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ /* Check if buf already registered */
+ if (get_registered_mregion(&inst->registered_output_bufs, mregion)) {
+ WFD_MSG_ERR("Duplicate output buffer\n");
+ rc = -EEXIST;
+ goto venc_set_output_buffer_fail;
+ }
+
+ mregion = kzalloc(sizeof(*mregion), GFP_KERNEL);
+
+ if (!mregion) {
+ WFD_MSG_ERR("Failed to allocate memory\n");
+ goto venc_set_output_buffer_fail;
+ }
+
+ *mregion = *(struct mem_region *)arg;
+ INIT_LIST_HEAD(&mregion->list);
+
+ rc = venc_map_user_to_kernel(inst, mregion);
+ if (rc) {
+ WFD_MSG_ERR("Failed to map output buffer\n");
+ goto venc_set_output_buffer_map_fail;
+ }
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ };
+
+ buf = (struct v4l2_buffer) {
+ .index = get_list_len(&inst->registered_output_bufs),
+ .type = BUF_TYPE_OUTPUT,
+ .bytesused = 0,
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Prepare %p with index, %d",
+ (void *)buf.m.planes[0].m.userptr, buf.index);
+ rc = msm_vidc_prepare_buf(inst->vidc_context, &buf);
+ if (rc) {
+ WFD_MSG_ERR("Failed to prepare output buffer\n");
+ goto venc_set_output_buffer_prepare_fail;
+ }
+
+ list_add_tail(&mregion->list, &inst->registered_output_bufs.list);
+ return rc;
+venc_set_output_buffer_prepare_fail:
+ venc_unmap_user_to_kernel(inst, mregion);
+venc_set_output_buffer_map_fail:
+ kfree(mregion);
+venc_set_output_buffer_fail:
+ return rc;
+}
+
+static long venc_set_format(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_format *fmt = arg, temp;
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_set_format_fail;
+ } else if (!fmt) {
+ WFD_MSG_ERR("Invalid format\n");
+ rc = -EINVAL;
+ goto venc_set_format_fail;
+ } else if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ WFD_MSG_ERR("Invalid buffer type %d\n", fmt->type);
+ rc = -ENOTSUPP;
+ goto venc_set_format_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ temp = (struct v4l2_format) {
+ .type = BUF_TYPE_OUTPUT,
+ .fmt.pix_mp = (struct v4l2_pix_format_mplane) {
+ .width = fmt->fmt.pix.width,
+ .height = fmt->fmt.pix.height,
+ .pixelformat = fmt->fmt.pix.pixelformat,
+ },
+ };
+
+ rc = msm_vidc_s_fmt(inst->vidc_context, &temp);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to format for output port\n");
+ goto venc_set_format_fail;
+ } else if (!temp.fmt.pix_mp.num_planes) {
+ WFD_MSG_ERR("No. of planes for output buffers make no sense\n");
+ rc = -EINVAL;
+ goto venc_set_format_fail;
+ }
+ fmt->fmt.pix.sizeimage = temp.fmt.pix_mp.plane_fmt[0].sizeimage;
+ inst->num_output_planes = temp.fmt.pix_mp.num_planes;
+
+ temp.type = BUF_TYPE_INPUT;
+ temp.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ rc = msm_vidc_s_fmt(inst->vidc_context, &temp);
+ inst->num_input_planes = temp.fmt.pix_mp.num_planes;
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to format for input port\n");
+ goto venc_set_format_fail;
+ }
+venc_set_format_fail:
+ return rc;
+}
+
+static long venc_set_framerate(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_control ctrl = {0};
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid framerate\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE;
+ ctrl.value = 30;
+ return msm_vidc_s_ctrl(inst->vidc_context, &ctrl);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct mem_region *mregion = NULL;
+ struct v4l2_buffer buffer = {0};
+ struct v4l2_plane plane = {0};
+ int index = 0, rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+
+ if (!mregion) {
+ WFD_MSG_ERR("Output buffer not registered\n");
+ return -ENOENT;
+ }
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ };
+
+ while (true) {
+ mutex_lock(&inst->lock);
+ index = next_free_index(&inst->free_output_indices);
+ mutex_unlock(&inst->lock);
+
+ if (index < 0)
+ wait_for_completion(&inst->dq_complete);
+ else
+ break;
+ }
+
+ buffer = (struct v4l2_buffer) {
+ .index = index,
+ .type = BUF_TYPE_OUTPUT,
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Fill buffer %p with index, %d",
+ (void *)buffer.m.planes[0].m.userptr, buffer.index);
+ rc = msm_vidc_qbuf(inst->vidc_context, &buffer);
+ if (!rc) {
+ mutex_lock(&inst->lock);
+ mark_index_busy(&inst->free_output_indices, index);
+ mutex_unlock(&inst->lock);
+ }
+ return rc;
+
+}
+
+static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct venc_buf_info *venc_buf = arg;
+ struct mem_region *mregion = NULL;
+ struct v4l2_buffer buffer = {0};
+ struct v4l2_plane plane = {0};
+ int index = 0, rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!venc_buf) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = venc_buf->mregion;
+
+ plane = (struct v4l2_plane) {
+ .length = mregion->size,
+ .m.userptr = (u32)mregion->paddr,
+ .bytesused = mregion->size,
+ };
+
+ while (true) {
+ mutex_lock(&inst->lock);
+ index = next_free_index(&inst->free_input_indices);
+ mutex_unlock(&inst->lock);
+
+ if (index < 0)
+ wait_for_completion(&inst->dq_complete);
+ else
+ break;
+ }
+
+ buffer = (struct v4l2_buffer) {
+ .index = index,
+ .type = BUF_TYPE_INPUT,
+ .timestamp = ns_to_timeval(venc_buf->timestamp),
+ .memory = V4L2_MEMORY_USERPTR,
+ .m.planes = &plane,
+ .length = 1,
+ };
+
+ WFD_MSG_DBG("Encode buffer %p with index, %d",
+ (void *)buffer.m.planes[0].m.userptr, buffer.index);
+ rc = msm_vidc_qbuf(inst->vidc_context, &buffer);
+ if (!rc) {
+ mutex_lock(&inst->lock);
+ mark_index_busy(&inst->free_input_indices, index);
+ mutex_unlock(&inst->lock);
+ }
+ return rc;
+}
+
+static long venc_alloc_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ /* vidc driver allocates internally on streamon */
+ return 0;
+}
+
+static long venc_free_buffer(struct venc_inst *inst, int type,
+ struct mem_region *to_free, bool unmap_user_buffer)
+{
+ struct mem_region *mregion = NULL;
+ struct mem_region *buf_list = NULL;
+
+ if (type == BUF_TYPE_OUTPUT) {
+ buf_list = &inst->registered_output_bufs;
+ } else if (type == BUF_TYPE_INPUT) {
+ buf_list = &inst->registered_input_bufs;
+ } else {
+ WFD_MSG_ERR("Trying to free a buffer of unknown type\n");
+ return -EINVAL;
+ }
+
+ mregion = get_registered_mregion(buf_list, to_free);
+
+ if (!mregion) {
+ WFD_MSG_ERR("Buffer not registered, cannot free\n");
+ return -ENOENT;
+ }
+
+ if (unmap_user_buffer) {
+ int rc = venc_unmap_user_to_kernel(inst, mregion);
+ if (rc)
+ WFD_MSG_WARN("Unable to unmap user buffer\n");
+ }
+
+ list_del(&mregion->list);
+ kfree(mregion);
+ return 0;
+}
+static long venc_free_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_free_output_buffer_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer\n");
+ rc = -EINVAL;
+ goto venc_free_output_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ return venc_free_buffer(inst, BUF_TYPE_OUTPUT, arg, true);
+venc_free_output_buffer_fail:
+ return rc;
+}
+
+static long venc_flush_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_encoder_cmd enc_cmd = {0};
+ int rc = 0;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_flush_buffers_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+
+ enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
+ enc_cmd.flags = BUF_TYPE_INPUT | BUF_TYPE_OUTPUT;
+ msm_vidc_encoder_cmd(inst->vidc_context, &enc_cmd);
+
+ wait_for_completion(&inst->cmd_complete);
+venc_flush_buffers_fail:
+ return rc;
+}
+
+static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ rc = -EINVAL;
+ goto venc_free_input_buffer_fail;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer\n");
+ rc = -EINVAL;
+ goto venc_free_input_buffer_fail;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ return venc_free_buffer(inst, BUF_TYPE_INPUT, arg, false);
+venc_free_input_buffer_fail:
+ return rc;
+}
+
+static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ /* vidc driver takes care of this */
+ return 0;
+}
+
+static long venc_set_property(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+ struct v4l2_control *ctrl = arg;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEADER_MODE) {
+ /* XXX: We don't support this yet, but to prevent unncessary
+ * target specific code for the client, we'll not error out.
+ * The client ideally shouldn't notice this */
+ return 0;
+ }
+
+ return msm_vidc_s_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
+}
+
+static long venc_get_property(struct v4l2_subdev *sd, void *arg)
+{
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ return msm_vidc_g_ctrl(inst->vidc_context, (struct v4l2_control *)arg);
+}
+
+long venc_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ unsigned long rc = 0, size = 0;
+ void *paddr = NULL;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mmap || !mmap->mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ inst->domain, 0, SZ_4K, 0, (unsigned long *)&paddr,
+ &size, 0, 0);
+
+ if (rc) {
+ WFD_MSG_ERR("Failed to get physical addr\n");
+ paddr = NULL;
+ } else if (size < mregion->size) {
+ WFD_MSG_ERR("Failed to map enough memory\n");
+ rc = -ENOMEM;
+ }
+
+ mregion->paddr = paddr;
+ return rc;
+}
+
+long venc_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion = NULL;
+ struct venc_inst *inst = NULL;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!mmap || !mmap->mregion) {
+ WFD_MSG_ERR("Memregion required for %s\n", __func__);
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = mmap->mregion;
+
+ ion_unmap_iommu(mmap->ion_client, mregion->ion_handle,
+ inst->domain, 0);
+ return 0;
+}
+
+long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ long rc = 0;
+ switch (cmd) {
+ case OPEN:
+ rc = venc_open(sd, arg);
+ break;
+ case CLOSE:
+ rc = venc_close(sd, arg);
+ break;
+ case ENCODE_START:
+ rc = venc_start(sd);
+ break;
+ case ENCODE_FRAME:
+ venc_encode_frame(sd, arg);
+ break;
+ case ENCODE_STOP:
+ rc = venc_stop(sd);
+ break;
+ case SET_PROP:
+ rc = venc_set_property(sd, arg);
+ break;
+ case GET_PROP:
+ rc = venc_get_property(sd, arg);
+ break;
+ case GET_BUFFER_REQ:
+ rc = venc_get_buffer_req(sd, arg);
+ break;
+ case SET_BUFFER_REQ:
+ rc = venc_set_buffer_req(sd, arg);
+ break;
+ case FREE_BUFFER:
+ break;
+ case FILL_OUTPUT_BUFFER:
+ rc = venc_fill_outbuf(sd, arg);
+ break;
+ case SET_FORMAT:
+ rc = venc_set_format(sd, arg);
+ break;
+ case SET_FRAMERATE:
+ rc = venc_set_framerate(sd, arg);
+ break;
+ case SET_INPUT_BUFFER:
+ rc = venc_set_input_buffer(sd, arg);
+ break;
+ case SET_OUTPUT_BUFFER:
+ rc = venc_set_output_buffer(sd, arg);
+ break;
+ case ALLOC_RECON_BUFFERS:
+ rc = venc_alloc_recon_buffers(sd, arg);
+ break;
+ case FREE_OUTPUT_BUFFER:
+ rc = venc_free_output_buffer(sd, arg);
+ break;
+ case FREE_INPUT_BUFFER:
+ rc = venc_free_input_buffer(sd, arg);
+ break;
+ case FREE_RECON_BUFFERS:
+ rc = venc_free_recon_buffers(sd, arg);
+ break;
+ case ENCODE_FLUSH:
+ rc = venc_flush_buffers(sd, arg);
+ break;
+ case ENC_MMAP:
+ rc = venc_mmap(sd, arg);
+ break;
+ case ENC_MUNMAP:
+ rc = venc_munmap(sd, arg);
+ break;
+ default:
+ WFD_MSG_ERR("Unknown ioctl %d to enc-subdev\n", cmd);
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-4-subdev.c
similarity index 67%
copy from drivers/media/video/msm_wfd/mdp-subdev.c
copy to drivers/media/video/msm_wfd/mdp-4-subdev.c
index 886b0ba..c68d5d4 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-4-subdev.c
@@ -10,53 +10,66 @@
* GNU General Public License for more details.
*
*/
+#include <linux/msm_mdp.h>
+#include <mach/iommu_domains.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
#include "mdp-subdev.h"
#include "wfd-util.h"
-#include <media/videobuf2-core.h>
-#include <linux/msm_mdp.h>
struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
+ bool secure;
+ bool uses_iommu_split_domain;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
+
int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
- void **cookie = (void **)arg;
+ struct mdp_msg_ops *mops = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto mdp_open_fail;
+ } else if (!mops) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ rc = -EINVAL;
+ goto mdp_open_fail;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
- goto exit;
+ goto mdp_open_fail;
}
/*Tell HDMI daemon to open fb2*/
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
if (rc) {
WFD_MSG_ERR("Failed add to kobj");
- goto exit;
+ goto mdp_open_fail;
}
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
- *cookie = inst;
+ inst->secure = mops->secure;
+ inst->uses_iommu_split_domain = mops->iommu_split_domain;
+
+ mops->cookie = inst;
return rc;
-exit:
+mdp_open_fail:
kfree(inst);
return rc;
}
@@ -134,8 +147,8 @@
fbdata.flags = 0;
fbdata.priv = (uint32_t)binfo->cookie;
- WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
- "fd = %u, priv = %p, iova = %p\n",
+ WFD_MSG_INFO("queue buffer to mdp with offset = %u, fd = %u, "\
+ "priv = %p, iova = %p\n",
fbdata.offset, fbdata.memory_id,
(void *)fbdata.priv, (void *)fbdata.iova);
rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@@ -179,6 +192,84 @@
inst->width = prop->width;
return 0;
}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0, domain = -1;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool use_iommu = true;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ if (inst->uses_iommu_split_domain) {
+ if (inst->secure)
+ use_iommu = false;
+ else
+ domain = DISPLAY_WRITE_DOMAIN;
+ } else {
+ domain = DISPLAY_READ_DOMAIN;
+ }
+
+ if (use_iommu) {
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ domain, GEN_POOL, SZ_4K, 0,
+ (unsigned long *)&mregion->paddr,
+ (unsigned long *)&mregion->size,
+ 0, 0);
+ } else {
+ rc = ion_phys(mmap->ion_client, mregion->ion_handle,
+ (unsigned long *)&mregion->paddr,
+ (size_t *)&mregion->size);
+ }
+
+ return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool use_iommu = false;
+ int domain = -1;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+
+ if (inst->uses_iommu_split_domain) {
+ if (inst->secure)
+ use_iommu = false;
+ else
+ domain = DISPLAY_WRITE_DOMAIN;
+ } else {
+ domain = DISPLAY_READ_DOMAIN;
+ }
+
+ if (use_iommu)
+ ion_unmap_iommu(mmap->ion_client,
+ mregion->ion_handle,
+ domain, GEN_POOL);
+
+ return 0;
+}
+
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -208,6 +299,12 @@
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
+ case MDP_MMAP:
+ rc = mdp_mmap(sd, arg);
+ break;
+ case MDP_MUNMAP:
+ rc = mdp_munmap(sd, arg);
+ break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.c b/drivers/media/video/msm_wfd/mdp-5-subdev.c
similarity index 72%
rename from drivers/media/video/msm_wfd/mdp-subdev.c
rename to drivers/media/video/msm_wfd/mdp-5-subdev.c
index 886b0ba..4f29389 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.c
+++ b/drivers/media/video/msm_wfd/mdp-5-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,53 +10,63 @@
* GNU General Public License for more details.
*
*/
+#include <linux/msm_mdp.h>
+#include <mach/iommu_domains.h>
+#include <media/videobuf2-core.h>
+#include "enc-subdev.h"
#include "mdp-subdev.h"
#include "wfd-util.h"
-#include <media/videobuf2-core.h>
-#include <linux/msm_mdp.h>
+
struct mdp_instance {
struct fb_info *mdp;
u32 height;
u32 width;
+ bool secure;
};
int mdp_init(struct v4l2_subdev *sd, u32 val)
{
return 0;
}
+
int mdp_open(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
GFP_KERNEL);
- void **cookie = (void **)arg;
+ struct mdp_msg_ops *mops = arg;
int rc = 0;
struct fb_info *fbi = NULL;
if (!inst) {
WFD_MSG_ERR("Out of memory\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto mdp_open_fail;
+ } else if (!mops) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ rc = -EINVAL;
+ goto mdp_open_fail;
}
fbi = msm_fb_get_writeback_fb();
if (!fbi) {
WFD_MSG_ERR("Failed to acquire mdp instance\n");
rc = -ENODEV;
- goto exit;
+ goto mdp_open_fail;
}
/*Tell HDMI daemon to open fb2*/
rc = kobject_uevent(&fbi->dev->kobj, KOBJ_ADD);
- if (rc) {
+ if (rc)
WFD_MSG_ERR("Failed add to kobj");
- goto exit;
- }
msm_fb_writeback_init(fbi);
inst->mdp = fbi;
- *cookie = inst;
+ inst->secure = mops->secure;
+
+ mops->cookie = inst;
return rc;
-exit:
+mdp_open_fail:
kfree(inst);
return rc;
}
@@ -85,6 +95,7 @@
exit:
return rc;
}
+
int mdp_stop(struct v4l2_subdev *sd, void *arg)
{
struct mdp_instance *inst = arg;
@@ -134,8 +145,8 @@
fbdata.flags = 0;
fbdata.priv = (uint32_t)binfo->cookie;
- WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
- "fd = %u, priv = %p, iova = %p\n",
+ WFD_MSG_DBG("queue buffer to mdp with offset = %u, fd = %u, "\
+ "priv = %p, iova = %p\n",
fbdata.offset, fbdata.memory_id,
(void *)fbdata.priv, (void *)fbdata.iova);
rc = msm_fb_writeback_queue_buffer(inst->mdp, &fbdata);
@@ -179,6 +190,58 @@
inst->width = prop->width;
return 0;
}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool domain = -1;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+ if (mregion->size % SZ_4K != 0) {
+ WFD_MSG_ERR("Memregion not aligned to %d\n", SZ_4K);
+ return -EINVAL;
+ }
+
+ domain = msm_fb_get_iommu_domain();
+ rc = ion_map_iommu(mmap->ion_client, mregion->ion_handle,
+ domain, 0, SZ_4K, 0,
+ (unsigned long *)&mregion->paddr,
+ (unsigned long *)&mregion->size,
+ 0, 0);
+ return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+ bool domain = -1;
+ struct mdp_instance *inst = NULL;
+
+ if (!mmap || !mmap->mregion || !mmap->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ inst = mmap->cookie;
+ mregion = mmap->mregion;
+
+ domain = msm_fb_get_iommu_domain();
+ ion_unmap_iommu(mmap->ion_client,
+ mregion->ion_handle,
+ domain, 0);
+ return 0;
+}
+
long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
int rc = 0;
@@ -208,6 +271,12 @@
case MDP_CLOSE:
rc = mdp_close(sd, arg);
break;
+ case MDP_MMAP:
+ rc = mdp_mmap(sd, arg);
+ break;
+ case MDP_MUNMAP:
+ rc = mdp_munmap(sd, arg);
+ break;
default:
WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
rc = -EINVAL;
diff --git a/drivers/media/video/msm_wfd/mdp-dummy-subdev.c b/drivers/media/video/msm_wfd/mdp-dummy-subdev.c
new file mode 100644
index 0000000..b2db208
--- /dev/null
+++ b/drivers/media/video/msm_wfd/mdp-dummy-subdev.c
@@ -0,0 +1,187 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* 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/list.h>
+#include <linux/msm_mdp.h>
+#include <media/videobuf2-core.h>
+
+#include "enc-subdev.h"
+#include "mdp-subdev.h"
+#include "wfd-util.h"
+
+struct mdp_buf_queue {
+ struct mdp_buf_info mdp_buf_info;
+ struct list_head node;
+};
+
+struct mdp_instance {
+ struct mdp_buf_queue mdp_bufs;
+ struct mutex mutex;
+};
+
+int mdp_init(struct v4l2_subdev *sd, u32 val)
+{
+ return 0;
+}
+int mdp_open(struct v4l2_subdev *sd, void *arg)
+{
+ struct mdp_instance *inst = kzalloc(sizeof(struct mdp_instance),
+ GFP_KERNEL);
+ void **cookie = (void **)arg;
+ int rc = 0;
+
+ if (!inst) {
+ WFD_MSG_ERR("Out of memory\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&inst->mdp_bufs.node);
+ mutex_init(&inst->mutex);
+ *cookie = inst;
+ return rc;
+}
+
+int mdp_start(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+int mdp_stop(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+int mdp_close(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+int mdp_q_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ static int foo;
+ int rc = 0;
+ struct mdp_buf_info *binfo = arg;
+ struct mdp_instance *inst = NULL;
+
+ if (!binfo || !binfo->inst || !binfo->cookie) {
+ WFD_MSG_ERR("Invalid argument\n");
+ return -EINVAL;
+ }
+
+
+ inst = binfo->inst;
+ if (binfo->kvaddr) {
+ struct mdp_buf_queue *new_entry = kzalloc(sizeof(*new_entry),
+ GFP_KERNEL);
+ memset((void *)binfo->kvaddr, foo++, 1024);
+ new_entry->mdp_buf_info = *binfo;
+ mutex_lock(&inst->mutex);
+ list_add_tail(&new_entry->node, &inst->mdp_bufs.node);
+ mutex_unlock(&inst->mutex);
+ WFD_MSG_DBG("Queue %p with cookie %p\n",
+ (void *)binfo->paddr, (void *)binfo->cookie);
+ } else {
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+int mdp_dq_buffer(struct v4l2_subdev *sd, void *arg)
+{
+ struct mdp_buf_info *binfo = arg;
+ struct mdp_buf_queue *head = NULL;
+ struct mdp_instance *inst = NULL;
+
+ inst = binfo->inst;
+
+ while (head == NULL) {
+ mutex_lock(&inst->mutex);
+ if (!list_empty(&inst->mdp_bufs.node))
+ head = list_first_entry(&inst->mdp_bufs.node,
+ struct mdp_buf_queue, node);
+ mutex_unlock(&inst->mutex);
+ }
+
+ if (head == NULL)
+ return -ENOBUFS;
+
+ mutex_lock(&inst->mutex);
+ list_del(&head->node);
+ mutex_unlock(&inst->mutex);
+
+ *binfo = head->mdp_buf_info;
+ WFD_MSG_DBG("Dequeue %p with cookie %p\n",
+ (void *)binfo->paddr, (void *)binfo->cookie);
+ return 0;
+
+}
+int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
+{
+ return 0;
+}
+
+int mdp_mmap(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct mem_region_map *mmap = arg;
+ struct mem_region *mregion;
+
+ mregion = mmap->mregion;
+ mregion->paddr = mregion->kvaddr;
+ return rc;
+}
+
+int mdp_munmap(struct v4l2_subdev *sd, void *arg)
+{
+ /* Whatever */
+ return 0;
+}
+
+long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ int rc = 0;
+ if (!sd) {
+ WFD_MSG_ERR("Invalid arguments\n");
+ return -EINVAL;
+ }
+ switch (cmd) {
+ case MDP_Q_BUFFER:
+ rc = mdp_q_buffer(sd, arg);
+ break;
+ case MDP_DQ_BUFFER:
+ rc = mdp_dq_buffer(sd, arg);
+ break;
+ case MDP_OPEN:
+ rc = mdp_open(sd, arg);
+ break;
+ case MDP_START:
+ rc = mdp_start(sd, arg);
+ break;
+ case MDP_STOP:
+ rc = mdp_stop(sd, arg);
+ break;
+ case MDP_SET_PROP:
+ rc = mdp_set_prop(sd, arg);
+ break;
+ case MDP_CLOSE:
+ rc = mdp_close(sd, arg);
+ break;
+ case MDP_MMAP:
+ rc = mdp_mmap(sd, arg);
+ break;
+ case MDP_MUNMAP:
+ rc = mdp_munmap(sd, arg);
+ break;
+ default:
+ WFD_MSG_ERR("IOCTL: %u not supported\n", cmd);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
diff --git a/drivers/media/video/msm_wfd/mdp-subdev.h b/drivers/media/video/msm_wfd/mdp-subdev.h
index 081fead..5e81e3c 100644
--- a/drivers/media/video/msm_wfd/mdp-subdev.h
+++ b/drivers/media/video/msm_wfd/mdp-subdev.h
@@ -34,6 +34,12 @@
u32 width;
};
+struct mdp_msg_ops {
+ void *cookie;
+ bool secure;
+ bool iommu_split_domain;
+};
+
static inline bool mdp_buf_info_equals(struct mdp_buf_info *a,
struct mdp_buf_info *b)
{
@@ -51,6 +57,10 @@
#define MDP_CLOSE _IOR(MDP_MAGIC_IOCTL, 5, void *)
#define MDP_START _IOR(MDP_MAGIC_IOCTL, 6, void *)
#define MDP_STOP _IOR(MDP_MAGIC_IOCTL, 7, void *)
+#define MDP_MMAP _IOR(MDP_MAGIC_IOCTL, 8, struct mem_region_map *)
+#define MDP_MUNMAP _IOR(MDP_MAGIC_IOCTL, 9, struct mem_region_map *)
+
+
extern int mdp_init(struct v4l2_subdev *sd, u32 val);
extern long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index 8981c1a..23af7e9 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -10,7 +10,6 @@
* GNU General Public License for more details.
*
*/
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -40,8 +39,8 @@
#define WFD_NUM_DEVICES 2
#define WFD_DEVICE_NUMBER_BASE 38
#define WFD_DEVICE_SECURE (WFD_DEVICE_NUMBER_BASE + 1)
-#define DEFAULT_WFD_WIDTH 640
-#define DEFAULT_WFD_HEIGHT 480
+#define DEFAULT_WFD_WIDTH 1280
+#define DEFAULT_WFD_HEIGHT 720
#define VENC_INPUT_BUFFERS 4
struct wfd_device {
@@ -152,11 +151,10 @@
static int wfd_allocate_ion_buffer(struct ion_client *client,
bool secure, struct mem_region *mregion)
{
- struct ion_handle *handle;
- void *kvaddr = NULL, *phys_addr = NULL;
- unsigned long size;
+ struct ion_handle *handle = NULL;
+ void *kvaddr = NULL;
unsigned int alloc_regions = 0;
- int rc;
+ int rc = 0;
alloc_regions = ION_HEAP(ION_CP_MM_HEAP_ID);
alloc_regions |= secure ? ION_SECURE :
@@ -178,32 +176,7 @@
goto alloc_fail;
}
- if (secure) {
- WFD_MSG_INFO("%s: calling ion_phys", __func__);
- rc = ion_phys(client,
- handle,
- (unsigned long *)&phys_addr, (size_t *)&size);
- } else {
- WFD_MSG_INFO("%s: calling ion_map_iommu", __func__);
- rc = ion_map_iommu(client, handle,
- VIDEO_DOMAIN, VIDEO_MAIN_POOL, SZ_4K,
- 0, (unsigned long *)&phys_addr,
- &size, 0, 0);
- }
-
- if (rc || !phys_addr) {
- WFD_MSG_ERR(
- "Failed to get physical addr, rc = %d, phys_addr = 0x%p\n",
- rc, phys_addr);
- goto alloc_fail;
- } else if (size < mregion->size) {
- WFD_MSG_ERR("Failed to map enough memory\n");
- rc = -ENOMEM;
- goto alloc_fail;
- }
-
mregion->kvaddr = kvaddr;
- mregion->paddr = phys_addr;
mregion->ion_handle = handle;
return rc;
@@ -273,6 +246,7 @@
spin_unlock_irqrestore(&inst->inst_lock, flags);
for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
+ struct mem_region_map mmap_context = {0};
mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
enc_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
mdp_mregion = kzalloc(sizeof(*enc_mregion), GFP_KERNEL);
@@ -281,12 +255,20 @@
rc = wfd_allocate_ion_buffer(wfd_dev->ion_client,
wfd_dev->secure_device, enc_mregion);
if (rc) {
- WFD_MSG_ERR("Failed to allocate input memory."
- " This error causes memory leak!!!\n");
+ WFD_MSG_ERR("Failed to allocate input memory\n");
goto alloc_fail;
}
- WFD_MSG_DBG("NOTE: enc paddr = %p, kvaddr = %p\n",
+ mmap_context.mregion = enc_mregion;
+ mmap_context.ion_client = wfd_dev->ion_client;
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENC_MMAP, &mmap_context);
+ if (rc || !enc_mregion->paddr) {
+ WFD_MSG_ERR("Failed to map input memory\n");
+ goto alloc_fail;
+ }
+
+ WFD_MSG_ERR("NOTE: enc paddr = %p, kvaddr = %p\n",
enc_mregion->paddr,
enc_mregion->kvaddr);
@@ -301,27 +283,12 @@
mdp_mregion->cookie = 0;
mdp_mregion->ion_handle = enc_mregion->ion_handle;
- if (wfd_dev->mdp_iommu_split_domain) {
- if (wfd_dev->secure_device) {
- rc = ion_phys(wfd_dev->ion_client,
- mdp_mregion->ion_handle,
- (unsigned long *)&mdp_mregion->paddr,
- (size_t *)&mdp_mregion->size);
- } else {
- rc = ion_map_iommu(wfd_dev->ion_client,
- mdp_mregion->ion_handle,
- DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
- 0, (unsigned long *)&mdp_mregion->paddr,
- (unsigned long *)&mdp_mregion->size,
- 0, 0);
- }
- } else {
- rc = ion_map_iommu(wfd_dev->ion_client,
- mdp_mregion->ion_handle,
- DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
- 0, (unsigned long *)&mdp_mregion->paddr,
- (unsigned long *)&mdp_mregion->size, 0, 0);
- }
+ memset(&mmap_context, 0, sizeof(mmap_context));
+ mmap_context.mregion = mdp_mregion;
+ mmap_context.ion_client = wfd_dev->ion_client;
+ mmap_context.cookie = inst->mdp_inst;
+ rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+ MDP_MMAP, (void *)&mmap_context);
if (rc || !mdp_mregion->paddr) {
WFD_MSG_ERR(
@@ -401,24 +368,24 @@
"from encoder\n");
if (mpair->mdp->paddr) {
- if (wfd_dev->mdp_iommu_split_domain) {
- if (!wfd_dev->secure_device)
- ion_unmap_iommu(wfd_dev->
- ion_client,
- mpair->mdp->ion_handle,
- DISPLAY_WRITE_DOMAIN,
- GEN_POOL);
- } else {
- ion_unmap_iommu(wfd_dev->ion_client,
- mpair->mdp->ion_handle,
- DISPLAY_READ_DOMAIN, GEN_POOL);
- }
+ struct mem_region_map temp = {0};
+
+ temp.ion_client = wfd_dev->ion_client;
+ temp.mregion = mpair->mdp;
+ temp.cookie = inst->mdp_inst;
+
+ v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+ ioctl, MDP_MUNMAP,
+ (void *)&temp);
}
- if (mpair->enc->paddr && !wfd_dev->secure_device)
- ion_unmap_iommu(wfd_dev->ion_client,
- mpair->enc->ion_handle,
- VIDEO_DOMAIN, VIDEO_MAIN_POOL);
+ if (mpair->enc->paddr) {
+ struct mem_region_map temp = {0};
+ temp.ion_client = wfd_dev->ion_client;
+ temp.mregion = mpair->enc;
+ v4l2_subdev_call(&wfd_dev->enc_sdev,
+ core, ioctl, ENC_MUNMAP, &temp);
+ }
wfd_free_ion_buffer(wfd_dev->ion_client, mpair->enc);
list_del(&mpair->list);
@@ -884,7 +851,7 @@
list_add_tail(&minfo_entry->list, &inst->minfo_list);
spin_unlock_irqrestore(&inst->inst_lock, flags);
} else
- WFD_MSG_INFO("Buffer already registered\n");
+ WFD_MSG_DBG("Buffer already registered\n");
return 0;
}
@@ -970,7 +937,7 @@
struct wfd_inst *inst = filp->private_data;
int rc;
- WFD_MSG_INFO("Waiting to dequeue buffer\n");
+ WFD_MSG_DBG("Waiting to dequeue buffer\n");
rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
if (rc)
@@ -1306,6 +1273,7 @@
struct wfd_inst *inst = NULL;
struct wfd_device *wfd_dev = NULL;
struct venc_msg_ops enc_mops;
+ struct mdp_msg_ops mdp_mops;
struct vsg_msg_ops vsg_mops;
WFD_MSG_DBG("wfd_open: E\n");
@@ -1339,12 +1307,15 @@
wfd_stats_init(&inst->stats, MINOR(filp->f_dentry->d_inode->i_rdev));
+ mdp_mops.secure = wfd_dev->secure_device;
+ mdp_mops.iommu_split_domain = wfd_dev->mdp_iommu_split_domain;
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
- (void *)&inst->mdp_inst);
+ (void *)&mdp_mops);
if (rc) {
WFD_MSG_ERR("Failed to open mdp subdevice: %d\n", rc);
goto err_mdp_open;
}
+ inst->mdp_inst = mdp_mops.cookie;
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, load_fw);
if (rc) {
diff --git a/drivers/media/video/msm_wfd/wfd-util.h b/drivers/media/video/msm_wfd/wfd-util.h
index b6bb245..2fe7360 100644
--- a/drivers/media/video/msm_wfd/wfd-util.h
+++ b/drivers/media/video/msm_wfd/wfd-util.h
@@ -21,16 +21,11 @@
/*#define DEBUG_WFD*/
#define WFD_TAG "wfd: "
-#ifdef DEBUG_WFD
- #define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
- #define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
-#else
- #define WFD_MSG_INFO(fmt...)
- #define WFD_MSG_WARN(fmt...)
-#endif
- #define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
- #define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
- #define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
+#define WFD_MSG_INFO(fmt...) pr_info(WFD_TAG fmt)
+#define WFD_MSG_WARN(fmt...) pr_warning(WFD_TAG fmt)
+#define WFD_MSG_ERR(fmt...) pr_err(KERN_ERR WFD_TAG fmt)
+#define WFD_MSG_CRIT(fmt...) pr_crit(KERN_CRIT WFD_TAG fmt)
+#define WFD_MSG_DBG(fmt...) pr_debug(WFD_TAG fmt)
struct wfd_stats_encode_sample {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index b153b27..841e5e8 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1336,34 +1336,41 @@
msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
unsigned int status)
{
- if (status & MCI_DATACRCFAIL) {
- if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
- || data->mrq->cmd->opcode == MMC_BUS_TEST_R
- || data->mrq->cmd->opcode ==
- MMC_SEND_TUNING_BLOCK_HS200)) {
- pr_err("%s: Data CRC error\n",
- mmc_hostname(host->mmc));
- pr_err("%s: opcode 0x%.8x\n", __func__,
- data->mrq->cmd->opcode);
- pr_err("%s: blksz %d, blocks %d\n", __func__,
- data->blksz, data->blocks);
- data->error = -EILSEQ;
+ if ((status & MCI_DATACRCFAIL) || (status & MCI_DATATIMEOUT)) {
+ u32 opcode = data->mrq->cmd->opcode;
+
+ if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
+ || (opcode == MMC_BUS_TEST_R) ||
+ (host->tuning_in_progress &&
+ (opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
+ opcode == MMC_SEND_TUNING_BLOCK)))) {
+ if (status & MCI_DATACRCFAIL) {
+ pr_err("%s: Data CRC error\n",
+ mmc_hostname(host->mmc));
+ pr_err("%s: opcode 0x%.8x\n", __func__, opcode);
+ pr_err("%s: blksz %d, blocks %d\n", __func__,
+ data->blksz, data->blocks);
+ } else {
+ pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
+ mmc_hostname(host->mmc), opcode,
+ (readl_relaxed(host->base
+ + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
+ msmsdcc_dump_sdcc_state(host);
+ }
}
- } else if (status & MCI_DATATIMEOUT) {
- /* CRC is optional for the bus test commands, not all
+
+ /*
+ * CRC is optional for the bus test commands, not all
* cards respond back with CRC. However controller
* waits for the CRC and times out. Hence ignore the
* data timeouts during the Bustest.
*/
- if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
- || data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
- pr_err("%s: CMD%d: Data timeout. DAT0 => %d\n",
- mmc_hostname(host->mmc),
- data->mrq->cmd->opcode,
- (readl_relaxed(host->base
- + MCI_TEST_INPUT) & 0x2) ? 1 : 0);
- data->error = -ETIMEDOUT;
- msmsdcc_dump_sdcc_state(host);
+ if (!((!host->tuning_in_progress && opcode == MMC_BUS_TEST_W)
+ || (opcode == MMC_BUS_TEST_R))) {
+ if (status & MCI_DATACRCFAIL)
+ data->error = -EILSEQ;
+ else
+ data->error = -ETIMEDOUT;
}
} else if (status & MCI_RXOVERRUN) {
pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d8baa29..2542845 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -442,4 +442,13 @@
help
Say Y to enable battery temperature measurements using
thermistor connected on BATCTRL ADC.
+
+config QPNP_BMS
+ tristate "QPNP Battery Monitoring System driver"
+ depends on SPMI
+ depends on MSM_QPNP_INT
+ help
+ Say Y here to enable support for QPNP chip bms device.
+ It registers a fuelgauge bms power supply to report
+ State of Charge.
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index f84b527..9dc1960 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -55,6 +55,7 @@
obj-$(CONFIG_SMB137B_CHARGER) += smb137b.o
obj-$(CONFIG_PM8XXX_CCADC) += pm8xxx-ccadc.o
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
+obj-$(CONFIG_QPNP_BMS) += qpnp-bms.o
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
obj-$(CONFIG_LTC4088_CHARGER) += ltc4088-charger.o
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
new file mode 100644
index 0000000..7b4d97e
--- /dev/null
+++ b/drivers/power/qpnp-bms.c
@@ -0,0 +1,353 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/power_supply.h>
+#include <linux/spmi.h>
+
+/* Interrupt offsets */
+#define INT_RT_STS(base) (base + 0x10)
+#define INT_SET_TYPE(base) (base + 0x11)
+#define INT_POLARITY_HIGH(base) (base + 0x12)
+#define INT_POLARITY_LOW(base) (base + 0x13)
+#define INT_LATCHED_CLR(base) (base + 0x14)
+#define INT_EN_SET(base) (base + 0x15)
+#define INT_EN_CLR(base) (base + 0x16)
+#define INT_LATCHED_STS(base) (base + 0x18)
+#define INT_PENDING_STS(base) (base + 0x19)
+#define INT_MID_SEL(base) (base + 0x1A)
+#define INT_PRIORITY(base) (base + 0x1B)
+
+/* BMS Register Offsets */
+#define BMS1_REVISION1 0x0
+#define BMS1_REVISION2 0x1
+#define BMS1_STATUS1 0x8
+#define BMS1_MODE_CTL 0X40
+/* Columb counter clear registers */
+#define BMS1_CC_DATA_CTL 0x42
+#define BMS1_CC_CLEAR_CTRL 0x43
+/* OCV limit registers */
+#define BMS1_OCV_USE_LOW_LIMIT_THR0 0x48
+#define BMS1_OCV_USE_LOW_LIMIT_THR1 0x49
+#define BMS1_OCV_USE_HIGH_LIMIT_THR0 0x4A
+#define BMS1_OCV_USE_HIGH_LIMIT_THR1 0x4B
+#define BMS1_OCV_USE_LIMIT_CTL 0x4C
+/* CC interrupt threshold */
+#define BMS1_CC_THR0 0x7A
+#define BMS1_CC_THR1 0x7B
+#define BMS1_CC_THR2 0x7C
+#define BMS1_CC_THR3 0x7D
+#define BMS1_CC_THR4 0x7E
+/* OCV for r registers */
+#define BMS1_OCV_FOR_R_DATA0 0x80
+#define BMS1_OCV_FOR_R_DATA1 0x81
+#define BMS1_VSENSE_FOR_R_DATA0 0x82
+#define BMS1_VSENSE_FOR_R_DATA1 0x83
+/* Columb counter data */
+#define BMS1_CC_DATA0 0x8A
+#define BMS1_CC_DATA1 0x8B
+#define BMS1_CC_DATA2 0x8C
+#define BMS1_CC_DATA3 0x8D
+#define BMS1_CC_DATA4 0x8E
+/* OCV for soc data */
+#define BMS1_OCV_FOR_SOC_DATA0 0x90
+#define BMS1_OCV_FOR_SOC_DATA1 0x91
+#define BMS1_VSENSE_PON_DATA0 0x94
+#define BMS1_VSENSE_PON_DATA1 0x95
+#define BMS1_VBAT_AVG_DATA0 0x9E
+#define BMS1_VBAT_AVG_DATA1 0x9F
+/* Extra bms registers */
+#define BMS1_BMS_DATA_REG_0 0xB0
+#define BMS1_BMS_DATA_REG_1 0xB1
+#define BMS1_BMS_DATA_REG_2 0xB2
+#define BMS1_BMS_DATA_REG_3 0xB3
+
+#define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
+
+struct qpnp_bms_chip {
+ struct device *dev;
+ struct power_supply bms_psy;
+ struct spmi_device *spmi;
+ u16 base;
+
+ u8 revision1;
+ u8 revision2;
+ int charger_status;
+ bool online;
+ /* platform data */
+ unsigned int r_sense_mohm;
+ unsigned int v_cutoff;
+ unsigned int max_voltage;
+ unsigned int r_conn_mohm;
+ int shutdown_soc_valid_limit;
+ int adjust_soc_low_threshold;
+ int adjust_soc_high_threshold;
+ int chg_term;
+};
+
+static struct of_device_id qpnp_bms_match_table[] = {
+ { .compatible = QPNP_BMS_DEV_NAME },
+ {}
+};
+
+static char *qpnp_bms_supplicants[] = {
+ "battery"
+};
+
+static enum power_supply_property msm_bms_power_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+};
+
+static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
+ u16 base, int count)
+{
+ int rc;
+ struct spmi_device *spmi = chip->spmi;
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val, count);
+ if (rc)
+ pr_err("SPMI read failed rc=%d\n", rc);
+
+ return 0;
+}
+
+/* Returns capacity as a SoC percentage between 0 and 100 */
+static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
+{
+ /* return 50 until a real algorithm is implemented */
+ return 50;
+}
+
+/* Returns instantaneous current in uA */
+static int get_prop_bms_current_now(struct qpnp_bms_chip *chip)
+{
+ /* temporarily return 0 until a real algorithm is put in */
+ return 0;
+}
+
+/* Returns full charge design in uAh */
+static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
+{
+ /* temporarily return 0 until a real algorithm is put in */
+ return 0;
+}
+
+static void set_prop_bms_online(struct qpnp_bms_chip *chip, bool online)
+{
+ chip->online = online;
+}
+
+static void set_prop_bms_status(struct qpnp_bms_chip *chip, int status)
+{
+ chip->charger_status = status;
+}
+
+static void qpnp_bms_external_power_changed(struct power_supply *psy)
+{
+}
+
+static int qpnp_bms_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+ bms_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = get_prop_bms_capacity(chip);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = get_prop_bms_current_now(chip);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ val->intval = get_prop_bms_charge_full_design(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int qpnp_bms_power_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+ bms_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ set_prop_bms_online(chip, val->intval);
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ set_prop_bms_status(chip, (bool)val->intval);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#define SPMI_PROPERTY_READ(chip_prop, qpnp_spmi_property, retval, errlabel)\
+do { \
+ retval = of_property_read_u32(spmi->dev.of_node, \
+ "qcom,bms-" qpnp_spmi_property, \
+ &chip->chip_prop); \
+ if (retval) { \
+ pr_err("Error reading " #qpnp_spmi_property \
+ " property %d\n", rc); \
+ goto errlabel; \
+ } \
+} while (0)
+
+static int __devinit
+qpnp_bms_probe(struct spmi_device *spmi)
+{
+ struct qpnp_bms_chip *chip;
+ struct resource *bms_resource;
+ int rc;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+
+ if (chip == NULL) {
+ pr_err("kzalloc() failed.\n");
+ return -ENOMEM;
+ }
+
+ chip->dev = &(spmi->dev);
+ chip->spmi = spmi;
+
+ bms_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!bms_resource) {
+ dev_err(&spmi->dev, "Unable to get BMS base address\n");
+ return -ENXIO;
+ }
+ chip->base = bms_resource->start;
+
+ rc = qpnp_read_wrapper(chip, &chip->revision1,
+ chip->base + BMS1_REVISION1, 1);
+ if (rc) {
+ pr_err("error reading version register %d\n", rc);
+ goto error_read;
+ }
+
+ rc = qpnp_read_wrapper(chip, &chip->revision2,
+ chip->base + BMS1_REVISION2, 1);
+ if (rc) {
+ pr_err("Error reading version register %d\n", rc);
+ goto error_read;
+ }
+
+ SPMI_PROPERTY_READ(r_sense_mohm, "r-sense-mohm", rc, error_read);
+ SPMI_PROPERTY_READ(v_cutoff, "v-cutoff-uv", rc, error_read);
+ SPMI_PROPERTY_READ(max_voltage, "max-voltage-uv", rc, error_read);
+ SPMI_PROPERTY_READ(r_conn_mohm, "r-conn-mohm", rc, error_read);
+ SPMI_PROPERTY_READ(shutdown_soc_valid_limit,
+ "shutdown-soc-valid-limit", rc, error_read);
+ SPMI_PROPERTY_READ(adjust_soc_low_threshold,
+ "adjust-soc-low-threshold", rc, error_read);
+ SPMI_PROPERTY_READ(adjust_soc_high_threshold,
+ "adjust-soc-high-threshold", rc, error_read);
+ SPMI_PROPERTY_READ(chg_term, "chg-term-ua", rc, error_read);
+
+ pr_debug("dts data: r_sense_mohm:%d, v_cutoff:%d, max_v:%d, r_conn:%d, shutdown_soc: %d, adjust_soc_low:%d, adjust_soc_high:%d, chg_term:%d\n",
+ chip->r_sense_mohm, chip->v_cutoff,
+ chip->max_voltage, chip->r_conn_mohm,
+ chip->shutdown_soc_valid_limit,
+ chip->adjust_soc_low_threshold,
+ chip->adjust_soc_high_threshold,
+ chip->chg_term);
+
+ dev_set_drvdata(&spmi->dev, chip);
+ device_init_wakeup(&spmi->dev, 1);
+
+ /* setup & register the battery power supply */
+ chip->bms_psy.name = "bms";
+ chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
+ chip->bms_psy.properties = msm_bms_power_props;
+ chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
+ chip->bms_psy.get_property = qpnp_bms_power_get_property;
+ chip->bms_psy.set_property = qpnp_bms_power_set_property;
+ chip->bms_psy.external_power_changed =
+ qpnp_bms_external_power_changed;
+ chip->bms_psy.supplied_to = qpnp_bms_supplicants;
+ chip->bms_psy.num_supplicants = ARRAY_SIZE(qpnp_bms_supplicants);
+
+ rc = power_supply_register(chip->dev, &chip->bms_psy);
+
+ if (rc < 0) {
+ pr_err("power_supply_register bms failed rc = %d\n", rc);
+ goto unregister_dc;
+ }
+
+ pr_info("probe success\n");
+ return 0;
+
+unregister_dc:
+ power_supply_unregister(&chip->bms_psy);
+ dev_set_drvdata(&spmi->dev, NULL);
+error_read:
+ kfree(chip);
+ return rc;
+}
+
+static int __devexit
+qpnp_bms_remove(struct spmi_device *spmi)
+{
+ struct qpnp_bms_chip *chip = dev_get_drvdata(&spmi->dev);
+
+ dev_set_drvdata(&spmi->dev, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static struct spmi_driver qpnp_bms_driver = {
+ .probe = qpnp_bms_probe,
+ .remove = __devexit_p(qpnp_bms_remove),
+ .driver = {
+ .name = QPNP_BMS_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_bms_match_table,
+ },
+};
+
+static int __init qpnp_bms_init(void)
+{
+ pr_info("QPNP BMS INIT\n");
+ return spmi_driver_register(&qpnp_bms_driver);
+}
+
+static void __exit qpnp_bms_exit(void)
+{
+ pr_info("QPNP BMS EXIT\n");
+ return spmi_driver_unregister(&qpnp_bms_driver);
+}
+
+module_init(qpnp_bms_init);
+module_exit(qpnp_bms_exit);
+
+MODULE_DESCRIPTION("QPNP BMS Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_BMS_DEV_NAME);
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e685785..e409a0b 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -100,17 +100,21 @@
return ret;
}
- ret = regulator_enable(dsi_drv.vdd_vreg);
- if (ret) {
- pr_err("%s: Failed to enable regulator.\n", __func__);
- return ret;
- }
-
ret = regulator_enable(dsi_drv.vdd_io_vreg);
if (ret) {
pr_err("%s: Failed to enable regulator.\n", __func__);
return ret;
}
+ msleep(20);
+ wmb();
+
+ ret = regulator_enable(dsi_drv.vdd_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n", __func__);
+ return ret;
+ }
+ msleep(20);
+ wmb();
ret = regulator_enable(dsi_drv.dsi_vreg);
if (ret) {
@@ -130,13 +134,13 @@
return ret;
}
- ret = regulator_disable(dsi_drv.vdd_io_vreg);
+ ret = regulator_disable(dsi_drv.dsi_vreg);
if (ret) {
pr_err("%s: Failed to disable regulator.\n", __func__);
return ret;
}
- ret = regulator_disable(dsi_drv.dsi_vreg);
+ ret = regulator_disable(dsi_drv.vdd_io_vreg);
if (ret) {
pr_err("%s: Failed to disable regulator.\n", __func__);
return ret;
@@ -165,11 +169,11 @@
return 0;
}
-static int mdss_dsi_off(struct mdss_panel_data *pdata)
+static int mdss_dsi_ctrl_unprepare(struct mdss_panel_data *pdata)
{
- int ret = 0;
struct mdss_panel_info *pinfo;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ int ret = 0;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
@@ -180,9 +184,6 @@
pinfo = &pdata->panel_info;
- if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
- mdss_dsi_controller_cfg(0, pdata);
-
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
ret = ctrl_pdata->off(pdata);
@@ -191,16 +192,23 @@
return ret;
}
+ return ret;
+}
+
+static int mdss_dsi_off(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+
spin_lock_bh(&dsi_clk_lock);
mdss_dsi_clk_disable(pdata);
- /* disable dsi engine */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, 0);
-
spin_unlock_bh(&dsi_clk_lock);
mdss_dsi_unprepare_clocks();
+ /* disable DSI controller */
+ mdss_dsi_controller_cfg(0, pdata);
+
ret = mdss_dsi_panel_power_on(0);
if (ret) {
pr_err("%s: Panel power off failed\n", __func__);
@@ -232,11 +240,13 @@
pinfo = &pdata->panel_info;
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 1);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0);
+ ret = mdss_dsi_panel_power_on(1);
+ if (ret) {
+ pr_err("%s: Panel power on failed\n", __func__);
+ return ret;
+ }
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
- mdss_dsi_phy_enable((ctrl_pdata->ctrl_base), 1);
mdss_dsi_phy_init(pdata);
mdss_dsi_prepare_clocks();
@@ -312,12 +322,6 @@
wmb();
}
- ret = mdss_dsi_panel_power_on(1);
- if (ret) {
- pr_err("%s: Panel power on failed\n", __func__);
- return ret;
- }
-
ret = ctrl_pdata->on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel\n", __func__);
@@ -481,6 +485,7 @@
(ctrl_pdata->panel_data).on = mdss_dsi_on;
(ctrl_pdata->panel_data).off = mdss_dsi_off;
+ (ctrl_pdata->panel_data).intf_unprepare = mdss_dsi_ctrl_unprepare;
memcpy(&((ctrl_pdata->panel_data).panel_info),
&(panel_data->panel_info),
sizeof(struct mdss_panel_info));
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index e47891e..5d0d578 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -861,6 +861,16 @@
sleep_us, timeout_us))
pr_info("%s: FIFO status=%x failed\n", __func__, status);
+ /* Check for VIDEO_MODE_ENGINE_BUSY */
+ if (readl_poll_timeout(((ctrl_pdata->ctrl_base) + 0x0008),
+ status,
+ ((status & 0x08) == 0),
+ sleep_us, timeout_us)) {
+ pr_debug("%s: DSI status=%x\n", __func__, status);
+ pr_debug("%s: Doing sw reset\n", __func__);
+ mdss_dsi_sw_reset(pdata);
+ }
+
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
if (enable)
dsi_ctrl |= 0x01;
@@ -884,14 +894,21 @@
return;
}
-
dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
- dsi_ctrl &= ~0x07;
+ /*If Video enabled, Keep Video and Cmd mode ON */
+ if (dsi_ctrl & 0x02)
+ dsi_ctrl &= ~0x05;
+ else
+ dsi_ctrl &= ~0x07;
+
if (mode == DSI_VIDEO_MODE) {
dsi_ctrl |= 0x03;
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
} else { /* command mode */
dsi_ctrl |= 0x05;
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+ dsi_ctrl |= 0x02;
+
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
DSI_INTR_CMD_MDP_DONE_MASK;
}
@@ -1102,6 +1119,7 @@
mdss_dsi_buf_init(tp);
mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
mdss_dsi_cmd_dma_tx(tp, pdata);
+ pr_debug("%s: Max packet size sent\n", __func__);
}
mdss_dsi_buf_init(tp);
@@ -1161,6 +1179,7 @@
rp->len -= diff; /* align bytes */
break;
default:
+ pr_debug("%s: Unknown cmd received\n", __func__);
break;
}
@@ -1261,6 +1280,8 @@
for (i = 0; i < cnt; i++) {
data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
*lp++ = ntohl(data); /* to network byte order */
+ pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
+ __func__, data, ntohl(data));
off -= 4;
rp->len += sizeof(*lp);
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 63ad5cc..b247e4d 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -40,20 +40,6 @@
static int rst_gpio;
static int disp_en;
-struct qpnp_pin_cfg param = {
- .mode = QPNP_PIN_MODE_DIG_OUT,
- .output_type = QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS,
- .invert = QPNP_PIN_INVERT_ENABLE,
- .pull = QPNP_PIN_MPP_PULL_UP_30KOHM,
- .vin_sel = QPNP_PIN_VIN3,
- .out_strength = QPNP_PIN_OUT_STRENGTH_HIGH,
- .select = QPNP_PIN_SEL_DTEST3,
- .master_en = QPNP_PIN_MASTER_ENABLE,
- .aout_ref = QPNP_PIN_AOUT_0V625,
- .ain_route = QPNP_PIN_AIN_AMUX_CH7,
- .cs_out = QPNP_PIN_CS_OUT_20MA,
-};
-
void mdss_dsi_panel_reset(int enable)
{
if (!disp_en)
@@ -64,13 +50,20 @@
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
+ pr_debug("%s: enable = %d\n", __func__, enable);
+
if (enable) {
- gpio_set_value(disp_en, 1);
gpio_set_value(rst_gpio, 1);
- usleep(10);
+ msleep(20);
+ wmb();
gpio_set_value(rst_gpio, 0);
- usleep(200);
+ udelay(200);
+ wmb();
gpio_set_value(rst_gpio, 1);
+ msleep(20);
+ wmb();
+ gpio_set_value(disp_en, 1);
+ wmb();
} else {
gpio_set_value(rst_gpio, 0);
gpio_set_value(disp_en, 0);
@@ -113,7 +106,7 @@
pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
mipi->mode);
- mdss_dsi_panel_reset(1);
+ mdss_dsi_sw_reset(pdata);
if (mipi->mode == DSI_VIDEO_MODE) {
mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
@@ -142,8 +135,6 @@
return -EINVAL;
}
- mdss_dsi_panel_reset(0);
-
return 0;
}
@@ -202,14 +193,6 @@
pr_err("%s:%d, reset gpio not specified\n",
__func__, __LINE__);
} else {
- rc = qpnp_pin_config(rst_gpio, ¶m);
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(disp_en);
- return rc;
- }
-
rc = gpio_request(rst_gpio, "disp_rst_n");
if (rc) {
pr_err("request reset gpio failed, rc=%d\n",
@@ -328,7 +311,7 @@
panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
- if ((!data) || (len != 8)) {
+ if ((!data) || (len != 7)) {
pr_err("%s:%d, Unable to read Phy regulator settings",
__func__, __LINE__);
goto error;
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b831909..f72ff8d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -593,6 +593,13 @@
ctl->power_on = false;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ if (pdata->intf_unprepare)
+ ret = pdata->intf_unprepare(pdata);
+
+ if (ret)
+ pr_err("%s: intf_unprepare failed\n", __func__);
+
if (ctl->stop_fnc)
ret = ctl->stop_fnc(ctl);
else
@@ -602,6 +609,7 @@
pr_warn("error powering off intf ctl=%d\n", ctl->num);
ret = pdata->off(pdata);
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ctl->play_cnt = 0;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index f1a4e50..5cdfe34 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -86,7 +86,7 @@
/* DSI PHY configuration */
struct mdss_dsi_phy_ctrl {
- uint32_t regulator[8];
+ uint32_t regulator[7];
uint32_t timing[12];
uint32_t ctrl[4];
uint32_t strength[2];
@@ -180,6 +180,7 @@
struct mdss_panel_info panel_info;
void (*set_backlight) (struct mdss_panel_data *pdata,
u32 bl_level);
+ int (*intf_unprepare) (struct mdss_panel_data *pdata);
unsigned char *mmss_cc_base;
/* function entry chain */
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 545d53c..1232ec6 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -212,25 +212,34 @@
{
/* start phy sw reset */
MIPI_OUTP(ctrl_base + 0x12c, 0x0001);
+ udelay(1000);
wmb();
- usleep(1);
/* end phy sw reset */
MIPI_OUTP(ctrl_base + 0x12c, 0x0000);
+ udelay(100);
wmb();
- usleep(1);
}
void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
{
if (on) {
+ MIPI_OUTP(ctrl_base + 0x03cc, 0x03);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0220, 0x006);
- usleep(10);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0268, 0x001);
- usleep(10);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0268, 0x000);
- usleep(10);
+ wmb();
+ usleep(100);
MIPI_OUTP(ctrl_base + 0x0220, 0x007);
wmb();
+ MIPI_OUTP(ctrl_base + 0x03cc, 0x01);
+ wmb();
+ usleep(100);
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
@@ -266,12 +275,25 @@
pd = ((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db;
+ /* Strength ctrl 0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, 0x07);
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
+
off = 0x0580; /* phy regulator ctrl settings */
- for (i = 0; i < 8; i++) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->regulator[i]);
- wmb();
- off += 4;
- }
+ /* Regulator ctrl - CAL_PWD_CFG */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 6), pd->regulator[6]);
+ /* Regulator ctrl - TEST */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 5), pd->regulator[5]);
+ /* Regulator ctrl 3 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 3), pd->regulator[3]);
+ /* Regulator ctrl 2 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 2), pd->regulator[2]);
+ /* Regulator ctrl 1 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 1), pd->regulator[1]);
+ /* Regulator ctrl 0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 0), pd->regulator[0]);
+ /* Regulator ctrl 4 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off + (4 * 4), pd->regulator[4]);
off = 0x0440; /* phy timing ctrl 0 - 11 */
for (i = 0; i < 12; i++) {
@@ -280,17 +302,15 @@
off += 4;
}
- /* Strength ctrl 0 - 1 */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0484, pd->strength[0]);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0474, 0x00);
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x5f);
wmb();
- off = 0x04b4; /* phy BIST ctrl 0 - 5 */
- for (i = 0; i < 6; i++) {
- MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
- wmb();
- off += 4;
- }
+ /* Strength ctrl 1 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0488, pd->strength[1]);
+ wmb();
/* 4 lanes + clk lane configuration */
/* lane config n * (0 - 4) & DataPath setup */
@@ -304,4 +324,20 @@
off += 4;
}
}
+
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0470, 0x7f);
+ wmb();
+
+ /* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04d4, 0x01);
+ wmb();
+
+ off = 0x04b4; /* phy BIST ctrl 0 - 5 */
+ for (i = 0; i < 6; i++) {
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + off, pd->bistCtrl[i]);
+ wmb();
+ off += 4;
+ }
+
}
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 45d51ce..288ed43 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -109,7 +109,7 @@
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
#define MSG_MASK_TBL_CNT 24
-#define EVENT_LAST_ID 0x08AD
+#define EVENT_LAST_ID 0x08C5
#define MSG_SSID_0 0
#define MSG_SSID_0_LAST 93
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index ac4ec09..1da6aa2 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -242,18 +242,18 @@
*/
struct adm_cmd_set_pp_params_v5 {
struct apr_hdr hdr;
- u32 data_payload_addr_lsw;
+ u32 payload_addr_lsw;
/* LSW of parameter data payload address.*/
- u32 data_payload_addr_msw;
+ u32 payload_addr_msw;
/* MSW of parameter data payload address.*/
- u32 mem_map_handle;
+ u32 mem_map_handle;
/* Memory map handle returned by ADM_CMD_SHARED_MEM_MAP_REGIONS
* command */
/* If mem_map_handle is zero implies the message is in
* the payload */
- u32 data_payload_size;
+ u32 payload_size;
/* Size in bytes of the variable payload accompanying this
* message or
* in shared memory. This is used for parsing the parameter
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index ac11f1a..a47e446 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -8379,8 +8379,9 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct tabla_priv *tabla = platform_get_drvdata(pdev);
- dev_dbg(dev, "%s: system resume\n", __func__);
- tabla->mbhc_last_resume = jiffies;
+ dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
+ if (tabla)
+ tabla->mbhc_last_resume = jiffies;
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index e5837b2..62257b4 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -41,6 +41,14 @@
wait_queue_head_t wait[Q6_AFE_MAX_PORTS];
};
+static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
+static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
+
+/* 0 - (MAX_AUDPROC_TYPES -1): audproc handles */
+/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1): audvol handles */
+atomic_t mem_map_handles[(2 * MAX_AUDPROC_TYPES)];
+atomic_t mem_map_index;
+
static struct adm_ctl this_adm;
static int32_t adm_callback(struct apr_client_data *data, void *priv)
@@ -63,6 +71,18 @@
}
this_adm.apr = NULL;
}
+ pr_debug("Resetting calibration blocks");
+ for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+ /* Device calibration */
+ mem_addr_audproc[i].cal_size = 0;
+ mem_addr_audproc[i].cal_kvaddr = 0;
+ mem_addr_audproc[i].cal_paddr = 0;
+
+ /* Volume calibration */
+ mem_addr_audvol[i].cal_size = 0;
+ mem_addr_audvol[i].cal_kvaddr = 0;
+ mem_addr_audvol[i].cal_paddr = 0;
+ }
return 0;
}
@@ -82,18 +102,23 @@
switch (payload[0]) {
case ADM_CMD_SET_PP_PARAMS_V5:
if (rtac_make_adm_callback(
- payload, data->payload_size))
+ payload, data->payload_size)) {
pr_debug("%s: payload[0]: 0x%x\n",
__func__, payload[0]);
break;
+ }
case ADM_CMD_DEVICE_CLOSE_V5:
case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
- case ADM_CMD_SHARED_MEM_MAP_REGIONS:
case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
- pr_debug("ADM_CMD_MATRIX_MAP_ROUTINGS\n");
+ pr_debug("%s: Basic callback received, wake up.\n",
+ __func__);
atomic_set(&this_adm.copp_stat[index], 1);
wake_up(&this_adm.wait[index]);
break;
+ case ADM_CMD_SHARED_MEM_MAP_REGIONS:
+ /* Block until memory handle comes back */
+ /* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ break;
default:
pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
payload[0]);
@@ -125,6 +150,14 @@
rtac_make_adm_callback(payload,
data->payload_size);
break;
+ case ADM_CMDRSP_SHARED_MEM_MAP_REGIONS:
+ pr_debug("%s: ADM_CMDRSP_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ atomic_set(&mem_map_handles[
+ atomic_read(&mem_map_index)], *payload);
+ atomic_set(&this_adm.copp_stat[0], 1);
+ wake_up(&this_adm.wait[index]);
+ break;
default:
pr_err("%s: Unknown cmd:0x%x\n", __func__,
data->opcode);
@@ -134,12 +167,143 @@
return 0;
}
-/* TODO: send_adm_cal_block function to be defined
- when calibration available for 8974 */
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+{
+ s32 result = 0;
+ struct adm_cmd_set_pp_params_v5 adm_params;
+ int index = afe_get_port_index(port_id);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: invalid port idx %d portid %d\n",
+ __func__, index, port_id);
+ return 0;
+ }
+
+ pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+
+ if (!aud_cal || aud_cal->cal_size == 0) {
+ pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+ __func__, port_id);
+ result = -EINVAL;
+ goto done;
+ }
+
+ adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_params.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(adm_params));
+ adm_params.hdr.src_svc = APR_SVC_ADM;
+ adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_params.hdr.src_port = port_id;
+ adm_params.hdr.dest_svc = APR_SVC_ADM;
+ adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ adm_params.hdr.token = port_id;
+ adm_params.hdr.opcode = ADM_CMD_SET_PP_PARAMS_V5;
+ adm_params.payload_addr_lsw = aud_cal->cal_paddr;
+ adm_params.payload_addr_msw = 0;
+ adm_params.mem_map_handle = atomic_read(&mem_map_handles[
+ atomic_read(&mem_map_index)]);
+ adm_params.payload_size = aud_cal->cal_size;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+ pr_debug("%s: Sending SET_PARAMS payload = 0x%x, size = %d\n",
+ __func__, adm_params.payload_addr_lsw,
+ adm_params.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+ if (result < 0) {
+ pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+ __func__, port_id, aud_cal->cal_paddr);
+ result = -EINVAL;
+ goto done;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.wait[index],
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+ __func__, port_id, aud_cal->cal_paddr);
+ result = -EINVAL;
+ goto done;
+ }
+
+ result = 0;
+done:
+ return result;
+}
+
static void send_adm_cal(int port_id, int path)
{
- /* function to be defined when calibration available for 8974 */
+ int result = 0;
+ s32 acdb_path;
+ struct acdb_cal_block aud_cal;
+ int size = 4096;
pr_debug("%s\n", __func__);
+
+ /* Maps audio_dev_ctrl path definition to ACDB definition */
+ acdb_path = path - 1;
+
+ pr_debug("%s: Sending audproc cal\n", __func__);
+ get_audproc_cal(acdb_path, &aud_cal);
+
+ /* map & cache buffers used */
+ if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
+ (aud_cal.cal_size > 0)) ||
+ (aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
+
+ atomic_set(&mem_map_index, acdb_path);
+ if (mem_addr_audproc[acdb_path].cal_paddr != 0)
+ adm_memory_unmap_regions(port_id,
+ &mem_addr_audproc[acdb_path].cal_paddr,
+ &size, 1);
+
+ result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
+ 0, &aud_cal.cal_size, 1);
+ if (result < 0)
+ pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
+ acdb_path, aud_cal.cal_paddr,
+ aud_cal.cal_size);
+ else
+ mem_addr_audproc[acdb_path] = aud_cal;
+ }
+
+ if (!send_adm_cal_block(port_id, &aud_cal))
+ pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+ else
+ pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+
+ pr_debug("%s: Sending audvol cal\n", __func__);
+ get_audvol_cal(acdb_path, &aud_cal);
+
+ /* map & cache buffers used */
+ if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
+ (aud_cal.cal_size > 0)) ||
+ (aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
+
+ atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
+ if (mem_addr_audvol[acdb_path].cal_paddr != 0)
+ adm_memory_unmap_regions(port_id,
+ &mem_addr_audvol[acdb_path].cal_paddr,
+ &size, 1);
+
+ result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
+ 0, &aud_cal.cal_size, 1);
+ if (result < 0)
+ pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
+ acdb_path, aud_cal.cal_paddr,
+ aud_cal.cal_size);
+ else
+ mem_addr_audvol[acdb_path] = aud_cal;
+ }
+
+ if (!send_adm_cal_block(port_id, &aud_cal))
+ pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
+ else
+ pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+ __func__, port_id, acdb_path);
}
int adm_connect_afe_port(int mode, int session_id, int port_id)
@@ -572,7 +736,8 @@
unmap_regions.hdr.dest_port = 0;
unmap_regions.hdr.token = 0;
unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
- unmap_regions.mem_map_handle = this_adm.mem_map_handle[index];
+ unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
+ atomic_read(&mem_map_index)]);
atomic_set(&this_adm.copp_stat[0], 0);
ret = apr_send_pkt(this_adm.apr, (uint32_t *) &unmap_regions);
if (ret < 0) {