Merge "board: 8930: turn off haptics clock in suspend" into msm-3.0
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index c8a4ff9..2698ea7 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -17,6 +17,238 @@
interrupt-controller;
#interrupt-cells = <3>;
+ qcom,pm8941@0 {
+ spmi-slave-container;
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pm8941_gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,gpio-num = <1>;
+ status = "disabled";
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,gpio-num = <2>;
+ status = "disabled";
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,gpio-num = <3>;
+ status = "disabled";
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,gpio-num = <4>;
+ status = "disabled";
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,gpio-num = <5>;
+ status = "disabled";
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,gpio-num = <6>;
+ status = "disabled";
+ };
+
+ gpio@c600 {
+ reg = <0xc600 0x100>;
+ qcom,gpio-num = <7>;
+ status = "disabled";
+ };
+
+ gpio@c700 {
+ reg = <0xc700 0x100>;
+ qcom,gpio-num = <8>;
+ status = "disabled";
+ };
+
+ gpio@c800 {
+ reg = <0xc800 0x100>;
+ qcom,gpio-num = <9>;
+ status = "disabled";
+ };
+
+ gpio@c900 {
+ reg = <0xc900 0x100>;
+ qcom,gpio-num = <10>;
+ status = "disabled";
+ };
+
+ gpio@ca00 {
+ reg = <0xca00 0x100>;
+ qcom,gpio-num = <11>;
+ status = "disabled";
+ };
+
+ gpio@cb00 {
+ reg = <0xcb00 0x100>;
+ qcom,gpio-num = <12>;
+ status = "disabled";
+ };
+
+ gpio@cc00 {
+ reg = <0xcc00 0x100>;
+ qcom,gpio-num = <13>;
+ status = "disabled";
+ };
+
+ gpio@cd00 {
+ reg = <0xcd00 0x100>;
+ qcom,gpio-num = <14>;
+ status = "disabled";
+ };
+
+ gpio@ce00 {
+ reg = <0xce00 0x100>;
+ qcom,gpio-num = <15>;
+ status = "disabled";
+ };
+
+ gpio@cf00 {
+ reg = <0xcf00 0x100>;
+ qcom,gpio-num = <16>;
+ status = "disabled";
+ };
+
+ gpio@d000 {
+ reg = <0xd000 0x100>;
+ qcom,gpio-num = <17>;
+ status = "disabled";
+ };
+
+ gpio@d100 {
+ reg = <0xd100 0x100>;
+ qcom,gpio-num = <18>;
+ status = "disabled";
+ };
+
+ gpio@d200 {
+ reg = <0xd200 0x100>;
+ qcom,gpio-num = <19>;
+ status = "disabled";
+ };
+
+ gpio@d300 {
+ reg = <0xd300 0x100>;
+ qcom,gpio-num = <20>;
+ status = "disabled";
+ };
+
+ gpio@d400 {
+ reg = <0xd400 0x100>;
+ qcom,gpio-num = <21>;
+ status = "disabled";
+ };
+
+ gpio@d500 {
+ reg = <0xd500 0x100>;
+ qcom,gpio-num = <22>;
+ status = "disabled";
+ };
+
+ gpio@d600 {
+ reg = <0xd600 0x100>;
+ qcom,gpio-num = <23>;
+ status = "disabled";
+ };
+
+ gpio@d700 {
+ reg = <0xd700 0x100>;
+ qcom,gpio-num = <24>;
+ status = "disabled";
+ };
+
+ gpio@d800 {
+ reg = <0xd800 0x100>;
+ qcom,gpio-num = <25>;
+ status = "disabled";
+ };
+
+ gpio@d900 {
+ reg = <0xd900 0x100>;
+ qcom,gpio-num = <26>;
+ status = "disabled";
+ };
+
+ gpio@da00 {
+ reg = <0xda00 0x100>;
+ qcom,gpio-num = <27>;
+ status = "disabled";
+ };
+
+ gpio@db00 {
+ reg = <0xdb00 0x100>;
+ qcom,gpio-num = <28>;
+ status = "disabled";
+ };
+
+ gpio@dc00 {
+ reg = <0xdc00 0x100>;
+ qcom,gpio-num = <29>;
+ status = "disabled";
+ };
+
+ gpio@dd00 {
+ reg = <0xdd00 0x100>;
+ qcom,gpio-num = <30>;
+ status = "disabled";
+ };
+
+ gpio@de00 {
+ reg = <0xde00 0x100>;
+ qcom,gpio-num = <31>;
+ status = "disabled";
+ };
+
+ gpio@df00 {
+ reg = <0xdf00 0x100>;
+ qcom,gpio-num = <32>;
+ status = "disabled";
+ };
+
+ gpio@e000 {
+ reg = <0xe000 0x100>;
+ qcom,gpio-num = <33>;
+ status = "disabled";
+ };
+
+ gpio@e100 {
+ reg = <0xe100 0x100>;
+ qcom,gpio-num = <34>;
+ status = "disabled";
+ };
+
+ gpio@e200 {
+ reg = <0xe200 0x100>;
+ qcom,gpio-num = <35>;
+ status = "disabled";
+ };
+
+ gpio@e300 {
+ reg = <0xe300 0x100>;
+ qcom,gpio-num = <36>;
+ status = "disabled";
+ };
+ };
+ };
+
qcom,pm8941@1 {
spmi-slave-container;
reg = <0x1>;
diff --git a/arch/arm/boot/dts/msmcopper-gpio.dtsi b/arch/arm/boot/dts/msmcopper-gpio.dtsi
new file mode 100644
index 0000000..7c3f5ce
--- /dev/null
+++ b/arch/arm/boot/dts/msmcopper-gpio.dtsi
@@ -0,0 +1,214 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,spmi@fc4c0000 {
+
+ qcom,pm8941@0 {
+
+ pm8941_gpios: pm8941_gpios {
+
+ gpio@c000 {
+ qcom,gpio-num = <1>;
+ status = "ok";
+ };
+
+ gpio@c100 {
+ qcom,gpio-num = <2>;
+ status = "ok";
+ };
+
+ gpio@c200 {
+ qcom,gpio-num = <3>;
+ status = "ok";
+ };
+
+ gpio@c300 {
+ qcom,gpio-num = <4>;
+ status = "ok";
+ };
+
+ gpio@c400 {
+ qcom,gpio-num = <5>;
+ status = "ok";
+ };
+
+ gpio@c500 {
+ qcom,gpio-num = <6>;
+ status = "ok";
+ };
+
+ gpio@c600 {
+ qcom,gpio-num = <7>;
+ status = "ok";
+ };
+
+ gpio@c700 {
+ qcom,gpio-num = <8>;
+ status = "ok";
+ };
+
+ gpio@c800 {
+ qcom,gpio-num = <9>;
+ status = "ok";
+ };
+
+ gpio@c900 {
+ qcom,gpio-num = <10>;
+ status = "ok";
+ };
+
+ gpio@ca00 {
+ qcom,gpio-num = <11>;
+ status = "ok";
+ };
+
+ gpio@cb00 {
+ qcom,gpio-num = <12>;
+ status = "ok";
+ };
+
+ gpio@cc00 {
+ qcom,gpio-num = <13>;
+ status = "ok";
+ };
+
+ gpio@cd00 {
+ qcom,gpio-num = <14>;
+ status = "ok";
+ };
+
+ gpio@ce00 {
+ qcom,gpio-num = <15>;
+ status = "ok";
+ };
+
+ gpio@cf00 {
+ qcom,gpio-num = <16>;
+ status = "ok";
+ };
+
+ gpio@d000 {
+ qcom,gpio-num = <17>;
+ status = "ok";
+ };
+
+ gpio@d100 {
+ qcom,gpio-num = <18>;
+ status = "ok";
+ };
+
+ gpio@d200 {
+ qcom,gpio-num = <19>;
+ status = "ok";
+ };
+
+ gpio@d300 {
+ qcom,gpio-num = <20>;
+ status = "ok";
+ };
+
+ gpio@d400 {
+ qcom,gpio-num = <21>;
+ status = "ok";
+ };
+
+ gpio@d500 {
+ qcom,gpio-num = <22>;
+ status = "ok";
+ };
+
+ gpio@d600 {
+ qcom,gpio-num = <23>;
+ status = "ok";
+ };
+
+ gpio@d700 {
+ qcom,gpio-num = <24>;
+ status = "ok";
+ };
+
+ gpio@d800 {
+ qcom,gpio-num = <25>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@d900 {
+ qcom,gpio-num = <26>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@da00 {
+ qcom,gpio-num = <27>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@db00 {
+ qcom,gpio-num = <28>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@dc00 {
+ qcom,gpio-num = <29>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@dd00 {
+ qcom,gpio-num = <30>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@de00 {
+ qcom,gpio-num = <31>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@df00 {
+ qcom,gpio-num = <32>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@e000 {
+ qcom,gpio-num = <33>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@e100 {
+ qcom,gpio-num = <34>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@e200 {
+ qcom,gpio-num = <35>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+
+ gpio@e300 {
+ qcom,gpio-num = <36>;
+ qcom,out-strength = <1>;
+ status = "ok";
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 4821290..e998ca9 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -14,6 +14,7 @@
/include/ "msm-pm8841.dtsi"
/include/ "msm-pm8941.dtsi"
/include/ "msmcopper-regulator.dtsi"
+/include/ "msmcopper-gpio.dtsi"
/ {
model = "Qualcomm MSM Copper";
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 99a3fa1..3431cd0 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -433,6 +433,19 @@
.drv = GPIOMUX_DRV_12MA,
.pull = GPIOMUX_PULL_NONE,
};
+
+static struct gpiomux_setting sx150x_suspended_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sx150x_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct gpiomux_setting cyts_sleep_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_6MA,
@@ -968,6 +981,16 @@
},
};
+static struct msm_gpiomux_config sx150x_int_configs[] __initdata = {
+ {
+ .gpio = 81,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sx150x_suspended_cfg,
+ [GPIOMUX_ACTIVE] = &sx150x_active_cfg,
+ },
+ },
+};
+
void __init apq8064_init_gpiomux(void)
{
int rc;
@@ -989,6 +1012,8 @@
msm_gpiomux_install(vcap_configs,
ARRAY_SIZE(vcap_configs));
#endif
+ msm_gpiomux_install(sx150x_int_configs,
+ ARRAY_SIZE(sx150x_int_configs));
} else {
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
msm_gpiomux_install(apq8064_ethernet_configs,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 8135806..d08fe01 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2356,6 +2356,7 @@
};
#define SX150X_EXP1_INT_N PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9)
+#define SX150X_EXP2_INT_N MSM_GPIO_TO_INT(81)
struct sx150x_platform_data mpq8064_sx150x_pdata[] = {
[SX150X_EXP1] = {
@@ -2375,7 +2376,8 @@
.io_pulldn_ena = 0x0,
.io_open_drain_ena = 0x0,
.io_polarity = 0,
- .irq_summary = -1,
+ .irq_summary = SX150X_EXP2_INT_N,
+ .irq_base = SX150X_EXP2_IRQ_BASE,
},
[SX150X_EXP3] = {
.gpio_base = SX150X_EXP3_GPIO_BASE,
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 33e5b29..0832a03 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -4932,8 +4932,6 @@
CLK_LOOKUP("src_clk", usb_fs1_src_clk.c, ""),
CLK_LOOKUP("alt_core_clk", usb_fs1_xcvr_clk.c, ""),
CLK_LOOKUP("sys_clk", usb_fs1_sys_clk.c, ""),
- CLK_LOOKUP("iface_clk", ce1_p_clk.c, ""),
- CLK_LOOKUP("core_clk", ce1_core_clk.c, ""),
CLK_LOOKUP("ref_clk", sata_phy_ref_clk.c, ""),
CLK_LOOKUP("cfg_clk", sata_phy_cfg_clk.c, ""),
CLK_LOOKUP("iface_clk", ce3_p_clk.c, "qce.0"),
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 55282b6..e8e88d7 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -316,7 +316,7 @@
void __iomem *cbcr_reg,
enum branch_state br_status)
{
- char *status_str = (br_status == BRANCH_ON) ? "on" : "off";
+ char *status_str = (br_status == BRANCH_ON) ? "off" : "on";
/*
* Use a memory barrier since some halt status registers are
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8328ee2..cf024cf 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -485,4 +485,12 @@
help
Say 'y' here to include support for the Qualcomm QPNP gpio
support. QPNP is a SPMI based PMIC implementation.
+
+config GPIO_QPNP_DEBUG
+ depends on GPIO_QPNP
+ depends on DEBUG_FS
+ bool "Qualcomm QPNP GPIO debug support"
+ help
+ Say 'y' here to include debug support for the Qualcomm
+ QPNP gpio support
endif
diff --git a/drivers/gpio/qpnp-gpio.c b/drivers/gpio/qpnp-gpio.c
index 594b974..bc0904ec 100644
--- a/drivers/gpio/qpnp-gpio.c
+++ b/drivers/gpio/qpnp-gpio.c
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/spmi.h>
#include <linux/platform_device.h>
+#include <linux/debugfs.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/of.h>
@@ -84,6 +85,20 @@
#define Q_REG_MASTER_EN_SHIFT 7
#define Q_REG_MASTER_EN_MASK 0x80
+enum qpnp_gpio_param_type {
+ Q_GPIO_CFG_DIRECTION,
+ Q_GPIO_CFG_OUTPUT_TYPE,
+ Q_GPIO_CFG_INVERT,
+ Q_GPIO_CFG_PULL,
+ Q_GPIO_CFG_VIN_SEL,
+ Q_GPIO_CFG_OUT_STRENGTH,
+ Q_GPIO_CFG_SRC_SELECT,
+ Q_GPIO_CFG_MASTER_EN,
+ Q_GPIO_CFG_INVALID,
+};
+
+#define Q_NUM_PARAMS Q_GPIO_CFG_INVALID
+
/* param error checking */
#define QPNP_GPIO_DIR_INVALID 3
#define QPNP_GPIO_INVERT_INVALID 2
@@ -104,6 +119,8 @@
u8 type; /* peripheral type */
u8 subtype; /* peripheral subtype */
struct device_node *node;
+ enum qpnp_gpio_param_type params[Q_NUM_PARAMS];
+ struct qpnp_gpio_chip *q_chip;
};
struct qpnp_gpio_chip {
@@ -115,6 +132,7 @@
uint32_t pmic_gpio_highest;
struct device_node *int_ctrl;
struct list_head chip_list;
+ struct dentry *dfs_dir;
};
static LIST_HEAD(qpnp_gpio_chips);
@@ -583,15 +601,254 @@
return rc;
}
+#ifdef CONFIG_GPIO_QPNP_DEBUG
+struct qpnp_gpio_reg {
+ uint32_t addr;
+ uint32_t idx;
+ uint32_t shift;
+ uint32_t mask;
+};
+
+static struct dentry *driver_dfs_dir;
+
+static int qpnp_gpio_reg_attr(enum qpnp_gpio_param_type type,
+ struct qpnp_gpio_reg *cfg)
+{
+ switch (type) {
+ case Q_GPIO_CFG_DIRECTION:
+ cfg->addr = Q_REG_MODE_CTL;
+ cfg->idx = Q_REG_I_MODE_CTL;
+ cfg->shift = Q_REG_MODE_SEL_SHIFT;
+ cfg->mask = Q_REG_MODE_SEL_MASK;
+ break;
+ case Q_GPIO_CFG_OUTPUT_TYPE:
+ cfg->addr = Q_REG_DIG_OUT_CTL;
+ cfg->idx = Q_REG_I_DIG_OUT_CTL;
+ cfg->shift = Q_REG_OUT_TYPE_SHIFT;
+ cfg->mask = Q_REG_OUT_TYPE_MASK;
+ break;
+ case Q_GPIO_CFG_INVERT:
+ cfg->addr = Q_REG_MODE_CTL;
+ cfg->idx = Q_REG_I_MODE_CTL;
+ cfg->shift = Q_REG_OUT_INVERT_SHIFT;
+ cfg->mask = Q_REG_OUT_INVERT_MASK;
+ break;
+ case Q_GPIO_CFG_PULL:
+ cfg->addr = Q_REG_DIG_PULL_CTL;
+ cfg->idx = Q_REG_I_DIG_PULL_CTL;
+ cfg->shift = Q_REG_PULL_SHIFT;
+ cfg->mask = Q_REG_PULL_MASK;
+ break;
+ case Q_GPIO_CFG_VIN_SEL:
+ cfg->addr = Q_REG_DIG_VIN_CTL;
+ cfg->idx = Q_REG_I_DIG_VIN_CTL;
+ cfg->shift = Q_REG_VIN_SHIFT;
+ cfg->mask = Q_REG_VIN_MASK;
+ break;
+ case Q_GPIO_CFG_OUT_STRENGTH:
+ cfg->addr = Q_REG_DIG_OUT_CTL;
+ cfg->idx = Q_REG_I_DIG_OUT_CTL;
+ cfg->shift = Q_REG_OUT_STRENGTH_SHIFT;
+ cfg->mask = Q_REG_OUT_STRENGTH_MASK;
+ break;
+ case Q_GPIO_CFG_SRC_SELECT:
+ cfg->addr = Q_REG_MODE_CTL;
+ cfg->idx = Q_REG_I_MODE_CTL;
+ cfg->shift = Q_REG_SRC_SEL_SHIFT;
+ cfg->mask = Q_REG_SRC_SEL_MASK;
+ break;
+ case Q_GPIO_CFG_MASTER_EN:
+ cfg->addr = Q_REG_EN_CTL;
+ cfg->idx = Q_REG_I_EN_CTL;
+ cfg->shift = Q_REG_MASTER_EN_SHIFT;
+ cfg->mask = Q_REG_MASTER_EN_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qpnp_gpio_debugfs_get(void *data, u64 *val)
+{
+ enum qpnp_gpio_param_type *idx = data;
+ struct qpnp_gpio_spec *q_spec;
+ struct qpnp_gpio_reg cfg = {};
+ int rc;
+
+ rc = qpnp_gpio_reg_attr(*idx, &cfg);
+ if (rc)
+ return rc;
+ q_spec = container_of(idx, struct qpnp_gpio_spec, params[*idx]);
+ *val = q_reg_get(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask);
+ return 0;
+}
+
+static int qpnp_gpio_check_reg_val(enum qpnp_gpio_param_type idx,
+ struct qpnp_gpio_spec *q_spec,
+ uint32_t val)
+{
+ switch (idx) {
+ case Q_GPIO_CFG_DIRECTION:
+ if (val >= QPNP_GPIO_DIR_INVALID)
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_OUTPUT_TYPE:
+ if ((val >= QPNP_GPIO_OUT_BUF_INVALID) ||
+ ((val == QPNP_GPIO_OUT_BUF_OPEN_DRAIN_NMOS ||
+ val == QPNP_GPIO_OUT_BUF_OPEN_DRAIN_PMOS) &&
+ (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
+ (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_8CH))))
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_INVERT:
+ if (val >= QPNP_GPIO_INVERT_INVALID)
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_PULL:
+ if (val >= QPNP_GPIO_PULL_INVALID)
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_VIN_SEL:
+ if (val >= QPNP_GPIO_VIN_INVALID)
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_OUT_STRENGTH:
+ if (val >= QPNP_GPIO_OUT_STRENGTH_INVALID ||
+ val == 0)
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_SRC_SELECT:
+ if (val >= QPNP_GPIO_SRC_INVALID)
+ return -EINVAL;
+ break;
+ case Q_GPIO_CFG_MASTER_EN:
+ if (val >= QPNP_GPIO_MASTER_INVALID)
+ return -EINVAL;
+ break;
+ default:
+ pr_err("invalid param type %u specified\n", idx);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int qpnp_gpio_debugfs_set(void *data, u64 val)
+{
+ enum qpnp_gpio_param_type *idx = data;
+ struct qpnp_gpio_spec *q_spec;
+ struct qpnp_gpio_chip *q_chip;
+ struct qpnp_gpio_reg cfg = {};
+ int rc;
+
+ q_spec = container_of(idx, struct qpnp_gpio_spec, params[*idx]);
+ q_chip = q_spec->q_chip;
+
+ rc = qpnp_gpio_check_reg_val(*idx, q_spec, val);
+ if (rc)
+ return rc;
+
+ rc = qpnp_gpio_reg_attr(*idx, &cfg);
+ if (rc)
+ return rc;
+ q_reg_clr_set(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask, val);
+ rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
+ Q_REG_ADDR(q_spec, cfg.addr),
+ &q_spec->regs[cfg.idx], 1);
+
+ return rc;
+}
+DEFINE_SIMPLE_ATTRIBUTE(qpnp_gpio_fops, qpnp_gpio_debugfs_get,
+ qpnp_gpio_debugfs_set, "%llu\n");
+
+#define DEBUGFS_BUF_SIZE 11 /* supports 2^32 in decimal */
+
+struct qpnp_gpio_debugfs_args {
+ enum qpnp_gpio_param_type type;
+ const char *filename;
+};
+
+static struct qpnp_gpio_debugfs_args dfs_args[] = {
+ { Q_GPIO_CFG_DIRECTION, "direction" },
+ { Q_GPIO_CFG_OUTPUT_TYPE, "output_type" },
+ { Q_GPIO_CFG_INVERT, "invert" },
+ { Q_GPIO_CFG_PULL, "pull" },
+ { Q_GPIO_CFG_VIN_SEL, "vin_sel" },
+ { Q_GPIO_CFG_OUT_STRENGTH, "out_strength" },
+ { Q_GPIO_CFG_SRC_SELECT, "src_select" },
+ { Q_GPIO_CFG_MASTER_EN, "master_en" }
+};
+
+static int qpnp_gpio_debugfs_create(struct qpnp_gpio_chip *q_chip)
+{
+ struct spmi_device *spmi = q_chip->spmi;
+ struct device *dev = &spmi->dev;
+ struct qpnp_gpio_spec *q_spec;
+ enum qpnp_gpio_param_type *params;
+ enum qpnp_gpio_param_type type;
+ char pmic_gpio[DEBUGFS_BUF_SIZE];
+ const char *filename;
+ struct dentry *dfs, *dfs_io_dir;
+ int i, j;
+
+ BUG_ON(Q_NUM_PARAMS != ARRAY_SIZE(dfs_args));
+
+ q_chip->dfs_dir = debugfs_create_dir(dev->of_node->name,
+ driver_dfs_dir);
+ if (q_chip->dfs_dir == NULL) {
+ dev_err(dev, "%s: cannot register chip debugfs directory %s\n",
+ __func__, dev->of_node->name);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < spmi->num_dev_node; i++) {
+ q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
+ params = q_spec->params;
+ snprintf(pmic_gpio, DEBUGFS_BUF_SIZE, "%u", q_spec->pmic_gpio);
+ dfs_io_dir = debugfs_create_dir(pmic_gpio,
+ q_chip->dfs_dir);
+ if (dfs_io_dir == NULL)
+ goto dfs_err;
+
+ for (j = 0; j < Q_NUM_PARAMS; j++) {
+ type = dfs_args[j].type;
+ filename = dfs_args[j].filename;
+
+ params[type] = type;
+ dfs = debugfs_create_file(
+ filename,
+ S_IRUGO | S_IWUSR,
+ dfs_io_dir,
+ &q_spec->params[type],
+ &qpnp_gpio_fops);
+ if (dfs == NULL)
+ goto dfs_err;
+ }
+ }
+ return 0;
+dfs_err:
+ dev_err(dev, "%s: cannot register debugfs for pmic gpio %u on"
+ " chip %s\n", __func__,
+ q_spec->pmic_gpio, dev->of_node->name);
+ debugfs_remove_recursive(q_chip->dfs_dir);
+ return -ENFILE;
+}
+#else
+static int qpnp_gpio_debugfs_create(struct qpnp_gpio_chip *q_chip)
+{
+ return 0;
+}
+#endif
+
static int qpnp_gpio_probe(struct spmi_device *spmi)
{
struct qpnp_gpio_chip *q_chip;
struct resource *res;
struct qpnp_gpio_spec *q_spec;
- const __be32 *prop;
- int i, rc, ret, gpio, len;
- int lowest_gpio = INT_MAX, highest_gpio = INT_MIN;
- u32 intspec[3];
+ int i, rc;
+ int lowest_gpio = UINT_MAX, highest_gpio = 0;
+ u32 intspec[3], gpio;
char buf[2];
q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
@@ -609,21 +866,14 @@
/* first scan through nodes to find the range required for allocation */
for (i = 0; i < spmi->num_dev_node; i++) {
- prop = of_get_property(spmi->dev_node[i].of_node,
- "qcom,gpio-num", &len);
- if (!prop) {
+ rc = of_property_read_u32(spmi->dev_node[i].of_node,
+ "qcom,gpio-num", &gpio);
+ if (rc) {
dev_err(&spmi->dev, "%s: unable to get"
" qcom,gpio-num property\n", __func__);
- ret = -EINVAL;
- goto err_probe;
- } else if (len != sizeof(__be32)) {
- dev_err(&spmi->dev, "%s: invalid qcom,gpio-num"
- " property\n", __func__);
- ret = -EINVAL;
goto err_probe;
}
- gpio = be32_to_cpup(prop);
if (gpio < lowest_gpio)
lowest_gpio = gpio;
if (gpio > highest_gpio)
@@ -633,12 +883,12 @@
if (highest_gpio < lowest_gpio) {
dev_err(&spmi->dev, "%s: no device nodes specified in"
" topology\n", __func__);
- ret = -EINVAL;
+ rc = -EINVAL;
goto err_probe;
} else if (lowest_gpio == 0) {
dev_err(&spmi->dev, "%s: 0 is not a valid PMIC GPIO\n",
__func__);
- ret = -EINVAL;
+ rc = -EINVAL;
goto err_probe;
}
@@ -654,7 +904,7 @@
if (!q_chip->pmic_gpios || !q_chip->chip_gpios) {
dev_err(&spmi->dev, "%s: unable to allocate memory\n",
__func__);
- ret = -ENOMEM;
+ rc = -ENOMEM;
goto err_probe;
}
@@ -663,7 +913,7 @@
if (!q_chip->int_ctrl) {
dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
__func__);
- ret = -EINVAL;
+ rc = -EINVAL;
goto err_probe;
}
@@ -676,20 +926,13 @@
__func__, spmi->dev_node[i].of_node->full_name);
}
- prop = of_get_property(spmi->dev_node[i].of_node,
- "qcom,gpio-num", &len);
- if (!prop) {
+ rc = of_property_read_u32(spmi->dev_node[i].of_node,
+ "qcom,gpio-num", &gpio);
+ if (rc) {
dev_err(&spmi->dev, "%s: unable to get"
" qcom,gpio-num property\n", __func__);
- ret = -EINVAL;
- goto err_probe;
- } else if (len != sizeof(__be32)) {
- dev_err(&spmi->dev, "%s: invalid qcom,qpnp-gpio-num"
- " property\n", __func__);
- ret = -EINVAL;
goto err_probe;
}
- gpio = be32_to_cpup(prop);
q_spec = kzalloc(sizeof(struct qpnp_gpio_spec),
GFP_KERNEL);
@@ -697,7 +940,7 @@
dev_err(&spmi->dev, "%s: unable to allocate"
" memory\n",
__func__);
- ret = -ENOMEM;
+ rc = -ENOMEM;
goto err_probe;
}
@@ -706,13 +949,13 @@
q_spec->gpio_chip_idx = i;
q_spec->pmic_gpio = gpio;
q_spec->node = spmi->dev_node[i].of_node;
+ q_spec->q_chip = q_chip;
rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
Q_REG_ADDR(q_spec, Q_REG_TYPE), &buf[0], 2);
if (rc) {
dev_err(&spmi->dev, "%s: unable to read type regs\n",
__func__);
- ret = rc;
goto err_probe;
}
q_spec->type = buf[0];
@@ -727,10 +970,10 @@
if (!q_spec->irq) {
dev_err(&spmi->dev, "%s: invalid irq for gpio"
" %u\n", __func__, gpio);
- ret = -EINVAL;
+ rc = -EINVAL;
goto err_probe;
}
- /* initialize lookup table entries */
+ /* initialize lookup table params */
qpnp_pmic_gpio_set_spec(q_chip, gpio, q_spec);
qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
}
@@ -752,43 +995,49 @@
if (rc) {
dev_err(&spmi->dev, "%s: Can't add gpio chip, rc = %d\n",
__func__, rc);
- ret = rc;
goto err_probe;
}
/* now configure gpio config defaults if they exist */
for (i = 0; i < spmi->num_dev_node; i++) {
q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
- if (WARN_ON(!q_spec))
- return -ENODEV;
+ if (WARN_ON(!q_spec)) {
+ rc = -ENODEV;
+ goto err_probe;
+ }
rc = qpnp_gpio_cache_regs(q_chip, q_spec);
- if (rc) {
- ret = rc;
+ if (rc)
goto err_probe;
- }
rc = qpnp_gpio_apply_config(q_chip, q_spec);
- if (rc) {
- ret = rc;
+ if (rc)
goto err_probe;
- }
}
dev_dbg(&spmi->dev, "%s: gpio_chip registered between %d-%u\n",
__func__, q_chip->gpio_chip.base,
(q_chip->gpio_chip.base + q_chip->gpio_chip.ngpio) - 1);
+
+ rc = qpnp_gpio_debugfs_create(q_chip);
+ if (rc) {
+ dev_err(&spmi->dev, "%s: debugfs creation failed\n", __func__);
+ goto err_probe;
+ }
+
return 0;
err_probe:
qpnp_gpio_free_chip(q_chip);
- return ret;
+ return rc;
}
static int qpnp_gpio_remove(struct spmi_device *spmi)
{
struct qpnp_gpio_chip *q_chip = dev_get_drvdata(&spmi->dev);
+ debugfs_remove_recursive(q_chip->dfs_dir);
+
return qpnp_gpio_free_chip(q_chip);
}
@@ -816,11 +1065,21 @@
static int __init qpnp_gpio_init(void)
{
+#ifdef CONFIG_GPIO_QPNP_DEBUG
+ driver_dfs_dir = debugfs_create_dir("qpnp_gpio", NULL);
+ if (driver_dfs_dir == NULL)
+ pr_err("Cannot register top level debugfs directory\n");
+#endif
+
return spmi_driver_register(&qpnp_gpio_driver);
}
static void __exit qpnp_gpio_exit(void)
{
+#ifdef CONFIG_GPIO_QPNP_DEBUG
+ debugfs_remove_recursive(driver_dfs_dir);
+#endif
+ spmi_driver_unregister(&qpnp_gpio_driver);
}
MODULE_DESCRIPTION("QPNP PMIC gpio driver");
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 00dba96..7c152721 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -263,7 +263,7 @@
*/
if (adreno_is_a3xx(adreno_dev)) {
- kgsl_mmu_device_setstate(device, flags);
+ kgsl_mmu_device_setstate(&device->mmu, flags);
return;
}
@@ -349,7 +349,7 @@
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
&link[0], sizedwords);
} else {
- kgsl_mmu_device_setstate(device, flags);
+ kgsl_mmu_device_setstate(&device->mmu, flags);
}
}
@@ -575,7 +575,7 @@
}
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- kgsl_mmu_stop(device);
+ kgsl_mmu_stop(&device->mmu);
error_clk_off:
kgsl_pwrctrl_disable(device);
@@ -590,7 +590,7 @@
adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
- kgsl_mmu_stop(device);
+ kgsl_mmu_stop(&device->mmu);
device->ftbl->irqctrl(device, 0);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 050fd83..e10edea 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1510,7 +1510,7 @@
if (context == NULL) {
/* No context - set the default apgetable and thats it */
- kgsl_mmu_setstate(device, device->mmu.defaultpagetable);
+ kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable);
return;
}
@@ -1523,7 +1523,7 @@
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->id;
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
- kgsl_mmu_setstate(device, context->pagetable);
+ kgsl_mmu_setstate(&device->mmu, context->pagetable);
#ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
kgsl_cffdump_syncmem(NULL, &context->gpustate,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 6b58545..8c5d76a 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2257,7 +2257,7 @@
if (context == NULL) {
/* No context - set the default pagetable and thats it */
- kgsl_mmu_setstate(device, device->mmu.defaultpagetable);
+ kgsl_mmu_setstate(&device->mmu, device->mmu.defaultpagetable);
return;
}
@@ -2270,7 +2270,7 @@
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, current_context);
cmds[4] = context->id;
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
- kgsl_mmu_setstate(device, context->pagetable);
+ kgsl_mmu_setstate(&device->mmu, context->pagetable);
/*
* Restore GMEM. (note: changes shader.
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 6bdf284..9d68c60 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -661,7 +661,7 @@
kgsl_regread(device, MH_MMU_MPU_END, &r1);
kgsl_regread(device, MH_MMU_VA_RANGE, &r2);
- r3 = kgsl_mmu_get_current_ptbase(device);
+ r3 = kgsl_mmu_get_current_ptbase(&device->mmu);
KGSL_LOG_DUMP(device,
" MPU_END = %08X | VA_RANGE = %08X | PT_BASE ="
" %08X\n", r1, r2, r3);
@@ -706,7 +706,7 @@
else if (adreno_is_a3xx(adreno_dev))
adreno_dump_a3xx(device);
- pt_base = kgsl_mmu_get_current_ptbase(device);
+ pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
cur_pt_base = pt_base;
kgsl_regread(device, REG_CP_RB_BASE, &cp_rb_base);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 2dc6f6c..a0907d7 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -531,7 +531,7 @@
int skip_pktsize = 1;
/* Get the physical address of the MMU pagetable */
- ptbase = kgsl_mmu_get_current_ptbase(device);
+ ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
/* Get the current read pointers for the RB */
kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
@@ -792,7 +792,7 @@
memset(vbo, 0, sizeof(vbo));
/* Get the physical address of the MMU pagetable */
- ptbase = kgsl_mmu_get_current_ptbase(device);
+ ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
/* Dump the ringbuffer */
snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 1d80a30..5a10654 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -686,12 +686,10 @@
return 0;
}
-static int kgsl_gpummu_stop(struct kgsl_mmu *mmu)
+static void kgsl_gpummu_stop(struct kgsl_mmu *mmu)
{
kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
mmu->flags &= ~KGSL_FLAGS_STARTED;
-
- return 0;
}
static int kgsl_gpummu_close(struct kgsl_mmu *mmu)
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index bf2a4ee..21f14ac 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -298,7 +298,7 @@
return ret;
}
-static int kgsl_iommu_stop(struct kgsl_mmu *mmu)
+static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
{
/*
* stop device mmu
@@ -312,8 +312,6 @@
mmu->flags &= ~KGSL_FLAGS_STARTED;
}
-
- return 0;
}
static int kgsl_iommu_close(struct kgsl_mmu *mmu)
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 2b359ec..e11b119 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -322,16 +322,6 @@
return 0;
}
-unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device)
-{
- struct kgsl_mmu *mmu = &device->mmu;
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
- return 0;
- else
- return mmu->mmu_ops->mmu_get_current_ptbase(mmu);
-}
-EXPORT_SYMBOL(kgsl_mmu_get_current_ptbase);
-
int
kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base)
{
@@ -351,19 +341,6 @@
}
EXPORT_SYMBOL(kgsl_mmu_get_ptname_from_ptbase);
-void kgsl_mmu_setstate(struct kgsl_device *device,
- struct kgsl_pagetable *pagetable)
-{
- struct kgsl_mmu *mmu = &device->mmu;
-
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
- return;
- else
- mmu->mmu_ops->mmu_setstate(mmu,
- pagetable);
-}
-EXPORT_SYMBOL(kgsl_mmu_setstate);
-
int kgsl_mmu_init(struct kgsl_device *device)
{
struct kgsl_mmu *mmu = &device->mmu;
@@ -555,16 +532,6 @@
}
EXPORT_SYMBOL(kgsl_setstate);
-void kgsl_mmu_device_setstate(struct kgsl_device *device, uint32_t flags)
-{
- struct kgsl_mmu *mmu = &device->mmu;
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
- return;
- else if (mmu->mmu_ops->mmu_device_setstate)
- mmu->mmu_ops->mmu_device_setstate(mmu, flags);
-}
-EXPORT_SYMBOL(kgsl_mmu_device_setstate);
-
void kgsl_mh_start(struct kgsl_device *device)
{
struct kgsl_mh *mh = &device->mh;
@@ -746,17 +713,6 @@
}
EXPORT_SYMBOL(kgsl_mmu_map_global);
-int kgsl_mmu_stop(struct kgsl_device *device)
-{
- struct kgsl_mmu *mmu = &device->mmu;
-
- if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
- return 0;
- else
- return mmu->mmu_ops->mmu_stop(mmu);
-}
-EXPORT_SYMBOL(kgsl_mmu_stop);
-
int kgsl_mmu_close(struct kgsl_device *device)
{
struct kgsl_mmu *mmu = &device->mmu;
@@ -814,16 +770,6 @@
}
EXPORT_SYMBOL(kgsl_mmu_enabled);
-int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
- unsigned int pt_base)
-{
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
- return true;
- else
- return pt->pt_ops->mmu_pt_equal(pt, pt_base);
-}
-EXPORT_SYMBOL(kgsl_mmu_pt_equal);
-
enum kgsl_mmutype kgsl_mmu_get_mmutype(void)
{
return kgsl_mmu_type;
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index e35f368..b476add 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -122,7 +122,7 @@
int (*mmu_init) (struct kgsl_mmu *mmu);
int (*mmu_close) (struct kgsl_mmu *mmu);
int (*mmu_start) (struct kgsl_mmu *mmu);
- int (*mmu_stop) (struct kgsl_mmu *mmu);
+ void (*mmu_stop) (struct kgsl_mmu *mmu);
void (*mmu_setstate) (struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable);
void (*mmu_device_setstate) (struct kgsl_mmu *mmu,
@@ -169,7 +169,6 @@
void kgsl_mh_intrcallback(struct kgsl_device *device);
int kgsl_mmu_init(struct kgsl_device *device);
int kgsl_mmu_start(struct kgsl_device *device);
-int kgsl_mmu_stop(struct kgsl_device *device);
int kgsl_mmu_close(struct kgsl_device *device);
int kgsl_mmu_map(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc,
@@ -180,19 +179,57 @@
struct kgsl_memdesc *memdesc);
unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
void kgsl_setstate(struct kgsl_mmu *mmu, uint32_t flags);
-void kgsl_mmu_device_setstate(struct kgsl_device *device, uint32_t flags);
-void kgsl_mmu_setstate(struct kgsl_device *device,
- struct kgsl_pagetable *pt);
int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base);
int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
enum kgsl_deviceid id);
void kgsl_mmu_ptpool_destroy(void *ptpool);
void *kgsl_mmu_ptpool_init(int entries);
int kgsl_mmu_enabled(void);
-int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
- unsigned int pt_base);
void kgsl_mmu_set_mmutype(char *mmutype);
-unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_device *device);
enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
unsigned int kgsl_mmu_get_ptsize(void);
+
+/*
+ * Static inline functions of MMU that simply call the SMMU specific
+ * function using a function pointer. These functions can be thought
+ * of as wrappers around the actual function
+ */
+
+static inline unsigned int kgsl_mmu_get_current_ptbase(struct kgsl_mmu *mmu)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_current_ptbase)
+ return mmu->mmu_ops->mmu_get_current_ptbase(mmu);
+ else
+ return 0;
+}
+
+static inline void kgsl_mmu_setstate(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pagetable)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_setstate)
+ mmu->mmu_ops->mmu_setstate(mmu, pagetable);
+}
+
+static inline void kgsl_mmu_device_setstate(struct kgsl_mmu *mmu,
+ uint32_t flags)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_device_setstate)
+ mmu->mmu_ops->mmu_device_setstate(mmu, flags);
+}
+
+static inline void kgsl_mmu_stop(struct kgsl_mmu *mmu)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_stop)
+ mmu->mmu_ops->mmu_stop(mmu);
+}
+
+static inline int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
+ unsigned int pt_base)
+{
+ if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+ return 1;
+ else
+ return pt->pt_ops->mmu_pt_equal(pt, pt_base);
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 24ea571..f61c74f 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -122,7 +122,7 @@
header->current_context = -1;
/* Get the current PT base */
- header->ptbase = kgsl_mmu_get_current_ptbase(device);
+ header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
/* And the PID for the task leader */
pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 3ca9e18..2df4c80 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -464,7 +464,7 @@
(ctrl & KGSL_CONTEXT_CTX_SWITCH)) {
KGSL_CMD_INFO(device, "context switch %d -> %d\n",
context->id, z180_dev->ringbuffer.prevctx);
- kgsl_mmu_setstate(device, pagetable);
+ kgsl_mmu_setstate(&device->mmu, pagetable);
cnt = PACKETSIZE_STATESTREAM;
ofs = 0;
}
@@ -613,7 +613,7 @@
del_timer_sync(&device->idle_timer);
- kgsl_mmu_stop(device);
+ kgsl_mmu_stop(&device->mmu);
/* Disable the clocks before the power rail. */
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index a276e84..72fba82 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -963,7 +963,8 @@
opcode = hci_opcode_pack(HCI_OGF_FM_COMMON_CTRL_CMD_REQ,
HCI_OCF_FM_DEFAULT_DATA_WRITE);
- return radio_hci_send_cmd(hdev, opcode, sizeof((*def_data_wr)),
+
+ return radio_hci_send_cmd(hdev, opcode, (def_data_wr->length+2),
def_data_wr);
}
@@ -2470,7 +2471,7 @@
radio->fm_hdev);
if (retval < 0)
FMDERR("Disable Failed after calibration %d", retval);
- return retval;
+ return retval;
}
static int iris_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
@@ -2726,10 +2727,44 @@
case V4L2_CID_PRIVATE_IRIS_WRITE_DEFAULT:
data = (ctrl->controls[0]).string;
memset(&default_data, 0, sizeof(default_data));
- if (copy_from_user(&default_data, data, sizeof(default_data)))
+ /*
+ * Check if length of the 'FM Default Data' to be sent
+ * is within the maximum 'FM Default Data' packet limit.
+ * Max. 'FM Default Data' packet length is 251 bytes:
+ * 1 byte - XFR Mode
+ * 1 byte - length of the default data
+ * 249 bytes - actual data to be configured
+ */
+ if (ctrl->controls[0].size > (DEFAULT_DATA_SIZE + 2)) {
+ pr_err("%s: Default data buffer overflow!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* copy only 'size' bytes of data as requested by user */
+ retval = copy_from_user(&default_data, data,
+ ctrl->controls[0].size);
+ if (retval > 0) {
+ pr_err("%s: Failed to copy %d bytes of default data"
+ " passed by user\n", __func__, retval);
return -EFAULT;
+ }
+ FMDBG("%s: XFR Mode\t: 0x%x\n", __func__, default_data.mode);
+ FMDBG("%s: XFR Data Length\t: %d\n", __func__,
+ default_data.length);
+ /*
+ * Check if the 'length' of the actual XFR data to be configured
+ * is valid or not. Length of actual XFR data should be always
+ * 2 bytes less than the total length of the 'FM Default Data'.
+ * Length of 'FM Default Data' DEF_DATA_LEN: (1+1+XFR Data Size)
+ * Length of 'Actual XFR Data' XFR_DATA_LEN: (DEF_DATA_LEN - 2)
+ */
+ if (default_data.length != (ctrl->controls[0].size - 2)) {
+ pr_err("%s: Invalid 'length' parameter passed for "
+ "actual xfr data\n", __func__);
+ return -EINVAL;
+ }
retval = hci_def_data_write(&default_data, radio->fm_hdev);
- break;
+ break;
case V4L2_CID_PRIVATE_IRIS_SET_CALIBRATION:
data = (ctrl->controls[0]).string;
bytes_to_copy = (ctrl->controls[0]).size;
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index e9c710a..b7ae0f4 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -244,9 +244,11 @@
WFD_MSG_DBG("EVENT: not expected = %d\n", event);
venc_stop_done(client_ctx, status);
break;
- case VCD_EVT_RESP_PAUSE:
case VCD_EVT_RESP_FLUSH_INPUT_DONE:
case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+ venc_notify_client(client_ctx);
+ break;
+ case VCD_EVT_RESP_PAUSE:
case VCD_EVT_IND_OUTPUT_RECONFIG:
WFD_MSG_DBG("EVENT: not expected = %d\n", event);
break;
@@ -1935,6 +1937,46 @@
(u8 *)kernel_vaddr);
}
+static long venc_flush_buffers(struct v4l2_subdev *sd, void *arg)
+{
+ int rc = 0;
+ struct venc_inst *inst = sd->dev_priv;
+ struct video_client_ctx *client_ctx = &inst->venc_client;
+ if (!client_ctx) {
+ WFD_MSG_ERR("Invalid input\n");
+ return -EINVAL;
+ }
+ rc = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_INPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to flush input buffers\n");
+ rc = -EIO;
+ goto flush_failed;
+ }
+ wait_for_completion(&client_ctx->event);
+ if (client_ctx->event_status) {
+ WFD_MSG_ERR("callback for vcd_flush input returned error: %u",
+ client_ctx->event_status);
+ rc = -EIO;
+ goto flush_failed;
+ }
+ rc = vcd_flush(client_ctx->vcd_handle, VCD_FLUSH_OUTPUT);
+ if (rc) {
+ WFD_MSG_ERR("Failed to flush output buffers\n");
+ rc = -EIO;
+ goto flush_failed;
+ }
+ wait_for_completion(&client_ctx->event);
+ if (client_ctx->event_status) {
+ WFD_MSG_ERR("callback for vcd_flush output returned error: %u",
+ client_ctx->event_status);
+ rc = -EIO;
+ goto flush_failed;
+ }
+
+flush_failed:
+ return rc;
+}
+
static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
{
int del_rc = 0, free_rc = 0;
@@ -2203,6 +2245,9 @@
case FREE_RECON_BUFFERS:
rc = venc_free_recon_buffers(sd, arg);
break;
+ case ENCODE_FLUSH:
+ rc = venc_flush_buffers(sd, arg);
+ break;
default:
rc = -1;
break;
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
index cafc9d5..5873e62 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.h
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -74,6 +74,7 @@
#define FREE_OUTPUT_BUFFER _IOWR('V', 21, struct mem_region *)
#define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
#define FREE_RECON_BUFFERS _IO('V', 23)
+#define ENCODE_FLUSH _IO('V', 24)
extern int venc_init(struct v4l2_subdev *sd, u32 val);
extern int venc_load_fw(struct v4l2_subdev *sd);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 7ab5d17..0a2b1c1 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -614,6 +614,10 @@
WFD_MSG_ERR("Failed to stop VSG\n");
kthread_stop(inst->mdp_task);
+ rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+ ENCODE_FLUSH, (void *)inst->venc_inst);
+ if (rc)
+ WFD_MSG_ERR("Failed to flush encoder\n");
WFD_MSG_DBG("enc stop\n");
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENCODE_STOP, (void *)inst->venc_inst);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 6ebc955..8156505 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -300,6 +300,27 @@
encoder->seq_header.virtual_base_addr,
encoder->seq_header.buffer_size,
ION_IOC_CLEAN_INV_CACHES);
+ if (encoder->slice_delivery_info.enable) {
+ DDL_MSG_LOW("%s: slice mode allocate memory for struct\n",
+ __func__);
+ ptr = ddl_pmem_alloc(&encoder->batch_frame.slice_batch_in,
+ DDL_ENC_SLICE_BATCH_INPSTRUCT_SIZE,
+ DDL_LINEAR_BUFFER_ALIGN_BYTES);
+ if (ptr) {
+ ptr = ddl_pmem_alloc(
+ &encoder->batch_frame.slice_batch_out,
+ DDL_ENC_SLICE_BATCH_OUTSTRUCT_SIZE,
+ DDL_LINEAR_BUFFER_ALIGN_BYTES);
+ }
+ if (!ptr) {
+ ddl_pmem_free(&encoder->batch_frame.slice_batch_in);
+ ddl_pmem_free(&encoder->batch_frame.slice_batch_out);
+ ddl_free_enc_hw_buffers(ddl);
+ ddl_pmem_free(&encoder->seq_header);
+ DDL_MSG_ERROR("ddlEncStart:SeqHdrAllocFailed");
+ return VCD_ERR_ALLOC_FAIL;
+ }
+ }
if (!ddl_take_command_channel(ddl_context, ddl, client_data))
return VCD_ERR_BUSY;
ddl_vidc_channel_set(ddl);
@@ -451,7 +472,17 @@
struct ddl_client_context *ddl =
(struct ddl_client_context *) ddl_handle;
struct ddl_context *ddl_context;
+ struct ddl_encoder_data *encoder =
+ &ddl->codec_data.encoder;
u32 vcd_status = VCD_S_SUCCESS;
+ if (encoder->slice_delivery_info.enable) {
+ return ddl_encode_frame_batch(ddl_handle,
+ input_frame,
+ output_bit,
+ 1,
+ encoder->slice_delivery_info.num_slices,
+ client_data);
+ }
DDL_MSG_HIGH("ddl_encode_frame");
if (vidc_msg_timing)
@@ -519,6 +550,76 @@
return vcd_status;
}
+u32 ddl_encode_frame_batch(u32 *ddl_handle,
+ struct ddl_frame_data_tag *input_frame,
+ struct ddl_frame_data_tag *output_bit,
+ u32 num_in_frames, u32 num_out_frames,
+ void *client_data)
+{
+ struct ddl_client_context *ddl =
+ (struct ddl_client_context *) ddl_handle;
+ struct ddl_context *ddl_context;
+ u32 vcd_status = VCD_S_SUCCESS;
+ struct ddl_encoder_data *encoder;
+
+ DDL_MSG_LOW("ddl_encode_frame_batch");
+ ddl_context = ddl_get_context();
+ if (!DDL_IS_INITIALIZED(ddl_context)) {
+ DDL_MSG_ERROR("ddl_enc_frame:Not_inited");
+ return VCD_ERR_ILLEGAL_OP;
+ }
+ if (DDL_IS_BUSY(ddl_context)) {
+ DDL_MSG_ERROR("ddl_enc_frame:Ddl_busy");
+ return VCD_ERR_BUSY;
+ }
+ if (!ddl || ddl->decoding) {
+ DDL_MSG_ERROR("ddl_enc_frame:Bad_handle");
+ return VCD_ERR_BAD_HANDLE;
+ }
+ if (!input_frame || !input_frame->vcd_frm.physical ||
+ !input_frame->vcd_frm.data_len) {
+ DDL_MSG_ERROR("ddl_enc_frame:Bad_input_params");
+ return VCD_ERR_ILLEGAL_PARM;
+ }
+ if ((((u32) input_frame->vcd_frm.physical +
+ input_frame->vcd_frm.offset) &
+ (DDL_STREAMBUF_ALIGN_GUARD_BYTES))) {
+ DDL_MSG_ERROR("ddl_enc_frame:Un_aligned_yuv_start_address");
+ return VCD_ERR_ILLEGAL_PARM;
+ }
+ if (!output_bit || !output_bit->vcd_frm.physical ||
+ !output_bit->vcd_frm.alloc_len) {
+ DDL_MSG_ERROR("ddl_enc_frame:Bad_output_params");
+ return VCD_ERR_ILLEGAL_PARM;
+ }
+ if ((ddl->codec_data.encoder.output_buf_req.sz +
+ output_bit->vcd_frm.offset) >
+ output_bit->vcd_frm.alloc_len)
+ DDL_MSG_ERROR("ddl_enc_frame:offset_large,"
+ "Exceeds_min_buf_size");
+ if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME)) {
+ DDL_MSG_ERROR("ddl_enc_frame:Wrong_state");
+ return VCD_ERR_ILLEGAL_OP;
+ }
+ if (!ddl_take_command_channel(ddl_context, ddl, client_data))
+ return VCD_ERR_BUSY;
+ encoder = &ddl->codec_data.encoder;
+ if (encoder->slice_delivery_info.enable) {
+ DDL_MEMCPY((void *)&(encoder->batch_frame.output_frame[0]),
+ (void *)output_bit,
+ sizeof(struct ddl_frame_data_tag) * num_out_frames);
+ encoder->batch_frame.num_output_frames = num_out_frames;
+ ddl->input_frame = *input_frame;
+ vcd_status = ddl_insert_input_frame_to_pool(ddl, input_frame);
+ if (!vcd_status)
+ ddl_vidc_encode_slice_batch_run(ddl);
+ else
+ DDL_MSG_ERROR("insert to frame pool failed %u",
+ vcd_status);
+ }
+ return vcd_status;
+}
+
u32 ddl_decode_end(u32 *ddl_handle, void *client_data)
{
struct ddl_client_context *ddl =
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index c3874fa..d05e542 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -113,6 +113,7 @@
DDL_CMD_ENCODE_FRAME = 0x8,
DDL_CMD_EOS = 0x9,
DDL_CMD_CHANNEL_END = 0xA,
+ DDL_CMD_ENCODE_CONTINUE = 0xB,
DDL_CMD_32BIT = 0x7FFFFFFF
};
enum ddl_client_state{
@@ -129,6 +130,7 @@
DDL_CLIENT_WAIT_FOR_CHEND = 0xA,
DDL_CLIENT_FATAL_ERROR = 0xB,
DDL_CLIENT_FAVIDC_ERROR = 0xC,
+ DDL_CLIENT_WAIT_FOR_CONTINUE = 0xD,
DDL_CLIENT_32BIT = 0x7FFFFFFF
};
struct ddl_hw_interface{
@@ -215,6 +217,15 @@
struct ddl_codec_data_hdr{
u32 decoding;
};
+struct ddl_batch_frame_data {
+ struct ddl_buf_addr slice_batch_in;
+ struct ddl_buf_addr slice_batch_out;
+ struct ddl_frame_data_tag input_frame;
+ struct ddl_frame_data_tag output_frame
+ [DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH];
+ u32 num_output_frames;
+ u32 out_frm_next_frmindex;
+};
struct ddl_encoder_data{
struct ddl_codec_data_hdr hdr;
struct vcd_property_codec codec;
@@ -262,6 +273,8 @@
u32 ext_enc_control_val;
u32 num_references_for_p_frame;
u32 closed_gop;
+ struct vcd_property_slice_delivery_info slice_delivery_info;
+ struct ddl_batch_frame_data batch_frame;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
@@ -344,6 +357,8 @@
(struct vidc_1080p_enc_seq_start_param *param);
void(*vidc_encode_frame_start[2])
(struct vidc_1080p_enc_frame_start_param *param);
+ void(*vidc_encode_slice_batch_start[2])
+ (struct vidc_1080p_enc_frame_start_param *param);
u32 frame_channel_depth;
};
struct ddl_client_context{
@@ -375,9 +390,12 @@
void ddl_vidc_channel_end(struct ddl_client_context *);
void ddl_vidc_encode_init_codec(struct ddl_client_context *);
void ddl_vidc_decode_init_codec(struct ddl_client_context *);
+void ddl_vidc_encode_frame_continue(struct ddl_client_context *);
void ddl_vidc_encode_frame_run(struct ddl_client_context *);
+void ddl_vidc_encode_slice_batch_run(struct ddl_client_context *);
void ddl_vidc_decode_frame_run(struct ddl_client_context *);
void ddl_vidc_decode_eos_run(struct ddl_client_context *ddl);
+void ddl_vidc_encode_eos_run(struct ddl_client_context *ddl);
void ddl_release_context_buffers(struct ddl_context *);
void ddl_release_client_internal_buffers(struct ddl_client_context *ddl);
u32 ddl_vidc_decode_set_buffers(struct ddl_client_context *);
@@ -438,9 +456,10 @@
u32 ddl_get_input_frame_from_pool(struct ddl_client_context *ddl,
u8 *input_buffer_address);
+u32 ddl_get_stream_buf_from_batch_pool(struct ddl_client_context *ddl,
+ struct ddl_frame_data_tag *stream_buffer);
u32 ddl_insert_input_frame_to_pool(struct ddl_client_context *ddl,
struct ddl_frame_data_tag *ddl_input_frame);
-
void ddl_decoder_chroma_dpb_change(struct ddl_client_context *ddl);
u32 ddl_check_reconfig(struct ddl_client_context *ddl);
void ddl_handle_reconfig(u32 res_change, struct ddl_client_context *ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
index 433dad4..5c1ee21 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_api.h
@@ -62,6 +62,11 @@
u32 disable_static_region_as_flag;
u32 disable_activity_region_flag;
};
+struct vcd_property_slice_delivery_info {
+ u32 enable;
+ u32 num_slices;
+ u32 num_slices_enc;
+};
struct ddl_property_dec_pic_buffers{
struct ddl_frame_data_tag *dec_pic_buffers;
u32 no_of_dec_pic_buf;
@@ -94,6 +99,11 @@
u32 ddl_encode_frame(u32 *ddl_handle,
struct ddl_frame_data_tag *input_frame,
struct ddl_frame_data_tag *output_bit, void *client_data);
+u32 ddl_encode_frame_batch(u32 *ddl_handle,
+ struct ddl_frame_data_tag *input_frame,
+ struct ddl_frame_data_tag *output_bit,
+ u32 num_in_frames, u32 num_out_frames,
+ void *client_data);
u32 ddl_encode_end(u32 *ddl_handle, void *client_data);
u32 ddl_decode_start(u32 *ddl_handle, struct vcd_sequence_hdr *header,
void *client_data);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index a8ccebf..41604b0 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -64,13 +64,20 @@
#define DDL_FW_INST_GLOBAL_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(800))
#define DDL_FW_H264DEC_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(800))
#define DDL_FW_H264ENC_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(20))
-#define DDL_FW_OTHER_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(10))
+#define DDL_FW_OTHER_CONTEXT_SPACE_SIZE (DDL_KILO_BYTE(20))
#define VCD_DEC_CPB_SIZE (DDL_KILO_BYTE(512))
#define DDL_DBG_CORE_DUMP_SIZE (DDL_KILO_BYTE(10))
+#define DDL_VIDC_1080P_BASE_OFFSET_SHIFT 11
#define DDL_BUFEND_PAD 256
#define DDL_ENC_SEQHEADER_SIZE (512+DDL_BUFEND_PAD)
+#define DDL_ENC_SLICE_BATCH_FACTOR 5
+#define DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH 8
+#define DDL_ENC_SLICE_BATCH_INPSTRUCT_SIZE (128 + \
+ 32 * DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH)
+#define DDL_ENC_SLICE_BATCH_OUTSTRUCT_SIZE (64 + \
+ 64 * DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH)
#define DDL_MAX_BUFFER_COUNT 32
#define DDL_MIN_BUFFER_COUNT 1
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 62f0976..0d0ba3e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -375,6 +375,8 @@
struct ddl_encoder_data *encoder =
&(ddl->codec_data.encoder);
ddl_pmem_free(&encoder->seq_header);
+ ddl_pmem_free(&encoder->batch_frame.slice_batch_in);
+ ddl_pmem_free(&encoder->batch_frame.slice_batch_out);
ddl_vidc_encode_dynamic_property(ddl, false);
encoder->dynamic_prop_change = 0;
ddl_free_enc_hw_buffers(ddl);
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 830c777c3..79e6c5d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -29,7 +29,11 @@
enum vidc_1080p_encode_frame frame_type);
static void ddl_get_dec_profile_level(struct ddl_decoder_data *decoder,
u32 profile, u32 level);
-static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl);
+static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
+ u32 eos_present);
+static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl);
+static void ddl_handle_enc_frame_done_slice_mode(
+ struct ddl_client_context *ddl, u32 eos_present);
static void ddl_fw_status_done_callback(struct ddl_context *ddl_context)
{
@@ -141,7 +145,7 @@
{
struct ddl_encoder_data *encoder;
- DDL_MSG_MED("ddl_encoder_seq_done_callback");
+ DDL_MSG_HIGH("ddl_encoder_seq_done_callback");
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_INITCODECDONE)) {
DDL_MSG_ERROR("STATE-CRITICAL-INITCODEC");
ddl_client_fatal_cb(ddl);
@@ -486,9 +490,9 @@
&(ddl->codec_data.encoder);
struct vcd_frame_data *output_frame =
&(ddl->output_frame.vcd_frm);
- u32 bottom_frame_tag;
+ u32 eos_present = false;
- DDL_MSG_MED("ddl_encoder_frame_run_callback");
+ DDL_MSG_MED("ddl_encoder_frame_run_callback\n");
if (!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_FRAME_DONE) &&
!DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
DDL_MSG_ERROR("STATE-CRITICAL-ENCFRMRUN");
@@ -499,47 +503,28 @@
DDL_MSG_LOW("ENC_FRM_RUN_DONE");
ddl->cmd_state = DDL_CMD_INVALID;
vidc_1080p_get_encode_frame_info(&encoder->enc_frame_info);
- vidc_sm_get_frame_tags(&ddl->shared_mem
- [ddl->command_channel],
- &output_frame->ip_frm_tag, &bottom_frame_tag);
if (encoder->meta_data_enable_flag)
vidc_sm_get_metadata_status(&ddl->shared_mem
[ddl->command_channel],
&encoder->enc_frame_info.meta_data_exists);
+ if (VCD_FRAME_FLAG_EOS & ddl->input_frame.vcd_frm.flags) {
+ DDL_MSG_LOW("%s EOS detected\n", __func__);
+ eos_present = true;
+ }
+
if (encoder->enc_frame_info.enc_frame_size ||
(encoder->enc_frame_info.enc_frame ==
VIDC_1080P_ENCODE_FRAMETYPE_SKIPPED) ||
DDLCLIENT_STATE_IS(ddl,
DDL_CLIENT_WAIT_FOR_EOS_DONE)) {
- u8 *input_buffer_address = NULL;
- output_frame->data_len =
- encoder->enc_frame_info.enc_frame_size;
- output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
- ddl_get_encoded_frame(output_frame,
- encoder->codec.codec,
- encoder->enc_frame_info.enc_frame);
- ddl_process_encoder_metadata(ddl);
- ddl_vidc_encode_dynamic_property(ddl, false);
- ddl->input_frame.frm_trans_end = false;
- input_buffer_address = ddl_context->dram_base_a.\
- align_physical_addr +
- encoder->enc_frame_info.enc_luma_address;
- ddl_get_input_frame_from_pool(ddl,
- input_buffer_address);
- ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
- VCD_S_SUCCESS, &(ddl->input_frame),
- sizeof(struct ddl_frame_data_tag),
- (u32 *)ddl, ddl->client_data);
- ddl->output_frame.frm_trans_end =
- DDLCLIENT_STATE_IS(ddl,
- DDL_CLIENT_WAIT_FOR_EOS_DONE) ? false : true;
- ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
- VCD_S_SUCCESS, &(ddl->output_frame),
- sizeof(struct ddl_frame_data_tag),
- (u32 *)ddl, ddl->client_data);
-
+ if (encoder->slice_delivery_info.enable) {
+ ddl_handle_enc_frame_done_slice_mode(ddl,
+ eos_present);
+ } else {
+ ddl_handle_enc_frame_done(ddl, eos_present);
+ }
if (DDLCLIENT_STATE_IS(ddl,
DDL_CLIENT_WAIT_FOR_EOS_DONE) &&
encoder->i_period.b_frames) {
@@ -547,7 +532,7 @@
(ddl->extra_output_buf_count >
encoder->i_period.b_frames)) {
DDL_MSG_ERROR("Invalid B frame output"
- "buffer index");
+ "buffer index");
} else {
struct vidc_1080p_enc_frame_start_param
enc_param;
@@ -581,7 +566,11 @@
ddl_context->vidc_encode_frame_start
[ddl->command_channel]
(&enc_param);
- } } else {
+ }
+ } else if (eos_present &&
+ encoder->slice_delivery_info.enable) {
+ ddl_vidc_encode_eos_run(ddl);
+ } else {
DDL_MSG_LOW("ddl_state_transition: %s ~~>"
"DDL_CLIENT_WAIT_FOR_FRAME",
ddl_get_state_string(
@@ -885,6 +874,7 @@
vidc_1080p_clear_returned_channel_inst_id();
ddl = ddl_get_current_ddl_client_for_channel_id(ddl_context,
ddl_context->response_cmd_ch_id);
+ DDL_MSG_LOW("ddl_encoder_eos_done\n");
if (ddl == NULL) {
DDL_MSG_ERROR("NO_DDL_CONTEXT");
} else {
@@ -896,9 +886,11 @@
&(ddl->codec_data.encoder);
vidc_1080p_get_encode_frame_info(
&encoder->enc_frame_info);
- ddl_handle_enc_frame_done(ddl);
+ if (!encoder->slice_delivery_info.enable) {
+ ddl_handle_enc_frame_done(ddl, true);
+ ddl->cmd_state = DDL_CMD_INVALID;
+ }
DDL_MSG_LOW("encoder_eos_done");
- ddl->cmd_state = DDL_CMD_INVALID;
DDL_MSG_LOW("ddl_state_transition: %s ~~>"
"DDL_CLIENT_WAIT_FOR_FRAME",
ddl_get_state_string(ddl->client_state));
@@ -913,6 +905,35 @@
}
}
+static u32 ddl_slice_done_callback(struct ddl_context *ddl_context)
+{
+ struct ddl_client_context *ddl;
+ u32 channel_inst_id;
+ u32 return_status = true;
+ DDL_MSG_LOW("ddl_sliceDoneCallback");
+ vidc_1080p_get_returned_channel_inst_id(&channel_inst_id);
+ vidc_1080p_clear_returned_channel_inst_id();
+ ddl = ddl_get_current_ddl_client_for_channel_id(ddl_context,
+ ddl_context->response_cmd_ch_id);
+ if (ddl == NULL) {
+ DDL_MSG_ERROR("NO_DDL_CONTEXT");
+ return_status = false;
+ } else if (ddl->cmd_state == DDL_CMD_ENCODE_FRAME) {
+ ddl->cmd_state = DDL_CMD_INVALID;
+ if (DDLCLIENT_STATE_IS(ddl,
+ DDL_CLIENT_WAIT_FOR_FRAME_DONE)) {
+ ddl_handle_slice_done_slice_batch(ddl);
+ } else {
+ DDL_MSG_ERROR("STATE-CRITICAL-ENCFRMRUN : %s\n",
+ __func__);
+ ddl_client_fatal_cb(ddl);
+ }
+ } else {
+ DDL_MSG_ERROR("UNKNOWN_SLICEDONE : %s\n", __func__);
+ }
+ return return_status;
+}
+
static u32 ddl_process_intr_status(struct ddl_context *ddl_context,
u32 intr_status)
{
@@ -931,6 +952,9 @@
case VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET:
return_status = ddl_frame_run_callback(ddl_context);
break;
+ case VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET:
+ ddl_slice_done_callback(ddl_context);
+ break;
case VIDC_1080P_RISC2HOST_CMD_SYS_INIT_RET:
ddl_sys_init_done_callback(ddl_context,
ddl_context->response_cmd_ch_id);
@@ -963,6 +987,8 @@
{
struct ddl_context *ddl_context;
struct ddl_hw_interface *ddl_hw_response;
+ struct ddl_client_context *ddl;
+ struct ddl_encoder_data *encoder;
ddl_context = ddl_get_context();
if (!ddl_context->core_virtual_base_addr) {
@@ -971,12 +997,37 @@
ddl_hw_response = &ddl_context->ddl_hw_response;
vidc_1080p_get_risc2host_cmd(&ddl_hw_response->cmd,
&ddl_hw_response->arg1, &ddl_hw_response->arg2,
- &ddl_hw_response->arg3, &ddl_hw_response->arg4);
+ &ddl_hw_response->arg3,
+ &ddl_hw_response->arg4);
+ DDL_MSG_LOW("%s vidc_1080p_get_risc2host_cmd cmd = %u"
+ "arg1 = %u arg2 = %u arg3 = %u"
+ "arg4 = %u\n",
+ __func__, ddl_hw_response->cmd,
+ ddl_hw_response->arg1, ddl_hw_response->arg2,
+ ddl_hw_response->arg3,
+ ddl_hw_response->arg4);
+ ddl = ddl_get_current_ddl_client_for_channel_id(ddl_context,
+ ddl_context->response_cmd_ch_id);
+ if (ddl) {
+ encoder = &(ddl->codec_data.encoder);
+ if (encoder && encoder->slice_delivery_info.enable
+ &&
+ ((ddl_hw_response->cmd ==
+ VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET)
+ || (ddl_hw_response->cmd ==
+ VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET))) {
+ vidc_sm_set_encoder_slice_batch_int_ctrl(
+ &ddl->shared_mem[ddl->command_channel],
+ 1);
+ }
+ }
vidc_1080p_clear_risc2host_cmd();
vidc_1080p_clear_interrupt();
vidc_1080p_get_risc2host_cmd_status(ddl_hw_response->arg2,
&ddl_context->cmd_err_status,
&ddl_context->disp_pic_err_status);
+ DDL_MSG_LOW("%s cmd_err_status = %d\n", __func__,
+ ddl_context->cmd_err_status);
ddl_context->response_cmd_ch_id = ddl_hw_response->arg1;
}
}
@@ -1638,39 +1689,214 @@
decoder->level.level = level;
}
-static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl)
+static void ddl_handle_enc_frame_done(struct ddl_client_context *ddl,
+ u32 eos_present)
{
struct ddl_context *ddl_context = ddl->ddl_context;
struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
struct vcd_frame_data *output_frame = &(ddl->output_frame.vcd_frm);
u32 bottom_frame_tag;
- u8 *input_buffer_address = NULL;
+ u8 *input_buffer_address = NULL;
vidc_sm_get_frame_tags(&ddl->shared_mem[ddl->command_channel],
&output_frame->ip_frm_tag, &bottom_frame_tag);
output_frame->data_len = encoder->enc_frame_info.enc_frame_size;
output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
(void)ddl_get_encoded_frame(output_frame,
- encoder->codec.codec, encoder->enc_frame_info.enc_frame);
+ encoder->codec.codec, encoder->enc_frame_info.enc_frame
+ );
ddl_process_encoder_metadata(ddl);
ddl_vidc_encode_dynamic_property(ddl, false);
ddl->input_frame.frm_trans_end = false;
input_buffer_address = ddl_context->dram_base_a.align_physical_addr +
encoder->enc_frame_info.enc_luma_address;
ddl_get_input_frame_from_pool(ddl, input_buffer_address);
-
ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
- VCD_S_SUCCESS, &(ddl->input_frame),
- sizeof(struct ddl_frame_data_tag),
- (u32 *) ddl, ddl->client_data);
-
- ddl->output_frame.frm_trans_end =
- DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_WAIT_FOR_EOS_DONE)
- ? false : true;
-
+ VCD_S_SUCCESS, &(ddl->input_frame),
+ sizeof(struct ddl_frame_data_tag),
+ (u32 *) ddl, ddl->client_data);
+ ddl->output_frame.frm_trans_end = eos_present ?
+ false : true;
ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
- VCD_S_SUCCESS, &(ddl->output_frame),
- sizeof(struct ddl_frame_data_tag),
- (u32 *) ddl, ddl->client_data);
+ VCD_S_SUCCESS, &(ddl->output_frame),
+ sizeof(struct ddl_frame_data_tag),
+ (u32 *) ddl, ddl->client_data);
+}
+static void ddl_handle_slice_done_slice_batch(struct ddl_client_context *ddl)
+{
+ struct ddl_context *ddl_context = ddl->ddl_context;
+ struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+ struct vcd_frame_data *output_frame = NULL;
+ u32 bottom_frame_tag;
+ struct vidc_1080p_enc_slice_batch_out_param *slice_output = NULL;
+ u32 num_slices_comp = 0;
+ u32 index = 0;
+ u32 start_bfr_idx = 0;
+ u32 actual_idx = 0;
+
+ DDL_MSG_LOW("%s\n", __func__);
+ vidc_sm_get_num_slices_comp(
+ &ddl->shared_mem[ddl->command_channel],
+ &num_slices_comp);
+ slice_output = (struct vidc_1080p_enc_slice_batch_out_param *)
+ (encoder->batch_frame.slice_batch_out.align_virtual_addr);
+ DDL_MSG_LOW(" after get no of slices = %d\n", num_slices_comp);
+ if (slice_output == NULL)
+ DDL_MSG_ERROR(" slice_output is NULL\n");
+ encoder->slice_delivery_info.num_slices_enc += num_slices_comp;
+ if (vidc_msg_timing) {
+ ddl_calc_core_proc_time_cnt(__func__, ENC_SLICE_OP_TIME,
+ num_slices_comp);
+ ddl_set_core_start_time(__func__, ENC_SLICE_OP_TIME);
+ }
+ DDL_MSG_LOW("%s : Slices Completed %d Total slices %d OutBfrInfo:"
+ "Cmd %d Size %d\n",
+ __func__,
+ num_slices_comp,
+ encoder->slice_delivery_info.num_slices_enc,
+ slice_output->cmd_type,
+ slice_output->output_size);
+ start_bfr_idx = encoder->batch_frame.out_frm_next_frmindex;
+ for (index = 0; index < num_slices_comp; index++) {
+ actual_idx =
+ slice_output->slice_info[start_bfr_idx+index].stream_buffer_idx;
+ DDL_MSG_LOW("Slice Info: OutBfrIndex %d SliceSize %d\n",
+ actual_idx,
+ slice_output->slice_info[start_bfr_idx+index].
+ stream_buffer_size);
+ output_frame = &(
+ encoder->batch_frame.output_frame[actual_idx].vcd_frm);
+ DDL_MSG_LOW("OutBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
+ "frmbfr(physical) 0x%x\n",
+ &output_frame,
+ output_frame.virtual_base_addr,
+ output_frame.physical_base_addr);
+ vidc_1080p_get_encode_frame_info(&encoder->enc_frame_info);
+ vidc_sm_get_frame_tags(&ddl->shared_mem
+ [ddl->command_channel],
+ &output_frame->ip_frm_tag, &bottom_frame_tag);
+ ddl_get_encoded_frame(output_frame,
+ encoder->codec.codec,
+ encoder->enc_frame_info.enc_frame);
+ output_frame->data_len =
+ slice_output->slice_info[actual_idx].stream_buffer_size;
+ ddl->output_frame =
+ encoder->batch_frame.output_frame[actual_idx];
+ ddl->output_frame.frm_trans_end = false;
+ ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
+ VCD_S_SUCCESS, &(ddl->output_frame),
+ sizeof(struct ddl_frame_data_tag),
+ (u32 *) ddl, ddl->client_data);
+ ddl->input_frame.frm_trans_end = false;
+ DDL_MSG_LOW("%s Set i/p o/p transactions to false\n", __func__);
+ }
+ encoder->batch_frame.out_frm_next_frmindex = start_bfr_idx + index;
+ ddl->cmd_state = DDL_CMD_ENCODE_FRAME;
+ vidc_sm_set_encoder_slice_batch_int_ctrl(
+ &ddl->shared_mem[ddl->command_channel],
+ 0);
+}
+
+static void ddl_handle_enc_frame_done_slice_mode(
+ struct ddl_client_context *ddl, u32 eos_present)
+{
+ struct ddl_context *ddl_context = ddl->ddl_context;
+ struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+ struct vcd_frame_data *output_frame = NULL;
+ u32 bottom_frame_tag;
+ u8 *input_buffer_address = NULL;
+ struct vidc_1080p_enc_slice_batch_out_param *slice_output = NULL;
+ u32 num_slices_comp = 0;
+ u32 index = 0;
+ u32 start_bfr_idx = 0;
+ u32 actual_idx = 0;
+ struct vcd_transc *transc;
+
+ DDL_MSG_LOW("%s\n", __func__);
+ vidc_sm_get_num_slices_comp(
+ &ddl->shared_mem[ddl->command_channel],
+ &num_slices_comp);
+ slice_output = (struct vidc_1080p_enc_slice_batch_out_param *)
+ encoder->batch_frame.slice_batch_out.align_virtual_addr;
+ encoder->slice_delivery_info.num_slices_enc += num_slices_comp;
+ if (vidc_msg_timing) {
+ ddl_calc_core_proc_time_cnt(__func__, ENC_OP_TIME,
+ num_slices_comp);
+ }
+ DDL_MSG_LOW("%s Slices Completed %d Total slices done = %d"
+ " OutBfrInfo: Cmd %d Size %d",
+ __func__,
+ num_slices_comp,
+ encoder->slice_delivery_info.num_slices_enc,
+ slice_output->cmd_type,
+ slice_output->output_size);
+ start_bfr_idx = encoder->batch_frame.out_frm_next_frmindex;
+ if ((encoder->slice_delivery_info.num_slices_enc %
+ encoder->batch_frame.num_output_frames) != 0) {
+ DDL_MSG_ERROR("ERROR : %d %d\n",
+ encoder->slice_delivery_info.num_slices_enc,
+ encoder->batch_frame.num_output_frames);
+ }
+ for (index = 0; index < num_slices_comp; index++) {
+ actual_idx =
+ slice_output->slice_info[start_bfr_idx+index]. \
+ stream_buffer_idx;
+ DDL_MSG_LOW("Slice Info: OutBfrIndex %d SliceSize %d",
+ actual_idx,
+ slice_output->slice_info[start_bfr_idx+index]. \
+ stream_buffer_size, 0);
+ output_frame =
+ &(encoder->batch_frame.output_frame[actual_idx].vcd_frm);
+ DDL_MSG_LOW("OutBfr: vcd_frm 0x%x frmbfr(virtual) 0x%x"
+ "frmbfr(physical) 0x%x",
+ &output_frame,
+ output_frame.virtual_base_addr,
+ output_frame.physical_base_addr);
+ vidc_1080p_get_encode_frame_info(
+ &encoder->enc_frame_info);
+ vidc_sm_get_frame_tags(&ddl->shared_mem
+ [ddl->command_channel],
+ &output_frame->ip_frm_tag, &bottom_frame_tag);
+ ddl_get_encoded_frame(output_frame,
+ encoder->codec.codec,
+ encoder->enc_frame_info.enc_frame);
+ output_frame->data_len =
+ slice_output->slice_info[actual_idx].stream_buffer_size;
+ ddl->output_frame =
+ encoder->batch_frame.output_frame[actual_idx];
+ DDL_MSG_LOW(" %s actual_idx = %d"
+ "encoder->batch_frame.num_output_frames = %d\n", __func__,
+ actual_idx, encoder->batch_frame.num_output_frames);
+ if (encoder->batch_frame.num_output_frames == (actual_idx+1)) {
+ output_frame->flags |= VCD_FRAME_FLAG_ENDOFFRAME;
+ ddl_vidc_encode_dynamic_property(ddl, false);
+ ddl->input_frame.frm_trans_end = true;
+ DDL_MSG_LOW("%s End of frame detected\n", __func__);
+ input_buffer_address =
+ ddl_context->dram_base_a.align_physical_addr +
+ encoder->enc_frame_info.enc_luma_address;
+ ddl_get_input_frame_from_pool(ddl,
+ input_buffer_address);
+ transc = (struct vcd_transc *)(ddl->client_data);
+ if (eos_present)
+ ddl->output_frame.frm_trans_end = false;
+ else
+ ddl->output_frame.frm_trans_end = true;
+ }
+ DDL_MSG_LOW("%s Before output done cb\n", __func__);
+ transc = (struct vcd_transc *)(ddl->client_data);
+ ddl->output_frame.vcd_frm = *output_frame;
+ ddl_context->ddl_callback(VCD_EVT_RESP_OUTPUT_DONE,
+ VCD_S_SUCCESS, &(ddl->output_frame),
+ sizeof(struct ddl_frame_data_tag),
+ (u32 *) ddl, ddl->client_data);
+ }
+ if (encoder->batch_frame.num_output_frames == (actual_idx+1)) {
+ DDL_MSG_LOW("%s sending input done\n", __func__);
+ ddl_context->ddl_callback(VCD_EVT_RESP_INPUT_DONE,
+ VCD_S_SUCCESS, &(ddl->input_frame),
+ sizeof(struct ddl_frame_data_tag),
+ (u32 *) ddl, ddl->client_data);
+ }
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 7b284e9..2138c9c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -287,6 +287,9 @@
ddl_set_default_decoder_buffer_req(decoder,
true);
}
+ DDL_MSG_LOW("set VCD_I_FRAME_SIZE width = %d"
+ " height = %d\n",
+ frame_size->width, frame_size->height);
vcd_status = VCD_S_SUCCESS;
}
}
@@ -608,7 +611,15 @@
struct vcd_property_multi_slice *multi_slice =
(struct vcd_property_multi_slice *)
property_value;
-
+ DDL_MSG_HIGH("VCD_I_MULTI_SLICE eMSliceSel %d nMSliceSize %d"
+ "Tot#of MB %d encoder->frame_size.width = %d"
+ "encoder->frame_size.height = %d",
+ (int)multi_slice->m_slice_sel,
+ multi_slice->m_slice_size,
+ DDL_NO_OF_MB(encoder->frame_size.width,
+ encoder->frame_size.height),
+ encoder->frame_size.width,
+ encoder->frame_size.height);
switch (multi_slice->m_slice_sel) {
case VCD_MSLICE_OFF:
vcd_status = VCD_S_SUCCESS;
@@ -618,11 +629,14 @@
vcd_status = VCD_S_SUCCESS;
break;
case VCD_MSLICE_BY_MB_COUNT:
- if (multi_slice->m_slice_size >= 1 &&
+ {
+ if ((multi_slice->m_slice_size >= 1) &&
(multi_slice->m_slice_size <=
DDL_NO_OF_MB(encoder->frame_size.width,
- encoder->frame_size.height)))
+ encoder->frame_size.height))) {
vcd_status = VCD_S_SUCCESS;
+ }
+ }
break;
case VCD_MSLICE_BY_BYTE_COUNT:
if (multi_slice->m_slice_size > 0)
@@ -850,6 +864,9 @@
encoder->client_output_buf_req.sz =
DDL_ALIGN(buffer_req->sz,
DDL_KILO_BYTE(4));
+ DDL_MSG_LOW("%s encoder->client_output_buf_req.sz"
+ " = %d\n", __func__,
+ encoder->client_output_buf_req.sz);
vcd_status = VCD_S_SUCCESS;
}
}
@@ -920,8 +937,14 @@
case VCD_I_METADATA_HEADER:
DDL_MSG_LOW("Meta Data Interface is Requested");
if (!res_trk_check_for_sec_session()) {
- vcd_status = ddl_set_metadata_params(ddl,
- property_hdr, property_value);
+ if (!encoder->slice_delivery_info.enable) {
+ vcd_status = ddl_set_metadata_params(ddl,
+ property_hdr, property_value);
+ } else {
+ DDL_MSG_ERROR("Ignoring meta data settting in "
+ "slice mode: %s\n", __func__);
+ vcd_status = VCD_S_SUCCESS;
+ }
} else {
DDL_MSG_ERROR("Meta Data Interface is not "
"supported in secure session");
@@ -946,6 +969,70 @@
}
break;
}
+ case VCD_I_SLICE_DELIVERY_MODE:
+ {
+ size_t output_buf_size;
+ u32 num_mb, num_slices;
+ struct vcd_property_hdr slice_property_hdr;
+ struct vcd_property_meta_data_enable slice_meta_data;
+ DDL_MSG_HIGH("Set property VCD_I_SLICE_DELIVERY_MODE\n");
+ if (sizeof(u32) == property_hdr->sz &&
+ encoder->codec.codec == VCD_CODEC_H264 &&
+ encoder->multi_slice.m_slice_sel
+ == VCD_MSLICE_BY_MB_COUNT &&
+ DDLCLIENT_STATE_IS(ddl, DDL_CLIENT_OPEN)) {
+ encoder->slice_delivery_info.enable
+ = *(u32 *)property_value;
+ DDL_MSG_HIGH("set encoder->slice_delivery_mode"
+ " = %u\n",
+ encoder->slice_delivery_info.enable);
+ output_buf_size =
+ encoder->client_output_buf_req.sz;
+ num_mb = DDL_NO_OF_MB(encoder->frame_size.width,
+ encoder->frame_size.height);
+ num_slices = num_mb/
+ encoder->multi_slice.m_slice_size;
+ num_slices = ((num_mb - num_slices *
+ encoder->multi_slice.m_slice_size) > 0)
+ ? (num_slices + 1) : num_slices;
+ encoder->slice_delivery_info.num_slices =
+ num_slices;
+ if (num_slices <= DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH) {
+ encoder->client_output_buf_req.min_count
+ = ((DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2)
+ > DDL_MAX_BUFFER_COUNT)
+ ? DDL_MAX_BUFFER_COUNT :
+ (DDL_ENC_SLICE_BATCH_FACTOR * num_slices + 2);
+ output_buf_size =
+ encoder->client_output_buf_req.sz/num_slices;
+ encoder->client_output_buf_req.sz =
+ DDL_ALIGN(output_buf_size, DDL_KILO_BYTE(4));
+ encoder->output_buf_req =
+ encoder->client_output_buf_req;
+ DDL_MSG_HIGH("%s num_mb = %u num_slices = %u "
+ "output_buf_count = %u "
+ "output_buf_size = %u aligned size = %u\n",
+ __func__, num_mb, num_slices,
+ encoder->client_output_buf_req.min_count,
+ output_buf_size,
+ encoder->client_output_buf_req.sz);
+ slice_property_hdr.prop_id =
+ VCD_I_METADATA_ENABLE;
+ slice_property_hdr.sz =
+ sizeof(struct vcd_property_meta_data_enable);
+ ddl_get_metadata_params(ddl,
+ &slice_property_hdr,
+ &slice_meta_data);
+ slice_meta_data.meta_data_enable_flag
+ &= ~VCD_METADATA_ENC_SLICE;
+ ddl_set_metadata_params(ddl,
+ &slice_property_hdr,
+ &slice_meta_data);
+ vcd_status = VCD_S_SUCCESS;
+ }
+ }
+ break;
+ }
case VCD_REQ_PERF_LEVEL:
vcd_status = VCD_S_SUCCESS;
break;
@@ -1354,7 +1441,10 @@
property_hdr->sz) {
*(struct vcd_buffer_requirement *)
property_value = encoder->client_output_buf_req;
- vcd_status = VCD_S_SUCCESS;
+ DDL_MSG_LOW("%s encoder->client_output_buf_req = %d\n",
+ __func__,
+ encoder->client_output_buf_req.sz);
+ vcd_status = VCD_S_SUCCESS;
}
break;
case VCD_I_BUFFER_FORMAT:
@@ -1421,6 +1511,14 @@
vcd_status = VCD_S_SUCCESS;
}
break;
+ case VCD_I_SLICE_DELIVERY_MODE:
+ if (sizeof(struct vcd_property_slice_delivery_info) ==
+ property_hdr->sz) {
+ *(struct vcd_property_slice_delivery_info *)
+ property_value = encoder->slice_delivery_info;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
default:
vcd_status = VCD_ERR_ILLEGAL_OP;
break;
@@ -1579,6 +1677,9 @@
encoder->closed_gop = true;
ddl_set_default_metadata_flag(ddl);
ddl_set_default_encoder_buffer_req(encoder);
+ encoder->slice_delivery_info.enable = 0;
+ encoder->slice_delivery_info.num_slices = 0;
+ encoder->slice_delivery_info.num_slices_enc = 0;
}
static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
@@ -1725,8 +1826,7 @@
encoder->client_input_buf_req = encoder->input_buf_req;
memset(&encoder->output_buf_req , 0 ,
sizeof(struct vcd_buffer_requirement));
- encoder->output_buf_req.min_count =
- encoder->i_period.b_frames + 2;
+ encoder->output_buf_req.min_count = encoder->i_period.b_frames + 2;
encoder->output_buf_req.actual_count =
encoder->output_buf_req.min_count + 3;
encoder->output_buf_req.max_count = DDL_MAX_BUFFER_COUNT;
@@ -1737,6 +1837,8 @@
DDL_ALIGN(y_cb_cr_size, DDL_KILO_BYTE(4));
ddl_set_default_encoder_metadata_buffer_size(encoder);
encoder->client_output_buf_req = encoder->output_buf_req;
+ DDL_MSG_LOW("%s encoder->client_output_buf_req.sz = %d\n",
+ __func__, encoder->client_output_buf_req.sz);
}
u32 ddl_set_default_decoder_buffer_req(struct ddl_decoder_data *decoder,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index cce779e..ac81916 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -156,6 +156,24 @@
#define VIDC_SM_NEW_I_PERIOD_VALUE_BMASK 0xffffffff
#define VIDC_SM_NEW_I_PERIOD_VALUE_SHFT 0
+#define VIDC_SM_BATCH_INPUT_ADDR 0x00a4
+#define VIDC_SM_BATCH_INPUT_ADDR_VALUE_BMSK 0xffffffff
+#define VIDC_SM_BATCH_INPUT_ADDRL_VALUE_SHFT 0
+#define VIDC_SM_BATCH_OUTPUT_ADDR 0x00a8
+#define VIDC_SM_BATCH_OUTPUT_ADDR_VALUE_BMSK 0xffffffff
+#define VIDC_SM_BATCH_OUTPUT_ADDR_VALUE_SHFT 0
+#define VIDC_SM_BATCH_OUTPUT_SIZE_ADDR 0x00ac
+#define VIDC_SM_BATCH_OUTPUT_SIZE_VALUE_BMSK 0xffffffff
+#define VIDC_SM_BATCH_OUTPUT_SIZE_VALUE_SHFT 0
+#define VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_ADDR 0x01c8
+#define VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_VALUE_BMSK 0x1
+#define VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_VALUE_SHFT 0
+#define VIDC_SM_ENC_NUM_OF_SLICE_ADDR 0x01cc
+#define VIDC_SM_ENC_NUM_OF_SLICE_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_NUM_OF_SLICE_VALUE_SHFT 0
+#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR 0x01d0
+#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_BMSK 0xffffffff
+#define VIDC_SM_ENC_NUM_OF_SLICE_COMP_VALUE_SHFT 0
#define VIDC_SM_ALLOCATED_LUMA_DPB_SIZE_ADDR 0x0064
#define VIDC_SM_ALLOCATED_CHROMA_DPB_SIZE_ADDR 0x0068
@@ -799,3 +817,48 @@
VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT);
}
}
+
+void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
+ u32 slice_batch_int_enable)
+{
+ u32 slice_batch_int_ctrl = VIDC_SETFIELD((slice_batch_int_enable) ?
+ 1 : 0,
+ VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_BMSK);
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_SLICE_BATCH_INT_CTRL_ADDR,
+ slice_batch_int_ctrl);
+}
+
+void vidc_sm_get_num_slices_comp(struct ddl_buf_addr *shared_mem,
+ u32 *num_slices_comp)
+{
+ *num_slices_comp = DDL_MEM_READ_32(shared_mem,
+ VIDC_SM_ENC_NUM_OF_SLICE_COMP_ADDR);
+}
+
+void vidc_sm_set_encoder_batch_config(struct ddl_buf_addr *shared_mem,
+ u32 num_slices,
+ u32 input_addr, u32 output_addr,
+ u32 output_buffer_size)
+{
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_ENC_NUM_OF_SLICE_ADDR,
+ num_slices);
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_BATCH_INPUT_ADDR,
+ input_addr);
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_BATCH_OUTPUT_ADDR,
+ output_addr);
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_BATCH_OUTPUT_SIZE_ADDR,
+ output_buffer_size);
+}
+
+void vidc_sm_get_encoder_batch_output_size(struct ddl_buf_addr *shared_mem,
+ u32 *output_buffer_size)
+{
+ *output_buffer_size = DDL_MEM_READ_32(shared_mem,
+ VIDC_SM_BATCH_OUTPUT_SIZE_ADDR);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index b0e6758..7d9896f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -181,4 +181,14 @@
enum vidc_sm_num_stuff_bytes_consume_info consume_info);
void vidc_sm_get_aspect_ratio_info(struct ddl_buf_addr *shared_mem,
struct vcd_aspect_ratio *aspect_ratio_info);
+void vidc_sm_set_encoder_slice_batch_int_ctrl(struct ddl_buf_addr *shared_mem,
+ u32 slice_batch_int_enable);
+void vidc_sm_get_num_slices_comp(struct ddl_buf_addr *shared_mem,
+ u32 *num_slices_comp);
+void vidc_sm_set_encoder_batch_config(struct ddl_buf_addr *shared_mem,
+ u32 num_slices,
+ u32 input_addr, u32 output_addr,
+ u32 output_buffer_size);
+void vidc_sm_get_encoder_batch_output_size(struct ddl_buf_addr *shared_mem,
+ u32 *output_buffer_size);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 126698c..27d3b5b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -385,6 +385,36 @@
}
}
+void ddl_calc_core_proc_time_cnt(const char *func_name, u32 index, u32 count)
+{
+ struct time_data *time_data = &proc_time[index];
+ if (time_data->ddl_t1) {
+ int ddl_t2;
+ struct timeval ddl_tv;
+ do_gettimeofday(&ddl_tv);
+ ddl_t2 = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
+ time_data->ddl_ttotal += (ddl_t2 - time_data->ddl_t1);
+ time_data->ddl_count += count;
+ DDL_MSG_TIME("\n%s(): cnt(%u) End Time (%u) Diff(%u) Avg(%u)",
+ func_name, time_data->ddl_count, ddl_t2,
+ ddl_t2 - time_data->ddl_t1,
+ time_data->ddl_ttotal/time_data->ddl_count);
+ time_data->ddl_t1 = 0;
+ }
+}
+
+void ddl_update_core_start_time(const char *func_name, u32 index)
+{
+ u32 act_time;
+ struct timeval ddl_tv;
+ struct time_data *time_data = &proc_time[index];
+ do_gettimeofday(&ddl_tv);
+ act_time = (ddl_tv.tv_sec * 1000) + (ddl_tv.tv_usec / 1000);
+ time_data->ddl_t1 = act_time;
+ DDL_MSG_LOW("\n%s(): Start time updated Act(%u)",
+ func_name, act_time);
+}
+
void ddl_reset_core_time_variables(u32 index)
{
proc_time[index].ddl_t1 = 0;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
index 10b3404..13bef35 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.h
@@ -24,6 +24,7 @@
DEC_OP_TIME,
DEC_IP_TIME,
ENC_OP_TIME,
+ ENC_SLICE_OP_TIME,
MAX_TIME_DATA
};
@@ -65,9 +66,12 @@
#define DDL_MIN(x, y) ((x < y) ? x : y)
#define DDL_MAX(x, y) ((x > y) ? x : y)
+#define DDL_MEMCPY(dest, src, len) memcpy((dest), (src), (len))
+#define DDL_MEMSET(src, value, len) memset((src), (value), (len))
void ddl_set_core_start_time(const char *func_name, u32 index);
void ddl_calc_core_proc_time(const char *func_name, u32 index);
void ddl_reset_core_time_variables(u32 index);
-
+void ddl_calc_core_proc_time_cnt(const char *func_name, u32 index, u32 count);
+void ddl_update_core_start_time(const char *func_name, u32 index);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 66e129c..d288ba3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -21,6 +21,7 @@
#else
#define DDL_PIX_CACHE_ENABLE true
#endif
+static unsigned int run_cnt;
void ddl_vidc_core_init(struct ddl_context *ddl_context)
{
@@ -57,6 +58,10 @@
vidc_1080p_encode_frame_start_ch0;
ddl_context->vidc_encode_frame_start[1] =
vidc_1080p_encode_frame_start_ch1;
+ ddl_context->vidc_encode_slice_batch_start[0] =
+ vidc_1080p_encode_slice_batch_start_ch0;
+ ddl_context->vidc_encode_slice_batch_start[1] =
+ vidc_1080p_encode_slice_batch_start_ch1;
vidc_1080p_release_sw_reset();
ddl_context->pix_cache_enable = DDL_PIX_CACHE_ENABLE;
if (ddl_context->pix_cache_enable) {
@@ -515,6 +520,29 @@
i_multi_slice_size, i_multi_slice_byte);
}
+static void ddl_vidc_encode_set_batch_slice_info(
+ struct ddl_client_context *ddl)
+{
+ struct ddl_context *ddl_context = ddl->ddl_context;
+ struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+ DDL_MSG_LOW("%s\n", __func__);
+ encoder->batch_frame.slice_batch_out.buffer_size =
+ encoder->output_buf_req.sz;
+ DDL_MSG_LOW("encoder->batch_frame.slice_batch_out.buffer_size = %d\n",
+ encoder->batch_frame.slice_batch_out.buffer_size);
+ vidc_sm_set_encoder_batch_config(
+ &ddl->shared_mem[ddl->command_channel],
+ 1,
+ DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+ encoder->batch_frame.slice_batch_in),
+ DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+ encoder->batch_frame.slice_batch_out),
+ encoder->batch_frame.slice_batch_out.buffer_size);
+ vidc_sm_set_encoder_slice_batch_int_ctrl(
+ &ddl->shared_mem[ddl->command_channel],
+ 0);
+}
+
void ddl_vidc_encode_init_codec(struct ddl_client_context *ddl)
{
struct ddl_context *ddl_context = ddl->ddl_context;
@@ -724,6 +752,7 @@
u32 dpb_addr_y[4], dpb_addr_c[4];
u32 index, y_addr, c_addr;
+ DDL_MSG_LOW("%s\n", __func__);
ddl_vidc_encode_set_metadata_output_buf(ddl);
encoder->enc_frame_info.meta_data_exists = false;
@@ -769,6 +798,7 @@
if (encoder->intra_frame_insertion)
encoder->intra_frame_insertion = false;
enc_param.input_flush = false;
+ enc_param.slice_enable = false;
vidc_sm_set_encoder_vop_time(
&ddl->shared_mem[ddl->command_channel], true,
encoder->vop_timing.vop_time_resolution,
@@ -800,6 +830,142 @@
&enc_param);
}
+void ddl_vidc_encode_frame_continue(struct ddl_client_context *ddl)
+{
+ struct ddl_context *ddl_context = ddl->ddl_context;
+ struct vcd_frame_data *input_vcd_frm = &(ddl->input_frame.vcd_frm);
+ u32 address_offset;
+ address_offset = (u32)(ddl->output_frame.vcd_frm.physical -
+ ddl_context->dram_base_a.align_physical_addr) >>
+ DDL_VIDC_1080P_BASE_OFFSET_SHIFT;
+ DDL_MSG_LOW("%s\n", __func__);
+ if (VCD_FRAME_FLAG_EOS & input_vcd_frm->flags)
+ ddl->client_state = DDL_CLIENT_WAIT_FOR_EOS_DONE;
+ else
+ ddl->client_state = DDL_CLIENT_WAIT_FOR_FRAME_DONE;
+ ddl->cmd_state = DDL_CMD_ENCODE_CONTINUE;
+ vidc_1080p_set_host2risc_cmd(VIDC_1080P_HOST2RISC_CMD_CONTINUE_ENC,
+ address_offset,
+ 0, 0, 0);
+}
+
+void ddl_vidc_encode_slice_batch_run(struct ddl_client_context *ddl)
+{
+ struct vidc_1080p_enc_frame_start_param enc_param;
+ struct ddl_context *ddl_context = ddl->ddl_context;
+ struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+ struct ddl_enc_buffers *enc_buffers = &(encoder->hw_bufs);
+ struct vcd_frame_data *input_vcd_frm =
+ &(ddl->input_frame.vcd_frm);
+ u32 dpb_addr_y[4], dpb_addr_c[4];
+ u32 index, y_addr, c_addr;
+ u32 bitstream_size;
+ struct vidc_1080p_enc_slice_batch_in_param *slice_batch_in =
+ (struct vidc_1080p_enc_slice_batch_in_param *)
+ encoder->batch_frame.slice_batch_in.align_virtual_addr;
+ DDL_MSG_LOW("%s\n", __func__);
+ DDL_MEMSET(slice_batch_in, 0,
+ sizeof(struct vidc_1080p_enc_slice_batch_in_param));
+ DDL_MEMSET(encoder->batch_frame.slice_batch_in.align_virtual_addr, 0,
+ sizeof(struct vidc_1080p_enc_slice_batch_in_param));
+ encoder->batch_frame.out_frm_next_frmindex = 0;
+ bitstream_size = encoder->batch_frame.output_frame[0].vcd_frm.alloc_len;
+ encoder->output_buf_req.sz = bitstream_size;
+ y_addr = DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
+ input_vcd_frm->physical);
+ c_addr = (y_addr + encoder->input_buf_size.size_y);
+ enc_param.encode = VIDC_1080P_ENC_TYPE_SLICE_BATCH_START;
+ DDL_MSG_LOW("ddl_state_transition: %s ~~>"
+ "DDL_CLIENT_WAIT_FOR_FRAME_DONE",
+ ddl_get_state_string(ddl->client_state));
+ slice_batch_in->cmd_type = VIDC_1080P_ENC_TYPE_SLICE_BATCH_START;
+ ddl->client_state = DDL_CLIENT_WAIT_FOR_FRAME_DONE;
+ ddl->cmd_state = DDL_CMD_ENCODE_FRAME;
+ vidc_1080p_set_encode_circular_intra_refresh(
+ encoder->intra_refresh.cir_mb_number);
+ ddl_vidc_encode_set_multi_slice_info(encoder);
+ enc_param.cmd_seq_num = ++ddl_context->cmd_seq_num;
+ enc_param.inst_id = ddl->instance_id;
+ enc_param.shared_mem_addr_offset = DDL_ADDR_OFFSET(
+ ddl_context->dram_base_a,
+ ddl->shared_mem[ddl->command_channel]);
+ enc_param.current_y_addr_offset = y_addr;
+ enc_param.current_c_addr_offset = c_addr;
+ enc_param.stream_buffer_size = bitstream_size;
+ slice_batch_in->num_stream_buffer =
+ encoder->batch_frame.num_output_frames;
+ slice_batch_in->stream_buffer_size = bitstream_size;
+ DDL_MSG_LOW("%s slice_batch_in->num_stream_buffer = %u size = %u\n",
+ __func__, slice_batch_in->num_stream_buffer,
+ slice_batch_in->stream_buffer_size);
+ for (index = 0; index < encoder->batch_frame.num_output_frames;
+ index++) {
+ slice_batch_in->stream_buffer_addr_offset[index] =
+ ((DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
+ encoder->batch_frame.output_frame[index].vcd_frm.physical)) >>
+ DDL_VIDC_1080P_BASE_OFFSET_SHIFT);
+ }
+ slice_batch_in->input_size = VIDC_1080P_SLICE_BATCH_IN_SIZE(index);
+ enc_param.intra_frame = encoder->intra_frame_insertion;
+ if (encoder->intra_frame_insertion)
+ encoder->intra_frame_insertion = false;
+ enc_param.input_flush = false;
+ enc_param.slice_enable =
+ encoder->slice_delivery_info.enable;
+ vidc_sm_set_encoder_vop_time(
+ &ddl->shared_mem[ddl->command_channel], true,
+ encoder->vop_timing.vop_time_resolution,
+ ddl->input_frame.frm_delta);
+ vidc_sm_set_frame_tag(&ddl->shared_mem[ddl->command_channel],
+ ddl->input_frame.vcd_frm.ip_frm_tag);
+ DDL_MSG_LOW("%sdpb_count = %d\n", __func__, enc_buffers->dpb_count);
+ if (ddl_context->pix_cache_enable) {
+ for (index = 0; index < enc_buffers->dpb_count;
+ index++) {
+ dpb_addr_y[index] =
+ (u32) VIDC_1080P_DEC_DPB_RESET_VALUE;
+ dpb_addr_c[index] = (u32) enc_buffers->dpb_c
+ [index].align_physical_addr;
+ }
+
+ dpb_addr_y[index] = (u32) input_vcd_frm->physical;
+ dpb_addr_c[index] = (u32) input_vcd_frm->physical +
+ encoder->input_buf_size.size_y;
+
+ vidc_pix_cache_init_luma_chroma_base_addr(
+ enc_buffers->dpb_count + 1, dpb_addr_y, dpb_addr_c);
+ vidc_pix_cache_set_frame_size(encoder->frame_size.width,
+ encoder->frame_size.height);
+ vidc_pix_cache_set_frame_range(enc_buffers->sz_dpb_y,
+ enc_buffers->sz_dpb_c);
+ vidc_pix_cache_clear_cache_tags();
+ }
+ if ((!encoder->rc_level.frame_level_rc) &&
+ (!encoder->rc_level.mb_level_rc)) {
+ encoder->session_qp.p_frame_qp++;
+ if (encoder->session_qp.p_frame_qp > encoder->qp_range.max_qp)
+ encoder->session_qp.p_frame_qp =
+ encoder->qp_range.min_qp;
+ vidc_sm_set_pand_b_frame_qp(
+ &ddl->shared_mem[ddl->command_channel],
+ encoder->session_qp.b_frame_qp,
+ encoder->session_qp.p_frame_qp);
+ }
+
+ if (vidc_msg_timing) {
+ if (run_cnt < 2) {
+ ddl_reset_core_time_variables(ENC_OP_TIME);
+ ddl_reset_core_time_variables(ENC_SLICE_OP_TIME);
+ run_cnt++;
+ }
+ ddl_update_core_start_time(__func__, ENC_SLICE_OP_TIME);
+ ddl_set_core_start_time(__func__, ENC_OP_TIME);
+ }
+ ddl_vidc_encode_set_batch_slice_info(ddl);
+ ddl_context->vidc_encode_slice_batch_start[ddl->command_channel] (
+ &enc_param);
+}
+
u32 ddl_vidc_decode_set_buffers(struct ddl_client_context *ddl)
{
struct ddl_context *ddl_context = ddl->ddl_context;
@@ -976,3 +1142,29 @@
ddl_context->vidc_decode_frame_start[ddl->command_channel] (
&dec_param);
}
+
+void ddl_vidc_encode_eos_run(struct ddl_client_context *ddl)
+{
+ struct vidc_1080p_enc_frame_start_param enc_param;
+ struct ddl_context *ddl_context = ddl->ddl_context;
+ struct ddl_encoder_data *encoder = &(ddl->codec_data.encoder);
+ DDL_MSG_LOW("%s\n", __func__);
+ ddl->client_state = DDL_CLIENT_WAIT_FOR_EOS_DONE;
+ ddl_vidc_encode_dynamic_property(ddl, true);
+ ddl->client_state = DDL_CMD_EOS;
+ DDL_MEMSET(&enc_param, 0, sizeof(enc_param));
+ enc_param.encode = VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA;
+ enc_param.cmd_seq_num = ++ddl_context->cmd_seq_num;
+ enc_param.inst_id = ddl->instance_id;
+ enc_param.shared_mem_addr_offset =
+ DDL_ADDR_OFFSET(ddl_context->dram_base_a,
+ ddl->shared_mem[ddl->command_channel]);
+ enc_param.current_y_addr_offset = 0;
+ enc_param.current_c_addr_offset = 0;
+ enc_param.stream_buffer_size = 0;
+ enc_param.intra_frame = encoder->intra_frame_insertion;
+ vidc_sm_set_frame_tag(&ddl->shared_mem[ddl->command_channel],
+ ddl->input_frame.vcd_frm.ip_frm_tag);
+ ddl_context->vidc_encode_frame_start[ddl->command_channel](
+ &enc_param);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.c b/drivers/video/msm/vidc/1080p/ddl/vidc.c
index 75014cc..d399847 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -77,6 +77,10 @@
#define VIDC_1080P_ENC_TYPE_FRAME_DATA 0x00020000
#define VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA 0x00030000
+#define VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK 0x00004000
+#define VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT 14
+#define VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK 0x80000000
+#define VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT 31
#define VIDC_1080P_MAX_INTRA_PERIOD 0xffff
u8 *VIDC_BASE_PTR;
@@ -779,6 +783,7 @@
void vidc_1080p_encode_frame_start_ch0(
struct vidc_1080p_enc_frame_start_param *param)
{
+ u32 input_flush;
VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
VIDC_HWIO_OUT(REG_117192,
@@ -791,8 +796,15 @@
VIDC_1080P_BASE_OFFSET_SHIFT);
VIDC_HWIO_OUT(REG_190381, param->intra_frame);
VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
- VIDC_HWIO_OUT(REG_404623, param->input_flush);
+ input_flush = VIDC_SETFIELD(param->input_flush,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+ input_flush |= VIDC_SETFIELD(param->slice_enable,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+ VIDC_HWIO_OUT(REG_404623, input_flush);
VIDC_HWIO_OUT(REG_397087, param->cmd_seq_num);
+
VIDC_HWIO_OUT(REG_666957, (u32)param->encode |
param->inst_id);
}
@@ -800,7 +812,7 @@
void vidc_1080p_encode_frame_start_ch1(
struct vidc_1080p_enc_frame_start_param *param)
{
-
+ u32 input_flush;
VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
VIDC_HWIO_OUT(REG_980194,
@@ -813,12 +825,71 @@
VIDC_1080P_BASE_OFFSET_SHIFT);
VIDC_HWIO_OUT(REG_887095, param->intra_frame);
VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
- VIDC_HWIO_OUT(REG_404623, param->input_flush);
+ input_flush = VIDC_SETFIELD(param->input_flush,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+ input_flush |= VIDC_SETFIELD(param->slice_enable,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+
+ VIDC_HWIO_OUT(REG_404623, input_flush);
VIDC_HWIO_OUT(REG_254093, param->cmd_seq_num);
VIDC_HWIO_OUT(REG_313350, (u32)param->encode |
param->inst_id);
}
+void vidc_1080p_encode_slice_batch_start_ch0(
+ struct vidc_1080p_enc_frame_start_param *param)
+{
+ u32 input_flush;
+ VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
+ VIDC_HWIO_OUT(REG_666957, VIDC_1080P_INIT_CH_INST_ID);
+ VIDC_HWIO_OUT(REG_612810, param->current_y_addr_offset >>
+ VIDC_1080P_BASE_OFFSET_SHIFT);
+ VIDC_HWIO_OUT(REG_175608, param->current_c_addr_offset >>
+ VIDC_1080P_BASE_OFFSET_SHIFT);
+ VIDC_HWIO_OUT(REG_190381, param->intra_frame);
+ VIDC_HWIO_OUT(REG_889944, param->shared_mem_addr_offset);
+ input_flush = VIDC_SETFIELD(param->input_flush,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+ input_flush |= VIDC_SETFIELD(param->slice_enable,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+ VIDC_HWIO_OUT(REG_404623, input_flush);
+ VIDC_HWIO_OUT(REG_397087, param->cmd_seq_num);
+
+ VIDC_HWIO_OUT(REG_666957, (u32)param->encode |
+ param->inst_id);
+
+}
+
+void vidc_1080p_encode_slice_batch_start_ch1(
+ struct vidc_1080p_enc_frame_start_param *param)
+{
+ u32 input_flush;
+ VIDC_HWIO_OUT(REG_695082, VIDC_1080P_RISC2HOST_CMD_EMPTY);
+ VIDC_HWIO_OUT(REG_313350, VIDC_1080P_INIT_CH_INST_ID);
+ VIDC_HWIO_OUT(REG_655721, param->current_y_addr_offset >>
+ VIDC_1080P_BASE_OFFSET_SHIFT);
+ VIDC_HWIO_OUT(REG_548308, param->current_c_addr_offset >>
+ VIDC_1080P_BASE_OFFSET_SHIFT);
+ VIDC_HWIO_OUT(REG_887095, param->intra_frame);
+ VIDC_HWIO_OUT(REG_652528, param->shared_mem_addr_offset);
+ input_flush = VIDC_SETFIELD(param->input_flush,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_INPUT_BUFFER_FLUSH_BMSK);
+ input_flush |= VIDC_SETFIELD(param->slice_enable,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_SHFT,
+ VIDC_1080P_SI_RG10_ENCODE_SLICE_IF_ENABLE_BMSK);
+
+ VIDC_HWIO_OUT(REG_404623, input_flush);
+ VIDC_HWIO_OUT(REG_254093, param->cmd_seq_num);
+ VIDC_HWIO_OUT(REG_313350, (u32)param->encode |
+ param->inst_id);
+
+}
+
void vidc_1080p_set_encode_picture(u32 number_p, u32 number_b)
{
u32 picture, ifrm_ctrl;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vidc.h b/drivers/video/msm/vidc/1080p/ddl/vidc.h
index 7573ee8..7460ef3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vidc.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vidc.h
@@ -21,11 +21,13 @@
#define VIDC_1080P_RISC2HOST_CMD_CLOSE_CH_RET 2
#define VIDC_1080P_RISC2HOST_CMD_SEQ_DONE_RET 4
#define VIDC_1080P_RISC2HOST_CMD_FRAME_DONE_RET 5
+#define VIDC_1080P_RISC2HOST_CMD_SLICE_DONE_RET 6
#define VIDC_1080P_RISC2HOST_CMD_ENC_COMPLETE_RET 7
#define VIDC_1080P_RISC2HOST_CMD_SYS_INIT_RET 8
#define VIDC_1080P_RISC2HOST_CMD_FW_STATUS_RET 9
#define VIDC_1080P_RISC2HOST_CMD_FLUSH_COMMAND_RET 12
#define VIDC_1080P_RISC2HOST_CMD_ABORT_RET 13
+#define VIDC_1080P_RISC2HOST_CMD_BATCH_ENC_RET 14
#define VIDC_1080P_RISC2HOST_CMD_INIT_BUFFERS_RET 15
#define VIDC_1080P_RISC2HOST_CMD_EDFU_INT_RET 16
#define VIDC_1080P_RISC2HOST_CMD_ERROR_RET 32
@@ -188,7 +190,9 @@
#define VIDC_1080P_ITLB_MISS_EXCEPTION_HANDLER 0x100
#define VIDC_1080P_DATA_PAGE_FAULT_EXCEPTION_HANDLER 0x200
#define VIDC_1080P_INST_PAGE_FAULT_EXCEPTION_HANDLER 0x400
-
+#define VIDC_1080P_SLICE_BATCH_MAX_STRM_BFR 8
+#define VIDC_1080P_SLICE_BATCH_IN_SIZE(idx) (4 * sizeof(u32) + \
+ idx * sizeof(u32))
enum vidc_1080p_reset{
VIDC_1080P_RESET_IN_SEQ_FIRST_STAGE = 0x0,
VIDC_1080P_RESET_IN_SEQ_SECOND_STAGE = 0x1,
@@ -318,10 +322,11 @@
VIDC_1080P_DEC_TYPE_32BIT = 0x7FFFFFFF
};
enum vidc_1080p_encode{
- VIDC_1080P_ENC_TYPE_SEQ_HEADER = 0x00010000,
- VIDC_1080P_ENC_TYPE_FRAME_DATA = 0x00020000,
- VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA = 0x00030000,
- VIDC_1080P_ENC_TYPE_32BIT = 0x7FFFFFFF
+ VIDC_1080P_ENC_TYPE_SEQ_HEADER = 0x00010000,
+ VIDC_1080P_ENC_TYPE_FRAME_DATA = 0x00020000,
+ VIDC_1080P_ENC_TYPE_LAST_FRAME_DATA = 0x00030000,
+ VIDC_1080P_ENC_TYPE_SLICE_BATCH_START = 0x00070000,
+ VIDC_1080P_ENC_TYPE_32BIT = 0x7FFFFFFF
};
struct vidc_1080p_dec_seq_start_param{
u32 cmd_seq_num;
@@ -391,6 +396,7 @@
u32 stream_buffer_size;
u32 intra_frame;
u32 input_flush;
+ u32 slice_enable;
enum vidc_1080p_encode encode;
};
struct vidc_1080p_enc_frame_info{
@@ -402,6 +408,23 @@
enum vidc_1080p_encode_frame enc_frame;
u32 meta_data_exists;
};
+struct vidc_1080p_enc_slice_batch_in_param {
+ u32 cmd_type;
+ u32 input_size;
+ u32 num_stream_buffer;
+ u32 stream_buffer_size;
+ u32 stream_buffer_addr_offset[VIDC_1080P_SLICE_BATCH_MAX_STRM_BFR];
+};
+struct vidc_1080p_enc_slice_info {
+ u32 stream_buffer_idx;
+ u32 stream_buffer_size;
+};
+struct vidc_1080p_enc_slice_batch_out_param {
+ u32 cmd_type;
+ u32 output_size;
+ struct vidc_1080p_enc_slice_info slice_info
+ [VIDC_1080P_SLICE_BATCH_MAX_STRM_BFR];
+};
struct vidc_1080p_dec_disp_info{
u32 disp_resl_change;
u32 dec_resl_change;
@@ -519,6 +542,10 @@
struct vidc_1080p_enc_frame_start_param *param);
void vidc_1080p_encode_frame_start_ch1(
struct vidc_1080p_enc_frame_start_param *param);
+void vidc_1080p_encode_slice_batch_start_ch0(
+ struct vidc_1080p_enc_frame_start_param *param);
+void vidc_1080p_encode_slice_batch_start_ch1(
+ struct vidc_1080p_enc_frame_start_param *param);
void vidc_1080p_set_encode_picture(u32 ifrm_ctrl, u32 number_b);
void vidc_1080p_set_encode_multi_slice_control(
enum vidc_1080p_MSlice_selection multiple_slice_selection,
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
index 9dc495b..7e201cf 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_internal_property.h
@@ -57,6 +57,12 @@
u32 activity_region_flag;
};
+struct vcd_property_slice_delivery_info {
+ u32 enable;
+ u32 num_slices;
+ u32 num_slices_enc;
+};
+
struct ddl_frame_data_tag;
struct ddl_property_dec_pic_buffers {
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index d93d07e..5542856 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1604,6 +1604,20 @@
}
if (!result) {
ERR("setting VEN_IOCTL_(G)SET_LIVE_MODE failed\n");
+ }
+ break;
+ }
+ case VEN_IOCTL_SET_SLICE_DELIVERY_MODE:
+ {
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 enable = true;
+ vcd_property_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
+ vcd_property_hdr.sz = sizeof(u32);
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &enable);
+ if (vcd_status) {
+ pr_err(" Setting slice delivery mode failed");
return -EIO;
}
break;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 6fdb1c6..55bbe00 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -63,7 +63,7 @@
static irqreturn_t vidc_isr(int irq, void *dev);
static spinlock_t vidc_spin_lock;
-u32 vidc_msg_timing, vidc_msg_pmem;
+u32 vidc_msg_timing, vidc_msg_pmem, vidc_msg_register;
#ifdef VIDC_ENABLE_DBGFS
struct dentry *vidc_debugfs_root;
@@ -311,6 +311,8 @@
(u32 *) &vidc_msg_timing);
vidc_debugfs_file_create(root, "vidc_msg_pmem",
(u32 *) &vidc_msg_pmem);
+ vidc_debugfs_file_create(root, "vidc_msg_register",
+ (u32 *) &vidc_msg_register);
}
#endif
return 0;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index 0d1ff7e..e557dab 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -393,4 +393,6 @@
u32 vcd_req_perf_level(struct vcd_clnt_ctxt *cctxt,
struct vcd_property_perf_level *);
+u32 vcd_set_num_slices(struct vcd_clnt_ctxt *cctxt);
+
#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index e33c8cd..d228146 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -185,6 +185,7 @@
u32 live;
u32 decoding;
u32 bframe;
+ u32 num_slices;
struct vcd_property_frame_rate frm_rate;
u32 frm_p_units;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index fd8d02a..d49f233 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -19,6 +19,7 @@
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MAP_TABLE_SZ 64
+#define VCD_ENC_MAX_OUTBFRS_PER_FRAME 8
struct vcd_msm_map_buffer {
phys_addr_t phy_addr;
@@ -942,7 +943,6 @@
list_del(&entry->list);
pool->q_len--;
}
-
return entry;
}
@@ -1122,6 +1122,7 @@
cctxt->bframe = 0;
cctxt->cmd_q.pending_cmd = VCD_CMD_NONE;
cctxt->status.last_evt = VCD_EVT_RESP_BASE;
+ cctxt->num_slices = 1;
return rc;
}
@@ -1293,6 +1294,7 @@
}
} else {
+ vcd_set_num_slices(transc->cctxt);
rc = ddl_encode_start(transc->cctxt->ddl_handle,
(void *)transc);
}
@@ -1492,7 +1494,8 @@
u32 rc = VCD_S_SUCCESS;
u32 evcode = 0;
struct ddl_frame_data_tag ddl_ip_frm;
- struct ddl_frame_data_tag ddl_op_frm;
+ struct ddl_frame_data_tag *ddl_op_frm;
+ u32 out_buf_cnt = 0;
VCD_MSG_LOW("vcd_submit_frame:");
cctxt = transc->cctxt;
@@ -1504,34 +1507,52 @@
transc->flags = ip_frm_entry->flags;
ip_frm_entry->ip_frm_tag = (u32) transc;
memset(&ddl_ip_frm, 0, sizeof(ddl_ip_frm));
- memset(&ddl_op_frm, 0, sizeof(ddl_op_frm));
if (cctxt->decoding) {
evcode = CLIENT_STATE_EVENT_NUMBER(decode_frame);
ddl_ip_frm.vcd_frm = *ip_frm_entry;
rc = ddl_decode_frame(cctxt->ddl_handle, &ddl_ip_frm,
- (void *) transc);
+ (void *) transc);
} else {
- op_buf_entry = vcd_buffer_pool_entry_de_q(
- &cctxt->out_buf_pool);
- if (!op_buf_entry) {
- VCD_MSG_ERROR("Sched provided frame when no"
- "op buffer was present");
- rc = VCD_ERR_FAIL;
- } else {
+ ddl_op_frm = (struct ddl_frame_data_tag *)
+ kmalloc((sizeof(struct ddl_frame_data_tag) *
+ VCD_ENC_MAX_OUTBFRS_PER_FRAME), GFP_KERNEL);
+ if (!ddl_op_frm) {
+ VCD_MSG_ERROR("Memory allocation failure");
+ return VCD_ERR_ALLOC_FAIL;
+ }
+ memset(ddl_op_frm, 0, (sizeof(struct ddl_frame_data_tag) *
+ VCD_ENC_MAX_OUTBFRS_PER_FRAME));
+ for (out_buf_cnt = 0; out_buf_cnt < cctxt->num_slices ;
+ out_buf_cnt++) {
+ op_buf_entry = vcd_buffer_pool_entry_de_q(
+ &cctxt->out_buf_pool);
+ if (!op_buf_entry) {
+ VCD_MSG_ERROR("Sched provided frame when no"
+ "op buffer was present");
+ rc = VCD_ERR_FAIL;
+ break;
+ }
op_buf_entry->in_use = true;
cctxt->out_buf_pool.in_use++;
- ddl_ip_frm.vcd_frm = *ip_frm_entry;
- ddl_ip_frm.frm_delta =
- vcd_calculate_frame_delta(cctxt,
- ip_frm_entry);
-
- ddl_op_frm.vcd_frm = op_buf_entry->frame;
-
- evcode = CLIENT_STATE_EVENT_NUMBER(encode_frame);
-
- rc = ddl_encode_frame(cctxt->ddl_handle,
- &ddl_ip_frm, &ddl_op_frm, (void *) transc);
+ ddl_op_frm[out_buf_cnt].vcd_frm = op_buf_entry->frame;
+ VCD_MSG_LOW("%s : buffer_cnt = %d framebfr(virtual)"
+ " 0x%p", __func__, out_buf_cnt,
+ op_buf_entry->frame.virtual);
+ VCD_MSG_LOW("framebfr(physical) 0x%p bfrlength %d",
+ op_buf_entry->frame.physical,
+ op_buf_entry->frame.alloc_len);
}
+ ddl_ip_frm.vcd_frm = *ip_frm_entry;
+ ddl_ip_frm.frm_delta =
+ vcd_calculate_frame_delta(cctxt,
+ ip_frm_entry);
+ evcode = CLIENT_STATE_EVENT_NUMBER(encode_frame);
+
+ if (!VCD_FAILED(rc)) {
+ rc = ddl_encode_frame(cctxt->ddl_handle,
+ &ddl_ip_frm, &ddl_op_frm[0], (void *) transc);
+ }
+ kfree(ddl_op_frm);
}
ip_frm_entry->ip_frm_tag = transc->ip_frm_tag;
if (!VCD_FAILED(rc)) {
@@ -1875,8 +1896,10 @@
void vcd_release_trans_tbl_entry(struct vcd_transc *trans_entry)
{
- if (trans_entry)
+ if (trans_entry) {
trans_entry->in_use = false;
+ VCD_MSG_LOW("%s in_use set to false\n", __func__);
+ }
}
u32 vcd_handle_input_done(
@@ -1888,6 +1911,7 @@
(struct ddl_frame_data_tag *) payload;
struct vcd_buffer_entry *orig_frame = NULL;
u32 rc;
+ VCD_MSG_LOW("%s\n", __func__);
if (!cctxt->status.frame_submitted &&
!cctxt->status.frame_delayed) {
@@ -1935,8 +1959,11 @@
transc->ip_buf_entry = NULL;
transc->input_done = true;
- if (transc->input_done && transc->frame_done)
+ if (transc->input_done && transc->frame_done) {
+ VCD_MSG_LOW("%s Calling vcd_release_trans_tbl_entry\n",
+ __func__);
vcd_release_trans_tbl_entry(transc);
+ }
if (VCD_FAILED(status)) {
VCD_MSG_ERROR("INPUT_DONE returned err = 0x%x", status);
@@ -1975,6 +2002,7 @@
(struct ddl_frame_data_tag *) payload;
u32 rc = VCD_ERR_FAIL, codec_config = false;
u32 core_type = res_trk_get_core_type();
+ VCD_MSG_LOW("%s\n", __func__);
rc = vcd_validate_io_done_pyld(cctxt, payload, status);
if (rc == VCD_ERR_CLIENT_FATAL)
vcd_handle_clnt_fatal_input_done(cctxt, frame->frm_trans_end);
@@ -2080,6 +2108,7 @@
struct ddl_frame_data_tag *frame =
(struct ddl_frame_data_tag *)payload;
u32 rc = VCD_S_SUCCESS;
+ VCD_MSG_LOW("%s\n", __func__);
if (!cctxt->status.frame_submitted &&
!cctxt->status.frame_delayed) {
@@ -2140,6 +2169,7 @@
struct vcd_transc *transc;
struct ddl_frame_data_tag *frame =
(struct ddl_frame_data_tag *)payload;
+ VCD_MSG_LOW("%s\n", __func__);
rc = vcd_validate_io_done_pyld(cctxt, payload, VCD_S_SUCCESS);
if (rc == VCD_ERR_CLIENT_FATAL)
@@ -2173,6 +2203,7 @@
struct vcd_transc *transc;
u32 rc;
s64 time_stamp;
+ VCD_MSG_LOW("%s\n", __func__);
rc = vcd_validate_io_done_pyld(cctxt, payload, status);
if (rc == VCD_ERR_CLIENT_FATAL)
@@ -2262,7 +2293,7 @@
struct ddl_frame_data_tag *frame =
(struct ddl_frame_data_tag *) payload;
u32 rc = VCD_S_SUCCESS;
- VCD_MSG_LOW("vcd_handle_frame_done_in_eos:");
+ VCD_MSG_LOW("%s\n", __func__);
rc = vcd_validate_io_done_pyld(cctxt, payload, status);
if (rc == VCD_ERR_CLIENT_FATAL)
vcd_handle_clnt_fatal(cctxt, frame->frm_trans_end);
@@ -3326,3 +3357,24 @@
0, cctxt, cctxt->client_data);
}
}
+
+u32 vcd_set_num_slices(struct vcd_clnt_ctxt *cctxt)
+{
+ struct vcd_property_hdr prop_hdr;
+ struct vcd_property_slice_delivery_info slice_delivery_info;
+ u32 rc = VCD_S_SUCCESS;
+ prop_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
+ prop_hdr.sz = prop_hdr.sz =
+ sizeof(struct vcd_property_slice_delivery_info);
+ rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
+ &slice_delivery_info);
+ VCD_FAILED_RETURN(rc, "Failed: Get VCD_I_SLICE_DELIVERY_MODE");
+ if (slice_delivery_info.enable) {
+ cctxt->num_slices = slice_delivery_info.num_slices;
+ VCD_MSG_LOW("%s slice delivery mode num_slices = %u\n",
+ __func__, cctxt->num_slices);
+ } else {
+ cctxt->num_slices = 1;
+ }
+ return rc;
+}
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index bf149eb..519c537 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -454,6 +454,10 @@
#define VEN_IOCTL_GET_EXTRADATA \
_IOR(VEN_IOCTLBASE_ENC, 49, struct venc_ioctl_msg)
+/*IOCTL params:SET: InputData - NULL, OutputData - NULL.*/
+#define VEN_IOCTL_SET_SLICE_DELIVERY_MODE \
+ _IO(VEN_IOCTLBASE_ENC, 50)
+
struct venc_switch{
unsigned char status;
};
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index 51cc78f..e776d41 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -52,6 +52,7 @@
#define VCD_I_DISABLE_DMX_SUPPORT (VCD_START_BASE + 0x24)
#define VCD_I_ENABLE_SPS_PPS_FOR_IDR (VCD_START_BASE + 0x25)
#define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
+#define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 7e9f5f4..d218fab 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -99,6 +99,28 @@
*/
#define BT_AMP_POLICY_PREFER_AMP 2
+#define BT_LE_PARAMS 100
+
+#define BT_LE_SCAN_WINDOW_MIN 0x0004
+#define BT_LE_SCAN_WINDOW_MAX 0x4000
+#define BT_LE_SCAN_WINDOW_DEF 0x0004
+
+#define BT_LE_SCAN_INTERVAL_MIN 0x0004
+#define BT_LE_SCAN_INTERVAL_MAX 0x4000
+#define BT_LE_SCAN_INTERVAL_DEF 0x0008
+
+#define BT_LE_CONN_INTERVAL_MIN 0x0006
+#define BT_LE_CONN_INTERVAL_MAX 0x0C80
+#define BT_LE_CONN_INTERVAL_MIN_DEF 0x0008
+#define BT_LE_CONN_INTERVAL_MAX_DEF 0x0100
+
+#define BT_LE_LATENCY_MAX 0x01F4
+#define BT_LE_LATENCY_DEF 0x0000
+
+#define BT_LE_SUP_TO_MIN 0x000A
+#define BT_LE_SUP_TO_MAX 0x0C80
+#define BT_LE_SUP_TO_DEFAULT 0X03E8
+
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
@@ -142,6 +164,20 @@
#define bt_sk(__sk) ((struct bt_sock *) __sk)
+struct bt_le_params {
+ __u8 prohibit_remote_chg;
+ __u8 filter_policy;
+ __u16 scan_interval;
+ __u16 scan_window;
+ __u16 interval_min;
+ __u16 interval_max;
+ __u16 latency;
+ __u16 supervision_timeout;
+ __u16 min_ce_len;
+ __u16 max_ce_len;
+ __u16 conn_timeout;
+};
+
struct bt_sock {
struct sock sk;
bdaddr_t src;
@@ -149,6 +185,7 @@
struct list_head accept_q;
struct sock *parent;
u32 defer_setup;
+ struct bt_le_params le_params;
};
struct bt_sock_list {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5053bd8..5749293 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -304,6 +304,7 @@
__u8 auth_initiator;
__u8 power_save;
__u16 disc_timeout;
+ __u16 conn_timeout;
unsigned long pend;
__u8 remote_cap;
@@ -597,6 +598,10 @@
struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
__u16 pkt_type, bdaddr_t *dst,
__u8 sec_level, __u8 auth_type);
+struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type,
+ bdaddr_t *dst, __u8 sec_level,
+ __u8 auth_type,
+ struct bt_le_params *le_params);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
int hci_conn_change_link_key(struct hci_conn *conn);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b903c5c..a098f3e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -685,6 +685,7 @@
int l2cap_ertm_tx(struct sock *sk, struct bt_l2cap_control *control,
struct sk_buff_head *skbs, u8 event);
+int l2cap_sock_le_params_valid(struct bt_le_params *le_params);
void l2cap_sock_set_timer(struct sock *sk, long timeout);
void l2cap_sock_clear_timer(struct sock *sk);
void __l2cap_sock_close(struct sock *sk, int reason);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index d60bf00..25b559b1 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -44,33 +44,77 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
-static void hci_le_connect(struct hci_conn *conn)
+struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type,
+ bdaddr_t *dst, __u8 sec_level, __u8 auth_type,
+ struct bt_le_params *le_params)
{
- struct hci_dev *hdev = conn->hdev;
+ struct hci_conn *le;
struct hci_cp_le_create_conn cp;
+ struct adv_entry *entry;
+ struct link_key *key;
- BT_DBG("%p", conn);
+ BT_DBG("%p", hdev);
- conn->state = BT_CONNECT;
- conn->out = 1;
- conn->link_mode |= HCI_LM_MASTER;
- conn->sec_level = BT_SECURITY_LOW;
- conn->type = LE_LINK;
+ le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+ if (le) {
+ hci_conn_hold(le);
+ return le;
+ }
+
+ key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
+ if (!key) {
+ entry = hci_find_adv_entry(hdev, dst);
+ if (entry)
+ le = hci_le_conn_add(hdev, dst,
+ entry->bdaddr_type);
+ else
+ le = hci_le_conn_add(hdev, dst, 0);
+ } else {
+ le = hci_le_conn_add(hdev, dst, key->addr_type);
+ }
+
+ if (!le)
+ return ERR_PTR(-ENOMEM);
+
+ hci_conn_hold(le);
+
+ le->state = BT_CONNECT;
+ le->out = 1;
+ le->link_mode |= HCI_LM_MASTER;
+ le->sec_level = BT_SECURITY_LOW;
+ le->type = LE_LINK;
memset(&cp, 0, sizeof(cp));
- cp.scan_interval = cpu_to_le16(0x0004);
- cp.scan_window = cpu_to_le16(0x0004);
- bacpy(&cp.peer_addr, &conn->dst);
- cp.peer_addr_type = conn->dst_type;
- cp.conn_interval_min = cpu_to_le16(0x0008);
- cp.conn_interval_max = cpu_to_le16(0x0100);
- cp.supervision_timeout = cpu_to_le16(1000);
- cp.min_ce_len = cpu_to_le16(0x0001);
- cp.max_ce_len = cpu_to_le16(0x0001);
+ if (l2cap_sock_le_params_valid(le_params)) {
+ cp.supervision_timeout =
+ cpu_to_le16(le_params->supervision_timeout);
+ cp.scan_interval = cpu_to_le16(le_params->scan_interval);
+ cp.scan_window = cpu_to_le16(le_params->scan_window);
+ cp.conn_interval_min = cpu_to_le16(le_params->interval_min);
+ cp.conn_interval_max = cpu_to_le16(le_params->interval_max);
+ cp.conn_latency = cpu_to_le16(le_params->latency);
+ cp.min_ce_len = cpu_to_le16(le_params->min_ce_len);
+ cp.max_ce_len = cpu_to_le16(le_params->max_ce_len);
+ le->conn_timeout = le_params->conn_timeout;
+ } else {
+ cp.supervision_timeout = cpu_to_le16(BT_LE_SUP_TO_DEFAULT);
+ cp.scan_interval = cpu_to_le16(BT_LE_SCAN_INTERVAL_DEF);
+ cp.scan_window = cpu_to_le16(BT_LE_SCAN_WINDOW_DEF);
+ cp.conn_interval_min = cpu_to_le16(BT_LE_CONN_INTERVAL_MIN_DEF);
+ cp.conn_interval_max = cpu_to_le16(BT_LE_CONN_INTERVAL_MAX_DEF);
+ cp.conn_latency = cpu_to_le16(BT_LE_LATENCY_DEF);
+ le->conn_timeout = 5;
+ }
+ bacpy(&cp.peer_addr, &le->dst);
+ cp.peer_addr_type = le->dst_type;
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
+
+ return le;
}
+EXPORT_SYMBOL(hci_le_connect);
static void hci_le_connect_cancel(struct hci_conn *conn)
{
@@ -685,41 +729,12 @@
{
struct hci_conn *acl;
struct hci_conn *sco;
- struct hci_conn *le;
BT_DBG("%s dst %s", hdev->name, batostr(dst));
- if (type == LE_LINK) {
- struct adv_entry *entry;
- struct link_key *key;
-
- le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
- if (le) {
- hci_conn_hold(le);
- return le;
- }
-
- key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
- if (!key) {
- entry = hci_find_adv_entry(hdev, dst);
- if (entry)
- le = hci_le_conn_add(hdev, dst,
- entry->bdaddr_type);
- else
- le = hci_le_conn_add(hdev, dst, 0);
- } else {
- le = hci_le_conn_add(hdev, dst, key->addr_type);
- }
-
- if (!le)
- return ERR_PTR(-ENOMEM);
-
- hci_le_connect(le);
-
- hci_conn_hold(le);
-
- return le;
- }
+ if (type == LE_LINK)
+ return hci_le_connect(hdev, pkt_type, dst, sec_level,
+ auth_type, NULL);
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (!acl) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 598c310..395a95c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1368,6 +1368,7 @@
{
struct hci_cp_le_create_conn *cp;
struct hci_conn *conn;
+ unsigned long exp = msecs_to_jiffies(5000);
BT_DBG("%s status 0x%x", hdev->name, status);
@@ -1396,11 +1397,11 @@
conn->out = 1;
else
BT_ERR("No memory for new connection");
- }
+ } else
+ exp = msecs_to_jiffies(conn->conn_timeout * 1000);
- if (conn)
- mod_timer(&conn->disc_timer,
- jiffies + msecs_to_jiffies(5000));
+ if (conn && exp)
+ mod_timer(&conn->disc_timer, jiffies + exp);
}
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 37ee9b1..9f9f17d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1277,8 +1277,9 @@
conn = hcon->l2cap_data;
} else {
if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
- hcon = hci_connect(hdev, LE_LINK, 0, dst,
- l2cap_pi(sk)->sec_level, auth_type);
+ hcon = hci_le_connect(hdev, 0, dst,
+ l2cap_pi(sk)->sec_level, auth_type,
+ &bt_sk(sk)->le_params);
else
hcon = hci_connect(hdev, ACL_LINK, 0, dst,
l2cap_pi(sk)->sec_level, auth_type);
@@ -1308,7 +1309,17 @@
sk->sk_state_change(sk);
} else {
sk->sk_state = BT_CONNECT;
- l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+ /* If we have valid LE Params, let timeout override default */
+ if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA &&
+ l2cap_sock_le_params_valid(&bt_sk(sk)->le_params)) {
+ u16 timeout = bt_sk(sk)->le_params.conn_timeout;
+
+ if (timeout)
+ l2cap_sock_set_timer(sk,
+ msecs_to_jiffies(timeout*1000));
+ } else
+ l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
+
sk->sk_state_change(sk);
if (hcon->state == BT_CONNECTED) {
@@ -5668,7 +5679,8 @@
struct hci_conn *hcon = conn->hcon;
struct l2cap_conn_param_update_req *req;
struct l2cap_conn_param_update_rsp rsp;
- u16 min, max, latency, to_multiplier, cmd_len;
+ struct sock *sk;
+ u16 min, max, latency, timeout, cmd_len;
int err;
if (!(hcon->link_mode & HCI_LM_MASTER))
@@ -5678,28 +5690,32 @@
if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
return -EPROTO;
- req = (struct l2cap_conn_param_update_req *) data;
- min = __le16_to_cpu(req->min);
- max = __le16_to_cpu(req->max);
- latency = __le16_to_cpu(req->latency);
- to_multiplier = __le16_to_cpu(req->to_multiplier);
-
- BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
- min, max, latency, to_multiplier);
-
memset(&rsp, 0, sizeof(rsp));
+ rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
- err = l2cap_check_conn_param(min, max, latency, to_multiplier);
- if (err)
- rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
- else
- rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+ sk = l2cap_find_sock_by_fixed_cid_and_dir(4, conn->src, conn->dst, 0);
+
+ if (sk && !bt_sk(sk)->le_params.prohibit_remote_chg) {
+ req = (struct l2cap_conn_param_update_req *) data;
+ min = __le16_to_cpu(req->min);
+ max = __le16_to_cpu(req->max);
+ latency = __le16_to_cpu(req->latency);
+ timeout = __le16_to_cpu(req->to_multiplier);
+
+ err = l2cap_check_conn_param(min, max, latency, timeout);
+ if (!err) {
+ rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
+ hci_le_conn_update(hcon, min, max, latency, timeout);
+ bt_sk(sk)->le_params.interval_min = min;
+ bt_sk(sk)->le_params.interval_max = max;
+ bt_sk(sk)->le_params.latency = latency;
+ bt_sk(sk)->le_params.supervision_timeout = timeout;
+ }
+ }
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
sizeof(rsp), &rsp);
- if (!err)
- hci_le_conn_update(hcon, min, max, latency, to_multiplier);
return 0;
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 8eb1e16..33d5d22 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -78,6 +78,23 @@
sk_stop_timer(sk, &sk->sk_timer);
}
+int l2cap_sock_le_params_valid(struct bt_le_params *le_params)
+{
+ if (!le_params || le_params->latency > BT_LE_LATENCY_MAX ||
+ le_params->scan_window > BT_LE_SCAN_WINDOW_MAX ||
+ le_params->scan_interval < BT_LE_SCAN_INTERVAL_MIN ||
+ le_params->scan_window > le_params->scan_interval ||
+ le_params->interval_min < BT_LE_CONN_INTERVAL_MIN ||
+ le_params->interval_max > BT_LE_CONN_INTERVAL_MAX ||
+ le_params->interval_min > le_params->interval_max ||
+ le_params->supervision_timeout < BT_LE_SUP_TO_MIN ||
+ le_params->supervision_timeout > BT_LE_SUP_TO_MAX) {
+ return 0;
+ }
+
+ return 1;
+}
+
static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
{
struct sock *sk;
@@ -547,6 +564,17 @@
err = -EFAULT;
break;
+ case BT_LE_PARAMS:
+ if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (copy_to_user(optval, (char *) &bt_sk(sk)->le_params,
+ sizeof(bt_sk(sk)->le_params)))
+ err = -EFAULT;
+ break;
+
default:
err = -ENOPROTOOPT;
break;
@@ -671,6 +699,7 @@
struct sock *sk = sock->sk;
struct bt_security sec;
struct bt_power pwr;
+ struct bt_le_params le_params;
struct l2cap_conn *conn;
int len, err = 0;
u32 opt;
@@ -786,6 +815,41 @@
break;
+ case BT_LE_PARAMS:
+ if (l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (copy_from_user((char *) &le_params, optval,
+ sizeof(struct bt_le_params))) {
+ err = -EFAULT;
+ break;
+ }
+
+ conn = l2cap_pi(sk)->conn;
+ if (!conn || !conn->hcon ||
+ l2cap_pi(sk)->scid != L2CAP_CID_LE_DATA) {
+ memcpy(&bt_sk(sk)->le_params, &le_params,
+ sizeof(le_params));
+ break;
+ }
+
+ if (!conn->hcon->out ||
+ !l2cap_sock_le_params_valid(&le_params)) {
+ err = -EINVAL;
+ break;
+ }
+
+ memcpy(&bt_sk(sk)->le_params, &le_params, sizeof(le_params));
+
+ hci_le_conn_update(conn->hcon,
+ le_params.interval_min,
+ le_params.interval_max,
+ le_params.latency,
+ le_params.supervision_timeout);
+ break;
+
default:
err = -ENOPROTOOPT;
break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e15609c..80f4bd6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1623,8 +1623,8 @@
entry = hci_find_adv_entry(hdev, &cp->bdaddr);
if (entry && entry->flags & 0x04) {
- conn = hci_connect(hdev, LE_LINK, 0, &cp->bdaddr, sec_level,
- auth_type);
+ conn = hci_le_connect(hdev, 0, &cp->bdaddr, sec_level,
+ auth_type, NULL);
} else {
/* ACL-SSP does not support io_cap 0x04 (KeyboadDisplay) */
if (io_cap == 0x04)
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index cb760fa..8e4e205 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -49,7 +49,7 @@
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 23134ea..6c44cba 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -50,7 +50,8 @@
{
.playback = {
.stream_name = "Multimedia1 Playback",
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
@@ -59,20 +60,22 @@
},
.capture = {
.stream_name = "Multimedia1 Capture",
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
},
- .ops = &msm_fe_dai_ops,
+ .ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia1",
},
{
.playback = {
.stream_name = "Multimedia2 Playback",
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 6,
@@ -81,14 +84,15 @@
},
.capture = {
.stream_name = "Multimedia2 Capture",
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
- .ops = &msm_fe_dai_ops,
+ .ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia2",
},
{
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 0a8282c..b509a09 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -77,7 +77,7 @@
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 4686386..39ce436 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -71,7 +71,7 @@
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,