Merge "power: qpnp-charger: report CURRENT_MAX for battery"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_watchdog.txt b/Documentation/devicetree/bindings/arm/msm/msm_watchdog.txt
index a665431..c7a19ef 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_watchdog.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_watchdog.txt
@@ -29,7 +29,7 @@
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
- interrupts = <0 3 0 0 4 0>;
+ interrupts = <0 3 0>, <0 4 0>;
qcom,bark-time = <11000>;
qcom,pet-time = <10000>;
qcom,ipi-ping;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index d523c67..c762405 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -17,10 +17,65 @@
/ {
model = "Qualcomm MSM 8610 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0>;
+ qcom,msm-id = <147 1 0>, <165 1 0>;
serial@f991f000 {
status = "ok";
};
};
+&sdhc_1 {
+ vdd-supply = <&pm8110_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 400000>;
+
+ vdd-io-supply = <&pm8110_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 60000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8110_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
+
+ vdd-io-supply = <&pm8110_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 50000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 42 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 42 0x1>;
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index f718d5e..e3eed72 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -17,10 +17,65 @@
/ {
model = "Qualcomm MSM 8610 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0>;
+ qcom,msm-id = <147 8 0>, <165 8 0>;
serial@f991f000 {
status = "ok";
};
};
+&sdhc_1 {
+ vdd-supply = <&pm8110_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 400000>;
+
+ vdd-io-supply = <&pm8110_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 60000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8110_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
+
+ vdd-io-supply = <&pm8110_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 50000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 42 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 42 0x1>;
+
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
index 4a5273b..9690d12 100644
--- a/arch/arm/boot/dts/msm8610-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -177,6 +177,27 @@
#interrupt-cells = <2>;
};
+ smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "slave-kernel";
+ qcom,remote-pid = <4>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "master-kernel";
+ qcom,remote-pid = <4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
qcom,smp2pgpio_test_smp2p_4_out {
compatible = "qcom,smp2pgpio_test_smp2p_4_out";
gpios = <&smp2pgpio_smp2p_4_out 0 0>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 82aca81..28a3c35 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -47,6 +47,8 @@
aliases {
spi0 = &spi_0;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
};
timer {
@@ -94,8 +96,17 @@
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
- qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
+ qcom,dp-manual-pullup;
+
+ qcom,msm-bus,name = "usb2";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <87 512 0 0>,
+ <87 512 60000 960000>;
};
android_usb@fe8050c8 {
@@ -135,6 +146,8 @@
qcom,bus-width = <8>;
qcom,nonremovable;
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+
+ status = "disabled";
};
sdcc2: qcom,sdcc@f98a4000 {
@@ -166,6 +179,32 @@
qcom,xpc;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
qcom,current-limit = <800>;
+
+ status = "disabled";
+ };
+
+ sdhc_1: sdhci@f9824900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 123 0>, <0 138 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <8>;
+ status = "disabled";
+ };
+
+ sdhc_2: sdhci@f98a4900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ interrupts = <0 125 0>, <0 221 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <4>;
+ status = "disabled";
};
qcom,sps {
@@ -331,6 +370,12 @@
vdd_pronto_pll-supply = <&pm8110_l10>;
qcom,firmware-name = "wcnss";
+
+ /* GPIO input from wcnss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+
+ /* GPIO output to wcnss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_4_out 0 0>;
};
sound {
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index a7544ab..28d1d61 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -67,14 +67,14 @@
qcom,gpu-pwrlevel@1 {
reg = <1>;
- qcom,gpu-freq = <300000000>;
+ qcom,gpu-freq = <320000000>;
qcom,bus-freq = <4>;
qcom,io-fraction = <66>;
};
qcom,gpu-pwrlevel@2 {
reg = <2>;
- qcom,gpu-freq = <300000000>;
+ qcom,gpu-freq = <320000000>;
qcom,bus-freq = <3>;
qcom,io-fraction = <66>;
};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 009b6df..50fb380 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -48,9 +48,9 @@
/* Nominal / SVS */
<26 512 0 4656000>, <89 604 0 3000000>,
/* Nominal */
- <26 512 0 4656000>, <89 604 0 5334880>,
+ <26 512 0 4656000>, <89 604 0 5120000>,
/* Turbo / Nominal */
- <26 512 0 7464000>, <89 604 0 5334880>,
+ <26 512 0 7464000>, <89 604 0 5120000>,
/* Turbo */
<26 512 0 7464000>, <89 604 0 6400000>;
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 435d0c1..56234a1 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1154,7 +1154,7 @@
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
- interrupts = <0 3 0 0 4 0>;
+ interrupts = <0 3 0>, <0 4 0>;
qcom,bark-time = <11000>;
qcom,pet-time = <10000>;
qcom,ipi-ping;
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index b673f93..0533d06 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -39,6 +39,8 @@
.user_val = 0x8,
.user_vco_mask = BIT(20),
.config_val = 0x04D0405D,
+ .has_lock_status = true,
+ .status_offset = 0x1C,
.low_vco_l_max = 65,
.low_vdd_l_max = 52,
.nom_vdd_l_max = 104,
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index a6f4423..e3a3f54 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -22,6 +22,7 @@
#include <linux/cpufreq.h>
#include <linux/cpu.h>
#include <linux/regulator/consumer.h>
+#include <linux/iopoll.h>
#include <asm/mach-types.h>
#include <asm/cpu.h>
@@ -131,8 +132,14 @@
writel_relaxed(0x6, sc->hfpll_base + drv.hfpll_data->mode_offset);
/* Wait for PLL to lock. */
- mb();
- udelay(60);
+ if (drv.hfpll_data->has_lock_status) {
+ u32 regval;
+ readl_tight_poll(sc->hfpll_base + drv.hfpll_data->status_offset,
+ regval, regval & BIT(16));
+ } else {
+ mb();
+ udelay(60);
+ }
/* Enable PLL output. */
writel_relaxed(0x7, sc->hfpll_base + drv.hfpll_data->mode_offset);
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 11d58dd..f02af98 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -171,8 +171,10 @@
* @user_val: Value to initialize the @user_offset register to.
* @user_vco_mask: Bit in the @user_offset to enable high-frequency VCO mode.
* @has_droop_ctl: Indicates the presence of a voltage droop controller.
+ * @has_lock_status: Indicates the presence of a lock status bit.
* @droop_offset: Droop controller register offset from base address.
* @droop_val: Value to initialize the @config_offset register to.
+ * @status_offset: PLL status register offset.
* @low_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_LOW.
* @nom_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_NOM.
* @low_vco_l_max: Maximum "L" value supported in low-frequency VCO mode.
@@ -190,8 +192,10 @@
const u32 user_val;
const u32 user_vco_mask;
const bool has_droop_ctl;
+ const bool has_lock_status;
const u32 droop_offset;
const u32 droop_val;
+ const u32 status_offset;
u32 low_vdd_l_max;
u32 nom_vdd_l_max;
const u32 low_vco_l_max;
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 92be927..a0644e6 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1979,6 +1979,8 @@
a2_props.options = SPS_BAM_OPT_IRQ_WAKEUP;
a2_props.num_pipes = A2_NUM_PIPES;
a2_props.summing_threshold = A2_SUMMING_THRESHOLD;
+ a2_props.constrained_logging = true;
+ a2_props.logging_number = 1;
if (cpu_is_msm9615() || satellite_mode)
a2_props.manage = SPS_BAM_MGR_DEVICE_REMOTE;
/* need to free on tear down */
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 9495b72..99db345 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -72,6 +72,10 @@
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
"msm_sdcc.2", NULL),
+ OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9824900, \
+ "msm_sdcc.1", NULL),
+ OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF98A4900, \
+ "msm_sdcc.2", NULL),
{}
};
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 662655b..25cbc87 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -410,6 +410,11 @@
u32 sec_config;
struct sps_bam_sec_config_props *p_sec_config_props;
+
+ /* Logging control */
+
+ bool constrained_logging;
+ u32 logging_number;
};
/**
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index 16dd8b8..366375b 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -473,6 +473,7 @@
}
return process_quota(client_id);
}
+EXPORT_SYMBOL(get_max_quota);
/* Synchronous eviction/restore calls */
/* Only a single eviction or restoration is allowed */
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index ef13c34..72253fd 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -47,7 +47,7 @@
void *ramdump_dev;
int wdog_irq;
struct work_struct work;
- void *riva_notif_hdle;
+ void *wcnss_notif_hdle;
void *modem_notif_hdle;
int crash_shutdown;
};
@@ -189,24 +189,19 @@
.shutdown = pil_lpass_shutdown_trusted,
};
-static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+static int wcnss_notifier_cb(struct notifier_block *this, unsigned long code,
void *ss_handle)
{
int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: R-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__, ret);
- break;
- }
+ pr_debug("%s: W-Notify: event %lu\n", __func__, code);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss", code);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
return NOTIFY_DONE;
}
-static struct notifier_block rnb = {
- .notifier_call = riva_notifier_cb,
+static struct notifier_block wnb = {
+ .notifier_call = wcnss_notifier_cb,
};
static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
@@ -480,10 +475,10 @@
if (ret < 0)
goto err_smsm;
- drv->riva_notif_hdle = subsys_notif_register_notifier("riva", &rnb);
- if (IS_ERR(drv->riva_notif_hdle)) {
- ret = PTR_ERR(drv->riva_notif_hdle);
- goto err_notif_riva;
+ drv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
+ if (IS_ERR(drv->wcnss_notif_hdle)) {
+ ret = PTR_ERR(drv->wcnss_notif_hdle);
+ goto err_notif_wcnss;
}
drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
@@ -510,8 +505,8 @@
err_kobj:
kobject_put(lpass_status);
err_notif_modem:
- subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
-err_notif_riva:
+ subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
+err_notif_wcnss:
smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
adsp_smsm_state_cb, drv);
err_smsm:
@@ -527,7 +522,7 @@
static int __devexit pil_lpass_driver_exit(struct platform_device *pdev)
{
struct lpass_data *drv = platform_get_drvdata(pdev);
- subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+ subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
adsp_smsm_state_cb, drv);
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index b7271bb..f1a7185 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -46,55 +46,6 @@
static struct clk *scm_clocks[NUM_CLKS];
-int pas_init_image(enum pas_id id, const u8 *metadata, size_t size)
-{
- int ret;
- struct pas_init_image_req {
- u32 proc;
- u32 image_addr;
- } request;
- u32 scm_ret = 0;
- /* Make memory physically contiguous */
- void *mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
-
- if (!mdata_buf)
- return -ENOMEM;
-
- request.proc = id;
- request.image_addr = virt_to_phys(mdata_buf);
-
- ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
- sizeof(request), &scm_ret, sizeof(scm_ret));
- kfree(mdata_buf);
-
- if (ret)
- return ret;
- return scm_ret;
-}
-EXPORT_SYMBOL(pas_init_image);
-
-int pas_mem_setup(enum pas_id id, u32 start_addr, u32 len)
-{
- int ret;
- struct pas_init_image_req {
- u32 proc;
- u32 start_addr;
- u32 len;
- } request;
- u32 scm_ret = 0;
-
- request.proc = id;
- request.start_addr = start_addr;
- request.len = len;
-
- ret = scm_call(SCM_SVC_PIL, PAS_MEM_SETUP_CMD, &request,
- sizeof(request), &scm_ret, sizeof(scm_ret));
- if (ret)
- return ret;
- return scm_ret;
-}
-EXPORT_SYMBOL(pas_mem_setup);
-
static struct msm_bus_paths scm_pas_bw_tbl[] = {
{
.vectors = (struct msm_bus_vectors[]){
@@ -176,18 +127,78 @@
mutex_unlock(&scm_pas_bw_mutex);
}
+int pas_init_image(enum pas_id id, const u8 *metadata, size_t size)
+{
+ int ret;
+ struct pas_init_image_req {
+ u32 proc;
+ u32 image_addr;
+ } request;
+ u32 scm_ret = 0;
+ void *mdata_buf;
+
+ ret = scm_pas_enable_bw();
+ if (ret)
+ return ret;
+
+ /* Make memory physically contiguous */
+ mdata_buf = kmemdup(metadata, size, GFP_KERNEL);
+
+ if (!mdata_buf)
+ return -ENOMEM;
+
+ request.proc = id;
+ request.image_addr = virt_to_phys(mdata_buf);
+
+ ret = scm_call(SCM_SVC_PIL, PAS_INIT_IMAGE_CMD, &request,
+ sizeof(request), &scm_ret, sizeof(scm_ret));
+
+ kfree(mdata_buf);
+ scm_pas_disable_bw();
+
+ if (ret)
+ return ret;
+ return scm_ret;
+}
+EXPORT_SYMBOL(pas_init_image);
+
+int pas_mem_setup(enum pas_id id, u32 start_addr, u32 len)
+{
+ int ret;
+ struct pas_init_image_req {
+ u32 proc;
+ u32 start_addr;
+ u32 len;
+ } request;
+ u32 scm_ret = 0;
+
+ request.proc = id;
+ request.start_addr = start_addr;
+ request.len = len;
+
+ ret = scm_call(SCM_SVC_PIL, PAS_MEM_SETUP_CMD, &request,
+ sizeof(request), &scm_ret, sizeof(scm_ret));
+ if (ret)
+ return ret;
+ return scm_ret;
+}
+EXPORT_SYMBOL(pas_mem_setup);
+
int pas_auth_and_reset(enum pas_id id)
{
- int ret, bus_ret;
+ int ret;
u32 proc = id, scm_ret = 0;
- bus_ret = scm_pas_enable_bw();
+ ret = scm_pas_enable_bw();
+ if (ret)
+ return ret;
+
ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
sizeof(proc), &scm_ret, sizeof(scm_ret));
if (ret)
scm_ret = ret;
- if (!bus_ret)
- scm_pas_disable_bw();
+
+ scm_pas_disable_bw();
return scm_ret;
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index ba0fd7c..739a753 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -610,7 +610,8 @@
/* write xts du size */
pce = cmdlistinfo->encr_xts_du_size;
if (use_pipe_key == true)
- pce->data = QCE_SECTOR_SIZE;
+ pce->data = min((unsigned int)QCE_SECTOR_SIZE,
+ creq->cryptlen);
else
pce->data = creq->cryptlen;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 31fa39e..d4f6a07 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -24,7 +24,7 @@
#define VFE32_BURST_LEN 3
#define VFE32_UB_SIZE 1024
-#define VFE32_EQUAL_SLICE_UB 117
+#define VFE32_EQUAL_SLICE_UB 204
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
#define VFE32_RDI_BASE(idx) (idx ? 0x734 + 0x4 * (idx - 1) : 0x06FC)
#define VFE32_XBAR_BASE(idx) (0x40 + 0x4 * (idx / 4))
@@ -592,7 +592,7 @@
stream_cfg_cmd->plane_cfg[plane_idx].
output_stride) << 16 |
(stream_cfg_cmd->plane_cfg[plane_idx].
- output_height - 1) << 4 | VFE32_BURST_LEN >> 2;
+ output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
@@ -602,7 +602,7 @@
stream_cfg_cmd->plane_cfg[plane_idx].
output_width) << 16 |
(stream_cfg_cmd->plane_cfg[plane_idx].
- output_height - 1) << 4 | VFE32_BURST_LEN >> 2;
+ output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
}
return;
@@ -945,7 +945,7 @@
}
struct msm_vfe_axi_hardware_info msm_vfe32_axi_hw_info = {
- .num_wm = 7,
+ .num_wm = 4,
.num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 4d3ede3..160d450 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2015,7 +2015,7 @@
{
int rc = 0;
int i;
- struct vidc_buffer_addr_info buffer_info;
+ struct vidc_buffer_addr_info buffer_info = {0};
struct hfi_device *hdev;
int extra_idx = 0;
@@ -2078,7 +2078,7 @@
struct v4l2_buffer *b)
{
int i, rc = 0, extra_idx = 0;
- struct vidc_buffer_addr_info buffer_info;
+ struct vidc_buffer_addr_info buffer_info = {0};
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index adf6dec..dc08c64 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -373,7 +373,6 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
int rc = 0;
@@ -382,15 +381,7 @@
event_notify = (struct msm_vidc_cb_event *) response->data;
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
- event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
- rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
- if (rc)
- dprintk(VIDC_WARN,
- "Failed to get Smooth streamng flag\n");
- if (!rc && control.value == true)
- event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 3ebb1cd..a117943 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -403,9 +403,21 @@
}
dev->state |= BAM_STATE_ENABLED;
- SPS_INFO("sps:BAM 0x%x (va:0x%x) enabled: ver:0x%x, number of pipes:%d",
- BAM_ID(dev), (u32) dev->base, dev->version,
- dev->props.num_pipes);
+
+ if (!dev->props.constrained_logging ||
+ (dev->props.constrained_logging && dev->props.logging_number)) {
+ if (dev->props.logging_number > 0)
+ dev->props.logging_number--;
+ SPS_INFO(
+ "sps:BAM 0x%x (va:0x%x) enabled: ver:0x%x, number of pipes:%d\n",
+ BAM_ID(dev), (u32) dev->base, dev->version,
+ dev->props.num_pipes);
+ } else
+ SPS_DBG2(
+ "sps:BAM 0x%x (va:0x%x) enabled: ver:0x%x, number of pipes:%d\n",
+ BAM_ID(dev), (u32) dev->base, dev->version,
+ dev->props.num_pipes);
+
return 0;
}
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index fd680e6..2c58e49 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -28,8 +28,9 @@
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_util.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_edid.o
-obj-$(CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334) += mhl_sii8334.o mhl_msc.o
obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_cec.o
+obj-$(CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334) += mhl_sii8334.o mhl_msc.o
obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
new file mode 100644
index 0000000..694fcde
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -0,0 +1,949 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <mach/board.h>
+
+#include "mdss_hdmi_cec.h"
+
+#define CEC_STATUS_WR_ERROR BIT(0)
+#define CEC_STATUS_WR_DONE BIT(1)
+
+/* Reference: HDMI 1.4a Specification section 7.1 */
+#define RETRANSMIT_MAX_NUM 5
+
+/*
+ * Ref. HDMI 1.4a: Supplement-1 CEC Section 6, 7
+ */
+struct hdmi_cec_msg {
+ u8 sender_id;
+ u8 recvr_id;
+ u8 opcode;
+ u8 operand[15];
+ u8 frame_size;
+ u8 retransmit;
+};
+
+struct hdmi_cec_msg_node {
+ struct hdmi_cec_msg msg;
+ struct list_head list;
+};
+
+struct hdmi_cec_ctrl {
+ bool cec_enabled;
+ bool compliance_response_enabled;
+ bool cec_engine_configed;
+
+ u8 cec_logical_addr;
+ u32 cec_msg_wr_status;
+
+ spinlock_t lock;
+ struct list_head msg_head;
+ struct work_struct cec_read_work;
+ struct completion cec_msg_wr_done;
+ struct hdmi_cec_init_data init_data;
+};
+
+static int hdmi_cec_msg_send(struct hdmi_cec_ctrl *cec_ctrl,
+ struct hdmi_cec_msg *msg);
+
+static void hdmi_cec_dump_msg(struct hdmi_cec_ctrl *cec_ctrl,
+ struct hdmi_cec_msg *msg)
+{
+ int i;
+ unsigned long flags;
+
+ if (!cec_ctrl || !msg) {
+ DEV_ERR("%pS->%s: invalid input\n",
+ __builtin_return_address(0), __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ DEV_DBG("=================%pS dump start =====================\n",
+ __builtin_return_address(0));
+
+ DEV_DBG("sender_id : %d", msg->sender_id);
+ DEV_DBG("recvr_id : %d", msg->recvr_id);
+
+ if (msg->frame_size < 2) {
+ DEV_DBG("polling message");
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ return;
+ }
+
+ DEV_DBG("opcode : %02x", msg->opcode);
+ for (i = 0; i < msg->frame_size - 2; i++)
+ DEV_DBG("operand(%2d) : %02x", i + 1, msg->operand[i]);
+
+ DEV_DBG("=================%pS dump end =====================\n",
+ __builtin_return_address(0));
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+} /* hdmi_cec_dump_msg */
+
+static inline void hdmi_cec_write_logical_addr(struct hdmi_cec_ctrl *cec_ctrl,
+ u8 addr)
+{
+ if (!cec_ctrl || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return;
+ }
+
+ DSS_REG_W(cec_ctrl->init_data.io, HDMI_CEC_ADDR, addr & 0xF);
+} /* hdmi_cec_write_logical_addr */
+
+static void hdmi_cec_disable(struct hdmi_cec_ctrl *cec_ctrl)
+{
+ u32 reg_val;
+ unsigned long flags;
+ struct dss_io_data *io = NULL;
+ struct hdmi_cec_msg_node *msg_node, *tmp;
+
+ if (!cec_ctrl || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return;
+ }
+
+ io = cec_ctrl->init_data.io;
+
+ /* Disable Engine */
+ DSS_REG_W(io, HDMI_CEC_CTRL, 0);
+
+ /* Disable CEC interrupts */
+ reg_val = DSS_REG_R(io, HDMI_CEC_INT);
+ DSS_REG_W(io, HDMI_CEC_INT, reg_val & !BIT(1) & !BIT(3) & !BIT(7));
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ list_for_each_entry_safe(msg_node, tmp, &cec_ctrl->msg_head, list) {
+ list_del(&msg_node->list);
+ kfree(msg_node);
+ }
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+} /* hdmi_cec_disable */
+
+static void hdmi_cec_enable(struct hdmi_cec_ctrl *cec_ctrl)
+{
+ struct dss_io_data *io = NULL;
+
+ if (!cec_ctrl || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return;
+ }
+
+ io = cec_ctrl->init_data.io;
+
+ INIT_LIST_HEAD(&cec_ctrl->msg_head);
+
+ /* Enable CEC interrupts */
+ DSS_REG_W(io, HDMI_CEC_INT, BIT(1) | BIT(3) | BIT(7));
+
+ /* Enable Engine */
+ DSS_REG_W(io, HDMI_CEC_CTRL, BIT(0));
+} /* hdmi_cec_enable */
+
+static int hdmi_cec_send_abort_opcode(struct hdmi_cec_ctrl *cec_ctrl,
+ struct hdmi_cec_msg *in_msg, u8 reason_operand)
+{
+ int i = 0;
+ struct hdmi_cec_msg out_msg;
+
+ if (!cec_ctrl || !in_msg) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ out_msg.sender_id = 0x4;
+ out_msg.recvr_id = in_msg->sender_id;
+ out_msg.opcode = 0x0; /* opcode for feature abort */
+ out_msg.operand[i++] = in_msg->opcode;
+ out_msg.operand[i++] = reason_operand;
+ out_msg.frame_size = i + 2;
+
+ return hdmi_cec_msg_send(cec_ctrl, &out_msg);
+} /* hdmi_cec_send_abort_opcode */
+
+static int hdmi_cec_msg_parser(struct hdmi_cec_ctrl *cec_ctrl,
+ struct hdmi_cec_msg *in_msg)
+{
+ int rc = 0, i = 0;
+ struct hdmi_cec_msg out_msg;
+
+ if (!cec_ctrl || !in_msg) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ DEV_DBG("%s: in_msg->opcode = 0x%x\n", __func__, in_msg->opcode);
+ switch (in_msg->opcode) {
+ case 0x64:
+ /* Set OSD String */
+ DEV_INFO("%s: Recvd OSD Str=[0x%x]\n", __func__,
+ in_msg->operand[3]);
+ break;
+ case 0x83:
+ /* Give Phy Addr */
+ DEV_INFO("%s: Recvd a Give Phy Addr cmd\n", __func__);
+
+ out_msg.sender_id = 0x4;
+ out_msg.recvr_id = 0xF; /* Broadcast */
+ out_msg.opcode = 0x84;
+ out_msg.operand[i++] = 0x10;
+ out_msg.operand[i++] = 0x0;
+ out_msg.operand[i++] = 0x04;
+ out_msg.frame_size = i + 2;
+
+ rc = hdmi_cec_msg_send(cec_ctrl, &out_msg);
+ break;
+ case 0xFF:
+ /* Abort */
+ DEV_INFO("%s: Recvd an abort cmd.\n", __func__);
+
+ /* reason = "Refused" */
+ rc = hdmi_cec_send_abort_opcode(cec_ctrl, in_msg, 0x04);
+ break;
+ case 0x46:
+ /* Give OSD name */
+ DEV_INFO("%s: Recvd 'Give OSD name' cmd.\n", __func__);
+
+ out_msg.sender_id = 0x4;
+ out_msg.recvr_id = in_msg->sender_id;
+ out_msg.opcode = 0x47; /* OSD Name */
+ /* Display control byte */
+ out_msg.operand[i++] = 0x0;
+ out_msg.operand[i++] = 'H';
+ out_msg.operand[i++] = 'e';
+ out_msg.operand[i++] = 'l';
+ out_msg.operand[i++] = 'l';
+ out_msg.operand[i++] = 'o';
+ out_msg.operand[i++] = ' ';
+ out_msg.operand[i++] = 'W';
+ out_msg.operand[i++] = 'o';
+ out_msg.operand[i++] = 'r';
+ out_msg.operand[i++] = 'l';
+ out_msg.operand[i++] = 'd';
+ out_msg.frame_size = i + 2;
+
+ rc = hdmi_cec_msg_send(cec_ctrl, &out_msg);
+ break;
+ case 0x8F:
+ /* Give Device Power status */
+ DEV_INFO("%s: Recvd a Power status message\n", __func__);
+
+ out_msg.sender_id = 0x4;
+ out_msg.recvr_id = in_msg->sender_id;
+ out_msg.opcode = 0x90; /* OSD String */
+ out_msg.operand[i++] = 'H';
+ out_msg.operand[i++] = 'e';
+ out_msg.operand[i++] = 'l';
+ out_msg.operand[i++] = 'l';
+ out_msg.operand[i++] = 'o';
+ out_msg.operand[i++] = ' ';
+ out_msg.operand[i++] = 'W';
+ out_msg.operand[i++] = 'o';
+ out_msg.operand[i++] = 'r';
+ out_msg.operand[i++] = 'l';
+ out_msg.operand[i++] = 'd';
+ out_msg.frame_size = i + 2;
+
+ rc = hdmi_cec_msg_send(cec_ctrl, &out_msg);
+ break;
+ case 0x80:
+ /* Routing Change cmd */
+ case 0x86:
+ /* Set Stream Path */
+ DEV_INFO("%s: Recvd Set Stream or Routing Change cmd\n",
+ __func__);
+
+ out_msg.sender_id = 0x4;
+ out_msg.recvr_id = 0xF; /* broadcast this message */
+ out_msg.opcode = 0x82; /* Active Source */
+ out_msg.operand[i++] = 0x10;
+ out_msg.operand[i++] = 0x0;
+ out_msg.frame_size = i + 2;
+
+ rc = hdmi_cec_msg_send(cec_ctrl, &out_msg);
+
+ /* todo: check if need to wait for msg response from sink */
+
+ /* sending <Image View On> message */
+ memset(&out_msg, 0x0, sizeof(struct hdmi_cec_msg));
+ i = 0;
+ out_msg.sender_id = 0x4;
+ out_msg.recvr_id = in_msg->sender_id;
+ out_msg.opcode = 0x04; /* opcode for Image View On */
+ out_msg.frame_size = i + 2;
+
+ rc = hdmi_cec_msg_send(cec_ctrl, &out_msg);
+ break;
+ case 0x44:
+ /* User Control Pressed */
+ DEV_INFO("%s: User Control Pressed\n", __func__);
+ break;
+ case 0x45:
+ /* User Control Released */
+ DEV_INFO("%s: User Control Released\n", __func__);
+ break;
+ default:
+ DEV_INFO("%s: Recvd an unknown cmd = [%u]\n", __func__,
+ in_msg->opcode);
+
+ /* reason = "Unrecognized opcode" */
+ rc = hdmi_cec_send_abort_opcode(cec_ctrl, in_msg, 0x0);
+ break;
+ }
+
+ return rc;
+} /* hdmi_cec_msg_parser */
+
+static int hdmi_cec_msg_send(struct hdmi_cec_ctrl *cec_ctrl,
+ struct hdmi_cec_msg *msg)
+{
+ int i, line_check_retry = 10;
+ u32 frame_retransmit = RETRANSMIT_MAX_NUM;
+ bool frame_type;
+ unsigned long flags;
+ struct dss_io_data *io = NULL;
+
+ if (!cec_ctrl || !cec_ctrl->init_data.io || !msg) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ io = cec_ctrl->init_data.io;
+
+ INIT_COMPLETION(cec_ctrl->cec_msg_wr_done);
+ cec_ctrl->cec_msg_wr_status = 0;
+ frame_type = (msg->recvr_id == 15 ? BIT(0) : 0);
+ if (msg->retransmit > 0 && msg->retransmit < RETRANSMIT_MAX_NUM)
+ frame_retransmit = msg->retransmit;
+
+ /* toggle cec in order to flush out bad hw state, if any */
+ DSS_REG_W(io, HDMI_CEC_CTRL, 0);
+ DSS_REG_W(io, HDMI_CEC_CTRL, BIT(0));
+
+ frame_retransmit = (frame_retransmit & 0xF) << 4;
+ DSS_REG_W(io, HDMI_CEC_RETRANSMIT, BIT(0) | frame_retransmit);
+
+ /* header block */
+ DSS_REG_W_ND(io, HDMI_CEC_WR_DATA,
+ (((msg->sender_id << 4) | msg->recvr_id) << 8) | frame_type);
+
+ /* data block 0 : opcode */
+ DSS_REG_W_ND(io, HDMI_CEC_WR_DATA,
+ ((msg->frame_size < 2 ? 0 : msg->opcode) << 8) | frame_type);
+
+ /* data block 1-14 : operand 0-13 */
+ for (i = 0; i < msg->frame_size - 2; i++)
+ DSS_REG_W_ND(io, HDMI_CEC_WR_DATA,
+ (msg->operand[i] << 8) | frame_type);
+
+ while ((DSS_REG_R(io, HDMI_CEC_STATUS) & BIT(0)) &&
+ line_check_retry--) {
+ DEV_DBG("%s: CEC line is busy(%d)\n", __func__,
+ line_check_retry);
+ schedule();
+ }
+
+ if (!line_check_retry && (DSS_REG_R(io, HDMI_CEC_STATUS) & BIT(0))) {
+ DEV_ERR("%s: CEC line is busy. Retry\n", __func__);
+ return -EAGAIN;
+ }
+
+ /* start transmission */
+ DSS_REG_W(io, HDMI_CEC_CTRL, BIT(0) | BIT(1) |
+ ((msg->frame_size & 0x1F) << 4) | BIT(9));
+
+ if (!wait_for_completion_interruptible_timeout(
+ &cec_ctrl->cec_msg_wr_done, HZ)) {
+ DEV_ERR("%s: timedout", __func__);
+ hdmi_cec_dump_msg(cec_ctrl, msg);
+ return -ETIMEDOUT;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (cec_ctrl->cec_msg_wr_status == CEC_STATUS_WR_ERROR)
+ DEV_ERR("%s: msg write failed.\n", __func__);
+ else
+ DEV_DBG("%s: CEC write frame done (frame len=%d)", __func__,
+ msg->frame_size);
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ hdmi_cec_dump_msg(cec_ctrl, msg);
+
+ return 0;
+} /* hdmi_cec_msg_send */
+
+static void hdmi_cec_msg_recv(struct work_struct *work)
+{
+ int i;
+ u32 data;
+ unsigned long flags;
+ struct hdmi_cec_ctrl *cec_ctrl = NULL;
+ struct dss_io_data *io = NULL;
+ struct hdmi_cec_msg_node *msg_node = NULL;
+
+ cec_ctrl = container_of(work, struct hdmi_cec_ctrl, cec_read_work);
+ if (!cec_ctrl || !cec_ctrl->cec_enabled || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = cec_ctrl->init_data.io;
+
+ msg_node = kzalloc(sizeof(*msg_node), GFP_KERNEL);
+ if (!msg_node) {
+ DEV_ERR("%s: FAILED: out of memory\n", __func__);
+ return;
+ }
+
+ data = DSS_REG_R(io, HDMI_CEC_RD_DATA);
+
+ msg_node->msg.recvr_id = (data & 0x000F);
+ msg_node->msg.sender_id = (data & 0x00F0) >> 4;
+ msg_node->msg.frame_size = (data & 0x1F00) >> 8;
+ DEV_DBG("%s: Recvd init=[%u] dest=[%u] size=[%u]\n", __func__,
+ msg_node->msg.sender_id, msg_node->msg.recvr_id,
+ msg_node->msg.frame_size);
+
+ if (msg_node->msg.frame_size < 1) {
+ DEV_ERR("%s: invalid message (frame length = %d)",
+ __func__, msg_node->msg.frame_size);
+ kfree(msg_node);
+ return;
+ } else if (msg_node->msg.frame_size == 1) {
+ DEV_DBG("%s: polling message (dest[%x] <- init[%x])", __func__,
+ msg_node->msg.recvr_id, msg_node->msg.sender_id);
+ kfree(msg_node);
+ return;
+ }
+
+ /* data block 0 : opcode */
+ data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
+ msg_node->msg.opcode = data & 0xFF;
+
+ /* data block 1-14 : operand 0-13 */
+ for (i = 0; i < msg_node->msg.frame_size - 2; i++) {
+ data = DSS_REG_R_ND(io, HDMI_CEC_RD_DATA);
+ msg_node->msg.operand[i] = data & 0xFF;
+ }
+
+ for (; i < 14; i++)
+ msg_node->msg.operand[i] = 0;
+
+ DEV_DBG("%s: CEC read frame done\n", __func__);
+ hdmi_cec_dump_msg(cec_ctrl, &msg_node->msg);
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (cec_ctrl->compliance_response_enabled) {
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ if (hdmi_cec_msg_parser(cec_ctrl, &msg_node->msg) != 0) {
+ DEV_ERR("%s: cec_msg_parser fail. Sending abort msg\n",
+ __func__);
+ /* reason = "Unrecognized opcode" */
+ hdmi_cec_send_abort_opcode(cec_ctrl,
+ &msg_node->msg, 0x0);
+ }
+ kfree(msg_node);
+ } else {
+ list_add_tail(&msg_node->list, &cec_ctrl->msg_head);
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ /* wake-up sysfs read_msg context */
+ sysfs_notify(cec_ctrl->init_data.sysfs_kobj, "cec", "rd_msg");
+ }
+} /* hdmi_cec_msg_recv*/
+
+static ssize_t hdmi_rda_cec_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ unsigned long flags;
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (cec_ctrl->cec_enabled && cec_ctrl->cec_engine_configed) {
+ DEV_DBG("%s: cec is enabled\n", __func__);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", 1);
+ } else if (cec_ctrl->cec_enabled && !cec_ctrl->cec_engine_configed) {
+ DEV_ERR("%s: CEC will be enabled when HDMI mirroring is on\n",
+ __func__);
+ ret = -EPERM;
+ } else {
+ DEV_DBG("%s: cec is disabled\n", __func__);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", 0);
+ }
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return ret;
+} /* hdmi_rda_cec_enable */
+
+static ssize_t hdmi_wta_cec_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int val;
+ bool cec_en;
+ unsigned long flags;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EPERM;
+ }
+
+ if (kstrtoint(buf, 10, &val)) {
+ DEV_ERR("%s: kstrtoint failed.\n", __func__);
+ return -EPERM;
+ }
+ cec_en = (val == 1) ? true : false;
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (cec_ctrl->cec_enabled == cec_en) {
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ DEV_INFO("%s: cec is already %s\n", __func__,
+ cec_en ? "enabled" : "disabled");
+ return ret;
+ }
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ if (!cec_en) {
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (!cec_ctrl->cec_engine_configed) {
+ DEV_DBG("%s: hdmi is already off. disable cec\n",
+ __func__);
+ cec_ctrl->cec_enabled = false;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ return ret;
+ }
+ cec_ctrl->cec_enabled = false;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ hdmi_cec_disable(cec_ctrl);
+ return ret;
+ } else {
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (!cec_ctrl->cec_engine_configed) {
+ DEV_DBG("%s: CEC will be enabled on mirroring\n",
+ __func__);
+ cec_ctrl->cec_enabled = true;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ return ret;
+ }
+ cec_ctrl->cec_enabled = true;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ hdmi_cec_enable(cec_ctrl);
+
+ return ret;
+ }
+} /* hdmi_wta_cec_enable */
+
+static ssize_t hdmi_rda_cec_enable_compliance(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ ssize_t ret;
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid cec_ctrl\n", __func__);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ cec_ctrl->compliance_response_enabled);
+
+ cec_ctrl->cec_logical_addr = 0x4;
+ hdmi_cec_write_logical_addr(cec_ctrl, cec_ctrl->cec_logical_addr);
+
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return ret;
+} /* hdmi_rda_cec_enable_compliance */
+
+static ssize_t hdmi_wta_cec_enable_compliance(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int val;
+ unsigned long flags;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid cec_ctrl\n", __func__);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (cec_ctrl->cec_enabled && cec_ctrl->cec_engine_configed) {
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ DEV_ERR("%s: Cannot en/dis compliance when CEC session is on\n",
+ __func__);
+ return -EPERM;
+ } else {
+ if (kstrtoint(buf, 10, &val)) {
+ DEV_ERR("%s: kstrtoint failed.\n", __func__);
+ return -EPERM;
+ }
+ cec_ctrl->compliance_response_enabled =
+ (val == 1) ? true : false;
+ }
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return ret;
+} /* hdmi_wta_cec_enable_compliance */
+
+static ssize_t hdmi_rda_cec_logical_addr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid cec_ctrl\n", __func__);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", cec_ctrl->cec_logical_addr);
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return ret;
+} /* hdmi_rda_cec_logical_addr */
+
+static ssize_t hdmi_wta_cec_logical_addr(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int logical_addr;
+ unsigned long flags;
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid cec_ctrl\n", __func__);
+ return -EPERM;
+ }
+
+ if (kstrtoint(buf, 10, &logical_addr)) {
+ DEV_ERR("%s: kstrtoint failed\n", __func__);
+ return -EPERM;
+ }
+
+ if (logical_addr < 0 || logical_addr > 15) {
+ DEV_ERR("%s: Invalid logical address\n", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ cec_ctrl->cec_logical_addr = (u8)logical_addr;
+ if (cec_ctrl->cec_enabled && cec_ctrl->cec_engine_configed)
+ hdmi_cec_write_logical_addr(cec_ctrl,
+ cec_ctrl->cec_logical_addr);
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return ret;
+} /* hdmi_wta_cec_logical_addr */
+
+static ssize_t hdmi_rda_cec_msg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i = 0;
+ unsigned long flags;
+ struct hdmi_cec_msg_node *msg_node, *tmp;
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid cec_ctrl\n", __func__);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+
+ if (cec_ctrl->compliance_response_enabled) {
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ DEV_ERR("%s: Read is disabled coz compliance response is on\n",
+ __func__);
+ return -EPERM;
+ }
+
+ if (list_empty_careful(&cec_ctrl->msg_head)) {
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ DEV_ERR("%s: CEC message queue is empty\n", __func__);
+ return -EPERM;
+ }
+
+ list_for_each_entry_safe(msg_node, tmp, &cec_ctrl->msg_head, list) {
+ if ((i+1) * sizeof(struct hdmi_cec_msg) > PAGE_SIZE) {
+ DEV_DBG("%s: Overflowing PAGE_SIZE.\n", __func__);
+ break;
+ }
+
+ memcpy(buf + (i * sizeof(struct hdmi_cec_msg)), &msg_node->msg,
+ sizeof(struct hdmi_cec_msg));
+ list_del(&msg_node->list);
+ kfree(msg_node);
+ i++;
+ }
+
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return i * sizeof(struct hdmi_cec_msg);
+} /* hdmi_rda_cec_msg */
+
+static ssize_t hdmi_wta_cec_msg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc;
+ unsigned long flags;
+ struct hdmi_cec_msg *msg = (struct hdmi_cec_msg *)buf;
+ struct hdmi_cec_ctrl *cec_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_CEC);
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid cec_ctrl\n", __func__);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ if (cec_ctrl->compliance_response_enabled) {
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+ DEV_ERR("%s: Write disabled coz compliance response is on.\n",
+ __func__);
+ return -EPERM;
+ }
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ rc = hdmi_cec_msg_send(cec_ctrl, msg);
+ if (rc) {
+ DEV_ERR("%s: hdmi_cec_msg_send failed\n", __func__);
+ return rc;
+ } else {
+ return sizeof(struct hdmi_cec_msg);
+ }
+} /* hdmi_wta_cec_msg */
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, hdmi_rda_cec_enable,
+ hdmi_wta_cec_enable);
+static DEVICE_ATTR(enable_compliance, S_IRUGO | S_IWUSR,
+ hdmi_rda_cec_enable_compliance, hdmi_wta_cec_enable_compliance);
+static DEVICE_ATTR(logical_addr, S_IRUGO | S_IWUSR,
+ hdmi_rda_cec_logical_addr, hdmi_wta_cec_logical_addr);
+static DEVICE_ATTR(rd_msg, S_IRUGO, hdmi_rda_cec_msg, NULL);
+static DEVICE_ATTR(wr_msg, S_IWUSR, NULL, hdmi_wta_cec_msg);
+
+static struct attribute *hdmi_cec_fs_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_enable_compliance.attr,
+ &dev_attr_logical_addr.attr,
+ &dev_attr_rd_msg.attr,
+ &dev_attr_wr_msg.attr,
+ NULL,
+};
+
+static struct attribute_group hdmi_cec_fs_attr_group = {
+ .name = "cec",
+ .attrs = hdmi_cec_fs_attrs,
+};
+
+int hdmi_cec_isr(void *input)
+{
+ int rc = 0;
+ u32 cec_intr, cec_status;
+ unsigned long flags;
+ struct dss_io_data *io = NULL;
+ struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
+
+ if (!cec_ctrl || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EPERM;
+ }
+
+ io = cec_ctrl->init_data.io;
+
+ if (!cec_ctrl->cec_enabled)
+ return 0;
+
+ cec_intr = DSS_REG_R_ND(io, HDMI_CEC_INT);
+ DEV_DBG("%s: cec interrupt status is [0x%x]\n", __func__, cec_intr);
+
+ cec_status = DSS_REG_R_ND(io, HDMI_CEC_STATUS);
+ DEV_DBG("%s: cec status is [0x%x]\n", __func__, cec_status);
+
+ if ((cec_intr & BIT(0)) && (cec_intr & BIT(1))) {
+ DEV_DBG("%s: CEC_IRQ_FRAME_WR_DONE\n", __func__);
+ DSS_REG_W(io, HDMI_CEC_INT, cec_intr | BIT(0));
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ cec_ctrl->cec_msg_wr_status |= CEC_STATUS_WR_DONE;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ if (!completion_done(&cec_ctrl->cec_msg_wr_done))
+ complete_all(&cec_ctrl->cec_msg_wr_done);
+ }
+
+ if ((cec_intr & BIT(2)) && (cec_intr & BIT(3))) {
+ DEV_DBG("%s: CEC_IRQ_FRAME_ERROR\n", __func__);
+ DSS_REG_W(io, HDMI_CEC_INT, cec_intr | BIT(2));
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ cec_ctrl->cec_msg_wr_status |= CEC_STATUS_WR_ERROR;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ if (!completion_done(&cec_ctrl->cec_msg_wr_done))
+ complete_all(&cec_ctrl->cec_msg_wr_done);
+ }
+
+ if ((cec_intr & BIT(6)) && (cec_intr & BIT(7))) {
+ DEV_DBG("%s: CEC_IRQ_FRAME_RD_DONE\n", __func__);
+
+ DSS_REG_W(io, HDMI_CEC_INT, cec_intr | BIT(6));
+ queue_work(cec_ctrl->init_data.workq, &cec_ctrl->cec_read_work);
+ }
+
+ return rc;
+} /* hdmi_cec_isr */
+
+int hdmi_cec_deconfig(void *input)
+{
+ unsigned long flags;
+ struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
+
+ if (!cec_ctrl) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EPERM;
+ }
+
+ hdmi_cec_disable(cec_ctrl);
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ cec_ctrl->cec_engine_configed = false;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return 0;
+} /* hdmi_cec_deconfig */
+
+int hdmi_cec_config(void *input)
+{
+ unsigned long flags;
+ u32 hdmi_hw_version;
+ struct dss_io_data *io = NULL;
+ struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
+
+ if (!cec_ctrl || !cec_ctrl->init_data.io) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ return -EPERM;
+ }
+
+ io = cec_ctrl->init_data.io;
+
+ /* 19.2Mhz * 0.00005 us = 950 = 0x3B6 */
+ DSS_REG_W(io, HDMI_CEC_REFTIMER, (0x3B6 & 0xFFF) | BIT(16));
+
+ hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION);
+ if (hdmi_hw_version == 0x30000001) {
+ DSS_REG_W(io, HDMI_CEC_RD_RANGE, 0x30AB9888);
+ DSS_REG_W(io, HDMI_CEC_WR_RANGE, 0x888AA888);
+
+ DSS_REG_W(io, HDMI_CEC_RD_START_RANGE, 0x88888888);
+ DSS_REG_W(io, HDMI_CEC_RD_TOTAL_RANGE, 0x99);
+ DSS_REG_W(io, HDMI_CEC_COMPL_CTL, 0xF);
+ DSS_REG_W(io, HDMI_CEC_WR_CHECK_CONFIG, 0x4);
+ } else {
+ DEV_INFO("%s: CEC is not supported on %d HDMI HW version.\n",
+ __func__, hdmi_hw_version);
+ return -EPERM;
+ }
+
+ DSS_REG_W(io, HDMI_CEC_RD_FILTER, BIT(0) | (0x7FF << 4));
+ DSS_REG_W(io, HDMI_CEC_TIME, BIT(0) | ((7 * 0x30) << 7));
+
+ if (cec_ctrl->cec_enabled)
+ hdmi_cec_enable(cec_ctrl);
+
+ spin_lock_irqsave(&cec_ctrl->lock, flags);
+ cec_ctrl->cec_engine_configed = true;
+ spin_unlock_irqrestore(&cec_ctrl->lock, flags);
+
+ return 0;
+} /* hdmi_cec_config */
+
+void hdmi_cec_deinit(void *input)
+{
+ struct hdmi_cec_msg_node *msg_node, *tmp;
+ struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
+
+ if (cec_ctrl) {
+ list_for_each_entry_safe(msg_node, tmp, &cec_ctrl->msg_head,
+ list) {
+ list_del(&msg_node->list);
+ kfree(msg_node);
+ }
+
+ sysfs_remove_group(cec_ctrl->init_data.sysfs_kobj,
+ &hdmi_cec_fs_attr_group);
+
+ kfree(cec_ctrl);
+ }
+} /* hdmi_cec_deinit */
+
+void *hdmi_cec_init(struct hdmi_cec_init_data *init_data)
+{
+ struct hdmi_cec_ctrl *cec_ctrl = NULL;
+
+ if (!init_data) {
+ DEV_ERR("%s: Invalid input\n", __func__);
+ goto error;
+ }
+
+ cec_ctrl = kzalloc(sizeof(*cec_ctrl), GFP_KERNEL);
+ if (!cec_ctrl) {
+ DEV_ERR("%s: FAILED: out of memory\n", __func__);
+ goto error;
+ }
+
+ cec_ctrl->init_data = *init_data;
+
+ if (sysfs_create_group(init_data->sysfs_kobj,
+ &hdmi_cec_fs_attr_group)) {
+ DEV_ERR("%s: cec sysfs group creation failed\n", __func__);
+ goto error;
+ }
+
+ spin_lock_init(&cec_ctrl->lock);
+ INIT_LIST_HEAD(&cec_ctrl->msg_head);
+ INIT_WORK(&cec_ctrl->cec_read_work, hdmi_cec_msg_recv);
+ init_completion(&cec_ctrl->cec_msg_wr_done);
+
+ goto exit;
+
+error:
+ kfree(cec_ctrl);
+ cec_ctrl = NULL;
+exit:
+ return (void *)cec_ctrl;
+} /* hdmi_cec_init */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.h b/drivers/video/msm/mdss/mdss_hdmi_cec.h
new file mode 100644
index 0000000..a554507
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MDSS_HDMI_CEC_H__
+#define __MDSS_HDMI_CEC_H__
+
+#include "mdss_hdmi_util.h"
+
+struct hdmi_cec_init_data {
+ struct workqueue_struct *workq;
+ struct kobject *sysfs_kobj;
+ struct dss_io_data *io;
+};
+
+int hdmi_cec_deconfig(void *cec_ctrl);
+int hdmi_cec_config(void *cec_ctrl);
+int hdmi_cec_isr(void *cec_ctrl);
+void hdmi_cec_deinit(void *cec_ctrl);
+void *hdmi_cec_init(struct hdmi_cec_init_data *init_data);
+#endif /* __MDSS_HDMI_CEC_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 66936e5..e28a4e9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -26,9 +26,10 @@
#include "mdss_debug.h"
#include "mdss_fb.h"
-#include "mdss_hdmi_tx.h"
+#include "mdss_hdmi_cec.h"
#include "mdss_hdmi_edid.h"
#include "mdss_hdmi_hdcp.h"
+#include "mdss_hdmi_tx.h"
#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_hdmi_mhl.h"
@@ -644,12 +645,14 @@
{
struct hdmi_edid_init_data edid_init_data;
struct hdmi_hdcp_init_data hdcp_init_data;
+ struct hdmi_cec_init_data cec_init_data;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
+ /* Initialize EDID feature */
edid_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
edid_init_data.mutex = &hdmi_ctrl->mutex;
edid_init_data.sysfs_kobj = hdmi_ctrl->kobj;
@@ -688,6 +691,17 @@
DEV_DBG("%s: HDCP feature initialized\n", __func__);
}
+
+ /* Initialize CEC feature */
+ cec_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ cec_init_data.sysfs_kobj = hdmi_ctrl->kobj;
+ cec_init_data.workq = hdmi_ctrl->workq;
+
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC] =
+ hdmi_cec_init(&cec_init_data);
+ if (!hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC])
+ DEV_WARN("%s: hdmi_cec_init failed\n", __func__);
+
return 0;
} /* hdmi_tx_init_features */
@@ -2169,6 +2183,8 @@
hdmi_ctrl->hpd_off_pending = false;
}
+ hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
+
mutex_lock(&hdmi_ctrl->mutex);
hdmi_ctrl->panel_power_on = false;
mutex_unlock(&hdmi_ctrl->mutex);
@@ -2253,10 +2269,12 @@
mutex_lock(&hdmi_ctrl->mutex);
hdmi_ctrl->panel_power_on = true;
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ hdmi_cec_config(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
if (hdmi_ctrl->hpd_state) {
DEV_DBG("%s: Turning HDMI on\n", __func__);
- mutex_unlock(&hdmi_ctrl->mutex);
rc = hdmi_tx_start(hdmi_ctrl);
if (rc) {
DEV_ERR("%s: hdmi_tx_start failed. rc=%d\n",
@@ -2264,8 +2282,6 @@
hdmi_tx_power_off(panel_data);
return rc;
}
- } else {
- mutex_unlock(&hdmi_ctrl->mutex);
}
dss_reg_dump(io->base, io->len, "HDMI-ON: ", REG_DUMP);
@@ -2345,6 +2361,10 @@
hdmi_ctrl->hpd_initialized = true;
+ DEV_INFO("%s: HDMI HW version = 0x%x\n", __func__,
+ DSS_REG_R_ND(&hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO],
+ HDMI_VERSION));
+
/* set timeout to 4.1ms (max) for hardware debounce */
reg_val = DSS_REG_R(io, HDMI_HPD_CTRL) | 0x1FFF;
@@ -2415,12 +2435,15 @@
queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_int_work);
}
- if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl) < 0)
+ if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__);
+ if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC])
+ if (hdmi_cec_isr(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]))
+ DEV_ERR("%s: hdmi_cec_isr failed\n", __func__);
+
if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP])
- if (hdmi_hdcp_isr(
- hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) < 0)
+ if (hdmi_hdcp_isr(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]))
DEV_ERR("%s: hdmi_hdcp_isr failed\n", __func__);
return IRQ_HANDLED;
@@ -2433,13 +2456,20 @@
return;
}
+ if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]) {
+ hdmi_cec_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC] = NULL;
+ }
+
if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]) {
hdmi_hdcp_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP] = NULL;
}
- if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID])
+ if (hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) {
hdmi_edid_deinit(hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]);
+ hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID] = NULL;
+ }
switch_dev_unregister(&hdmi_ctrl->audio_sdev);
switch_dev_unregister(&hdmi_ctrl->sdev);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index cf42346..e99e549 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -201,6 +201,11 @@
#define HDMI_TPG_INITIAL_VALUE (0x00000354)
#define HDMI_TPG_BLK_WHT_PATTERN_FRAMES (0x00000358)
#define HDMI_TPG_RGB_MAPPING (0x0000035C)
+#define HDMI_CEC_COMPL_CTL (0x00000360)
+#define HDMI_CEC_RD_START_RANGE (0x00000364)
+#define HDMI_CEC_RD_TOTAL_RANGE (0x00000368)
+#define HDMI_CEC_RD_ERR_RESP_LO (0x0000036C)
+#define HDMI_CEC_WR_CHECK_CONFIG (0x00000370)
/* HDMI PHY Registers */
#define HDMI_PHY_ANA_CFG0 (0x00000000)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 1ced200..fa53656 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -986,6 +986,19 @@
if (ret) {
pr_warn("error powering off intf ctl=%d\n", ctl->num);
} else {
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, 0);
+ if (sctl)
+ mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_TOP, 0);
+
+ if (ctl->mixer_left) {
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(
+ ctl->mixer_left->num), 0);
+ }
+ if (ctl->mixer_right) {
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(
+ ctl->mixer_right->num), 0);
+ }
+
ctl->power_on = false;
ctl->play_cnt = 0;
ctl->clk_rate = 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 4df66d0..25bb72f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -472,6 +472,7 @@
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
+ voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
return 0;
}