Merge "defconfig: msm9625: enable msm_rmnet_bam"
diff --git a/Documentation/arm/msm/tspp.txt b/Documentation/arm/msm/tspp.txt
index a56f014..d770260 100644
--- a/Documentation/arm/msm/tspp.txt
+++ b/Documentation/arm/msm/tspp.txt
@@ -157,13 +157,12 @@
API
===
-int tspp_open_stream(tspp_device *dev, void *stream, void *channel, tspp_mode
- mode);
-int tspp_close_stream(tspp_device *dev, void *stream);
-int tspp_open_channel(tspp_device *dev, int dest, int bufsize, void *channel);
-int tspp_close_channel(tspp_device *dev, void *channel);
-int tspp_register_filter(tspp_device *dev, void *channel, tspp_filter *filter);
-int tspp_unregister_filter(tspp_device *dev, void *channel, int pid);
+int tspp_open_stream(u32 dev, u32 channel, struct tspp_select_source *source);
+int tspp_close_stream(u32 dev, u32 channel);
+int tspp_open_channel(u32 dev, u32 channel);
+int tspp_close_channelu(32 dev, u32 channel);
+int tspp_add_filter(u32 dev, u32 channel, struct tspp_filter *filter);
+int tspp_remove_filter(u32 dev, u32 channel, struct tspp_filter *filter);
Refer to chrdev implementation in kernel/drivers/misc/tspp.c for an example of
how to use this api.
diff --git a/Documentation/devicetree/bindings/regulator/stub-regulator.txt b/Documentation/devicetree/bindings/regulator/stub-regulator.txt
new file mode 100644
index 0000000..1057e17
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/stub-regulator.txt
@@ -0,0 +1,48 @@
+Stub Voltage Regulators
+
+stub-regulators are place-holder regulator devices which do not impact any
+hardware state. They provide a means for consumer devices to utilize all
+regulator features for testing purposes.
+
+Required properties:
+- compatible: Must be "qcom,stub-regulator".
+- regulator-name: A string used as a descriptive name for regulator outputs.
+
+Optional properties:
+- parent-supply: phandle to the parent supply/regulator node if one exists.
+- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load
+ which requires the regulator to be in high power mode.
+- qcom,system-load: Load in uA present on regulator that is not captured by any
+ consumer request.
+
+All properties specified within the core regulator framework can also be used.
+These bindings can be found in regulator.txt.
+
+Example:
+
+/ {
+ pm8026_s3: regulator-s3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_s3";
+ qcom,hpm-min-load = <100000>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8026_l1: regulator-l1 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l1";
+ parent-supply = <&pm8026_s3>;
+ qcom,hpm-min-load = <10000>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8026_l20: regulator-l20 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8026_l20";
+ qcom,hpm-min-load = <5000>;
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 9f3719b..96e3a61 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -28,6 +28,10 @@
- qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
- qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
- qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ - qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
+ - qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
+ - qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
+ - qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
- qcom,cdc-slim-ifd-dev - namme of the codec slim interface device.
- qcom,cdc-slim-ifd-elemental-addr - codec slimbus slave interface device
@@ -76,6 +80,10 @@
qcom,cdc-micbias2-cfilt-sel = <0x1>;
qcom,cdc-micbias3-cfilt-sel = <0x2>;
qcom,cdc-micbias4-cfilt-sel = <0x2>;
+ qcom,cdc-micbias1-ext-cap;
+ qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
qcom,cdc-slim-ifd = "taiko-slim-ifd";
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index 460caf2..b63595b 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -403,3 +403,9 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 2625e7a..3f51ec9 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -263,7 +263,7 @@
cs-gpios = <&msmgpio 55 0>;
};
- slim@fe12f000 {
+ slim_msm: slim@fe12f000 {
cell-index = <1>;
compatible = "qcom,slim-msm";
reg = <0xfe12f000 0x35000>,
@@ -340,10 +340,10 @@
"MIC BIAS1 Internal1", "Handset Mic",
"AMIC2", "MIC BIAS2 External",
"MIC BIAS2 External", "Headset Mic",
- "AMIC3", "MIC BIAS3 Internal1",
- "MIC BIAS3 Internal1", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS1 Internal2",
- "MIC BIAS1 Internal2", "ANCLeft Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
"DMIC1", "MIC BIAS1 External",
"MIC BIAS1 External", "Digital Mic1",
"DMIC2", "MIC BIAS1 External",
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index e2d1496..2f2518d 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -234,7 +234,6 @@
qcom,sdcc-sup-voltages = <2950 2950>;
qcom,sdcc-bus-width = <4>;
qcom,sdcc-bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50";
- status = "disable";
};
qcom,bam_dmux@fc834000 {
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
index a9dadee..24e3452 100644
--- a/arch/arm/configs/msm8910_defconfig
+++ b/arch/arm/configs/msm8910_defconfig
@@ -10,6 +10,7 @@
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
+CONFIG_VFP=y
# CONFIG_FAIR_GROUP_SCHED is not set
CONFIG_RT_GROUP_SCHED=y
CONFIG_NAMESPACES=y
@@ -75,6 +76,16 @@
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
# CONFIG_MISC_FILESYSTEMS is not set
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 0fca83a..36f417e 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -52,6 +52,11 @@
CONFIG_VMALLOC_RESERVE=0x19000000
CONFIG_USE_OF=y
CONFIG_CPU_IDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 098f854..61213cf 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -143,7 +143,7 @@
};
static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 950000, 3200000 },
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 950000, 100000 },
{ 1, { 384000, HFPLL, 2, 40 }, L2(3), 950000, 3200000 },
{ 1, { 460800, HFPLL, 2, 48 }, L2(3), 950000, 3200000 },
{ 1, { 537600, HFPLL, 1, 28 }, L2(5), 950000, 3200000 },
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
index 1c92494f..9afc05e 100644
--- a/arch/arm/mach-msm/board-8910.c
+++ b/arch/arm/mach-msm/board-8910.c
@@ -44,6 +44,9 @@
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", HSUSB_IFACE_CLK, "f9a55000.usb", OFF),
CLK_DUMMY("core_clk", HSUSB_CORE_CLK, "f9a55000.usb", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9824000.qcom,sdcc", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9824000.qcom,sdcc", OFF),
+ CLK_DUMMY("bus_clk", NULL, "f9824000.qcom,sdcc", OFF),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index adf1733..934bf88 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1208,8 +1208,6 @@
.b = {
.ctl_reg = AHB_EN3_REG,
.en_mask = BIT(1),
- .hwcg_reg = AHB_EN3_REG,
- .hwcg_mask = BIT(0),
.reset_reg = SW_RESET_AHB2_REG,
.reset_mask = BIT(2),
.halt_reg = DBG_BUS_VEC_J_REG,
@@ -6332,7 +6330,7 @@
}
if (cpu_is_apq8064() || cpu_is_apq8064ab())
- rmwreg(0x00000001, AHB_EN3_REG, 0x00000001);
+ rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
/* Deassert all locally-owned MM AHB resets. */
rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
diff --git a/arch/arm/mach-msm/include/mach/irqs-8910.h b/arch/arm/mach-msm/include/mach/irqs-8910.h
index 22fdc16..e883214 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8910.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8910.h
@@ -31,7 +31,7 @@
#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
#define NR_MSM_IRQS 256
-#define NR_GPIO_IRQS 146
+#define NR_GPIO_IRQS 102
#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
#define NR_BOARD_IRQS NR_QPNP_IRQS
#define NR_TLMM_MSM_DIR_CONN_IRQ 8
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
index 48be504..5395b88 100644
--- a/arch/arm/mach-msm/include/mach/msm_tspp.h
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -35,8 +35,8 @@
u32 *phys_base, void *user);
/* Kernel API functions */
-int tspp_open_stream(u32 dev, u32 channel_id, enum tspp_source src,
- enum tspp_tsif_mode mode);
+int tspp_open_stream(u32 dev, u32 channel_id,
+ struct tspp_select_source *source);
int tspp_close_stream(u32 dev, u32 channel_id);
int tspp_open_channel(u32 dev, u32 channel_id);
int tspp_close_channel(u32 dev, u32 channel_id);
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 0b30c26..380fde1 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -127,7 +127,7 @@
struct list_head req_list;
struct work_struct work;
int prio;
- int pending;
+ atomic_t pending;
bool passive;
};
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c82eac1..20e56c2 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -174,7 +174,6 @@
static LIST_HEAD(xprt_info_list);
static DEFINE_MUTEX(xprt_info_list_lock);
-DECLARE_COMPLETION(msm_ipc_remote_router_up);
static DECLARE_COMPLETION(msm_ipc_local_router_up);
#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
@@ -765,7 +764,7 @@
return ret;
}
-static int msm_ipc_router_send_server_list(
+static int msm_ipc_router_send_server_list(uint32_t node_id,
struct msm_ipc_router_xprt_info *xprt_info)
{
union rr_control_msg ctl;
@@ -787,8 +786,8 @@
ctl.srv.instance = server->name.instance;
list_for_each_entry(server_port,
&server->server_port_list, list) {
- if (server_port->server_addr.node_id ==
- xprt_info->remote_node_id)
+ if (server_port->server_addr.node_id !=
+ node_id)
continue;
ctl.srv.node_id =
@@ -1166,14 +1165,86 @@
msm_ipc_cleanup_routing_table(xprt_info);
}
+static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
+ struct rr_header *hdr)
+{
+ int i, rc = 0;
+ union rr_control_msg ctl;
+ struct msm_ipc_routing_table_entry *rt_entry;
+
+ if (!hdr)
+ return -EINVAL;
+
+ RR("o HELLO NID %d\n", hdr->src_node_id);
+
+ xprt_info->remote_node_id = hdr->src_node_id;
+ /*
+ * Find the entry from Routing Table corresponding to Node ID.
+ * Under SSR, an entry will be found. When the system boots up
+ * for the 1st time, an entry will not be found and hence allocate
+ * an entry. Update the entry with the Node ID that it corresponds
+ * to and the XPRT through which it can be reached.
+ */
+ mutex_lock(&routing_table_lock);
+ rt_entry = lookup_routing_table(hdr->src_node_id);
+ if (!rt_entry) {
+ rt_entry = alloc_routing_table_entry(hdr->src_node_id);
+ if (!rt_entry) {
+ mutex_unlock(&routing_table_lock);
+ pr_err("%s: rt_entry allocation failed\n", __func__);
+ return -ENOMEM;
+ }
+ add_routing_table_entry(rt_entry);
+ }
+ mutex_lock(&rt_entry->lock);
+ rt_entry->neighbor_node_id = xprt_info->remote_node_id;
+ rt_entry->xprt_info = xprt_info;
+ mutex_unlock(&rt_entry->lock);
+ mutex_unlock(&routing_table_lock);
+
+ /* Cleanup any remote ports, if the node is coming out of reset */
+ msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
+
+ /* Send a reply HELLO message */
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
+ rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
+ if (rc < 0) {
+ pr_err("%s: Error sending reply HELLO message\n", __func__);
+ return rc;
+ }
+ xprt_info->initialized = 1;
+
+ /*
+ * Send list of servers from the local node and from nodes
+ * outside the mesh network in which this XPRT is part of.
+ */
+ mutex_lock(&routing_table_lock);
+ for (i = 0; i < RT_HASH_SIZE; i++) {
+ list_for_each_entry(rt_entry, &routing_table[i], list) {
+ if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
+ (rt_entry->xprt_info->xprt->link_id ==
+ xprt_info->xprt->link_id))
+ continue;
+ rc = msm_ipc_router_send_server_list(rt_entry->node_id,
+ xprt_info);
+ if (rc < 0) {
+ mutex_unlock(&routing_table_lock);
+ return rc;
+ }
+ }
+ }
+ mutex_unlock(&routing_table_lock);
+ RR("HELLO message processed\n");
+ return rc;
+}
+
static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
struct rr_packet *pkt)
{
- union rr_control_msg ctl;
union rr_control_msg *msg;
struct msm_ipc_router_remote_port *rport_ptr;
int rc = 0;
- static uint32_t first = 1;
struct sk_buff *temp_ptr;
struct rr_header *hdr;
struct msm_ipc_server *server;
@@ -1199,43 +1270,9 @@
switch (msg->cmd) {
case IPC_ROUTER_CTRL_CMD_HELLO:
- RR("o HELLO NID %d\n", hdr->src_node_id);
- xprt_info->remote_node_id = hdr->src_node_id;
-
- mutex_lock(&routing_table_lock);
- rt_entry = lookup_routing_table(hdr->src_node_id);
- if (!rt_entry) {
- rt_entry = alloc_routing_table_entry(hdr->src_node_id);
- if (!rt_entry) {
- mutex_unlock(&routing_table_lock);
- pr_err("%s: rt_entry allocation failed\n",
- __func__);
- return -ENOMEM;
- }
- add_routing_table_entry(rt_entry);
- }
- mutex_lock(&rt_entry->lock);
- rt_entry->neighbor_node_id = xprt_info->remote_node_id;
- rt_entry->xprt_info = xprt_info;
- mutex_unlock(&rt_entry->lock);
- mutex_unlock(&routing_table_lock);
- msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
-
- memset(&ctl, 0, sizeof(ctl));
- ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
- msm_ipc_router_send_control_msg(xprt_info, &ctl);
-
- xprt_info->initialized = 1;
-
- /* Send list of servers one at a time */
- msm_ipc_router_send_server_list(xprt_info);
-
- if (first) {
- first = 0;
- complete_all(&msm_ipc_remote_router_up);
- }
- RR("HELLO message processed\n");
+ rc = process_hello_msg(xprt_info, hdr);
break;
+
case IPC_ROUTER_CTRL_CMD_RESUME_TX:
RR("o RESUME_TX id=%d:%08x\n",
msg->cli.node_id, msg->cli.port_id);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 96c4809..aa9b344 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -27,6 +27,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/krait-regulator.h>
+#include <mach/msm_iomap.h>
#include "spm.h"
@@ -87,6 +88,11 @@
#define CPU_TRGTD_DBG_RST 0x00000010
#define APC_PWR_GATE_CTL 0x00000014
#define APC_LDO_VREF_SET 0x00000018
+#define APC_PWR_GATE_MODE 0x0000001C
+#define APC_PWR_GATE_DLY 0x00000020
+
+#define PWR_GATE_CONFIG 0x00000044
+#define VERSION 0x00000FD0
/* bit definitions for APC_PWR_GATE_CTL */
#define BHS_CNT_BIT_POS 24
@@ -135,6 +141,7 @@
int pmic_phase_count;
struct list_head krait_power_vregs;
struct mutex krait_power_vregs_lock;
+ bool pfm_mode;
};
static struct pmic_gang_vreg *the_gang;
@@ -156,6 +163,8 @@
void __iomem *reg_base;
};
+static u32 version;
+
static void krait_masked_write(struct krait_power_vreg *kvreg,
int reg, uint32_t mask, uint32_t val)
{
@@ -534,6 +543,9 @@
return rc;
}
+#define PMIC_FTS_MODE_PFM 0x00
+#define PMIC_FTS_MODE_PWM 0x80
+#define PFM_LOAD_UA 500000
static unsigned int krait_power_get_optimum_mode(struct regulator_dev *rdev,
int input_uV, int output_uV, int load_uA)
{
@@ -545,10 +557,40 @@
mutex_lock(&pvreg->krait_power_vregs_lock);
+ reg_mode = kvreg->mode;
+
kvreg->load_uA = load_uA;
load_total_uA = get_total_load(kvreg);
+ if (load_total_uA < PFM_LOAD_UA) {
+ if (!pvreg->pfm_mode) {
+ rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
+ if (rc) {
+ dev_err(&rdev->dev,
+ "%s enter PFM failed load %d rc = %d\n",
+ kvreg->name, load_total_uA, rc);
+ goto out;
+ } else {
+ pvreg->pfm_mode = true;
+ }
+ }
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ return reg_mode;
+ }
+
+ if (pvreg->pfm_mode) {
+ rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PWM);
+ if (rc) {
+ dev_err(&rdev->dev,
+ "%s exit PFM failed load %d rc = %d\n",
+ kvreg->name, load_total_uA, rc);
+ goto out;
+ } else {
+ pvreg->pfm_mode = false;
+ }
+ }
+
rc = pmic_gang_set_phases(kvreg, load_total_uA);
if (rc < 0) {
dev_err(&rdev->dev, "%s failed set mode %d rc = %d\n",
@@ -556,7 +598,6 @@
goto out;
}
- reg_mode = kvreg->mode;
out:
mutex_unlock(&pvreg->krait_power_vregs_lock);
return reg_mode;
@@ -599,6 +640,15 @@
BHS_SEG_EN_MASK, BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS);
}
+static void glb_init(struct platform_device *pdev)
+{
+ /* configure bi-modal switch */
+ writel_relaxed(0x0008736E, MSM_APCS_GCC_BASE + PWR_GATE_CONFIG);
+ /* read kpss version */
+ version = readl_relaxed(MSM_APCS_GCC_BASE + VERSION);
+ pr_debug("version= 0x%x\n", version);
+}
+
static int __devinit krait_power_probe(struct platform_device *pdev)
{
struct krait_power_vreg *kvreg;
@@ -614,6 +664,8 @@
"failed to init pmic gang rc = %d\n", rc);
return rc;
}
+ /* global initializtion */
+ glb_init(pdev);
}
if (pdev->dev.of_node) {
@@ -738,8 +790,10 @@
{
/* 605mV retention and 705mV operational voltage */
writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
- writel_relaxed(0x430000, base_ptr + 0x20);
- writel_relaxed(0x21, base_ptr + 0x1C);
+ /* HS_EN_DLY=3; LDO_BYP_DLY=1; */
+ writel_relaxed(0x430000, base_ptr + APC_PWR_GATE_DLY);
+ /* MODE = BHS; EN=1; */
+ writel_relaxed(0x21, base_ptr + APC_PWR_GATE_MODE);
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index ea17efe..e0ab983 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -485,7 +485,7 @@
};
#define M_PRIOLVL_OVERRIDE_ADDR(b, n) \
- (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000220)
enum bimc_m_priolvl_override {
M_PRIOLVL_OVERRIDE_RMSK = 0x301,
M_PRIOLVL_OVERRIDE_BMSK = 0x300,
@@ -495,10 +495,10 @@
};
#define M_RD_CMD_OVERRIDE_ADDR(b, n) \
- (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
enum bimc_m_read_command_override {
- M_RD_CMD_OVERRIDE_RMSK = 0x3071f7f,
- M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000,
+ M_RD_CMD_OVERRIDE_RMSK = 0x37f3f,
+ M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x300000,
M_RD_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
M_RD_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
M_RD_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
@@ -529,15 +529,13 @@
};
#define M_WR_CMD_OVERRIDE_ADDR(b, n) \
- (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000250)
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
enum bimc_m_write_command_override {
- M_WR_CMD_OVERRIDE_RMSK = 0x3071f7f,
- M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000,
- M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
- M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
- M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
- M_WR_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000,
- M_WR_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc,
+ M_WR_CMD_OVERRIDE_RMSK = 0x37f3f,
+ M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x30000,
+ M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x10,
+ M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x7000,
+ M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0xc,
M_WR_CMD_OVERRIDE_ASHARED_BMSK = 0x800,
M_WR_CMD_OVERRIDE_ASHARED_SHFT = 0xb,
M_WR_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400,
@@ -546,10 +544,8 @@
M_WR_CMD_OVERRIDE_AOOO_SHFT = 0x9,
M_WR_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100,
M_WR_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8,
- M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40,
- M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6,
- M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20,
- M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x20,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x5,
M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10,
M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4,
M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8,
@@ -1458,7 +1454,7 @@
* boundary in future
*/
wmb();
- set_qos_mode(binfo->base, mas_index, 0, 1, 1);
+ set_qos_mode(binfo->base, mas_index, 1, 1, 1);
break;
case BIMC_QOS_MODE_BYPASS:
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index cfd84eb..f0f5cd8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -1049,8 +1049,9 @@
.qport = qports_kmpss,
.ws = 10000,
.mas_hw_id = MAS_APPSS_PROC,
- .prio_rd = 1,
- .prio_wr = 1,
+ .prio_lvl = 0,
+ .prio_rd = 2,
+ .prio_wr = 2,
},
{
.id = MSM_BUS_MASTER_AMPSS_M1,
@@ -1063,8 +1064,6 @@
.qport = qports_kmpss,
.ws = 10000,
.mas_hw_id = MAS_APPSS_PROC,
- .prio_rd = 1,
- .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_MSS_PROC,
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 5a85eec..3d9639f 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -404,7 +404,7 @@
if (offset < 0)
return -EINVAL;
- if (len < region_size)
+ if (len < OCMEM_MIN_ALLOC)
return -EINVAL;
pr_debug("ocmem: mode_transistion to %x\n", new_mode);
@@ -425,7 +425,7 @@
/* Set the region to its new mode */
region->mode = new_mode;
atomic_inc(®ion->mode_counter);
- pr_debug("Region (%d) switching to mode %d\n",
+ pr_debug("Region (%d) switching to mode %d\n",
i, new_mode);
continue;
} else if (region->mode != new_mode) {
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4aba69c..818a20a 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -58,6 +58,7 @@
#define BR_CLIENT_n_IDX(x) ((x) * 0x4)
#define BR_CLIENT_n_ctrl(x) (BR_CLIENT_BASE + (BR_CLIENT_n_IDX(x)))
#define BR_STATUS (0x14)
+#define BR_LAST_ADDR (0x18)
/* 16 entries per client are supported */
/* Use entries 0 - 15 for client0 */
#define BR_CLIENT0_MASK (0x1000)
@@ -76,7 +77,7 @@
#define BR_TBL_ENTRY_ENABLE 0x1
#define BR_TBL_START 0x0
#define BR_TBL_END 0x8
-#define BR_RW_SHIFT 0x2
+#define BR_RW_SHIFT 0x1
#define DM_TBL_START 0x10
#define DM_TBL_END 0x18
@@ -134,13 +135,13 @@
pr_debug("irq:dm_status %x irq_status %x\n", status, irq_status);
if (irq_status & BIT(0)) {
pr_debug("Data mover completed\n");
- irq_status &= ~BIT(0);
- ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ ocmem_write(BIT(0), dm_base + DM_INTR_CLR);
+ pr_debug("Last re-mapped address block %x\n",
+ ocmem_read(br_base + BR_LAST_ADDR));
complete(&dm_transfer_event);
} else if (irq_status & BIT(1)) {
pr_debug("Data clear engine completed\n");
- irq_status &= ~BIT(1);
- ocmem_write(irq_status, dm_base + DM_INTR_CLR);
+ ocmem_write(BIT(1), dm_base + DM_INTR_CLR);
complete(&dm_clear_event);
} else {
BUG_ON(1);
@@ -259,6 +260,7 @@
pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
wait_for_completion(&dm_transfer_event);
+ pr_debug("Completed transferring %d segments\n", num_chunks);
ocmem_disable_core_clock();
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index c380c54..38813e1 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -45,6 +45,7 @@
OP_COMPLETE = 0x0,
OP_RESCHED,
OP_PARTIAL,
+ OP_EVICT,
OP_FAIL = ~0x0,
};
@@ -74,7 +75,8 @@
* hardware state changes can occur. The value will be tweaked on actual
* hardware.
*/
-#define SCHED_DELAY 10
+/* Delay in ms for switching to low power mode for OCMEM */
+#define SCHED_DELAY 5000
static struct list_head rdm_queue;
static struct mutex rdm_mutex;
@@ -128,6 +130,7 @@
static struct rb_root sched_tree;
static struct mutex sched_mutex;
+static struct mutex allocation_mutex;
/* A region represents a continuous interval in OCMEM address space */
struct ocmem_region {
@@ -307,6 +310,7 @@
INIT_LIST_HEAD(&p->sched_list);
init_rwsem(&p->rw_sem);
SET_STATE(p, R_FREE);
+ pr_debug("request %p created\n", p);
return p;
}
@@ -594,6 +598,16 @@
if (rc < 0)
goto br_clock_fail;
+
+ rc = ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
+ get_mode(req->owner));
+
+ if (rc < 0) {
+ pr_err("ocmem: Failed to secure request %p for %d\n", req,
+ req->owner);
+ goto lock_failed;
+ }
+
rc = do_map(req);
if (rc < 0) {
@@ -602,19 +616,12 @@
goto process_map_fail;
}
-
- if (ocmem_lock(req->owner, phys_to_offset(req->req_start), req->req_sz,
- get_mode(req->owner))) {
- pr_err("ocmem: Failed to secure request %p for %d\n", req,
- req->owner);
- rc = -EINVAL;
- goto lock_failed;
- }
-
+ pr_debug("ocmem: Mapped request %p\n", req);
return 0;
-lock_failed:
- do_unmap(req);
+
process_map_fail:
+ ocmem_unlock(req->owner, phys_to_offset(req->req_start), req->req_sz);
+lock_failed:
ocmem_disable_br_clock();
br_clock_fail:
ocmem_disable_iface_clock();
@@ -630,22 +637,24 @@
{
int rc = 0;
- if (ocmem_unlock(req->owner, phys_to_offset(req->req_start),
- req->req_sz)) {
- pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
- req->owner);
- rc = -EINVAL;
- goto unlock_failed;
- }
-
rc = do_unmap(req);
if (rc < 0)
goto process_unmap_fail;
+ rc = ocmem_unlock(req->owner, phys_to_offset(req->req_start),
+ req->req_sz);
+
+ if (rc < 0) {
+ pr_err("ocmem: Failed to un-secure request %p for %d\n", req,
+ req->owner);
+ goto unlock_failed;
+ }
+
ocmem_disable_br_clock();
ocmem_disable_iface_clock();
ocmem_disable_core_clock();
+ pr_debug("ocmem: Unmapped request %p\n", req);
return 0;
unlock_failed:
@@ -1009,7 +1018,8 @@
retry = false;
- pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+ pr_debug("ocmem: do_allocate: %s request size %lx\n",
+ get_name(owner), sz);
retry_next_step:
@@ -1036,6 +1046,7 @@
/* update request state */
CLEAR_STATE(req, R_FREE);
+ CLEAR_STATE(req, R_PENDING);
SET_STATE(req, R_ALLOCATED);
SET_STATE(req, R_MUST_MAP);
req->op = SCHED_NOP;
@@ -1065,8 +1076,11 @@
/* resolve conflicting regions based on priority */
if (overlap_r->max_prio < prio) {
if (min == max) {
- pr_err("ocmem: Requires eviction support\n");
- goto err_not_supported;
+ req->req_start = zone->z_head;
+ req->req_end = zone->z_head + sz - 1;
+ req->req_sz = 0x0;
+ req->edata = NULL;
+ goto trigger_eviction;
} else {
/* Try to allocate atleast >= 'min' immediately */
sz -= step;
@@ -1109,6 +1123,11 @@
return OP_COMPLETE;
+trigger_eviction:
+ pr_debug("Trigger eviction of region %p\n", overlap_r);
+ destroy_region(region);
+ return OP_EVICT;
+
err_not_supported:
pr_err("ocmem: Scheduled unsupported operation\n");
return OP_FAIL;
@@ -1219,12 +1238,9 @@
if (rc < 0)
return -EINVAL;
- /* Map the newly grown region */
- if (is_tcm(req->owner)) {
- rc = process_map(req, req->req_start, req->req_end);
- if (rc < 0)
- return -EINVAL;
- }
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
offset = phys_to_offset(req->req_start);
@@ -1281,8 +1297,23 @@
static int ocmem_schedule_pending(void)
{
- schedule_delayed_work(&ocmem_sched_thread,
- msecs_to_jiffies(SCHED_DELAY));
+
+ bool need_sched = false;
+ int i = 0;
+
+ for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+ if (!list_empty(&sched_queue[i])) {
+ need_sched = true;
+ break;
+ }
+ }
+
+ if (need_sched == true) {
+ cancel_delayed_work(&ocmem_sched_thread);
+ schedule_delayed_work(&ocmem_sched_thread,
+ msecs_to_jiffies(SCHED_DELAY));
+ pr_debug("ocmem: Scheduled delayed work\n");
+ }
return 0;
}
@@ -1298,6 +1329,8 @@
goto err_free_fail;
}
+ pr_debug("ocmem: do_free: client %s req %p\n", get_name(req->owner),
+ req);
/* Grab the sched mutex */
mutex_lock(&sched_mutex);
rc = __sched_free(req);
@@ -1346,10 +1379,15 @@
return -EINVAL;
}
- if (is_tcm(req->owner)) {
+ if (!TEST_STATE(req, R_FREE)) {
+
rc = process_unmap(req, req->req_start, req->req_end);
if (rc < 0)
return -EINVAL;
+
+ rc = do_free(req);
+ if (rc < 0)
+ return -EINVAL;
}
if (req->req_sz != 0) {
@@ -1365,10 +1403,6 @@
}
- rc = do_free(req);
- if (rc < 0)
- return -EINVAL;
-
inc_ocmem_stat(zone_of(req), NR_FREES);
ocmem_destroy_req(req);
@@ -1437,18 +1471,10 @@
return -EINVAL;
if (!is_mapped(req)) {
- pr_err("Buffer is not already mapped\n");
+ pr_err("Buffer is not currently mapped\n");
goto transfer_out_error;
}
- rc = process_unmap(req, req->req_start, req->req_end);
- if (rc < 0) {
- pr_err("Unmapping the buffer failed\n");
- goto transfer_out_error;
- }
-
- inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
-
rc = queue_transfer(req, handle, list, TO_DDR);
if (rc < 0) {
@@ -1457,6 +1483,7 @@
goto transfer_out_error;
}
+ inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_DDR);
return 0;
transfer_out_error:
@@ -1474,19 +1501,14 @@
if (!req)
return -EINVAL;
- if (is_mapped(req)) {
- pr_err("Buffer is already mapped\n");
+
+ if (!is_mapped(req)) {
+ pr_err("Buffer is not already mapped for transfer\n");
goto transfer_in_error;
}
- rc = process_map(req, req->req_start, req->req_end);
- if (rc < 0) {
- pr_err("Mapping the buffer failed\n");
- goto transfer_in_error;
- }
inc_ocmem_stat(zone_of(req), NR_TRANSFERS_TO_OCMEM);
-
rc = queue_transfer(req, handle, list, TO_OCMEM);
if (rc < 0) {
@@ -1525,13 +1547,21 @@
edata = req->edata;
- if (is_tcm(req->owner))
- do_unmap(req);
+ if (!edata) {
+ pr_err("Unable to find eviction data\n");
+ return -EINVAL;
+ }
+
+ pr_debug("Found edata %p in request %p\n", edata, req);
inc_ocmem_stat(zone_of(req), NR_SHRINKS);
if (size == 0) {
- pr_info("req %p being shrunk to zero\n", req);
+ pr_debug("req %p being shrunk to zero\n", req);
+ if (is_mapped(req))
+ rc = process_unmap(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
rc = do_free(req);
if (rc < 0)
return -EINVAL;
@@ -1541,9 +1571,12 @@
return -EINVAL;
}
- edata->pending--;
- if (edata->pending == 0) {
- pr_debug("All regions evicted");
+ req->edata = NULL;
+ CLEAR_STATE(req, R_ALLOCATED);
+ SET_STATE(req, R_FREE);
+
+ if (atomic_dec_and_test(&edata->pending)) {
+ pr_debug("ocmem: All conflicting allocations were shrunk\n");
complete(&edata->completion);
}
@@ -1567,82 +1600,313 @@
return rc;
}
-int ocmem_eviction_thread(struct work_struct *work)
+static struct ocmem_eviction_data *init_eviction(int id)
{
+ struct ocmem_eviction_data *edata = NULL;
+ int prio = ocmem_client_table[id].priority;
+
+ edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+
+ if (!edata) {
+ pr_err("ocmem: Could not allocate eviction data\n");
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&edata->victim_list);
+ INIT_LIST_HEAD(&edata->req_list);
+ edata->prio = prio;
+ atomic_set(&edata->pending, 0);
+ return edata;
+}
+
+static void free_eviction(struct ocmem_eviction_data *edata)
+{
+
+ if (!edata)
+ return;
+
+ if (!list_empty(&edata->req_list))
+ pr_err("ocmem: Eviction data %p not empty\n", edata);
+
+ kfree(edata);
+ edata = NULL;
+}
+
+static bool is_overlapping(struct ocmem_req *new, struct ocmem_req *old)
+{
+
+ if (!new || !old)
+ return false;
+
+ pr_debug("check overlap [%lx -- %lx] on [%lx -- %lx]\n",
+ new->req_start, new->req_end,
+ old->req_start, old->req_end);
+
+ if ((new->req_start < old->req_start &&
+ new->req_end >= old->req_start) ||
+ (new->req_start >= old->req_start &&
+ new->req_start <= old->req_end &&
+ new->req_end >= old->req_end)) {
+ pr_debug("request %p overlaps with existing req %p\n",
+ new, old);
+ return true;
+ }
+ return false;
+}
+
+static int __evict_common(struct ocmem_eviction_data *edata,
+ struct ocmem_req *req)
+{
+ struct rb_node *rb_node = NULL;
+ struct ocmem_req *e_req = NULL;
+ bool needs_eviction = false;
+ int j = 0;
+
+ for (rb_node = rb_first(&sched_tree); rb_node;
+ rb_node = rb_next(rb_node)) {
+
+ struct ocmem_region *tmp_region = NULL;
+
+ tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+ if (tmp_region->max_prio < edata->prio) {
+ for (j = edata->prio - 1; j > NO_PRIO; j--) {
+ needs_eviction = false;
+ e_req = find_req_match(j, tmp_region);
+ if (!e_req)
+ continue;
+ if (edata->passive == true) {
+ needs_eviction = true;
+ } else {
+ needs_eviction = is_overlapping(req,
+ e_req);
+ }
+
+ if (needs_eviction) {
+ pr_debug("adding %p in region %p to eviction list\n",
+ e_req, tmp_region);
+ list_add_tail(
+ &e_req->eviction_list,
+ &edata->req_list);
+ atomic_inc(&edata->pending);
+ e_req->edata = edata;
+ }
+ }
+ } else {
+ pr_debug("Skipped region %p\n", tmp_region);
+ }
+ }
+
+ pr_debug("%d requests will be evicted\n", atomic_read(&edata->pending));
+
+ if (!atomic_read(&edata->pending))
+ return -EINVAL;
return 0;
}
+static void trigger_eviction(struct ocmem_eviction_data *edata)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+ struct ocmem_buf buffer;
+
+ if (!edata)
+ return;
+
+ BUG_ON(atomic_read(&edata->pending) == 0);
+
+ init_completion(&edata->completion);
+
+ list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+ {
+ if (req) {
+ pr_debug("ocmem: Evicting request %p\n", req);
+ buffer.addr = req->req_start;
+ buffer.len = 0x0;
+ dispatch_notification(req->owner, OCMEM_ALLOC_SHRINK,
+ &buffer);
+ }
+ }
+ return;
+}
+
int process_evict(int id)
{
struct ocmem_eviction_data *edata = NULL;
- int prio = ocmem_client_table[id].priority;
- struct rb_node *rb_node = NULL;
- struct ocmem_req *req = NULL;
- struct ocmem_buf buffer;
- int j = 0;
+ int rc = 0;
- edata = kzalloc(sizeof(struct ocmem_eviction_data), GFP_ATOMIC);
+ edata = init_eviction(id);
- INIT_LIST_HEAD(&edata->victim_list);
- INIT_LIST_HEAD(&edata->req_list);
- edata->prio = prio;
- edata->pending = 0;
- edata->passive = 1;
- evictions[id] = edata;
+ if (!edata)
+ return -EINVAL;
+
+ edata->passive = true;
mutex_lock(&sched_mutex);
- for (rb_node = rb_first(&sched_tree); rb_node;
- rb_node = rb_next(rb_node)) {
- struct ocmem_region *tmp_region = NULL;
- tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
- if (tmp_region->max_prio < prio) {
- for (j = id - 1; j > NO_PRIO; j--) {
- req = find_req_match(j, tmp_region);
- if (req) {
- pr_info("adding %p to eviction list\n",
- tmp_region);
- list_add_tail(
- &tmp_region->eviction_list,
- &edata->victim_list);
- list_add_tail(
- &req->eviction_list,
- &edata->req_list);
- edata->pending++;
- req->edata = edata;
- buffer.addr = req->req_start;
- buffer.len = 0x0;
- inc_ocmem_stat(zone_of(req),
- NR_EVICTIONS);
- dispatch_notification(req->owner,
- OCMEM_ALLOC_SHRINK, &buffer);
- }
- }
- } else {
- pr_info("skipping %p from eviction\n", tmp_region);
+ rc = __evict_common(edata, NULL);
+
+ if (rc < 0)
+ goto skip_eviction;
+
+ trigger_eviction(edata);
+
+ evictions[id] = edata;
+
+ mutex_unlock(&sched_mutex);
+
+ wait_for_completion(&edata->completion);
+
+ return 0;
+
+skip_eviction:
+ evictions[id] = NULL;
+ mutex_unlock(&sched_mutex);
+ return 0;
+}
+
+static int run_evict(struct ocmem_req *req)
+{
+ struct ocmem_eviction_data *edata = NULL;
+ int rc = 0;
+
+ if (!req)
+ return -EINVAL;
+
+ edata = init_eviction(req->owner);
+
+ if (!edata)
+ return -EINVAL;
+
+ edata->passive = false;
+
+ rc = __evict_common(edata, req);
+
+ if (rc < 0)
+ goto skip_eviction;
+
+ trigger_eviction(edata);
+
+ pr_debug("ocmem: attaching eviction %p to request %p", edata, req);
+ req->edata = edata;
+
+ wait_for_completion(&edata->completion);
+
+ pr_debug("ocmem: eviction completed successfully\n");
+ return 0;
+
+skip_eviction:
+ pr_err("ocmem: Unable to run eviction\n");
+ free_eviction(edata);
+ return -EINVAL;
+}
+
+static int __restore_common(struct ocmem_eviction_data *edata)
+{
+
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+
+ if (!edata)
+ return -EINVAL;
+
+ list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
+ {
+ if (req) {
+ pr_debug("ocmem: restoring evicted request %p\n",
+ req);
+ list_del(&req->eviction_list);
+ req->op = SCHED_ALLOCATE;
+ sched_enqueue(req);
+ inc_ocmem_stat(zone_of(req), NR_RESTORES);
}
}
- mutex_unlock(&sched_mutex);
- pr_debug("Waiting for all regions to be shrunk\n");
- if (edata->pending > 0) {
- init_completion(&edata->completion);
- wait_for_completion(&edata->completion);
+
+ pr_debug("Scheduled all evicted regions\n");
+
+ return 0;
+}
+
+static int sched_restore(struct ocmem_req *req)
+{
+
+ int rc = 0;
+
+ if (!req)
+ return -EINVAL;
+
+ if (!req->edata)
+ return 0;
+
+ rc = __restore_common(req->edata);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ free_eviction(req->edata);
+ return 0;
+}
+
+int process_restore(int id)
+{
+ struct ocmem_eviction_data *edata = evictions[id];
+ int rc = 0;
+
+ if (!edata)
+ return -EINVAL;
+
+ rc = __restore_common(edata);
+
+ if (rc < 0) {
+ pr_err("Failed to restore evicted requests\n");
+ return -EINVAL;
}
+
+ free_eviction(edata);
+ evictions[id] = NULL;
+ ocmem_schedule_pending();
return 0;
}
static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
{
int rc = 0;
+ int ret = 0;
struct ocmem_buf *buffer = req->buffer;
down_write(&req->rw_sem);
+ mutex_lock(&allocation_mutex);
+retry_allocate:
+
/* Take the scheduler mutex */
mutex_lock(&sched_mutex);
rc = __sched_allocate(req, can_block, can_wait);
mutex_unlock(&sched_mutex);
+ if (rc == OP_EVICT) {
+
+ ret = run_evict(req);
+
+ if (ret == 0) {
+ rc = sched_restore(req);
+ if (rc < 0) {
+ pr_err("Failed to restore for req %p\n", req);
+ goto err_allocate_fail;
+ }
+ req->edata = NULL;
+
+ pr_debug("Attempting to re-allocate req %p\n", req);
+ req->req_start = 0x0;
+ req->req_end = 0x0;
+ goto retry_allocate;
+ } else {
+ goto err_allocate_fail;
+ }
+ }
+
+ mutex_unlock(&allocation_mutex);
+
if (rc == OP_FAIL) {
inc_ocmem_stat(zone_of(req), NR_ALLOCATION_FAILS);
goto err_allocate_fail;
@@ -1667,6 +1931,7 @@
up_write(&req->rw_sem);
return 0;
err_allocate_fail:
+ mutex_unlock(&allocation_mutex);
up_write(&req->rw_sem);
return -EINVAL;
}
@@ -1699,33 +1964,6 @@
return -EINVAL;
}
-int process_restore(int id)
-{
- struct ocmem_req *req = NULL;
- struct ocmem_req *next = NULL;
- struct ocmem_eviction_data *edata = evictions[id];
-
- if (!edata)
- return 0;
-
- list_for_each_entry_safe(req, next, &edata->req_list, eviction_list)
- {
- if (req) {
- pr_debug("ocmem: Fetched evicted request %p\n",
- req);
- list_del(&req->sched_list);
- req->op = SCHED_ALLOCATE;
- sched_enqueue(req);
- inc_ocmem_stat(zone_of(req), NR_RESTORES);
- }
- }
- kfree(edata);
- evictions[id] = NULL;
- pr_debug("Restore all evicted regions\n");
- ocmem_schedule_pending();
- return 0;
-}
-
int process_allocate(int id, struct ocmem_handle *handle,
unsigned long min, unsigned long max,
unsigned long step, bool can_block, bool can_wait)
@@ -1774,13 +2012,11 @@
handle->req = req;
- if (is_tcm(id)) {
+ if (req->req_sz != 0) {
+
rc = process_map(req, req->req_start, req->req_end);
if (rc < 0)
goto map_error;
- }
-
- if (req->req_sz != 0) {
offset = phys_to_offset(req->req_start);
@@ -1795,6 +2031,7 @@
return 0;
power_ctl_error:
+ process_unmap(req, req->req_start, req->req_end);
map_error:
handle->req = NULL;
do_free(req);
@@ -1819,15 +2056,18 @@
if (rc < 0)
goto do_allocate_error;
+ /* The request can still be pending */
+ if (TEST_STATE(req, R_PENDING))
+ return 0;
+
inc_ocmem_stat(zone_of(req), NR_ASYNC_ALLOCATIONS);
- if (is_tcm(id)) {
+ if (req->req_sz != 0) {
+
rc = process_map(req, req->req_start, req->req_end);
if (rc < 0)
goto map_error;
- }
- if (req->req_sz != 0) {
offset = phys_to_offset(req->req_start);
@@ -1849,6 +2089,7 @@
return 0;
power_ctl_error:
+ process_unmap(req, req->req_start, req->req_end);
map_error:
handle->req = NULL;
do_free(req);
@@ -1965,6 +2206,7 @@
sched_tree = RB_ROOT;
pdata = platform_get_drvdata(pdev);
+ mutex_init(&allocation_mutex);
mutex_init(&sched_mutex);
mutex_init(&sched_queue_mutex);
ocmem_vaddr = pdata->vbase;
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 8432328..daafd1d 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -57,6 +57,7 @@
void __iomem *metadata_base;
unsigned long metadata_phys;
struct pil_device *pil;
+ struct pil_desc desc;
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
struct clk *xo;
@@ -294,6 +295,23 @@
return IRQ_HANDLED;
}
+static int mss_start(const struct subsys_desc *desc)
+{
+ void *ret;
+ struct mba_data *drv = subsys_to_drv(desc);
+
+ ret = pil_get(drv->desc.name);
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void mss_stop(const struct subsys_desc *desc)
+{
+ struct mba_data *drv = subsys_to_drv(desc);
+ pil_put(drv->pil);
+}
+
static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
@@ -328,10 +346,7 @@
drv->metadata_phys = res->start;
}
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!drv)
- return -ENOMEM;
-
+ desc = &drv->desc;
ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
&desc->name);
if (ret)
@@ -360,6 +375,8 @@
drv->subsys_desc.powerup = modem_powerup;
drv->subsys_desc.ramdump = modem_ramdump;
drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+ drv->subsys_desc.start = mss_start;
+ drv->subsys_desc.stop = mss_stop;
drv->ramdump_dev = create_ramdump_device("modem");
if (!drv->ramdump_dev) {
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index ecb3800..ad27cd1 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -342,6 +342,26 @@
return NOTIFY_DONE;
}
+static int modem_start(const struct subsys_desc *subsys)
+{
+ void *ret;
+ struct modem_data *drv;
+
+ drv = container_of(subsys, struct modem_data, subsys_desc);
+ ret = pil_get("modem");
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void modem_stop(const struct subsys_desc *subsys)
+{
+ struct modem_data *drv;
+
+ drv = container_of(subsys, struct modem_data, subsys_desc);
+ pil_put(drv->pil);
+}
+
static int modem_shutdown(const struct subsys_desc *subsys)
{
struct modem_data *drv;
@@ -467,6 +487,11 @@
goto err_notify;
drv->subsys_desc.name = "modem";
+ drv->subsys_desc.depends_on = "q6";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = modem_start;
+ drv->subsys_desc.stop = modem_stop;
drv->subsys_desc.shutdown = modem_shutdown;
drv->subsys_desc.powerup = modem_powerup;
drv->subsys_desc.ramdump = modem_ramdump;
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 5685787..04b3a21 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -27,6 +27,7 @@
#include <linux/workqueue.h>
#include <linux/wcnss_wlan.h>
+#include <mach/peripheral-loader.h>
#include <mach/subsystem_restart.h>
#include <mach/peripheral-loader.h>
#include <mach/msm_smsm.h>
@@ -75,6 +76,7 @@
void __iomem *axi_halt_base;
unsigned long start_addr;
struct pil_device *pil;
+ struct pil_desc desc;
struct subsys_device *subsys;
struct subsys_desc subsys_desc;
struct clk *cxo;
@@ -241,6 +243,23 @@
#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
+static int pronto_start(const struct subsys_desc *desc)
+{
+ void *ret;
+ struct pronto_data *drv = subsys_to_drv(desc);
+
+ ret = pil_get(drv->desc.name);
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void pronto_stop(const struct subsys_desc *desc)
+{
+ struct pronto_data *drv = subsys_to_drv(desc);
+ pil_put(drv->pil);
+}
+
static void log_wcnss_sfr(void)
{
char *smem_reset_reason;
@@ -401,10 +420,7 @@
drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
+ desc = &drv->desc;
ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
&desc->name);
if (ret)
@@ -456,6 +472,8 @@
drv->subsys_desc.powerup = wcnss_powerup;
drv->subsys_desc.ramdump = wcnss_ramdump;
drv->subsys_desc.crash_shutdown = crash_shutdown;
+ drv->subsys_desc.start = pronto_start;
+ drv->subsys_desc.stop = pronto_stop;
INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 1a226de..9de9c60 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -248,6 +248,26 @@
pr_info("Q6 NMI was sent.\n");
}
+static int lpass_q6_start(const struct subsys_desc *subsys)
+{
+ void *ret;
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ ret = pil_get("q6");
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void lpass_q6_stop(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ pil_put(drv->pil);
+}
+
static int lpass_q6_shutdown(const struct subsys_desc *subsys)
{
struct q6v3_data *drv;
@@ -377,6 +397,10 @@
return PTR_ERR(drv->pil);
drv->subsys_desc.name = "lpass";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = lpass_q6_start;
+ drv->subsys_desc.stop = lpass_q6_stop;
drv->subsys_desc.shutdown = lpass_q6_shutdown;
drv->subsys_desc.powerup = lpass_q6_powerup;
drv->subsys_desc.ramdump = lpass_q6_ramdump;
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index a0432550..8164d64 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -43,6 +43,7 @@
void *ramdump_dev;
struct work_struct work;
int loadable;
+ void *pil;
};
static int pil_q6v4_lpass_boot(struct pil_desc *pil)
@@ -192,6 +193,25 @@
#define subsys_to_lpass(d) container_of(d, struct lpass_q6v4, subsys_desc)
+static int lpass_start(const struct subsys_desc *desc)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(desc);
+
+ if (drv->loadable) {
+ drv->pil = pil_get("q6");
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+ }
+ return 0;
+}
+
+static void lpass_stop(const struct subsys_desc *desc)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(desc);
+ if (drv->loadable)
+ pil_put(drv->pil);
+}
+
static int lpass_shutdown(const struct subsys_desc *subsys)
{
struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
@@ -306,6 +326,10 @@
}
drv->subsys_desc.name = "lpass";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = lpass_start;
+ drv->subsys_desc.stop = lpass_stop;
drv->subsys_desc.shutdown = lpass_shutdown;
drv->subsys_desc.powerup = lpass_powerup;
drv->subsys_desc.ramdump = lpass_ramdump;
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index 61b5536..fe8c3b1 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -48,6 +48,7 @@
struct subsys_desc subsys_desc;
int crash_shutdown;
int loadable;
+ void *pil;
};
static DEFINE_MUTEX(pil_q6v4_modem_lock);
@@ -169,6 +170,25 @@
#define desc_to_modem(d) container_of(d, struct q6v4_modem, subsys_desc)
+static int modem_start(const struct subsys_desc *desc)
+{
+ struct q6v4_modem *drv = desc_to_modem(desc);
+
+ if (drv->loadable) {
+ drv->pil = pil_get("modem");
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+ }
+ return 0;
+}
+
+static void modem_stop(const struct subsys_desc *desc)
+{
+ struct q6v4_modem *drv = desc_to_modem(desc);
+ if (drv->loadable)
+ pil_put(drv->pil);
+}
+
static int modem_shutdown(const struct subsys_desc *subsys)
{
struct q6v4_modem *drv = desc_to_modem(subsys);
@@ -396,6 +416,11 @@
}
drv->subsys_desc.name = "modem";
+ drv->subsys_desc.depends_on = "lpass";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = modem_start;
+ drv->subsys_desc.stop = modem_stop;
drv->subsys_desc.shutdown = modem_shutdown;
drv->subsys_desc.powerup = modem_powerup;
drv->subsys_desc.ramdump = modem_ramdump;
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index c48ea02..3c68da0 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -337,6 +337,23 @@
return IRQ_HANDLED;
}
+static int lpass_start(const struct subsys_desc *desc)
+{
+ void *ret;
+ struct lpass_data *drv = subsys_to_drv(desc);
+
+ ret = pil_get(drv->q6->desc.name);
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void lpass_stop(const struct subsys_desc *desc)
+{
+ struct lpass_data *drv = subsys_to_drv(desc);
+ pil_put(drv->q6->pil);
+}
+
static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
{
struct lpass_data *drv;
@@ -397,6 +414,8 @@
drv->subsys_desc.powerup = adsp_powerup;
drv->subsys_desc.ramdump = adsp_ramdump;
drv->subsys_desc.crash_shutdown = adsp_crash_shutdown;
+ drv->subsys_desc.start = lpass_start;
+ drv->subsys_desc.stop = lpass_stop;
INIT_WORK(&drv->work, adsp_fatal_fn);
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index dbb4408..a0e39ea 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -372,6 +372,27 @@
wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
}
+static int riva_start(const struct subsys_desc *desc)
+{
+ void *ret;
+ struct riva_data *drv;
+
+ drv = container_of(desc, struct riva_data, subsys_desc);
+
+ ret = pil_get("wcnss");
+ if (IS_ERR(ret))
+ return PTR_ERR(ret);
+ return 0;
+}
+
+static void riva_stop(const struct subsys_desc *desc)
+{
+ struct riva_data *drv;
+
+ drv = container_of(desc, struct riva_data, subsys_desc);
+ pil_put(drv->pil);
+}
+
static int riva_shutdown(const struct subsys_desc *desc)
{
struct riva_data *drv;
@@ -515,6 +536,10 @@
goto err_smsm;
drv->subsys_desc.name = "wcnss";
+ drv->subsys_desc.dev = &pdev->dev;
+ drv->subsys_desc.owner = THIS_MODULE;
+ drv->subsys_desc.start = riva_start;
+ drv->subsys_desc.stop = riva_stop;
drv->subsys_desc.shutdown = riva_shutdown;
drv->subsys_desc.powerup = riva_powerup;
drv->subsys_desc.ramdump = riva_ramdump;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index b865daa..62085f6 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -272,6 +272,7 @@
/* 9625 IDs */
[134] = MSM_CPU_9625,
+ [152] = MSM_CPU_9625,
/* 8960AB IDs */
[138] = MSM_CPU_8960AB,
@@ -283,6 +284,7 @@
[142] = MSM_CPU_8930AA,
[143] = MSM_CPU_8930AA,
[144] = MSM_CPU_8930AA,
+ [160] = MSM_CPU_8930AA,
/* 8226 IDs */
[145] = MSM_CPU_8226,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d0817b2..18784ac 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1400,6 +1400,11 @@
} else {
adreno_context = context->devctxt;
adreno_context->flags |= CTXT_FLAGS_GPU_HANG;
+ /*
+ * set the invalid ts flag to 0 for this context since we have
+ * detected a hang for it
+ */
+ context->wait_on_invalid_ts = false;
}
/* Extract valid contents from rb which can still be executed after
@@ -2193,14 +2198,24 @@
if (timestamp_cmp(timestamp, ts_issued) > 0) {
if (adreno_ctx == NULL ||
!(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
- KGSL_DRV_ERR(device,
+ if (context && !context->wait_on_invalid_ts) {
+ KGSL_DRV_ERR(device,
"Cannot wait for invalid ts <%d:0x%x>, "
"last issued ts <%d:0x%x>\n",
context_id, timestamp, context_id, ts_issued);
+ /*
+ * Prevent the above message from spamming the
+ * kernel logs and causing a watchdog
+ */
+ context->wait_on_invalid_ts = true;
+ }
status = -EINVAL;
goto done;
} else
retry_ts_cmp = 1;
+ } else if (context && context->wait_on_invalid_ts) {
+ /* Once we wait for a valid ts reset the invalid wait flag */
+ context->wait_on_invalid_ts = false;
}
/*
@@ -2276,13 +2291,19 @@
ts_issued =
adreno_dev->ringbuffer.timestamp[context_id];
if (timestamp_cmp(timestamp, ts_issued) > 0) {
- KGSL_DRV_ERR(device,
- "Cannot wait for user-generated ts <%d:0x%x>, "
- "not submitted within server timeout period. "
- "last issued ts <%d:0x%x>\n",
- context_id, timestamp, context_id, ts_issued);
+ if (context && !context->wait_on_invalid_ts) {
+ KGSL_DRV_ERR(device,
+ "Cannot wait for user-generated ts <%d:0x%x>, "
+ "not submitted within server timeout period. "
+ "last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id,
+ ts_issued);
+ context->wait_on_invalid_ts = true;
+ }
status = -EINVAL;
goto done;
+ } else if (context && context->wait_on_invalid_ts) {
+ context->wait_on_invalid_ts = false;
}
retry_ts_cmp = 0;
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index afe384b..7194e47 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1469,11 +1469,10 @@
}
static int memdesc_sg_virt(struct kgsl_memdesc *memdesc,
- void *addr, int size)
+ unsigned long paddr, int size)
{
int i;
int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
- unsigned long paddr = (unsigned long) addr;
memdesc->sg = kgsl_sg_alloc(sglen);
@@ -1524,34 +1523,33 @@
return -EINVAL;
}
-static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry,
+static int kgsl_setup_useraddr(struct kgsl_mem_entry *entry,
struct kgsl_pagetable *pagetable,
- void *hostptr, unsigned int offset,
+ unsigned long useraddr, unsigned int offset,
size_t size)
{
struct vm_area_struct *vma;
unsigned int len;
down_read(¤t->mm->mmap_sem);
- vma = find_vma(current->mm, (unsigned int) hostptr);
+ vma = find_vma(current->mm, useraddr);
up_read(¤t->mm->mmap_sem);
if (!vma) {
- KGSL_CORE_ERR("find_vma(%p) failed\n", hostptr);
+ KGSL_CORE_ERR("find_vma(%lx) failed\n", useraddr);
return -EINVAL;
}
/* We don't necessarily start at vma->vm_start */
- len = vma->vm_end - (unsigned long) hostptr;
+ len = vma->vm_end - useraddr;
if (offset >= len)
return -EINVAL;
- if (!KGSL_IS_PAGE_ALIGNED((unsigned long) hostptr) ||
+ if (!KGSL_IS_PAGE_ALIGNED(useraddr) ||
!KGSL_IS_PAGE_ALIGNED(len)) {
- KGSL_CORE_ERR("user address len(%u)"
- "and start(%p) must be page"
- "aligned\n", len, hostptr);
+ KGSL_CORE_ERR("bad alignment: start(%lx) len(%u)\n",
+ useraddr, len);
return -EINVAL;
}
@@ -1572,28 +1570,27 @@
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = size;
- entry->memdesc.hostptr = hostptr + (offset & PAGE_MASK);
+ entry->memdesc.useraddr = useraddr + (offset & PAGE_MASK);
- return memdesc_sg_virt(&entry->memdesc,
- hostptr + (offset & PAGE_MASK), size);
+ return memdesc_sg_virt(&entry->memdesc, entry->memdesc.useraddr,
+ size);
}
#ifdef CONFIG_ASHMEM
static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
struct kgsl_pagetable *pagetable,
- int fd, void *hostptr, size_t size)
+ int fd, unsigned long useraddr, size_t size)
{
int ret;
struct vm_area_struct *vma;
struct file *filep, *vmfile;
unsigned long len;
- unsigned int hostaddr = (unsigned int) hostptr;
- vma = kgsl_get_vma_from_start_addr(hostaddr);
+ vma = kgsl_get_vma_from_start_addr(useraddr);
if (vma == NULL)
return -EINVAL;
- if (vma->vm_pgoff || vma->vm_start != hostaddr) {
+ if (vma->vm_pgoff || vma->vm_start != useraddr) {
KGSL_CORE_ERR("Invalid vma region\n");
return -EINVAL;
}
@@ -1604,8 +1601,8 @@
size = len;
if (size != len) {
- KGSL_CORE_ERR("Invalid size %d for vma region %p\n",
- size, hostptr);
+ KGSL_CORE_ERR("Invalid size %d for vma region %lx\n",
+ size, useraddr);
return -EINVAL;
}
@@ -1625,9 +1622,9 @@
entry->priv_data = filep;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = ALIGN(size, PAGE_SIZE);
- entry->memdesc.hostptr = hostptr;
+ entry->memdesc.useraddr = useraddr;
- ret = memdesc_sg_virt(&entry->memdesc, hostptr, size);
+ ret = memdesc_sg_virt(&entry->memdesc, useraddr, size);
if (ret)
goto err;
@@ -1640,7 +1637,7 @@
#else
static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
struct kgsl_pagetable *pagetable,
- int fd, void *hostptr, size_t size)
+ int fd, unsigned long useraddr, size_t size)
{
return -EINVAL;
}
@@ -1737,8 +1734,8 @@
if (param->hostptr == 0)
break;
- result = kgsl_setup_hostptr(entry, private->pagetable,
- (void *) param->hostptr,
+ result = kgsl_setup_useraddr(entry, private->pagetable,
+ param->hostptr,
param->offset, param->len);
entry->memtype = KGSL_MEM_ENTRY_USER;
break;
@@ -1755,7 +1752,7 @@
break;
result = kgsl_setup_ashmem(entry, private->pagetable,
- param->fd, (void *) param->hostptr,
+ param->fd, param->hostptr,
param->len);
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
@@ -2232,6 +2229,8 @@
kgsl_gpumem_vm_close(struct vm_area_struct *vma)
{
struct kgsl_mem_entry *entry = vma->vm_private_data;
+
+ entry->memdesc.useraddr = 0;
kgsl_mem_entry_put(entry);
}
@@ -2243,6 +2242,7 @@
static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
{
+ unsigned int ret;
unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
struct kgsl_device_private *dev_priv = file->private_data;
struct kgsl_process_private *private = dev_priv->process_priv;
@@ -2269,8 +2269,20 @@
if (!entry->memdesc.ops ||
!entry->memdesc.ops->vmflags ||
- !entry->memdesc.ops->vmfault)
- return -EINVAL;
+ !entry->memdesc.ops->vmfault) {
+ ret = -EINVAL;
+ goto err_put;
+ }
+
+ if (entry->memdesc.useraddr != 0) {
+ ret = -EBUSY;
+ goto err_put;
+ }
+
+ if (entry->memdesc.size != (vma->vm_end - vma->vm_start)) {
+ ret = -ERANGE;
+ goto err_put;
+ }
vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc);
@@ -2279,7 +2291,12 @@
vma->vm_ops = &kgsl_gpumem_vm_ops;
vma->vm_file = file;
+ entry->memdesc.useraddr = vma->vm_start;
+
return 0;
+err_put:
+ kgsl_mem_entry_put(entry);
+ return ret;
}
static irqreturn_t kgsl_irq_handler(int irq, void *data)
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 2861117..56950a6 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -129,7 +129,8 @@
/* shared memory allocation */
struct kgsl_memdesc {
struct kgsl_pagetable *pagetable;
- void *hostptr;
+ void *hostptr; /* kernel virtual address */
+ unsigned long useraddr; /* userspace address */
unsigned int gpuaddr;
unsigned int physaddr;
unsigned int size;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 4394118..d962bf1 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -235,7 +235,8 @@
* context was responsible for causing it
*/
unsigned int reset_status;
-
+ /* Flag indicating if we tried to wait for bad timestamp for this ctx */
+ bool wait_on_invalid_ts;
/*
* Timeline used to create fences that can be signaled when a
* sync_pt timestamp expires.
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 77617ba..53dc468 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -514,18 +514,19 @@
void *addr = memdesc->hostptr;
int size = memdesc->size;
- switch (op) {
- case KGSL_CACHE_OP_FLUSH:
- dmac_flush_range(addr, addr + size);
- break;
- case KGSL_CACHE_OP_CLEAN:
- dmac_clean_range(addr, addr + size);
- break;
- case KGSL_CACHE_OP_INV:
- dmac_inv_range(addr, addr + size);
- break;
+ if (addr != NULL) {
+ switch (op) {
+ case KGSL_CACHE_OP_FLUSH:
+ dmac_flush_range(addr, addr + size);
+ break;
+ case KGSL_CACHE_OP_CLEAN:
+ dmac_clean_range(addr, addr + size);
+ break;
+ case KGSL_CACHE_OP_INV:
+ dmac_inv_range(addr, addr + size);
+ break;
+ }
}
-
outer_cache_range_op_sg(memdesc->sg, memdesc->sglen, op);
}
EXPORT_SYMBOL(kgsl_cache_range_op);
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index e4f00c0..68af7e1 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -272,23 +272,27 @@
static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed)
{
struct mpq_demux *mpq_demux = feed->demux->priv;
- enum tspp_source tspp_source;
+ struct tspp_select_source tspp_source;
struct tspp_filter tspp_filter;
int tsif;
int ret;
int channel_id;
int *channel_ref_count;
- enum tspp_tsif_mode mode;
+
+ tspp_source.clk_inverse = 0;
+ tspp_source.data_inverse = 0;
+ tspp_source.sync_inverse = 0;
+ tspp_source.enable_inverse = 0;
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
- tspp_source = TSPP_SOURCE_TSIF0;
- mode = (enum tspp_tsif_mode)tsif0_mode;
+ tspp_source.source = TSPP_SOURCE_TSIF0;
+ tspp_source.mode = (enum tspp_tsif_mode)tsif0_mode;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
- tspp_source = TSPP_SOURCE_TSIF1;
- mode = (enum tspp_tsif_mode)tsif1_mode;
+ tspp_source.source = TSPP_SOURCE_TSIF1;
+ tspp_source.mode = (enum tspp_tsif_mode)tsif1_mode;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
@@ -341,13 +345,13 @@
}
/* set TSPP source */
- ret = tspp_open_stream(0, channel_id, tspp_source, mode);
+ ret = tspp_open_stream(0, channel_id, &tspp_source);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tspp_select_source(%d,%d) failed (%d)\n",
__func__,
channel_id,
- tspp_source,
+ tspp_source.source,
ret);
goto add_channel_close_ch;
@@ -418,7 +422,7 @@
* accordingly.
*/
tspp_filter.mode = TSPP_MODE_RAW;
- tspp_filter.source = tspp_source;
+ tspp_filter.source = tspp_source.source;
tspp_filter.decrypt = 0;
ret = tspp_add_filter(0, channel_id, &tspp_filter);
if (ret < 0) {
@@ -553,6 +557,7 @@
/* channel is not used any more, release it */
tspp_unregister_notification(0, channel_id);
tspp_close_channel(0, channel_id);
+ tspp_close_stream(0, channel_id);
}
mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index 4628ba7..22d37e9 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -2085,7 +2085,7 @@
struct video_event *ev)
{
int rc;
- struct vdec_msginfo vdec_msg_info;
+ struct vdec_msginfo vdec_msg_info = {};
memset(ev, 0, sizeof(struct video_event));
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 77922e2..48ce577 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -426,6 +426,10 @@
stats.aec.buff = stats.buffer;
stats.aec.fd = stats.fd;
break;
+ case MSG_ID_STATS_BE:
+ stats.be.buff = stats.buffer;
+ stats.be.fd = stats.fd;
+ break;
case MSG_ID_STATS_AF:
case MSG_ID_STATS_BF:
stats.af.buff = stats.buffer;
@@ -514,6 +518,7 @@
CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
switch (cfgcmd.cmd_type) {
case CMD_STATS_BG_ENABLE:
+ case CMD_STATS_BE_ENABLE:
case CMD_STATS_BF_ENABLE:
case CMD_STATS_BHIST_ENABLE:
case CMD_STATS_AF_ENABLE:
@@ -611,6 +616,8 @@
cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
else if (buf.type == STAT_BG)
cfgcmd.cmd_type = CMD_STATS_BG_BUF_RELEASE;
+ else if (buf.type == STAT_BE)
+ cfgcmd.cmd_type = CMD_STATS_BE_BUF_RELEASE;
else if (buf.type == STAT_BF)
cfgcmd.cmd_type = CMD_STATS_BF_BUF_RELEASE;
else if (buf.type == STAT_BHIST)
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 1875df2..e131193 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -210,6 +210,7 @@
case MSM_PMEM_SKIN:
case MSM_PMEM_AEC_AWB:
case MSM_PMEM_BAYER_GRID:
+ case MSM_PMEM_BAYER_EXPOSURE:
case MSM_PMEM_BAYER_FOCUS:
case MSM_PMEM_BAYER_HIST:
rc = msm_pmem_table_add(ptype, pinfo, client, domain_num);
@@ -241,6 +242,7 @@
case MSM_PMEM_SKIN:
case MSM_PMEM_AEC_AWB:
case MSM_PMEM_BAYER_GRID:
+ case MSM_PMEM_BAYER_EXPOSURE:
case MSM_PMEM_BAYER_FOCUS:
case MSM_PMEM_BAYER_HIST:
hlist_for_each_entry_safe(region, node, n,
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 6091a0d..287c77c 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -254,6 +254,8 @@
V40_COLORXFORM_ENC_CFG_OFF, 0xFF},
[161] = {VFE_CMD_COLORXFORM_VIEW_UPDATE, V40_COLORXFORM_VIEW_CFG_LEN,
V40_COLORXFORM_VIEW_CFG_OFF, 0xFF},
+ [163] = {VFE_CMD_STATS_BE_START, V40_STATS_BE_LEN, V40_STATS_BE_OFF},
+ [164] = {VFE_CMD_STATS_BE_STOP},
};
static const uint32_t vfe40_AXI_WM_CFG[] = {
@@ -818,29 +820,34 @@
CDBG("%s: Use bayer stats = %d\n", __func__,
vfe40_use_bayer_stats(vfe40_ctrl));
- msm_camera_io_w(0x8350001F,
- vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_HIST_WR_UB_CFG);
- msm_camera_io_w(0x8370002F,
- vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_BG_WR_UB_CFG);
- msm_camera_io_w(0x83A0002F,
- vfe40_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_BF_WR_UB_CFG);
- msm_camera_io_w(0x83D0000F,
+ msm_camera_io_w(0x82F80007,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_RS_WR_UB_CFG);
- msm_camera_io_w(0x83E00007,
+ msm_camera_io_w(0x8300000F,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_CS_WR_UB_CFG);
- msm_camera_io_w(0x83E80007,
+
+ msm_camera_io_w(0x8310003F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BG_WR_UB_CFG);
+ msm_camera_io_w(0x8350003F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_UB_CFG);
+ msm_camera_io_w(0x8390003F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BF_WR_UB_CFG);
+
+ msm_camera_io_w(0x83D0000F,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_UB_CFG);
+ msm_camera_io_w(0x83E0000F,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_SKIN_WR_UB_CFG);
+
msm_camera_io_w(0x83F0000F,
vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_AWB_WR_UB_CFG);
-
/* stats frame subsample config*/
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
@@ -850,6 +857,9 @@
VFE_BUS_STATS_BG_WR_FRAMEDROP_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_BF_WR_FRAMEDROP_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
@@ -873,6 +883,9 @@
VFE_BUS_STATS_BG_WR_IRQ_SUBSAMPLE_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe40_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_BF_WR_IRQ_SUBSAMPLE_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
vfe40_ctrl->share_ctrl->vfebase +
@@ -894,13 +907,16 @@
struct vfe40_ctrl_type *vfe40_ctrl)
{
/* Stats control variables. */
- memset(&(vfe40_ctrl->afbfStatsControl), 0,
+ memset(&(vfe40_ctrl->bfStatsControl), 0,
sizeof(struct vfe_stats_control));
memset(&(vfe40_ctrl->awbStatsControl), 0,
sizeof(struct vfe_stats_control));
- memset(&(vfe40_ctrl->aecbgStatsControl), 0,
+ memset(&(vfe40_ctrl->bgStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe40_ctrl->beStatsControl), 0,
sizeof(struct vfe_stats_control));
memset(&(vfe40_ctrl->bhistStatsControl), 0,
@@ -1086,7 +1102,6 @@
{
uint32_t addr;
unsigned long flags;
-
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_AWB);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
@@ -1111,7 +1126,40 @@
return 0;
}
-static uint32_t vfe_stats_aec_bg_buf_init(
+static uint32_t vfe_stats_be_buf_init(
+ struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ uint32_t addr;
+ unsigned long flags;
+ uint32_t stats_type;
+
+ stats_type = MSM_STATS_TYPE_BE;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq BE ping buf from free buf queue\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_PING_ADDR);
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (!addr) {
+ pr_err("%s: dq BE pong buf from free buf queue\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_camera_io_w(addr,
+ vfe40_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_BE_WR_PONG_ADDR);
+ return 0;
+}
+
+static uint32_t vfe_stats_bg_buf_init(
struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
@@ -1144,7 +1192,7 @@
return 0;
}
-static int vfe_stats_af_bf_buf_init(
+static int vfe_stats_bf_buf_init(
struct vfe40_ctrl_type *vfe40_ctrl)
{
uint32_t addr;
@@ -1189,7 +1237,6 @@
{
uint32_t addr;
unsigned long flags;
-
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, MSM_STATS_TYPE_BHIST);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
@@ -1856,7 +1903,7 @@
rc = -EFAULT;
goto proc_general_done;
}
- rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bg_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AEC",
__func__);
@@ -1890,7 +1937,7 @@
rc = -EFAULT;
goto proc_general_done;
}
- rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bf_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of AF",
__func__);
@@ -2030,15 +2077,25 @@
break;
case VFE_CMD_STATS_BG_START:
+ case VFE_CMD_STATS_BE_START:
case VFE_CMD_STATS_BF_START:
case VFE_CMD_STATS_BHIST_START: {
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
module_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
- if (VFE_CMD_STATS_BG_START == cmd->id) {
+
+ if (VFE_CMD_STATS_BE_START == cmd->id) {
+ module_val |= BE_ENABLE_MASK;
+ rc = vfe_stats_be_buf_init(vfe40_ctrl);
+ if (rc < 0) {
+ pr_err("%s: cannot config ping/pong address of BG",
+ __func__);
+ goto proc_general_done;
+ }
+ } else if (VFE_CMD_STATS_BG_START == cmd->id) {
module_val |= BG_ENABLE_MASK;
- rc = vfe_stats_aec_bg_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bg_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of BG",
__func__);
@@ -2046,7 +2103,7 @@
}
} else if (VFE_CMD_STATS_BF_START == cmd->id) {
module_val |= BF_ENABLE_MASK;
- rc = vfe_stats_af_bf_buf_init(vfe40_ctrl);
+ rc = vfe_stats_bf_buf_init(vfe40_ctrl);
if (rc < 0) {
pr_err("%s: cannot config ping/pong address of BF",
__func__);
@@ -2679,11 +2736,6 @@
break;
case VFE_CMD_STATS_AWB_STOP: {
- if (vfe40_use_bayer_stats(vfe40_ctrl)) {
- /* Error */
- rc = -EFAULT;
- goto proc_general_done;
- }
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~AWB_ENABLE_MASK;
@@ -2691,29 +2743,36 @@
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
- case VFE_CMD_STATS_AE_STOP: {
- if (vfe40_use_bayer_stats(vfe40_ctrl)) {
- /* Error */
- rc = -EFAULT;
- goto proc_general_done;
- }
+ case VFE_CMD_STATS_BG_STOP: {
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
- old_val &= BG_ENABLE_MASK;
+ old_val &= ~BG_ENABLE_MASK;
msm_camera_io_w(old_val,
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
- case VFE_CMD_STATS_AF_STOP: {
- if (vfe40_use_bayer_stats(vfe40_ctrl)) {
- /* Error */
- rc = -EFAULT;
- goto proc_general_done;
- }
+ case VFE_CMD_STATS_BF_STOP: {
old_val = msm_camera_io_r(
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~BF_ENABLE_MASK;
msm_camera_io_w(old_val,
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+
+ rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
+ MSM_STATS_TYPE_BF);
+ if (rc < 0) {
+ pr_err("%s: dq stats buf err = %d",
+ __func__, rc);
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case VFE_CMD_STATS_BE_STOP: {
+ old_val = msm_camera_io_r(
+ vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~BE_ENABLE_MASK;
+ msm_camera_io_w(old_val,
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
@@ -2745,8 +2804,6 @@
}
break;
- case VFE_CMD_STATS_BG_STOP:
- case VFE_CMD_STATS_BF_STOP:
case VFE_CMD_STATS_BHIST_STOP: {
if (!vfe40_use_bayer_stats(vfe40_ctrl)) {
/* Error */
@@ -2761,15 +2818,6 @@
msm_camera_io_w(old_val,
vfe40_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
- if (VFE_CMD_STATS_BF_STOP == cmd->id) {
- rc = vfe40_stats_flush_enqueue(vfe40_ctrl,
- MSM_STATS_TYPE_BF);
- if (rc < 0) {
- pr_err("%s: dq stats buf err = %d",
- __func__, rc);
- return -EINVAL;
- }
- }
}
break;
@@ -4015,6 +4063,16 @@
vfe40_ctrl->stats_ops.client);
}
break;
+ case statsBeNum:{
+ msgStats.id = MSG_ID_STATS_BE;
+ stats_type = MSM_STATS_TYPE_BE;
+ rc = vfe40_ctrl->stats_ops.dispatch(
+ vfe40_ctrl->stats_ops.stats_ctrl,
+ stats_type, bufAddress,
+ &msgStats.buf_idx, &vaddr, &msgStats.fd,
+ vfe40_ctrl->stats_ops.client);
+ }
+ break;
case statsBfNum:{
msgStats.id = MSG_ID_STATS_BF;
stats_type = MSM_STATS_TYPE_BF;
@@ -4101,9 +4159,9 @@
msgStats.status_bits = status_bits;
- msgStats.aec.buff = vfe40_ctrl->aecbgStatsControl.bufToRender;
+ msgStats.aec.buff = vfe40_ctrl->bgStatsControl.bufToRender;
msgStats.awb.buff = vfe40_ctrl->awbStatsControl.bufToRender;
- msgStats.af.buff = vfe40_ctrl->afbfStatsControl.bufToRender;
+ msgStats.af.buff = vfe40_ctrl->bfStatsControl.bufToRender;
msgStats.ihist.buff = vfe40_ctrl->ihistStatsControl.bufToRender;
msgStats.rs.buff = vfe40_ctrl->rsStatsControl.bufToRender;
@@ -4118,6 +4176,29 @@
&msgStats);
}
+static void vfe40_process_stats_be_irq(struct vfe40_ctrl_type *vfe40_ctrl)
+{
+ unsigned long flags;
+ uint32_t addr;
+ uint32_t stats_type;
+ stats_type = MSM_STATS_TYPE_BE;
+ spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
+ spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
+ if (addr) {
+ vfe40_ctrl->beStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(vfe40_ctrl, statsBeNum,
+ addr);
+
+ vfe_send_stats_msg(vfe40_ctrl,
+ vfe40_ctrl->beStatsControl.bufToRender, statsBeNum);
+ } else{
+ vfe40_ctrl->beStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe40_ctrl->beStatsControl.droppedStatsFrameCount);
+ }
+}
+
static void vfe40_process_stats_bg_irq(struct vfe40_ctrl_type *vfe40_ctrl)
{
unsigned long flags;
@@ -4128,16 +4209,16 @@
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (addr) {
- vfe40_ctrl->aecbgStatsControl.bufToRender =
+ vfe40_ctrl->bgStatsControl.bufToRender =
vfe40_process_stats_irq_common(vfe40_ctrl, statsBgNum,
addr);
vfe_send_stats_msg(vfe40_ctrl,
- vfe40_ctrl->aecbgStatsControl.bufToRender, statsBgNum);
+ vfe40_ctrl->bgStatsControl.bufToRender, statsBgNum);
} else{
- vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bgStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount);
+ vfe40_ctrl->bgStatsControl.droppedStatsFrameCount);
}
}
@@ -4172,16 +4253,16 @@
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl, stats_type);
spin_unlock_irqrestore(&vfe40_ctrl->stats_bufq_lock, flags);
if (addr) {
- vfe40_ctrl->afbfStatsControl.bufToRender =
+ vfe40_ctrl->bfStatsControl.bufToRender =
vfe40_process_stats_irq_common(vfe40_ctrl, statsBfNum,
addr);
vfe_send_stats_msg(vfe40_ctrl,
- vfe40_ctrl->afbfStatsControl.bufToRender, statsBfNum);
+ vfe40_ctrl->bfStatsControl.bufToRender, statsBfNum);
} else{
- vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bfStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
- vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount);
+ vfe40_ctrl->bfStatsControl.droppedStatsFrameCount);
}
}
@@ -4282,22 +4363,39 @@
CDBG("%s, stats = 0x%x\n", __func__, status_bits);
spin_lock_irqsave(&vfe40_ctrl->stats_bufq_lock, flags);
- stats_type = MSM_STATS_TYPE_BG;
+ stats_type = MSM_STATS_TYPE_BE;
+ if (status_bits & VFE_IRQ_STATUS0_STATS_BE) {
+ addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
+ stats_type);
+ if (addr) {
+ vfe40_ctrl->beStatsControl.bufToRender =
+ vfe40_process_stats_irq_common(
+ vfe40_ctrl, statsBeNum, addr);
+ process_stats = true;
+ } else{
+ vfe40_ctrl->beStatsControl.bufToRender = 0;
+ vfe40_ctrl->beStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe40_ctrl->beStatsControl.bufToRender = 0;
+ }
+
+ stats_type = MSM_STATS_TYPE_BG;
if (status_bits & VFE_IRQ_STATUS0_STATS_BG) {
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
stats_type);
if (addr) {
- vfe40_ctrl->aecbgStatsControl.bufToRender =
+ vfe40_ctrl->bgStatsControl.bufToRender =
vfe40_process_stats_irq_common(
vfe40_ctrl, statsBgNum, addr);
process_stats = true;
} else{
- vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
- vfe40_ctrl->aecbgStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bgStatsControl.bufToRender = 0;
+ vfe40_ctrl->bgStatsControl.droppedStatsFrameCount++;
}
} else {
- vfe40_ctrl->aecbgStatsControl.bufToRender = 0;
+ vfe40_ctrl->bgStatsControl.bufToRender = 0;
}
if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
@@ -4322,17 +4420,17 @@
addr = (uint32_t)vfe40_stats_dqbuf(vfe40_ctrl,
stats_type);
if (addr) {
- vfe40_ctrl->afbfStatsControl.bufToRender =
+ vfe40_ctrl->bfStatsControl.bufToRender =
vfe40_process_stats_irq_common(
vfe40_ctrl, statsBfNum,
addr);
process_stats = true;
} else {
- vfe40_ctrl->afbfStatsControl.bufToRender = 0;
- vfe40_ctrl->afbfStatsControl.droppedStatsFrameCount++;
+ vfe40_ctrl->bfStatsControl.bufToRender = 0;
+ vfe40_ctrl->bfStatsControl.droppedStatsFrameCount++;
}
} else {
- vfe40_ctrl->afbfStatsControl.bufToRender = 0;
+ vfe40_ctrl->bfStatsControl.bufToRender = 0;
}
if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
@@ -4441,6 +4539,10 @@
CDBG("Stats BG irq occured.\n");
vfe40_process_stats_bg_irq(vfe40_ctrl);
break;
+ case VFE_IRQ_STATUS0_STATS_BE:
+ CDBG("Stats BE irq occured.\n");
+ vfe40_process_stats_be_irq(vfe40_ctrl);
+ break;
case VFE_IRQ_STATUS0_STATS_BF:
CDBG("Stats BF irq occured.\n");
vfe40_process_stats_bf_irq(vfe40_ctrl);
@@ -4522,6 +4624,8 @@
(qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_BG) |
(qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BE) |
+ (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB) |
(qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_BF) |
@@ -4610,6 +4714,12 @@
(void *)VFE_IRQ_STATUS0_STATS_BG);
if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_BE)
+ v4l2_subdev_notify(&vfe40_ctrl->subdev,
+ NOTIFY_VFE_IRQ,
+ (void *)VFE_IRQ_STATUS0_STATS_BE);
+
+ if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
@@ -4879,6 +4989,7 @@
cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_BE_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
@@ -4922,6 +5033,7 @@
(cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
(cmd->cmd_type == CMD_STATS_AEC_ENABLE) ||
(cmd->cmd_type == CMD_STATS_BG_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_BE_ENABLE) ||
(cmd->cmd_type == CMD_STATS_BF_ENABLE) ||
(cmd->cmd_type == CMD_STATS_BHIST_ENABLE)) {
struct axidata *axid;
@@ -4945,6 +5057,7 @@
switch (cmd->cmd_type) {
case CMD_STATS_AEC_ENABLE:
case CMD_STATS_BG_ENABLE:
+ case CMD_STATS_BE_ENABLE:
case CMD_STATS_BF_ENABLE:
case CMD_STATS_BHIST_ENABLE:
case CMD_STATS_AWB_ENABLE:
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index 6363bfb..4acc7e4 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -796,7 +796,7 @@
#define VFE_BUS_STATS_BE_WR_PING_ADDR 0x00000168
#define VFE_BUS_STATS_BE_WR_PONG_ADDR 0x0000016C
#define VFE_BUS_STATS_BE_WR_ADDR_CFG 0x00000170
-#define VFE_BUS_STATS_BE_UB_CFG 0x00000174
+#define VFE_BUS_STATS_BE_WR_UB_CFG 0x00000174
#define VFE_BUS_STATS_BE_WR_FRAMEDROP_PATTERN 0x00000178
#define VFE_BUS_STATS_BE_WR_IRQ_SUBSAMPLE_PATTERN 0x0000017C
@@ -1014,9 +1014,10 @@
uint32_t sync_timer_number;
struct msm_ver_num_info ver_num;
- struct vfe_stats_control afbfStatsControl;
+ struct vfe_stats_control beStatsControl;
+ struct vfe_stats_control bfStatsControl;
struct vfe_stats_control awbStatsControl;
- struct vfe_stats_control aecbgStatsControl;
+ struct vfe_stats_control bgStatsControl;
struct vfe_stats_control ihistStatsControl;
struct vfe_stats_control rsStatsControl;
struct vfe_stats_control csStatsControl;
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index e1a0994..7d44fea 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -442,12 +442,13 @@
struct buffer_info {
struct list_head list;
int type;
- int fd;
- int buff_off;
- int size;
- u32 uvaddr;
- u32 device_addr;
- struct msm_smem *handle;
+ int num_planes;
+ int fd[VIDEO_MAX_PLANES];
+ int buff_off[VIDEO_MAX_PLANES];
+ int size[VIDEO_MAX_PLANES];
+ u32 uvaddr[VIDEO_MAX_PLANES];
+ u32 device_addr[VIDEO_MAX_PLANES];
+ struct msm_smem *handle[VIDEO_MAX_PLANES];
};
struct msm_v4l2_vid_inst {
@@ -472,26 +473,37 @@
}
struct buffer_info *get_registered_buf(struct list_head *list,
- int fd, u32 buff_off, u32 size)
+ int fd, u32 buff_off, u32 size, int *plane)
{
struct buffer_info *temp;
struct buffer_info *ret = NULL;
- if (!list || fd < 0) {
+ int i;
+ if (!list || fd < 0 || !plane) {
dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
+ *plane = 0;
if (!list_empty(list)) {
list_for_each_entry(temp, list, list) {
- if (temp && temp->fd == fd &&
- (CONTAINS(temp->buff_off, temp->size, buff_off)
- || CONTAINS(buff_off, size, temp->buff_off)
- || OVERLAPS(buff_off, size,
- temp->buff_off, temp->size))) {
- dprintk(VIDC_INFO,
- "This memory region is already mapped\n");
- ret = temp;
- break;
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->fd[i] == fd &&
+ (CONTAINS(temp->buff_off[i],
+ temp->size[i], buff_off)
+ || CONTAINS(buff_off,
+ size, temp->buff_off[i])
+ || OVERLAPS(buff_off, size,
+ temp->buff_off[i],
+ temp->size[i]))) {
+ dprintk(VIDC_DBG,
+ "This memory region is already mapped\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
}
+ if (ret)
+ break;
}
}
err_invalid_input:
@@ -499,25 +511,62 @@
}
struct buffer_info *get_same_fd_buffer(struct list_head *list,
- int fd)
+ int fd, int *plane)
{
struct buffer_info *temp;
struct buffer_info *ret = NULL;
- if (!list || fd < 0) {
+ int i;
+ if (!list || fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+ *plane = 0;
+ if (!list_empty(list)) {
+ list_for_each_entry(temp, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->fd[i] == fd) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ }
+err_invalid_input:
+ return ret;
+}
+static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+{
+ struct buffer_info *temp;
+ u32 uvaddr = 0;
+ int i;
+ if (!list || !device_addr) {
dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
if (!list_empty(list)) {
list_for_each_entry(temp, list, list) {
- if (temp && temp->fd == fd) {
- dprintk(VIDC_INFO, "Found same fd buffer\n");
- ret = temp;
- break;
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->device_addr[i]
+ == device_addr) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ uvaddr = temp->uvaddr[i];
+ break;
+ }
}
+ if (uvaddr)
+ break;
}
}
err_invalid_input:
- return ret;
+ return uvaddr;
}
static int msm_v4l2_open(struct file *filp)
@@ -567,23 +616,27 @@
struct list_head *ptr, *next;
struct buffer_info *bi;
struct v4l2_buffer buffer_info;
- struct v4l2_plane plane;
+ struct v4l2_plane plane[VIDEO_MAX_PLANES];
int rc = 0;
+ int i;
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);
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ plane[i].reserved[0] = bi->fd[i];
+ plane[i].reserved[1] = bi->buff_off[i];
+ plane[i].length = bi->size[i];
+ plane[i].m.userptr = bi->device_addr[i];
+ buffer_info.m.planes = plane;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[i].reserved[0],
+ buffer_info.m.planes[i].reserved[1],
+ buffer_info.m.planes[i].length);
+ }
+ buffer_info.length = bi->num_planes;
rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
&buffer_info);
if (rc)
@@ -593,11 +646,13 @@
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);
+ for (i = 0; i < bi->num_planes; i++) {
+ if (bi->handle[i])
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle[i]);
}
+ kfree(bi);
+ }
}
return rc;
}
@@ -609,6 +664,7 @@
struct buffer_info *bi;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
+ int i;
vidc_inst = get_vidc_inst(filp, NULL);
v4l2_inst = get_v4l2_inst(filp, NULL);
rc = msm_v4l2_release_output_buffers(v4l2_inst);
@@ -620,9 +676,12 @@
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);
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (bi->handle[i])
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle[i]);
+ }
kfree(bi);
}
}
@@ -696,6 +755,7 @@
struct buffer_info *temp;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
+ int plane = 0;
int i, rc = 0;
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
@@ -704,34 +764,41 @@
rc = -ENOMEM;
goto exit;
}
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+ b->length, VIDEO_MAX_PLANES);
+ rc = -EINVAL;
+ goto exit;
+ }
for (i = 0; i < b->length; ++i) {
- binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ temp = get_registered_buf(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- if (binfo) {
- dprintk(VIDC_INFO,
+ b->m.planes[i].length, &plane);
+ if (temp) {
+ dprintk(VIDC_DBG,
"This memory region has already been prepared\n");
rc = -EINVAL;
- goto exit;
- }
- binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
- if (!binfo) {
- dprintk(VIDC_ERR, "Out of memory\n");
- rc = -ENOMEM;
+ kfree(binfo);
goto exit;
}
temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0]);
+ b->m.planes[i].reserved[0], &plane);
if (temp) {
binfo->type = b->type;
- binfo->fd = b->m.planes[i].reserved[0];
- binfo->buff_off = b->m.planes[i].reserved[1];
- binfo->size = b->m.planes[i].length;
- binfo->uvaddr = b->m.planes[i].m.userptr;
- binfo->device_addr =
- temp->handle->device_addr + binfo->buff_off;
- binfo->handle = NULL;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->device_addr[i] =
+ temp->handle[plane]->device_addr + binfo->buff_off[i];
+ binfo->handle[i] = NULL;
} else {
handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
b->m.planes[i].reserved[0],
@@ -745,21 +812,22 @@
goto exit;
}
binfo->type = b->type;
- binfo->fd = b->m.planes[i].reserved[0];
- binfo->buff_off = b->m.planes[i].reserved[1];
- binfo->size = b->m.planes[i].length;
- binfo->uvaddr = b->m.planes[i].m.userptr;
- binfo->device_addr =
- handle->device_addr + binfo->buff_off;
- binfo->handle = handle;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->device_addr[i] =
+ handle->device_addr + binfo->buff_off[i];
+ binfo->handle[i] = handle;
dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
b->m.planes[i].length);
}
- list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
- b->m.planes[i].m.userptr = binfo->device_addr;
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
}
+ binfo->num_planes = b->length;
+ list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
exit:
return rc;
@@ -771,15 +839,21 @@
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
struct buffer_info *binfo;
+ int plane = 0;
int rc = 0;
int i;
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
+ b->length);
+ return -EINVAL;
+ }
vidc_inst = get_vidc_inst(file, fh);
v4l2_inst = get_v4l2_inst(file, fh);
for (i = 0; i < b->length; ++i) {
binfo = get_registered_buf(&v4l2_inst->registered_bufs,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
- b->m.planes[i].length);
+ b->m.planes[i].length, &plane);
if (!binfo) {
dprintk(VIDC_ERR,
"This buffer is not registered: %d, %d, %d\n",
@@ -789,12 +863,12 @@
rc = -EINVAL;
goto err_invalid_buff;
}
- b->m.planes[i].m.userptr = binfo->device_addr;
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
- binfo->device_addr);
- if (binfo->handle) {
+ binfo->device_addr[i]);
+ if (binfo->handle[i]) {
rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
- binfo->handle);
+ binfo->handle[i]);
if (rc) {
dprintk(VIDC_ERR,
"Failed to clean caches: %d\n", rc);
@@ -810,8 +884,37 @@
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
+ int rc = 0;
+ int i;
+ struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
- return msm_vidc_dqbuf((void *)vidc_inst, b);
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
+ b->length);
+ return -EINVAL;
+ }
+ v4l2_inst = get_v4l2_inst(file, fh);
+ rc = msm_vidc_dqbuf((void *)vidc_inst, b);
+ if (rc) {
+ dprintk(VIDC_DBG,
+ "Failed to dqbuf, capability: %d, rc: %d\n",
+ b->type, rc);
+ goto fail_dq_buf;
+ }
+ for (i = 0; i < b->length; i++) {
+ b->m.planes[i].m.userptr = device_to_uvaddr(
+ &v4l2_inst->registered_bufs,
+ b->m.planes[i].m.userptr);
+ if (!b->m.planes[i].m.userptr) {
+ dprintk(VIDC_ERR,
+ "Failed to find user virtual address, 0x%lx, %d, %d\n",
+ b->m.planes[i].m.userptr, b->type, i);
+ rc = -EINVAL;
+ goto fail_dq_buf;
+ }
+ }
+fail_dq_buf:
+ return rc;
}
int msm_v4l2_streamon(struct file *file, void *fh,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index b615352..058c835 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -20,7 +20,6 @@
#include "msm_vidc_debug.h"
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
-#define MAX_PLANES 1
#define DEFAULT_HEIGHT 720
#define DEFAULT_WIDTH 1280
#define MAX_SUPPORTED_WIDTH 1920
@@ -150,6 +149,17 @@
.menu_skip_mask = 0,
.qmenu = NULL,
},
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
+ .name = "Sync Frame Decode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -175,11 +185,6 @@
size = ALIGN(size, SZ_4K);
return size;
}
-static u32 get_frame_size_nv21(int plane,
- u32 height, u32 width)
-{
- return height * width * 2;
-}
static u32 get_frame_size_compressed(int plane,
u32 height, u32 width)
@@ -192,7 +197,7 @@
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12,
- .num_planes = 1,
+ .num_planes = 2,
.get_frame_size = get_frame_size_nv12,
.type = CAPTURE_PORT,
},
@@ -253,14 +258,6 @@
.type = OUTPUT_PORT,
},
{
- .name = "YCrCb Semiplanar 4:2:0",
- .description = "Y/CrCb 4:2:0",
- .fourcc = V4L2_PIX_FMT_NV21,
- .num_planes = 1,
- .get_frame_size = get_frame_size_nv21,
- .type = CAPTURE_PORT,
- },
- {
.name = "DIVX 311",
.description = "DIVX 311 compressed format",
.fourcc = V4L2_PIX_FMT_DIVX_311,
@@ -321,45 +318,48 @@
struct v4l2_buffer *b)
{
int rc = 0;
- int i;
struct vidc_buffer_addr_info buffer_info;
+ int extra_idx = 0;
+ int i;
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG, "device_addr = %ld, size = %d\n",
- b->m.planes[i].m.userptr,
+ if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, allocated: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; (i < b->length)
+ && (i < VIDEO_MAX_PLANES); ++i) {
+ dprintk(VIDC_DBG,
+ "prepare plane: %d, device_addr = 0x%lx, size = %d\n",
+ i, b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- if (!inst->extradata_handle) {
- inst->extradata_handle =
- msm_smem_alloc(inst->mem_client,
- 4096 * 1024, 1, SMEM_UNCACHED,
- inst->core->resources.io_map[NS_MAP].domain,
- 0, 0);
- if (!inst->extradata_handle) {
- dprintk(VIDC_ERR,
- "Failed to allocate extradata memory\n");
- rc = -ENOMEM;
- break;
- }
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
+ dprintk(VIDC_DBG,
+ "extradata: 0x%lx\n",
+ b->m.planes[extra_idx].m.userptr);
+ buffer_info.extradata_size =
+ b->m.planes[extra_idx].length;
}
- buffer_info.extradata_addr =
- inst->extradata_handle->device_addr;
- buffer_info.extradata_size = 4096 * 1024;
rc = vidc_hal_session_set_buffers((void *)inst->session,
&buffer_info);
- if (rc) {
+ if (rc)
dprintk(VIDC_ERR,
- "vidc_hal_session_set_buffers failed\n");
- break;
- }
- }
+ "vidc_hal_session_set_buffers failed");
break;
default:
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
@@ -372,9 +372,10 @@
struct v4l2_buffer *b)
{
int rc = 0;
- int i;
struct vidc_buffer_addr_info buffer_info;
struct msm_vidc_core *core = inst->core;
+ int extra_idx = 0;
+ int i;
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
@@ -382,28 +383,40 @@
core);
goto exit;
}
+
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- for (i = 0; i < b->length; i++) {
- dprintk(VIDC_DBG,
- "Release device_addr = %ld, size = %d\n",
- b->m.planes[i].m.userptr,
+ if (b->length !=
+ inst->fmts[CAPTURE_PORT]->num_planes) {
+ dprintk(VIDC_ERR,
+ "Planes mismatch: needed: %d, to release: %d\n",
+ inst->fmts[CAPTURE_PORT]->num_planes,
+ b->length);
+ rc = -EINVAL;
+ break;
+ }
+ for (i = 0; i < b->length; ++i) {
+ dprintk(VIDC_DBG,
+ "Release plane: %d device_addr = 0x%lx, size = %d\n",
+ i, b->m.planes[i].m.userptr,
b->m.planes[i].length);
- buffer_info.buffer_size = b->m.planes[i].length;
+ }
+ buffer_info.buffer_size = b->m.planes[0].length;
buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
buffer_info.num_buffers = 1;
buffer_info.align_device_addr =
- b->m.planes[i].m.userptr;
- buffer_info.extradata_addr =
- inst->extradata_handle->device_addr;
+ b->m.planes[0].m.userptr;
+ extra_idx = EXTRADATA_IDX(b->length);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+ buffer_info.extradata_addr =
+ b->m.planes[extra_idx].m.userptr;
rc = vidc_hal_session_release_buffers(
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
- "vidc_hal_session_release_buffers failed\n");
- }
+ "vidc_hal_session_release_buffers failed");
break;
default:
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
@@ -475,7 +488,10 @@
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
+ struct hal_frame_size frame_sz;
+ int extra_idx = 0;
int rc = 0;
+ int ret;
int i;
if (!inst || !f) {
dprintk(VIDC_ERR,
@@ -489,21 +505,41 @@
if (fmt) {
f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
if (inst->in_reconfig == true) {
inst->prop.height = inst->reconfig_height;
inst->prop.width = inst->reconfig_width;
}
f->fmt.pix_mp.height = inst->prop.height;
f->fmt.pix_mp.width = inst->prop.width;
- f->fmt.pix_mp.num_planes = fmt->num_planes;
- for (i = 0; i < fmt->num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- fmt->get_frame_size(i, inst->prop.height,
- inst->prop.width);
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->prop.width;
+ frame_sz.height = inst->prop.height;
+ dprintk(VIDC_DBG, "width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ ret = msm_comm_try_set_prop(inst,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ ret = ret || msm_comm_try_get_bufreqs(inst);
+ if (ret || (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i,
+ f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ } else {
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
+ }
}
} else {
- dprintk(VIDC_ERR, "Buf type not recognized, type = %d\n",
- f->type);
+ dprintk(VIDC_ERR,
+ "Buf type not recognized, type = %d\n",
+ f->type);
rc = -EINVAL;
}
return rc;
@@ -512,7 +548,10 @@
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
+ struct hal_frame_size frame_sz;
+ int extra_idx = 0;
int rc = 0;
+ int ret = 0;
int i;
if (!inst || !f) {
dprintk(VIDC_ERR,
@@ -525,64 +564,67 @@
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
CAPTURE_PORT);
- if (fmt && fmt->type != CAPTURE_PORT) {
+ if (!fmt || (fmt && fmt->type != CAPTURE_PORT)) {
dprintk(VIDC_ERR,
- "Format: %d not supported on CAPTURE"
- "port\n", f->fmt.pix_mp.pixelformat);
- rc = -EINVAL;
- goto err_invalid_fmt;
- }
-
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
-
- frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
- dprintk(VIDC_DBG,
- "width = %d, height = %d\n",
- frame_sz.width, frame_sz.height);
- rc = vidc_hal_session_set_property((void *)inst->session,
- HAL_PARAM_FRAME_SIZE, &frame_sz);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to set hal property for framesize\n");
- goto err_invalid_fmt;
- }
- } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
- fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
- ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
- OUTPUT_PORT);
- if (fmt && fmt->type != OUTPUT_PORT) {
- dprintk(VIDC_ERR,
- "Format: %d not supported on OUTPUT port\n",
+ "Format: %d not supported on CAPTURE port\n",
f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto err_invalid_fmt;
}
- }
-
- if (fmt) {
- f->fmt.pix_mp.num_planes = fmt->num_planes;
- for (i = 0; i < fmt->num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- fmt->get_frame_size(i, f->fmt.pix_mp.height,
- f->fmt.pix_mp.width);
- }
inst->fmts[fmt->type] = fmt;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to open instance\n");
- goto err_invalid_fmt;
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->prop.width;
+ frame_sz.height = inst->prop.height;
+ dprintk(VIDC_DBG, "width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ ret = msm_comm_try_set_prop(inst,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ ret = ret || msm_comm_try_get_bufreqs(inst);
+ if (ret) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i,
+ f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ } else {
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ f->fmt.pix_mp.plane_fmt[1].sizeimage =
+ inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
}
}
- } else {
- dprintk(VIDC_ERR,
- "Buf type not recognized, type = %d\n", f->type);
- rc = -EINVAL;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->prop.width = f->fmt.pix_mp.width;
+ inst->prop.height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats),
+ f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (!fmt || fmt->type != OUTPUT_PORT) {
+ dprintk(VIDC_ERR,
+ "Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ inst->fmts[fmt->type] = fmt;
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to open instance\n");
+ goto err_invalid_fmt;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->prop.width;
+ frame_sz.height = inst->prop.height;
+ msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ fmt->get_frame_size(0, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
}
err_invalid_fmt:
return rc;
@@ -646,14 +688,17 @@
struct msm_vidc_inst *inst;
unsigned long flags;
struct hal_buffer_requirements *bufreq;
- if (!q || !q->drv_priv) {
- dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
+ int extra_idx = 0;
+ if (!q || !num_buffers || !num_planes
+ || !sizes || !q->drv_priv) {
+ dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
+ q, num_buffers, num_planes);
return -EINVAL;
}
inst = q->drv_priv;
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- *num_planes = 1;
+ *num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
@@ -664,6 +709,7 @@
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
+ *num_planes = inst->fmts[CAPTURE_PORT]->num_planes;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
@@ -675,7 +721,6 @@
"Failed to get buffer requirements: %d\n", rc);
break;
}
- *num_planes = 1;
spin_lock_irqsave(&inst->lock, flags);
if (*num_buffers && *num_buffers >
inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
@@ -700,11 +745,13 @@
inst->buff_req.buffer[1].buffer_count_actual,
inst->buff_req.buffer[1].buffer_size,
inst->buff_req.buffer[1].buffer_alignment);
- for (i = 0; i < *num_planes; i++) {
- sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
- i, inst->prop.height, inst->prop.width);
+ sizes[0] = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].buffer_size;
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ sizes[extra_idx] =
+ inst->buff_req.buffer[HAL_BUFFER_EXTRADATA_OUTPUT].buffer_size;
}
-
break;
default:
dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
@@ -987,6 +1034,12 @@
hal_property.enable = control.value;
pdata = &hal_property;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
+ property_id =
+ HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
default:
break;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index ed234b9..54c3d5f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -685,7 +685,7 @@
struct vb2_buffer *vb;
struct vidc_hal_fbd *fill_buf_done;
if (!response) {
- pr_err("Invalid response from vidc_hal\n");
+ dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
return;
}
inst = (struct msm_vidc_inst *)response->session_id;
@@ -1545,14 +1545,14 @@
dprintk(VIDC_DBG, "Sent etb to HAL\n");
} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
struct vidc_seq_hdr seq_hdr;
+ int extra_idx = 0;
frame_data.filled_len = 0;
frame_data.buffer_type = HAL_BUFFER_OUTPUT;
- if (inst->extradata_handle) {
+ extra_idx =
+ EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
+ if (extra_idx)
frame_data.extradata_addr =
- inst->extradata_handle->device_addr;
- } else {
- frame_data.extradata_addr = 0;
- }
+ vb->v4l2_planes[extra_idx].m.userptr;
dprintk(VIDC_DBG,
"Sending ftb to hal: Alloc: %d :filled: %d",
frame_data.alloc_len, frame_data.filled_len);
@@ -1596,6 +1596,12 @@
{
int rc = 0;
mutex_lock(&inst->sync_lock);
+ if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+ dprintk(VIDC_ERR,
+ "Not in proper state to query buffer requirements\n");
+ rc = -EAGAIN;
+ goto exit;
+ }
init_completion(
&inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
rc = vidc_hal_session_get_buf_req((void *) inst->session);
@@ -1721,6 +1727,29 @@
return rc;
}
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, void *pdata)
+{
+ int rc = 0;
+ if (!inst) {
+ dprintk(VIDC_ERR, "Invalid input: %p\n", inst);
+ return -EINVAL;
+ }
+ mutex_lock(&inst->sync_lock);
+ if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+ dprintk(VIDC_ERR, "Not in proper state to set property\n");
+ rc = -EAGAIN;
+ goto exit;
+ }
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ ptype, pdata);
+ if (rc)
+ dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 20b4bc2..7562058 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -27,6 +27,8 @@
struct msm_vidc_inst *inst, enum v4l2_buf_type type);
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+ enum hal_property ptype, void *pdata);
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 0f6740f..f288cc6 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -74,6 +74,8 @@
uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
buf_size = y_buf_size + uv_buf_size; }
+#define EXTRADATA_IDX(__num_planes) (__num_planes - 1)
+
enum vidc_ports {
OUTPUT_PORT,
CAPTURE_PORT,
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 89f0273..190e132 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1188,6 +1188,16 @@
pkt->size += sizeof(u32) * 2;
break;
}
+ case HAL_PARAM_VDEC_SYNC_FRAME_DECODE:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
{
struct hfi_enable *hfi;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index c586172..0e70e30 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -224,6 +224,15 @@
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \
+ (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
+
#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000)
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 9def3e3..d3fa1d0 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -138,6 +138,7 @@
HAL_CONFIG_VENC_TIMESTAMP_SCALE,
HAL_PARAM_VENC_LOW_LATENCY,
HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+ HAL_PARAM_VDEC_SYNC_FRAME_DECODE,
};
enum hal_domain {
@@ -358,7 +359,7 @@
HAL_BUFFER_EXTRADATA_OUTPUT2,
HAL_BUFFER_INTERNAL_SCRATCH,
HAL_BUFFER_INTERNAL_PERSIST,
- HAL_UNUSED_BUFFER = 0x10000000,
+ HAL_BUFFER_MAX
};
struct hal_frame_rate {
@@ -941,7 +942,7 @@
};
struct buffer_requirements {
- struct hal_buffer_requirements buffer[8];
+ struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
};
/* VIDC_HAL CORE API's */
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 7757b5c..72a3f3b 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -501,7 +501,7 @@
buf = container_of(vb, struct vcap_buffer, vb);
buf->ion_handle = ion_import_dma_buf(dev->ion_client, b->m.userptr);
- if (IS_ERR((void *)buf->ion_handle)) {
+ if (IS_ERR_OR_NULL((void *)buf->ion_handle)) {
pr_err("%s: Could not alloc memory\n", __func__);
buf->ion_handle = NULL;
return -ENOMEM;
@@ -521,23 +521,32 @@
return 0;
}
-void free_ion_handle_work(struct vcap_dev *dev, struct vb2_buffer *vb)
+void free_ion_handle_work(struct vcap_client_data *c_data,
+ struct vb2_buffer *vb)
{
struct vcap_buffer *buf;
+ struct vcap_dev *dev = c_data->dev;
+ struct ion_handle *handle;
+ unsigned long flags = 0;
buf = container_of(vb, struct vcap_buffer, vb);
- if (buf->ion_handle == NULL) {
+
+ spin_lock_irqsave(&c_data->cap_slock, flags);
+ handle = buf->ion_handle;
+ buf->ion_handle = NULL;
+ spin_unlock_irqrestore(&c_data->cap_slock, flags);
+
+ if (handle == NULL) {
pr_debug("%s: no ION handle to free\n", __func__);
return;
}
buf->paddr = 0;
- ion_unmap_iommu(dev->ion_client, buf->ion_handle, dev->domain_num, 0);
- ion_free(dev->ion_client, buf->ion_handle);
- buf->ion_handle = NULL;
+ ion_unmap_iommu(dev->ion_client, handle, dev->domain_num, 0);
+ ion_free(dev->ion_client, handle);
return;
}
-int free_ion_handle(struct vcap_dev *dev, struct vb2_queue *q,
+int free_ion_handle(struct vcap_client_data *c_data, struct vb2_queue *q,
struct v4l2_buffer *b)
{
struct vb2_buffer *vb;
@@ -555,7 +564,7 @@
if (NULL == vb)
return -EINVAL;
- free_ion_handle_work(dev, vb);
+ free_ion_handle_work(c_data, vb);
return 0;
}
@@ -627,7 +636,7 @@
/* clean ion handles */
list_for_each_entry(vb, &vq->queued_list, queued_entry)
- free_ion_handle_work(c_data->dev, vb);
+ free_ion_handle_work(c_data, vb);
return 0;
}
@@ -725,7 +734,7 @@
/* clean ion handles */
list_for_each_entry(vb, &vq->queued_list, queued_entry)
- free_ion_handle_work(c_data->dev, vb);
+ free_ion_handle_work(c_data, vb);
return 0;
}
@@ -823,7 +832,7 @@
/* clean ion handles */
list_for_each_entry(vb, &vq->queued_list, queued_entry)
- free_ion_handle_work(c_data->dev, vb);
+ free_ion_handle_work(c_data, vb);
return 0;
}
@@ -1056,7 +1065,7 @@
return rc;
rc = vcvp_qbuf(&c_data->vc_vidq, p);
if (rc < 0)
- free_ion_handle(c_data->dev,
+ free_ion_handle(c_data,
&c_data->vc_vidq, p);
return rc;
}
@@ -1065,7 +1074,7 @@
return rc;
rc = vb2_qbuf(&c_data->vc_vidq, p);
if (rc < 0)
- free_ion_handle(c_data->dev, &c_data->vc_vidq, p);
+ free_ion_handle(c_data, &c_data->vc_vidq, p);
return rc;
case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
if (c_data->op_mode == VC_AND_VP_VCAP_OP)
@@ -1075,7 +1084,7 @@
return rc;
rc = vb2_qbuf(&c_data->vp_in_vidq, p);
if (rc < 0)
- free_ion_handle(c_data->dev, &c_data->vp_in_vidq, p);
+ free_ion_handle(c_data, &c_data->vp_in_vidq, p);
return rc;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
rc = get_phys_addr(c_data->dev, &c_data->vp_out_vidq, p);
@@ -1083,7 +1092,7 @@
return rc;
rc = vb2_qbuf(&c_data->vp_out_vidq, p);
if (rc < 0)
- free_ion_handle(c_data->dev, &c_data->vp_out_vidq, p);
+ free_ion_handle(c_data, &c_data->vp_out_vidq, p);
return rc;
default:
pr_err("VCAP Error: %s: Unknown buffer type\n", __func__);
@@ -1097,6 +1106,9 @@
struct vcap_client_data *c_data = to_client_data(file->private_data);
int rc;
+ if (c_data->streaming == 0)
+ return -EPERM;
+
pr_debug("VCAP In DQ Buf %08x\n", (unsigned int)p->type);
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1105,7 +1117,7 @@
rc = vb2_dqbuf(&c_data->vc_vidq, p, file->f_flags & O_NONBLOCK);
if (rc < 0)
return rc;
- return free_ion_handle(c_data->dev, &c_data->vc_vidq, p);
+ return free_ion_handle(c_data, &c_data->vc_vidq, p);
case V4L2_BUF_TYPE_INTERLACED_IN_DECODER:
if (c_data->op_mode == VC_AND_VP_VCAP_OP)
return -EINVAL;
@@ -1113,13 +1125,13 @@
O_NONBLOCK);
if (rc < 0)
return rc;
- return free_ion_handle(c_data->dev, &c_data->vp_in_vidq, p);
+ return free_ion_handle(c_data, &c_data->vp_in_vidq, p);
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
rc = vb2_dqbuf(&c_data->vp_out_vidq, p, file->f_flags &
O_NONBLOCK);
if (rc < 0)
return rc;
- return free_ion_handle(c_data->dev, &c_data->vp_out_vidq, p);
+ return free_ion_handle(c_data, &c_data->vp_out_vidq, p);
default:
pr_err("VCAP Error: %s: Unknown buffer type", __func__);
return -EINVAL;
@@ -1860,6 +1872,9 @@
struct vb2_queue *q;
unsigned int mask = 0;
+ if (c_data->streaming == 0)
+ return 0;
+
pr_debug("%s: Enter slect/poll\n", __func__);
switch (c_data->op_mode) {
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 92b205e..c7637b6 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -248,6 +248,20 @@
c_data->vc_action.top_field =
!c_data->vc_action.top_field;
+ if (c_data->vc_format.mode == HAL_VCAP_MODE_INT)
+ c_data->vc_action.field_dropped =
+ !c_data->vc_action.field_dropped;
+
+ atomic_inc(&dev->dbg_p.vc_drop_count);
+ continue;
+ }
+ if (c_data->vc_format.mode == HAL_VCAP_MODE_INT &&
+ c_data->vc_action.field_dropped) {
+ spin_unlock(&c_data->cap_slock);
+ c_data->vc_action.field_dropped =
+ !c_data->vc_action.field_dropped;
+ c_data->vc_action.top_field =
+ !c_data->vc_action.top_field;
atomic_inc(&dev->dbg_p.vc_drop_count);
continue;
}
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 70f4cd5..0e4240c 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -216,6 +216,7 @@
struct mutex pwm_mutex;
struct device *dev;
bool is_lpg_supported;
+ bool is_pwm_enable_sync_workaround_needed;
};
static struct pm8xxx_pwm_chip *pwm_chip;
@@ -815,9 +816,18 @@
if (pwm_chip->is_lpg_supported) {
if (pwm->dtest_mode_supported)
pm8xxx_pwm_set_dtest(pwm, 1);
+
pm8xxx_pwm_bank_sel(pwm);
rc = pm8xxx_pwm_bank_enable(pwm, 1);
pm8xxx_pwm_start(pwm, 1, 0);
+
+ /* In PM8038, due to hardware bug, PWM_VALUE register
+ * needs to be written one more time after enabling
+ * PWM mode.
+ */
+ if (pwm->chip->is_pwm_enable_sync_workaround_needed)
+ rc = pm8xxx_lpg_pwm_write(pwm, 3, 4);
+
} else {
pm8xxx_pwm_enable(pwm);
}
@@ -1391,6 +1401,12 @@
version == PM8XXX_VERSION_8038) {
chip->is_lpg_supported = 1;
}
+
+ if (version == PM8XXX_VERSION_8038)
+ chip->is_pwm_enable_sync_workaround_needed = 1;
+ else
+ chip->is_pwm_enable_sync_workaround_needed = 0;
+
if (chip->is_lpg_supported) {
if (version == PM8XXX_VERSION_8922 ||
version == PM8XXX_VERSION_8038) {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 62f1a93..a8e40f7 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -988,6 +988,20 @@
}
micbias->bias4_cfilt_sel = (u8)prop_val;
+ /* micbias external cap */
+ micbias->bias1_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ micbias->bias2_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias2-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ micbias->bias3_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias3-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ micbias->bias4_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+
dev_dbg(dev, "ldoh_v %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv,
(u32)micbias->cfilt2_mv, (u32)micbias->cfilt3_mv);
@@ -998,6 +1012,11 @@
dev_dbg(dev, "bias3_cfilt_sel %u bias4_cfilt_sel %u\n",
(u32)micbias->bias3_cfilt_sel, (u32)micbias->bias4_cfilt_sel);
+ dev_dbg(dev, "bias1_ext_cap %d bias2_ext_cap %d\n",
+ micbias->bias1_cap_mode, micbias->bias2_cap_mode);
+ dev_dbg(dev, "bias3_ext_cap %d bias4_ext_cap %d\n",
+ micbias->bias3_cap_mode, micbias->bias4_cap_mode);
+
return 0;
}
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 103c1a3..53e965c 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -218,6 +218,8 @@
if (ret < 0) {
dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
ret);
+ dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
+ disable_irq_nosync(wcd9xxx->irq);
wcd9xxx_unlock_sleep(wcd9xxx);
return IRQ_NONE;
}
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 1792104..8a1e0da 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -323,6 +323,10 @@
u32 time_limit;
u32 ref_count;
enum tspp_tsif_mode mode;
+ int clock_inverse;
+ int data_inverse;
+ int sync_inverse;
+ int enable_inverse;
/* debugfs */
struct dentry *dent_tsif;
@@ -698,6 +702,19 @@
if (start_hardware) {
ctl = TSIF_STS_CTL_EN_IRQ |
TSIF_STS_CTL_EN_DM;
+
+ if (tsif_device->clock_inverse)
+ ctl |= TSIF_STS_CTL_INV_CLOCK;
+
+ if (tsif_device->data_inverse)
+ ctl |= TSIF_STS_CTL_INV_DATA;
+
+ if (tsif_device->sync_inverse)
+ ctl |= TSIF_STS_CTL_INV_SYNC;
+
+ if (tsif_device->enable_inverse)
+ ctl |= TSIF_STS_CTL_INV_ENABLE;
+
switch (tsif_device->mode) {
case TSPP_TSIF_MODE_LOOPBACK:
ctl |= TSIF_STS_CTL_EN_NULL |
@@ -852,6 +869,10 @@
pdev->tsif[i].ref_count = 1; /* allows stopping hw */
tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
+ pdev->tsif[i].clock_inverse = 0;
+ pdev->tsif[i].data_inverse = 0;
+ pdev->tsif[i].sync_inverse = 0;
+ pdev->tsif[i].enable_inverse = 0;
}
writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
wmb();
@@ -913,7 +934,7 @@
}
/* open the stream */
- tspp_open_stream(dev, channel_id, src->source, src->mode);
+ tspp_open_stream(dev, channel_id, src);
return 0;
}
@@ -1011,14 +1032,37 @@
channel->pdev->tsif[index].mode = mode;
}
+static void tspp_set_signal_inversion(struct tspp_channel *channel,
+ int clock_inverse, int data_inverse,
+ int sync_inverse, int enable_inverse)
+{
+ int index;
+
+ switch (channel->src) {
+ case TSPP_SOURCE_TSIF0:
+ index = 0;
+ break;
+ case TSPP_SOURCE_TSIF1:
+ index = 1;
+ break;
+ default:
+ return;
+ }
+ channel->pdev->tsif[index].clock_inverse = clock_inverse;
+ channel->pdev->tsif[index].data_inverse = data_inverse;
+ channel->pdev->tsif[index].sync_inverse = sync_inverse;
+ channel->pdev->tsif[index].enable_inverse = enable_inverse;
+}
+
/*** TSPP API functions ***/
-int tspp_open_stream(u32 dev, u32 channel_id, enum tspp_source src, enum tspp_tsif_mode mode)
+int tspp_open_stream(u32 dev, u32 channel_id, struct tspp_select_source *source)
{
u32 val;
struct tspp_device *pdev;
struct tspp_channel *channel;
- TSPP_DEBUG("tspp_open_stream %i %i %i %i", dev, channel_id, src, mode);
+ TSPP_DEBUG("tspp_open_stream %i %i %i %i",
+ dev, channel_id, source->source, source->mode);
if (dev >= TSPP_MAX_DEVICES) {
pr_err("tspp: device id out of range");
return -ENODEV;
@@ -1035,10 +1079,13 @@
return -ENODEV;
}
channel = &pdev->channels[channel_id];
- channel->src = src;
- tspp_set_tsif_mode(channel, mode);
+ channel->src = source->source;
+ tspp_set_tsif_mode(channel, source->mode);
+ tspp_set_signal_inversion(channel, source->clk_inverse,
+ source->data_inverse, source->sync_inverse,
+ source->enable_inverse);
- switch (src) {
+ switch (source->source) {
case TSPP_SOURCE_TSIF0:
/* make sure TSIF0 is running & enabled */
if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
@@ -1064,7 +1111,8 @@
case TSPP_SOURCE_MEM:
break;
default:
- pr_err("tspp: channel %i invalid source %i", channel->id, src);
+ pr_err("tspp: channel %i invalid source %i",
+ channel->id, source->source);
return -EBUSY;
}
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 76a758b..1907adc 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -64,7 +64,7 @@
#define QPNP_PON_RESET_TYPE_MAX 0xF
#define PON_S1_COUNT_MAX 0xF
-#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(500)
+#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
enum pon_type {
PON_KPDPWR,
diff --git a/drivers/regulator/stub-regulator.c b/drivers/regulator/stub-regulator.c
index 1c4b935..85c5972 100644
--- a/drivers/regulator/stub-regulator.c
+++ b/drivers/regulator/stub-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,11 +16,14 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/kernel.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/stub-regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/stub-regulator.h>
#define STUB_REGULATOR_MAX_NAME 40
@@ -138,27 +141,74 @@
static int __devinit regulator_stub_probe(struct platform_device *pdev)
{
+ struct regulator_init_data *init_data = NULL;
+ struct device *dev = &pdev->dev;
struct stub_regulator_pdata *vreg_pdata;
struct regulator_desc *rdesc;
struct regulator_stub *vreg_priv;
int rc;
- vreg_pdata = pdev->dev.platform_data;
- if (!vreg_pdata) {
- dev_err(&pdev->dev, "%s: no platform data\n", __func__);
- return -EINVAL;
- }
-
vreg_priv = kzalloc(sizeof(*vreg_priv), GFP_KERNEL);
if (!vreg_priv) {
- dev_err(&pdev->dev, "%s: Unable to allocate memory\n",
+ dev_err(dev, "%s: Unable to allocate memory\n",
__func__);
return -ENOMEM;
}
- dev_set_drvdata(&pdev->dev, vreg_priv);
+
+ if (dev->of_node) {
+ /* Use device tree. */
+ init_data = of_get_regulator_init_data(dev,
+ dev->of_node);
+ if (!init_data) {
+ dev_err(dev, "%s: unable to allocate memory\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err_probe;
+ }
+
+ if (init_data->constraints.name == NULL) {
+ dev_err(dev, "%s: regulator name not specified\n",
+ __func__);
+ rc = -EINVAL;
+ goto err_probe;
+ }
+
+ if (of_get_property(dev->of_node, "parent-supply", NULL))
+ init_data->supply_regulator = "parent";
+
+ of_property_read_u32(dev->of_node, "qcom,system-load",
+ &vreg_priv->system_uA);
+ of_property_read_u32(dev->of_node, "qcom,hpm-min-load",
+ &vreg_priv->hpm_min_load);
+
+ init_data->constraints.input_uV = init_data->constraints.max_uV;
+
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_STATUS;
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_VOLTAGE;
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
+ init_data->constraints.valid_modes_mask
+ = REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+ } else {
+ /* Use platform data. */
+ vreg_pdata = dev->platform_data;
+ if (!vreg_pdata) {
+ dev_err(dev, "%s: no platform data\n", __func__);
+ rc = -EINVAL;
+ goto err_probe;
+ }
+ init_data = &vreg_pdata->init_data;
+
+ vreg_priv->system_uA = vreg_pdata->system_uA;
+ vreg_priv->hpm_min_load = vreg_pdata->hpm_min_load;
+ }
+
+ dev_set_drvdata(dev, vreg_priv);
rdesc = &vreg_priv->rdesc;
- strncpy(vreg_priv->name, vreg_pdata->init_data.constraints.name,
+ strlcpy(vreg_priv->name, init_data->constraints.name,
STUB_REGULATOR_MAX_NAME);
rdesc->name = vreg_priv->name;
rdesc->ops = ®ulator_stub_ops;
@@ -168,8 +218,8 @@
* which have a specified voltage constraint range, as well as those
* that do not.
*/
- if (vreg_pdata->init_data.constraints.min_uV == 0 &&
- vreg_pdata->init_data.constraints.max_uV == 0)
+ if (init_data->constraints.min_uV == 0 &&
+ init_data->constraints.max_uV == 0)
rdesc->n_voltages = 0;
else
rdesc->n_voltages = 2;
@@ -177,16 +227,20 @@
rdesc->id = pdev->id;
rdesc->owner = THIS_MODULE;
rdesc->type = REGULATOR_VOLTAGE;
- vreg_priv->system_uA = vreg_pdata->system_uA;
- vreg_priv->hpm_min_load = vreg_pdata->hpm_min_load;
- vreg_priv->voltage = vreg_pdata->init_data.constraints.min_uV;
+ vreg_priv->voltage = init_data->constraints.min_uV;
+ if (vreg_priv->system_uA >= vreg_priv->hpm_min_load)
+ vreg_priv->mode = REGULATOR_MODE_NORMAL;
+ else
+ vreg_priv->mode = REGULATOR_MODE_IDLE;
- vreg_priv->rdev = regulator_register(rdesc, &pdev->dev,
- &(vreg_pdata->init_data), vreg_priv, NULL);
+ vreg_priv->rdev = regulator_register(rdesc, dev, init_data, vreg_priv,
+ dev->of_node);
+
if (IS_ERR(vreg_priv->rdev)) {
rc = PTR_ERR(vreg_priv->rdev);
vreg_priv->rdev = NULL;
- dev_err(&pdev->dev, "%s: regulator_register failed\n",
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "%s: regulator_register failed\n",
__func__);
goto err_probe;
}
@@ -206,12 +260,18 @@
return 0;
}
+static struct of_device_id regulator_stub_match_table[] = {
+ { .compatible = "qcom," STUB_REGULATOR_DRIVER_NAME, },
+ {}
+};
+
static struct platform_driver regulator_stub_driver = {
.probe = regulator_stub_probe,
.remove = __devexit_p(regulator_stub_remove),
.driver = {
.name = STUB_REGULATOR_DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = regulator_stub_match_table,
},
};
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index f60e318..a932f6b 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -64,7 +64,7 @@
#define TSENS_UPPER_STATUS_CLR BIT((tsens_status_cntl_start + 2))
#define TSENS_MAX_STATUS_MASK BIT((tsens_status_cntl_start + 3))
-#define TSENS_MEASURE_PERIOD 4 /* 1 sec. default */
+#define TSENS_MEASURE_PERIOD 1
#define TSENS_8960_SLP_CLK_ENA BIT(26)
#define TSENS_THRESHOLD_ADDR (MSM_CLK_CTL_BASE + 0x00003624)
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 6887fef..8e13fbf 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -50,7 +50,13 @@
#define TSENS_TRDY_MASK BIT(0)
#define TSENS_CTRL_ADDR(n) (n)
+#define TSENS_EN BIT(0)
#define TSENS_SW_RST BIT(1)
+#define TSENS_ADC_CLK_SEL BIT(2)
+#define TSENS_SENSOR0_SHIFT 3
+#define TSENS_312_5_MS_MEAS_PERIOD 2
+#define TSENS_MEAS_PERIOD_SHIFT 18
+
#define TSENS_SN_MIN_MAX_STATUS_CTRL(n) ((n) + 4)
#define TSENS_GLOBAL_CONFIG(n) ((n) + 0x34)
#define TSENS_S0_MAIN_CONFIG(n) ((n) + 0x38)
@@ -156,7 +162,6 @@
#define TSENS_THRESHOLD_MAX_CODE 0x3ff
#define TSENS_THRESHOLD_MIN_CODE 0x0
-#define TSENS_CTRL_INIT_DATA1 0x1cfff9
#define TSENS_GLOBAL_INIT_DATA 0x302f16c
#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
@@ -521,8 +526,10 @@
reg_cntl = readl_relaxed(TSENS_CTRL_ADDR(tmdev->tsens_addr));
writel_relaxed(reg_cntl | TSENS_SW_RST,
TSENS_CTRL_ADDR(tmdev->tsens_addr));
- writel_relaxed(TSENS_CTRL_INIT_DATA1,
- TSENS_CTRL_ADDR(tmdev->tsens_addr));
+ reg_cntl |= ((TSENS_312_5_MS_MEAS_PERIOD << TSENS_MEAS_PERIOD_SHIFT) |
+ (((1 << tmdev->tsens_num_sensor) - 1) << TSENS_SENSOR0_SHIFT) |
+ TSENS_EN);
+ writel_relaxed(reg_cntl, TSENS_CTRL_ADDR(tmdev->tsens_addr));
writel_relaxed(TSENS_GLOBAL_INIT_DATA,
TSENS_GLOBAL_CONFIG(tmdev->tsens_addr));
writel_relaxed(TSENS_S0_MAIN_CFG_INIT_DATA,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index dc35da8..9b1576b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1490,7 +1490,7 @@
{
struct dwc3 *dwc = gadget_to_dwc(_gadget);
unsigned long flags;
- int ret;
+ int ret = 0;
if (!dwc->dotg)
return -EPERM;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ca5f890..b711fd9 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -81,6 +81,42 @@
unsigned long arg);
static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+void mdss_fb_no_update_notify_timer_cb(unsigned long data)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
+ if (!mfd)
+ pr_err("%s mfd NULL\n", __func__);
+ complete(&mfd->no_update.comp);
+}
+
+static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
+ unsigned long *argp)
+{
+ int ret, notify;
+
+ ret = copy_from_user(¬ify, argp, sizeof(int));
+ if (ret) {
+ pr_err("%s:ioctl failed\n", __func__);
+ return ret;
+ }
+
+ if (notify > NOTIFY_UPDATE_STOP)
+ return -EINVAL;
+
+ if (notify == NOTIFY_UPDATE_START) {
+ INIT_COMPLETION(mfd->update.comp);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->update.comp, 4 * HZ);
+ } else {
+ INIT_COMPLETION(mfd->no_update.comp);
+ ret = wait_for_completion_interruptible_timeout(
+ &mfd->no_update.comp, 4 * HZ);
+ }
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ return (ret > 0) ? 0 : ret;
+}
+
#define MAX_BACKLIGHT_BRIGHTNESS 255
static int lcd_backlight_registered;
@@ -101,7 +137,9 @@
if (!bl_lvl && value)
bl_lvl = 1;
+ mutex_lock(&mfd->lock);
mdss_fb_set_backlight(mfd, bl_lvl);
+ mutex_unlock(&mfd->lock);
}
static struct led_classdev backlight_led = {
@@ -209,6 +247,8 @@
mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
mfd->panel_info.frame_count = 0;
mfd->bl_level = 0;
+ mfd->bl_scale = 1024;
+ mfd->bl_min_lvl = 30;
mfd->fb_imgType = MDP_RGBA_8888;
mfd->pdev = pdev;
@@ -269,6 +309,11 @@
pr_err("msm_fb_remove: can't stop the device %d\n",
mfd->index);
+ if (mfd->no_update.timer.function)
+ del_timer(&mfd->no_update.timer);
+ complete(&mfd->no_update.comp);
+ complete(&mfd->update.comp);
+
/* remove /dev/fb* */
unregister_framebuffer(mfd->fbi);
@@ -416,9 +461,46 @@
static int unset_bl_level, bl_updated;
static int bl_level_old;
+static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
+ struct mdp_bl_scale_data *data)
+{
+ int ret = 0;
+ int curr_bl;
+ mutex_lock(&mfd->lock);
+ curr_bl = mfd->bl_level;
+ mfd->bl_scale = data->scale;
+ mfd->bl_min_lvl = data->min_lvl;
+ pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
+ mfd->bl_min_lvl);
+
+ /* update current backlight to use new scaling*/
+ mdss_fb_set_backlight(mfd, curr_bl);
+ mutex_unlock(&mfd->lock);
+ return ret;
+}
+
+static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
+{
+ u32 temp = *bl_lvl;
+ pr_debug("input = %d, scale = %d", temp, mfd->bl_scale);
+ if (temp >= mfd->bl_min_lvl) {
+ /* bl_scale is the numerator of scaling fraction (x/1024)*/
+ temp = (temp * mfd->bl_scale) / 1024;
+
+ /*if less than minimum level, use min level*/
+ if (temp < mfd->bl_min_lvl)
+ temp = mfd->bl_min_lvl;
+ }
+ pr_debug("output = %d", temp);
+
+ (*bl_lvl) = temp;
+}
+
+/* must call this function from within mfd->lock */
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
{
struct mdss_panel_data *pdata;
+ u32 temp = bkl_lvl;
if (!mfd->panel_power_on || !bl_updated) {
unset_bl_level = bkl_lvl;
@@ -430,15 +512,22 @@
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
- mutex_lock(&mfd->lock);
- if (bl_level_old == bkl_lvl) {
- mutex_unlock(&mfd->lock);
+ mdss_fb_scale_bl(mfd, &temp);
+ /*
+ * Even though backlight has been scaled, want to show that
+ * backlight has been set to bkl_lvl to those that read from
+ * sysfs node. Thus, need to set bl_level even if it appears
+ * the backlight has already been set to the level it is at,
+ * as well as setting bl_level to bkl_lvl even though the
+ * backlight has been set to the scaled value.
+ */
+ if (bl_level_old == temp) {
+ mfd->bl_level = bkl_lvl;
return;
}
+ pdata->set_backlight(pdata, temp);
mfd->bl_level = bkl_lvl;
- pdata->set_backlight(pdata, mfd->bl_level);
- bl_level_old = mfd->bl_level;
- mutex_unlock(&mfd->lock);
+ bl_level_old = temp;
}
}
@@ -822,6 +911,13 @@
mfd->op_enable = true;
+ mutex_init(&mfd->no_update.lock);
+ init_timer(&mfd->no_update.timer);
+ mfd->no_update.timer.function = mdss_fb_no_update_notify_timer_cb;
+ mfd->no_update.timer.data = (unsigned long)mfd;
+ init_completion(&mfd->update.comp);
+ init_completion(&mfd->no_update.comp);
+
if (mfd->lut_update) {
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret)
@@ -1124,7 +1220,8 @@
return 0;
}
-static int mdss_fb_handle_pp_ioctl(void __user *argp)
+static int mdss_fb_handle_pp_ioctl(struct msm_fb_data_type *mfd,
+ void __user *argp)
{
int ret;
struct msmfb_mdp_pp mdp_pp;
@@ -1179,6 +1276,10 @@
ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
©back);
break;
+ case mdp_bl_scale_cfg:
+ ret = mdss_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
+ &mdp_pp.data.bl_scale_data);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -1256,7 +1357,11 @@
break;
case MSMFB_MDP_PP:
- ret = mdss_fb_handle_pp_ioctl(argp);
+ ret = mdss_fb_handle_pp_ioctl(mfd, argp);
+ break;
+
+ case MSMFB_NOTIFY_UPDATE:
+ ret = mdss_fb_notify_update(mfd, argp);
break;
default:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 25c39f6..78f2b9a 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -41,6 +41,13 @@
int panel_power_on;
};
+struct disp_info_notify {
+ int type;
+ struct timer_list timer;
+ struct completion comp;
+ struct mutex lock;
+};
+
struct msm_fb_data_type {
u32 key;
u32 index;
@@ -83,6 +90,8 @@
unsigned long cursor_buf_iova;
u32 bl_level;
+ u32 bl_scale;
+ u32 bl_min_lvl;
struct mutex lock;
struct platform_device *pdev;
@@ -98,6 +107,8 @@
struct list_head overlay_list;
struct list_head pipes_used;
struct list_head pipes_cleanup;
+ struct disp_info_notify update;
+ struct disp_info_notify no_update;
};
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 8b4434e..c9acc65 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -150,8 +150,11 @@
(fmt->bits[C1_B_Cb] << 2) |
(fmt->bits[C0_G_Y] << 0);
- if (fmt->alpha_enable)
+ if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
dst_format |= BIT(8); /* DSTC3_EN */
+ if (!fmt->alpha_enable)
+ dst_format |= BIT(14); /* DST_ALPHA_X */
+ }
if (fmt->fetch_planes != MDSS_MDP_PLANE_PLANAR) {
pattern = (fmt->element[3] << 24) | (fmt->element[2] << 15) |
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 452ebdc..d52df66 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -406,6 +406,15 @@
if (IS_ERR_VALUE(ret))
return ret;
+ complete(&mfd->update.comp);
+ mutex_lock(&mfd->no_update.lock);
+ if (mfd->no_update.timer.function)
+ del_timer(&(mfd->no_update.timer));
+
+ mfd->no_update.timer.expires = jiffies + (2 * HZ);
+ add_timer(&mfd->no_update.timer);
+ mutex_unlock(&mfd->no_update.lock);
+
mutex_lock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
list_del(&pipe->cleanup_list);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 6e04124..e4be407 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -99,6 +99,7 @@
u32 hist_cnt_read;
u32 hist_cnt_sent;
u32 frame_cnt;
+ u32 is_kick_ready;
struct completion comp;
u32 data[HIST_V_SIZE];
};
@@ -365,6 +366,7 @@
struct pp_hist_col_info *hist_info;
struct pp_sts_type *pp_sts;
u32 data, tbl_idx, col_state;
+ unsigned long flag;
int i;
dspp_num = mixer->num;
/* no corresponding dspp */
@@ -377,20 +379,19 @@
/* HIST_EN & AUTO_CLEAR */
opmode |= (1 << 16) | (1 << 17);
mutex_lock(&mdss_mdp_hist_mutex);
- if (hist_info->col_state == HIST_READY)
- pp_hist_read(base + MDSS_MDP_REG_DSPP_HIST_CTL_BASE +
- 0x1C, hist_info);
- spin_lock(&mdss_hist_lock);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
col_state = hist_info->col_state;
- if ((col_state == HIST_IDLE) ||
- (col_state == HIST_READY) ||
- (col_state == HIST_START)) {
+ if (hist_info->is_kick_ready &&
+ ((col_state == HIST_IDLE) ||
+ ((false == hist_info->read_request) &&
+ col_state == HIST_READY))) {
/* Kick off collection */
MDSS_MDP_REG_WRITE(base +
MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
hist_info->col_state = HIST_START;
}
- spin_unlock(&mdss_hist_lock);
+ hist_info->is_kick_ready = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
mutex_unlock(&mdss_mdp_hist_mutex);
}
@@ -1263,6 +1264,7 @@
int i, ret = 0;
u32 disp_num, dspp_num = 0;
u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ unsigned long flag;
if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(req->block >= MDP_BLOCK_MAX))
@@ -1296,7 +1298,7 @@
__func__, dspp_num);
goto hist_start_exit;
}
- spin_lock(&mdss_hist_lock);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
hist_info->frame_cnt = req->frame_cnt;
init_completion(&hist_info->comp);
hist_info->hist_cnt_read = 0;
@@ -1304,7 +1306,8 @@
hist_info->read_request = false;
hist_info->col_state = HIST_RESET;
hist_info->col_en = true;
- spin_unlock(&mdss_hist_lock);
+ hist_info->is_kick_ready = false;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
mdss_pp_res->hist_col[disp_num][i] =
&mdss_pp_res->dspp_hist[dspp_num];
mdss_mdp_hist_irq_enable(3 << done_shift_bit);
@@ -1329,6 +1332,7 @@
u32 dspp_num, disp_num, ctl_base, done_bit;
struct pp_hist_col_info *hist_info;
u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ unsigned long flag;
if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
(block >= MDP_BLOCK_MAX))
@@ -1362,10 +1366,11 @@
goto hist_stop_exit;
}
complete_all(&hist_info->comp);
- spin_lock(&mdss_hist_lock);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
hist_info->col_en = false;
hist_info->col_state = HIST_UNKNOWN;
- spin_unlock(&mdss_hist_lock);
+ hist_info->is_kick_ready = false;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
mdss_mdp_hist_irq_disable(done_bit);
MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
}
@@ -1386,6 +1391,7 @@
struct pp_hist_col_info *hist_info;
u32 dspp_num, disp_num, ctl_base;
u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ unsigned long flag;
if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(hist->block >= MDP_BLOCK_MAX))
@@ -1418,55 +1424,50 @@
ret = -EINVAL;
goto hist_collect_exit;
}
- spin_lock(&mdss_hist_lock);
- if ((hist_info->col_state == HIST_READY) ||
- (hist_info->hist_cnt_read == 0)) {
- /* wait for hist done if cache has no data */
- if ((hist_info->col_state != HIST_READY) &&
- (hist_info->hist_cnt_read == 0)) {
- hist_info->read_request = true;
- spin_unlock(&mdss_hist_lock);
- timeout = HIST_WAIT_TIMEOUT *
- hist_info->frame_cnt;
- mutex_unlock(&mdss_mdp_hist_mutex);
- wait_ret = wait_for_completion_killable_timeout(
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ /* wait for hist done if cache has no data */
+ if (hist_info->col_state != HIST_READY) {
+ hist_info->read_request = true;
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ timeout = HIST_WAIT_TIMEOUT *
+ hist_info->frame_cnt;
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ wait_ret = wait_for_completion_killable_timeout(
&(hist_info->comp), timeout);
- mutex_lock(&mdss_mdp_hist_mutex);
- hist_info->read_request = false;
- if (wait_ret == 0) {
- ret = -ETIMEDOUT;
- pr_debug("%s: bin collection timedout",
+ mutex_lock(&mdss_mdp_hist_mutex);
+ if (wait_ret == 0) {
+ ret = -ETIMEDOUT;
+ pr_debug("%s: bin collection timedout",
__func__);
- goto hist_collect_exit;
- } else if (wait_ret < 0) {
- ret = -EINTR;
- pr_debug("%s: bin collection interrupted",
+ goto hist_collect_exit;
+ } else if (wait_ret < 0) {
+ ret = -EINTR;
+ pr_debug("%s: bin collection interrupted",
__func__);
- goto hist_collect_exit;
- }
- if (hist_info->col_state != HIST_READY) {
- ret = -EBUSY;
- pr_err("%s: collection state is not ready: %d",
- __func__, hist_info->col_state);
- goto hist_collect_exit;
- }
- } else {
- spin_unlock(&mdss_hist_lock);
+ goto hist_collect_exit;
}
- if (hist_info->col_state == HIST_READY) {
- v_base = ctl_base + 0x1C;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pp_hist_read(v_base, hist_info);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- spin_lock(&mdss_hist_lock);
- hist_info->col_state = HIST_IDLE;
- spin_unlock(&mdss_hist_lock);
+ if (hist_info->col_state != HIST_READY) {
+ ret = -ENODATA;
+ pr_debug("%s: collection state is not ready: %d",
+ __func__, hist_info->col_state);
+ goto hist_collect_exit;
}
} else {
- spin_unlock(&mdss_hist_lock);
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
}
- hist_info->hist_cnt_sent = hist_info->hist_cnt_read;
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ if (hist_info->col_state == HIST_READY) {
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
+ v_base = ctl_base + 0x1C;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ pp_hist_read(v_base, hist_info);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ spin_lock_irqsave(&mdss_hist_lock, flag);
+ hist_info->read_request = false;
+ hist_info->col_state = HIST_IDLE;
+ }
+ spin_unlock_irqrestore(&mdss_hist_lock, flag);
}
if (mixer_cnt > 1) {
memset(&mdss_pp_res->hist_data[disp_num][0],
@@ -1482,7 +1483,7 @@
} else {
*hist_data_addr = (u32)hist_info->data;
}
-
+ hist_info->hist_cnt_sent++;
hist_collect_exit:
mutex_unlock(&mdss_mdp_hist_mutex);
return ret;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 1cdc434..98050ce 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -399,7 +399,7 @@
uint32_t block;
uint8_t frame_cnt;
uint8_t bit_mask;
- uint8_t num_bins;
+ uint16_t num_bins;
};
/*
diff --git a/include/linux/regulator/stub-regulator.h b/include/linux/regulator/stub-regulator.h
index e7f4110..1155d82 100644
--- a/include/linux/regulator/stub-regulator.h
+++ b/include/linux/regulator/stub-regulator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,5 +31,24 @@
int system_uA;
};
+#ifdef CONFIG_REGULATOR_STUB
+
+/**
+ * regulator_stub_init() - register platform driver for stub-regulator
+ *
+ * This initialization function should be called in systems in which driver
+ * registration ordering must be controlled precisely.
+ */
+
int __init regulator_stub_init(void);
+
+#else
+
+static inline int __init regulator_stub_init(void)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_REGULATOR_STUB */
+
#endif
diff --git a/include/linux/tspp.h b/include/linux/tspp.h
index 3f0cc81..551fbb0 100644
--- a/include/linux/tspp.h
+++ b/include/linux/tspp.h
@@ -42,6 +42,10 @@
struct tspp_select_source {
enum tspp_source source;
enum tspp_tsif_mode mode;
+ int clk_inverse;
+ int data_inverse;
+ int sync_inverse;
+ int enable_inverse;
};
struct tspp_pid {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index cc390d0..41ff312 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1804,6 +1804,12 @@
V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0,
V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 23)
+enum v4l2_mpeg_vidc_video_sync_frame_decode {
+ V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE = 0,
+ V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE = 1
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 6658b8c..9af15e3 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -536,6 +536,8 @@
#define CMD_STATS_BHIST_BUF_RELEASE 58
#define CMD_VFE_PIX_SOF_COUNT_UPDATE 59
#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60
+#define CMD_STATS_BE_ENABLE 61
+#define CMD_STATS_BE_BUF_RELEASE 62
#define CMD_AXI_CFG_PRIM BIT(8)
#define CMD_AXI_CFG_PRIM_ALL_CHNLS BIT(9)
@@ -599,7 +601,8 @@
#define MSM_PMEM_BAYER_GRID 20
#define MSM_PMEM_BAYER_FOCUS 21
#define MSM_PMEM_BAYER_HIST 22
-#define MSM_PMEM_MAX 23
+#define MSM_PMEM_BAYER_EXPOSURE 23
+#define MSM_PMEM_MAX 24
#define STAT_AEAW 0
#define STAT_AEC 1
@@ -611,8 +614,9 @@
#define STAT_SKIN 7
#define STAT_BG 8
#define STAT_BF 9
-#define STAT_BHIST 10
-#define STAT_MAX 11
+#define STAT_BE 10
+#define STAT_BHIST 11
+#define STAT_MAX 12
#define FRAME_PREVIEW_OUTPUT1 0
#define FRAME_PREVIEW_OUTPUT2 1
@@ -631,6 +635,7 @@
MSM_STATS_TYPE_SKIN, /* legacy based SKIN */
MSM_STATS_TYPE_BG, /* Bayer Grids */
MSM_STATS_TYPE_BF, /* Bayer Focus */
+ MSM_STATS_TYPE_BE, /* Bayer Exposure*/
MSM_STATS_TYPE_BHIST, /* Bayer Hist */
MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/
MSM_STATS_TYPE_COMP, /* Composite stats */
@@ -807,6 +812,7 @@
struct stats_buff aec;
struct stats_buff awb;
struct stats_buff af;
+ struct stats_buff be;
struct stats_buff ihist;
struct stats_buff rs;
struct stats_buff cs;
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index faaa522..8b4ae19 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -70,6 +70,7 @@
#define MSG_ID_RDI2_UPDATE_ACK 51
#define MSG_ID_PIX0_UPDATE_ACK 52
#define MSG_ID_PREV_STOP_ACK 53
+#define MSG_ID_STATS_BE 54
/* ISP command IDs */
@@ -236,7 +237,8 @@
#define VFE_CMD_COLORXFORM_ENC_UPDATE 160
#define VFE_CMD_COLORXFORM_VIEW_UPDATE 161
#define VFE_CMD_TEST_GEN_CFG 162
-
+#define VFE_CMD_STATS_BE_START 163
+#define VFE_CMD_STATS_BE_STOP 164
struct msm_isp_cmd {
int32_t id;
uint16_t length;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 6d684ef..3db949c 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -110,6 +110,7 @@
uint8_t buf_num;
bool top_field;
+ bool field_dropped;
struct timeval vc_ts;
uint32_t last_ts;
diff --git a/include/sound/asound.h b/include/sound/asound.h
index a2e4ff5..7bf01b6 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -458,6 +458,36 @@
SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
};
+/* channel positions */
+enum {
+ SNDRV_CHMAP_UNKNOWN = 0,
+ SNDRV_CHMAP_FL, /* front left */
+ SNDRV_CHMAP_FC, /* front center */
+ SNDRV_CHMAP_FR, /* front right */
+ SNDRV_CHMAP_FLC, /* front left center */
+ SNDRV_CHMAP_FRC, /* front right center */
+ SNDRV_CHMAP_RL, /* rear left */
+ SNDRV_CHMAP_RC, /* rear center */
+ SNDRV_CHMAP_RR, /* rear right */
+ SNDRV_CHMAP_RLC, /* rear left center */
+ SNDRV_CHMAP_RRC, /* rear right center */
+ SNDRV_CHMAP_SL, /* side left */
+ SNDRV_CHMAP_SR, /* side right */
+ SNDRV_CHMAP_LFE, /* LFE */
+ SNDRV_CHMAP_FLW, /* front left wide */
+ SNDRV_CHMAP_FRW, /* front right wide */
+ SNDRV_CHMAP_FLH, /* front left high */
+ SNDRV_CHMAP_FCH, /* front center high */
+ SNDRV_CHMAP_FRH, /* front right high */
+ SNDRV_CHMAP_TC, /* top center */
+ SNDRV_CHMAP_NA, /* N/A, silent */
+ SNDRV_CHMAP_LAST = SNDRV_CHMAP_NA,
+};
+
+#define SNDRV_CHMAP_POSITION_MASK 0xffff
+#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16)
+#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16)
+
#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 485e1c5..028e683 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -446,6 +446,7 @@
struct snd_info_entry *proc_xrun_debug_entry;
#endif
#endif
+ struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
};
struct snd_pcm {
@@ -1080,4 +1081,51 @@
const char *snd_pcm_format_name(snd_pcm_format_t format);
+/*
+ * PCM channel-mapping control API
+ */
+/* array element of channel maps */
+struct snd_pcm_chmap_elem {
+ unsigned char channels;
+ unsigned char map[15];
+};
+
+/* channel map information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_chmap {
+ struct snd_pcm *pcm; /* assigned PCM instance */
+ int stream; /* PLAYBACK or CAPTURE */
+ struct snd_kcontrol *kctl;
+ const struct snd_pcm_chmap_elem *chmap;
+ unsigned int max_channels;
+ unsigned int channel_mask; /* optional: active channels bitmask */
+ void *private_data; /* optional: private data pointer */
+};
+
+/* get the PCM substream assigned to the given chmap info */
+static inline struct snd_pcm_substream *
+snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx)
+{
+ struct snd_pcm_substream *s;
+ for (s = info->pcm->streams[info->stream].substream; s; s = s->next)
+ if (s->number == idx)
+ return s;
+ return NULL;
+}
+
+/* ALSA-standard channel maps (RL/RR prior to C/LFE) */
+extern const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[];
+/* Other world's standard channel maps (C/LFE prior to RL/RR) */
+extern const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[];
+
+/* bit masks to be passed to snd_pcm_chmap.channel_mask field */
+#define SND_PCM_CHMAP_MASK_24 ((1U << 2) | (1U << 4))
+#define SND_PCM_CHMAP_MASK_246 (SND_PCM_CHMAP_MASK_24 | (1U << 6))
+#define SND_PCM_CHMAP_MASK_2468 (SND_PCM_CHMAP_MASK_246 | (1U << 8))
+
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_chmap_elem *chmap,
+ int max_channels,
+ unsigned long private_value,
+ struct snd_pcm_chmap **info_ret);
+
#endif /* __SOUND_PCM_H */
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
index 7067e2d..de36aaa 100644
--- a/include/sound/tlv.h
+++ b/include/sound/tlv.h
@@ -73,4 +73,12 @@
#define TLV_DB_GAIN_MUTE -9999999
+/*
+ * channel-mapping TLV items
+ * TLV length must match with num_channels
+ */
+#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */
+#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */
+#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */
+
#endif /* __SOUND_TLV_H */
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 09bf06e..d98e160 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1195,6 +1195,10 @@
break;
}
snd_unregister_device(devtype, pcm->card, pcm->device);
+ if (pcm->streams[cidx].chmap_kctl) {
+ snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
+ pcm->streams[cidx].chmap_kctl = NULL;
+ }
}
unlock:
mutex_unlock(®ister_mutex);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index b5d5a75..e0ab899 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -25,6 +25,7 @@
#include <linux/export.h>
#include <sound/core.h>
#include <sound/control.h>
+#include <sound/tlv.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -2289,3 +2290,216 @@
}
EXPORT_SYMBOL(snd_pcm_lib_readv);
+
+/*
+ * standard channel mapping helpers
+ */
+
+/* default channel maps for multi-channel playbacks, up to 8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_FC } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+ { .channels = 8,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
+
+/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
+ { .channels = 1,
+ .map = { SNDRV_CHMAP_FC } },
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 8,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+ { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
+
+static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
+{
+ if (ch > info->max_channels)
+ return false;
+ return !info->channel_mask || (info->channel_mask & (1U << ch));
+}
+
+static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 0;
+ uinfo->count = info->max_channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+ return 0;
+}
+
+/* get callback for channel map ctl element
+ * stores the channel position firstly matching with the current channels
+ */
+static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ struct snd_pcm_substream *substream;
+ const struct snd_pcm_chmap_elem *map;
+
+ if (snd_BUG_ON(!info->chmap))
+ return -EINVAL;
+ substream = snd_pcm_chmap_substream(info, idx);
+ if (!substream)
+ return -ENODEV;
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+ if (!substream->runtime)
+ return 0; /* no channels set */
+ for (map = info->chmap; map->channels; map++) {
+ int i;
+ if (map->channels == substream->runtime->channels &&
+ valid_chmap_channels(info, map->channels)) {
+ for (i = 0; i < map->channels; i++)
+ ucontrol->value.integer.value[i] = map->map[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/* tlv callback for channel map ctl element
+ * expands the pre-defined channel maps in a form of TLV
+ */
+static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ const struct snd_pcm_chmap_elem *map;
+ unsigned int __user *dst;
+ int c, count = 0;
+
+ if (snd_BUG_ON(!info->chmap))
+ return -EINVAL;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+ return -EFAULT;
+ size -= 8;
+ dst = tlv + 2;
+ for (map = info->chmap; map->channels; map++) {
+ int chs_bytes = map->channels * 4;
+ if (!valid_chmap_channels(info, map->channels))
+ continue;
+ if (size < 8)
+ return -ENOMEM;
+ if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
+ put_user(chs_bytes, dst + 1))
+ return -EFAULT;
+ dst += 2;
+ size -= 8;
+ count += 8;
+ if (size < chs_bytes)
+ return -ENOMEM;
+ size -= chs_bytes;
+ count += chs_bytes;
+ for (c = 0; c < map->channels; c++) {
+ if (put_user(map->map[c], dst))
+ return -EFAULT;
+ dst++;
+ }
+ }
+ if (put_user(count, tlv + 1))
+ return -EFAULT;
+ return 0;
+}
+
+static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ info->pcm->streams[info->stream].chmap_kctl = NULL;
+ kfree(info);
+}
+
+/**
+ * snd_pcm_add_chmap_ctls - create channel-mapping control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @chmap: channel map elements (for query)
+ * @max_channels: the max number of channels for the stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_chmap instance if non-NULL
+ *
+ * Create channel-mapping control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+ const struct snd_pcm_chmap_elem *chmap,
+ int max_channels,
+ unsigned long private_value,
+ struct snd_pcm_chmap **info_ret)
+{
+ struct snd_pcm_chmap *info;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = pcm_chmap_ctl_info,
+ .get = pcm_chmap_ctl_get,
+ .tlv.c = pcm_chmap_ctl_tlv,
+ };
+ int err;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pcm = pcm;
+ info->stream = stream;
+ info->chmap = chmap;
+ info->max_channels = max_channels;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ knew.name = "Playback Channel Map";
+ else
+ knew.name = "Capture Channel Map";
+ knew.device = pcm->device;
+ knew.count = pcm->streams[stream].substream_count;
+ knew.private_value = private_value;
+ info->kctl = snd_ctl_new1(&knew, info);
+ if (!info->kctl) {
+ kfree(info);
+ return -ENOMEM;
+ }
+ info->kctl->private_free = pcm_chmap_ctl_private_free;
+ err = snd_ctl_add(pcm->card, info->kctl);
+ if (err < 0)
+ return err;
+ pcm->streams[stream].chmap_kctl = info->kctl;
+ if (info_ret)
+ *info_ret = info;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index dcaf67f..1703c37 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -297,6 +297,7 @@
snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x02);
snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_4, 0xFF, 0xFF);
snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x04);
+ snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x00);
snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x00);
snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x80);
@@ -309,12 +310,26 @@
static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
+ struct snd_soc_codec *codec = w->codec;
+
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x0f, 0x01);
+ break;
+
case SND_SOC_DAPM_POST_PMU:
usleep_range(1000, 1000);
break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x0f, 0x08);
+ break;
}
return 0;
}
@@ -1932,7 +1947,7 @@
int anc_size_remaining;
u32 *anc_ptr;
u16 reg;
- u8 mask, val, old_val;
+ u8 mask, val;
pr_debug("%s %d\n", __func__, event);
switch (event) {
@@ -1999,9 +2014,7 @@
for (i = 0; i < anc_writes_size; i++) {
TAIKO_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
mask, val);
- old_val = snd_soc_read(codec, reg);
- snd_soc_write(codec, reg, (old_val & ~mask) |
- (val & mask));
+ snd_soc_write(codec, reg, val);
}
release_firmware(fw);
@@ -2599,15 +2612,27 @@
{"LINEOUT4", NULL, "LINEOUT4 PA"},
{"SPK_OUT", NULL, "SPK PA"},
+ {"LINEOUT1 PA", NULL, "CP"},
{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
+
+ {"LINEOUT2 PA", NULL, "CP"},
{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
+
+ {"LINEOUT3 PA", NULL, "CP"},
{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
+
+ {"LINEOUT4 PA", NULL, "CP"},
{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
+ {"CP", NULL, "CLASS_H_LINEOUTS_PA"},
+ {"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
+
+
+
{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
{"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
@@ -3886,6 +3911,9 @@
SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
+
SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
taiko_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -4369,6 +4397,20 @@
}
}
+ /* Set micbias capless mode with tail current */
+ value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x16);
+ snd_soc_update_bits(codec, TAIKO_A_MICB_1_CTL, 0x1E, value);
+ value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x16);
+ snd_soc_update_bits(codec, TAIKO_A_MICB_2_CTL, 0x1E, value);
+ value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x16);
+ snd_soc_update_bits(codec, TAIKO_A_MICB_3_CTL, 0x1E, value);
+ value = (pdata->micbias.bias4_cap_mode == MICBIAS_EXT_BYP_CAP ?
+ 0x00 : 0x16);
+ snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
+
taiko_config_ear_class_h(codec, 32);
taiko_config_hph_class_h(codec, 16);
@@ -4423,6 +4465,9 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+ /* TX VHIGH comparator */
+ TAIKO_REG_VAL(TAIKO_A_TX_SUP_SWITCH_CTRL_2, 0x90),
};
static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 3d7c0d4..653effa 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -68,7 +68,7 @@
#define FW_READ_ATTEMPTS 15
#define FW_READ_TIMEOUT 2000000
-#define BUTTON_POLLING_SUPPORTED false
+#define BUTTON_POLLING_SUPPORTED true
#define MCLK_RATE_12288KHZ 12288000
#define MCLK_RATE_9600KHZ 9600000
@@ -564,9 +564,21 @@
return;
pr_debug("%s: Setting up %s detection\n", __func__,
ins ? "insert" : "removal");
- /* Enable interrupt and insertion detection */
+ /* Disable detection to avoid glitch */
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
+ /* Override mbhc power switch to avoid false IRQs */
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_1_MBHC, 1 << 2,
+ !ins << 2);
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_2_MBHC, 1 << 2,
+ !ins << 2);
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_3_MBHC, 1 << 2,
+ !ins << 2);
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MICB_4_MBHC, 1 << 2,
+ !ins << 2);
snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
- (0x69 | (ins ? (1 << 1) : 0)));
+ (0x68 | (ins ? (1 << 1) : 0)));
+ /* Re-enable detection */
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
}
/* called under codec_resource_lock acquisition */
@@ -835,8 +847,6 @@
cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
- snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
-
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x84);
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index fcfcb66..98c28aa 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -224,14 +224,14 @@
prtd->channel_map[0] = PCM_CHANNEL_FL;
} else if (prtd->channel_mode == 2) {
prtd->channel_map[0] = PCM_CHANNEL_FL;
- prtd->channel_map[0] = PCM_CHANNEL_FR;
+ prtd->channel_map[1] = PCM_CHANNEL_FR;
} else if (prtd->channel_mode == 6) {
prtd->channel_map[0] = PCM_CHANNEL_FC;
- prtd->channel_map[0] = PCM_CHANNEL_FL;
- prtd->channel_map[0] = PCM_CHANNEL_FR;
- prtd->channel_map[0] = PCM_CHANNEL_LB;
- prtd->channel_map[0] = PCM_CHANNEL_RB;
- prtd->channel_map[0] = PCM_CHANNEL_LFE;
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ prtd->channel_map[3] = PCM_CHANNEL_LB;
+ prtd->channel_map[4] = PCM_CHANNEL_RB;
+ prtd->channel_map[5] = PCM_CHANNEL_LFE;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
prtd->channel_mode);
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 7d04f95..bd4a521 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -276,8 +276,8 @@
if (prtd->channel_mode == 1) {
prtd->channel_map[0] = PCM_CHANNEL_FL;
} else if (prtd->channel_mode == 2) {
- prtd->channel_map[1] = PCM_CHANNEL_FL;
- prtd->channel_map[2] = PCM_CHANNEL_FR;
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[1] = PCM_CHANNEL_FR;
} else if (prtd->channel_mode == 6) {
prtd->channel_map[0] = PCM_CHANNEL_FC;
prtd->channel_map[1] = PCM_CHANNEL_FL;
@@ -513,16 +513,6 @@
return rc;
}
-void multi_ch_pcm_set_channel_map(char *channel_mapping)
-{
- pr_debug("%s\n", __func__);
- if (multi_ch_pcm_audio.prtd) {
- multi_ch_pcm_audio.prtd->set_channel_map = true;
- memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
- PCM_FORMAT_MAX_NUM_CHANNEL);
- }
-}
-
static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
{
@@ -823,13 +813,51 @@
.mmap = msm_pcm_mmap,
};
+
+static int pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ pr_debug("%s", __func__);
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+ if (multi_ch_pcm_audio.prtd) {
+ multi_ch_pcm_audio.prtd->set_channel_map = true;
+ memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+ return 0;
+}
+
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
- int ret = 0;
+ struct snd_pcm *pcm = rtd->pcm->streams[0].pcm;
+ struct snd_pcm_chmap *chmap_info;
+ struct snd_kcontrol *kctl;
+ char device_num[3];
+ int i, ret = 0;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ pr_debug("%s, Channel map cntrl add\n", __func__);
+ ret = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, PCM_FORMAT_MAX_NUM_CHANNEL, 0,
+ &chmap_info);
+ if (ret < 0)
+ return ret;
+ kctl = chmap_info->kctl;
+ for (i = 0; i < kctl->count; i++)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ snprintf(device_num, sizeof(device_num), "%d", pcm->device);
+ strlcat(kctl->id.name, device_num, sizeof(kctl->id.name));
+ pr_debug("%s, Overwriting channel map control name to: %s",
+ __func__, kctl->id.name);
+ kctl->put = pcm_chmap_ctl_put;
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 2b889b5..800bea8 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -78,7 +78,6 @@
static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
static int msm_route_ec_ref_rx;
-static char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
#define MAX_EQ_SESSIONS MSM_FRONTEND_DAI_CS_VOICE
@@ -864,27 +863,6 @@
return 0;
}
-static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int i;
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
- ucontrol->value.integer.value[i] = channel_mapping[i];
- return 0;
-}
-
-static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int i;
-
- for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
- channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
- multi_ch_pcm_set_channel_map(channel_mapping);
-
- return 0;
-}
-
static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1938,12 +1916,6 @@
msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
};
-static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
- SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 8,
- 0, 8, msm_routing_get_channel_map_mixer,
- msm_routing_put_channel_map_mixer),
-};
-
static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SRS TruMedia",
@@ -2931,9 +2903,6 @@
ec_ref_rx_mixer_controls,
ARRAY_SIZE(ec_ref_rx_mixer_controls));
- snd_soc_add_platform_controls(platform,
- multi_ch_channel_map_mixer_controls,
- ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index c046b63..d38bcbb 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -31,6 +31,7 @@
#define AUDIO_OCMEM_BUF_SIZE (512 * SZ_1K)
enum {
+ OCMEM_STATE_DEFAULT = 0,
OCMEM_STATE_ALLOC = 1,
OCMEM_STATE_MAP_TRANSITION,
OCMEM_STATE_MAP_COMPL,
@@ -80,6 +81,8 @@
{
int rc = NOTIFY_DONE;
unsigned long flags;
+ struct ocmem_buf *rbuf;
+ int vwait = 0;
pr_debug("%s: event[%ld] cur state[%x]\n", __func__,
event1, atomic_read(&audio_ocmem_lcl.audio_state));
@@ -105,11 +108,21 @@
OCMEM_STATE_UNMAP_FAIL);
break;
case OCMEM_ALLOC_GROW:
- audio_ocmem_lcl.buf = data;
- pr_debug("%s: Alloc grow request received buf->addr: 0x%ld\n",
+ rbuf = data;
+ if (rbuf->len == AUDIO_OCMEM_BUF_SIZE) {
+ audio_ocmem_lcl.buf = data;
+ pr_debug("%s: Alloc grow request received buf->addr: 0x%08lx\n",
__func__,
(audio_ocmem_lcl.buf)->addr);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
+ atomic_set(&audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_GROW);
+ } else {
+ pr_debug("%s: Alloc grow request with size: %ld",
+ __func__,
+ rbuf->len);
+ vwait = 1;
+ }
+
break;
case OCMEM_ALLOC_SHRINK:
pr_debug("%s: Alloc shrink request received\n", __func__);
@@ -120,7 +133,7 @@
break;
}
spin_unlock_irqrestore(&audio_ocmem_lcl.audio_lock, flags);
- if (atomic_read(&audio_ocmem_lcl.audio_cond)) {
+ if (!vwait && (atomic_read(&audio_ocmem_lcl.audio_cond))) {
atomic_set(&audio_ocmem_lcl.audio_cond, 0);
wake_up(&audio_ocmem_lcl.audio_wait);
}
@@ -189,7 +202,7 @@
lp_segptr->mem_segment[i].start_address_lsw;
audio_ocmem_lcl.mlist.chunks[j].size =
lp_segptr->mem_segment[i].size;
- pr_debug("%s: ro:%d, ddr_paddr[%x], size[%x]\n", __func__,
+ pr_debug("%s: ro:%d, ddr_paddr[0x%08x], size[0x%x]\n", __func__,
audio_ocmem_lcl.mlist.chunks[j].ro,
(uint32_t)audio_ocmem_lcl.mlist.chunks[j].ddr_paddr,
(uint32_t)audio_ocmem_lcl.mlist.chunks[j].size);
@@ -204,7 +217,7 @@
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
- pr_debug("%s: buf->addr: 0x%ld, len: %ld, audio_state[0x%x]\n",
+ pr_debug("%s: buf->addr: 0x%08lx, len: %ld, audio_state[0x%x]\n",
__func__,
audio_ocmem_lcl.buf->addr,
audio_ocmem_lcl.buf->len,
@@ -214,7 +227,7 @@
ret = ocmem_map(cid, audio_ocmem_lcl.buf, &audio_ocmem_lcl.mlist);
if (ret) {
pr_err("%s: ocmem_map failed\n", __func__);
- goto fail_cmd;
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
}
pr_debug("%s: audio_cond[%d] audio_state[0x%x]\n", __func__,
@@ -285,6 +298,7 @@
break;
}
}
+ ret = 0;
fail_cmd:
pr_debug("%s: exit\n", __func__);
return ret;
@@ -301,15 +315,19 @@
int audio_ocmem_disable(int cid)
{
int ret;
+ int cur_state;
pr_debug("%s: disable\n", __func__);
- if (atomic_read(&audio_ocmem_lcl.audio_cond))
- atomic_set(&audio_ocmem_lcl.audio_cond, 0);
+ cur_state = atomic_read(&audio_ocmem_lcl.audio_state);
+ if (atomic_cmpxchg(&audio_ocmem_lcl.audio_cond, 1, 0)) {
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
+ wake_up(&audio_ocmem_lcl.audio_wait);
+ }
pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n", __func__,
atomic_read(&audio_ocmem_lcl.audio_cond),
atomic_read(&audio_ocmem_lcl.audio_state));
- switch (atomic_read(&audio_ocmem_lcl.audio_state)) {
+ switch (cur_state) {
case OCMEM_STATE_MAP_COMPL:
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
@@ -326,6 +344,9 @@
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
case OCMEM_STATE_UNMAP_COMPL:
+ case OCMEM_STATE_MAP_FAIL:
+ case OCMEM_STATE_MAP_TRANSITION:
+ case OCMEM_STATE_ALLOC:
ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
if (ret) {
pr_err("%s: ocmem_free failed, state[%d]\n",
@@ -333,10 +354,14 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
+ pr_debug("%s: state=%d", __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
pr_debug("%s: ocmem_free success\n", __func__);
+ break;
+
default:
- pr_debug("%s: state=%d", __func__,
+ pr_debug("%s:error: state=%d", __func__,
atomic_read(&audio_ocmem_lcl.audio_state));
break;
@@ -556,6 +581,7 @@
init_waitqueue_head(&audio_ocmem_lcl.audio_wait);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
atomic_set(&audio_ocmem_lcl.audio_exit, 0);
spin_lock_init(&audio_ocmem_lcl.audio_lock);
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index d85bbbc..7ba6514 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -48,6 +48,7 @@
struct snd_msm {
struct msm_audio *prtd;
unsigned volume;
+ atomic_t audio_ocmem_req;
};
static struct snd_msm compressed_audio = {NULL, 0x2000} ;
@@ -434,8 +435,11 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- audio_ocmem_process_req(AUDIO, true);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req,
+ 0, 1))
+ audio_ocmem_process_req(AUDIO, true);
+ }
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
switch (compr->info.codec_param.codec.id) {
@@ -456,9 +460,6 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- audio_ocmem_process_req(AUDIO, false);
-
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AMRWB:
@@ -565,6 +566,7 @@
populate_codec_list(compr, runtime);
runtime->private_data = compr;
atomic_set(&prtd->eos, 0);
+ atomic_set(&compressed_audio.audio_ocmem_req, 0);
compressed_audio.prtd = &compr->prtd;
ret = compressed_set_volume(compressed_audio.volume);
if (ret < 0)
@@ -611,6 +613,8 @@
dir = IN;
atomic_set(&prtd->pending_buffer, 0);
+ if (atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 1, 0))
+ audio_ocmem_process_req(AUDIO, false);
prtd->pcm_irq_pos = 0;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
compressed_audio.prtd = NULL;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 19e0464..2f0a9d7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -42,6 +42,7 @@
struct snd_msm {
struct msm_audio *prtd;
unsigned volume;
+ atomic_t audio_ocmem_req;
};
static struct snd_msm lpa_audio;
@@ -227,7 +228,8 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
- audio_ocmem_process_req(AUDIO, true);
+ if (!atomic_cmpxchg(&lpa_audio.audio_ocmem_req, 0, 1))
+ audio_ocmem_process_req(AUDIO, true);
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
pr_debug("SNDRV_PCM_TRIGGER_START\n");
@@ -237,7 +239,6 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
- audio_ocmem_process_req(AUDIO, false);
atomic_set(&prtd->start, 0);
atomic_set(&prtd->stop, 1);
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
@@ -328,6 +329,7 @@
prtd->dsp_cnt = 0;
atomic_set(&prtd->pending_buffer, 1);
atomic_set(&prtd->stop, 1);
+ atomic_set(&lpa_audio.audio_ocmem_req, 0);
runtime->private_data = prtd;
lpa_audio.prtd = prtd;
lpa_set_volume(lpa_audio.volume);
@@ -387,6 +389,9 @@
dir = IN;
atomic_set(&prtd->pending_buffer, 0);
+
+ if (atomic_cmpxchg(&lpa_audio.audio_ocmem_req, 1, 0))
+ audio_ocmem_process_req(AUDIO, false);
lpa_audio.prtd = NULL;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,