diff --git a/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi b/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi index 848606b6a11..fac381100a0 100644 --- a/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/apq8084-mdss.dtsi @@ -144,6 +144,7 @@ mdss_fb1: qcom,mdss_fb_external { cell-index = <1>; compatible = "qcom,mdss-fb"; + qcom,memblock-reserve = <0x05200000 0x01E00000>; }; mdss_fb2: qcom,mdss_fb_wfd { @@ -332,9 +333,8 @@ cell-index = <0>; compatible = "qcom,hdmi-tx"; reg = <0xfd922100 0x380>, - <0xfd922500 0x7C>, <0xfc4b8000 0x6100>; - reg-names = "core_physical", "phy_physical", "qfprom_physical"; + reg-names = "core_physical", "qfprom_physical"; hpd-gdsc-supply = <&gdsc_mdss>; hpd-5v-supply = <&pma8084_mvs1>; diff --git a/arch/arm/configs/apq8084-perf_defconfig b/arch/arm/configs/apq8084-perf_defconfig index a53f9492d55..ee0ca7974ab 100644 --- a/arch/arm/configs/apq8084-perf_defconfig +++ b/arch/arm/configs/apq8084-perf_defconfig @@ -188,6 +188,7 @@ CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NF_CONNTRACK_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig index 76b15d17cb7..d7c574c229d 100644 --- a/arch/arm/configs/apq8084_defconfig +++ b/arch/arm/configs/apq8084_defconfig @@ -190,6 +190,7 @@ CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NF_CONNTRACK_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y diff --git a/arch/arm/mach-msm/board-8084-gpiomux.c b/arch/arm/mach-msm/board-8084-gpiomux.c index b046e583cb3..d0a78e1b5bf 100644 --- a/arch/arm/mach-msm/board-8084-gpiomux.c +++ b/arch/arm/mach-msm/board-8084-gpiomux.c @@ -1278,7 +1278,7 @@ void __init apq8084_init_gpiomux(void) } else { msm_gpiomux_install(apq8084_hsic_configs, ARRAY_SIZE(apq8084_hsic_configs)); - msm_gpiomux_install(msm_hdmi_configs, + msm_gpiomux_install_nowrite(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs)); msm_gpiomux_install(hap_lvl_shft_config, ARRAY_SIZE(hap_lvl_shft_config)); @@ -1292,7 +1292,7 @@ void __init apq8084_init_gpiomux(void) msm_gpiomux_install(msm_sbc_sensor_configs, ARRAY_SIZE(msm_sbc_sensor_configs)); else - msm_gpiomux_install(msm_sensor_configs, + msm_gpiomux_install_nowrite(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs)); msm_gpiomux_install(msm_pcie_configs, ARRAY_SIZE(msm_pcie_configs)); msm_gpiomux_install(msm_epm_configs, ARRAY_SIZE(msm_epm_configs)); diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c index f5f77639852..1a1b97c5427 100644 --- a/arch/arm/mach-msm/clock-mdss-8974.c +++ b/arch/arm/mach-msm/clock-mdss-8974.c @@ -216,6 +216,8 @@ static void hdmi_vco_disable(struct clk *c) REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); udelay(5); REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG); + udelay(5); + REG_W(0x7F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); clk_disable(mdss_ahb_clk); @@ -253,7 +255,7 @@ static int hdmi_vco_enable(struct clk *c) REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); udelay(350); - /* PLL Power-Up */ + /* PLL Power-Up */ REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); udelay(350); @@ -479,9 +481,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0xF4, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -523,9 +536,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x2a, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0X1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); - REG_W(0X0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0XDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -567,9 +591,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x2A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x03, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -609,9 +644,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x8A, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -655,9 +701,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0xE6, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x02, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -698,9 +755,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x38, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x04, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -741,9 +809,19 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x3E, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -784,9 +862,20 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0xCD, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG10); REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_CAL_CFG11); REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); - udelay(50); + udelay(200); + + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL0); + udelay(200); + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -798,7 +887,7 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x1A, hdmi_phy_base + HDMI_PHY_DCC_CFG1); REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG0); REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG1); - REG_W(0x02, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2); + REG_W(0x3F, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2); REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3); udelay(200); break; @@ -812,7 +901,15 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) REG_W(0x1F, hdmi_phy_base + HDMI_PHY_PD_CTRL0); udelay(50); + REG_W(0x01, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x05, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x07, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); REG_W(0x0F, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG); + udelay(200); + REG_W(0x00, hdmi_phy_base + HDMI_PHY_PD_CTRL1); REG_W(0x10, hdmi_phy_base + HDMI_PHY_ANA_CFG2); REG_W(0xDB, hdmi_phy_base + HDMI_PHY_ANA_CFG0); @@ -838,18 +935,9 @@ static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) if (rate < 825000000) REG_W(0x01, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2); else - REG_W(0x00, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2); + REG_W(0x3F, hdmi_phy_base + HDMI_PHY_TXCAL_CFG2); REG_W(0x05, hdmi_phy_base + HDMI_PHY_TXCAL_CFG3); - REG_W(0x62, hdmi_phy_base + HDMI_PHY_BIST_PATN0); - REG_W(0x03, hdmi_phy_base + HDMI_PHY_BIST_PATN1); - REG_W(0x69, hdmi_phy_base + HDMI_PHY_BIST_PATN2); - REG_W(0x02, hdmi_phy_base + HDMI_PHY_BIST_PATN3); - - udelay(200); - - REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG1); - REG_W(0x00, hdmi_phy_base + HDMI_PHY_BIST_CFG0); } /* Make sure writes complete before disabling iface clock */ @@ -2810,6 +2898,7 @@ static struct clk_ops hdmi_mux_ops; static int hdmi_mux_prepare(struct clk *c) { int ret = 0; + ret = clk_prepare(mdss_ahb_clk); if (c && c->ops && c->ops->set_rate) ret = c->ops->set_rate(c, c->rate); diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h deleted file mode 100644 index 39730440872..00000000000 --- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2012-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 __MSM_HDMI_AUDIO_CODEC_H__ -#define __MSM_HDMI_AUDIO_CODEC_H__ - -#include -#include - -struct msm_hdmi_audio_edid_blk { - u8 *audio_data_blk; - unsigned int audio_data_blk_size; /* in bytes */ - u8 *spk_alloc_data_blk; - unsigned int spk_alloc_data_blk_size; /* in bytes */ -}; - -struct msm_hdmi_audio_codec_ops { - int (*audio_info_setup)(struct platform_device *pdev, - u32 sample_rate, u32 num_of_channels, - u32 channel_allocation, u32 level_shift, - bool down_mix); - int (*get_audio_edid_blk) (struct platform_device *pdev, - struct msm_hdmi_audio_edid_blk *blk); - int (*hdmi_cable_status) (struct platform_device *pdev, u32 vote); -}; - -int msm_hdmi_register_audio_codec(struct platform_device *pdev, - struct msm_hdmi_audio_codec_ops *ops); - -#endif /* __MSM_HDMI_AUDIO_CODEC_H__ */ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8120c059b24..708d87a5dca 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -433,6 +433,9 @@ static ssize_t store_##file_name \ if (ret) \ return -EINVAL; \ \ + new_policy.min = new_policy.user_policy.min; \ + new_policy.max = new_policy.user_policy.max; \ + \ ret = sscanf(buf, "%u", &new_policy.object); \ if (ret != 1) \ return -EINVAL; \ @@ -441,7 +444,9 @@ static ssize_t store_##file_name \ if (ret) \ pr_err("cpufreq: Frequency verification failed\n"); \ \ - policy->user_policy.object = new_policy.object; \ + policy->user_policy.min = new_policy.min; \ + policy->user_policy.max = new_policy.max; \ + \ ret = cpufreq_set_policy(policy, &new_policy); \ \ return ret ? ret : count; \ @@ -657,10 +662,15 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) { struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); - ssize_t ret; + ssize_t ret = -EINVAL; + + get_online_cpus(); + + if (!cpu_online(policy->cpu)) + goto unlock; if (!down_read_trylock(&cpufreq_rwsem)) - return -EINVAL; + goto unlock; down_read(&policy->rwsem); @@ -671,7 +681,8 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) up_read(&policy->rwsem); up_read(&cpufreq_rwsem); - +unlock: + put_online_cpus(); return ret; } @@ -1270,10 +1281,10 @@ static int __cpufreq_remove_dev_finish(struct device *dev, unsigned long flags; struct cpufreq_policy *policy; - read_lock_irqsave(&cpufreq_driver_lock, flags); + write_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); per_cpu(cpufreq_cpu_data, cpu) = NULL; - read_unlock_irqrestore(&cpufreq_driver_lock, flags); + write_unlock_irqrestore(&cpufreq_driver_lock, flags); if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); @@ -1439,14 +1450,22 @@ EXPORT_SYMBOL(cpufreq_quick_get_max); static unsigned int __cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); + struct cpufreq_policy *policy; unsigned int ret_freq = 0; + unsigned long flags; if (!cpufreq_driver->get) return ret_freq; + read_lock_irqsave(&cpufreq_driver_lock, flags); + policy = per_cpu(cpufreq_cpu_data, cpu); + read_unlock_irqrestore(&cpufreq_driver_lock, flags); + ret_freq = cpufreq_driver->get(cpu); + if (!policy) + return ret_freq; + if (ret_freq && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { /* verify no discrepancy between actual and @@ -1468,12 +1487,17 @@ static unsigned int __cpufreq_get(unsigned int cpu) */ unsigned int cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); + struct cpufreq_policy *policy; unsigned int ret_freq = 0; + unsigned long flags; if (cpufreq_disabled() || !cpufreq_driver) return -ENOENT; + read_lock_irqsave(&cpufreq_driver_lock, flags); + policy = per_cpu(cpufreq_cpu_data, cpu); + read_unlock_irqrestore(&cpufreq_driver_lock, flags); + BUG_ON(!policy); if (!down_read_trylock(&cpufreq_rwsem)) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index bcf55559067..c4c0578fd4b 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -35,8 +35,6 @@ #define MAX_INIT_FRAME_DROP 31 #define ISP_Q2 (1 << 2) -#define AVTIMER_ITERATION_CTR 16 - #define VFE_PING_FLAG 0xFFFFFFFF #define VFE_PONG_FLAG 0x0 @@ -481,8 +479,6 @@ struct vfe_device { int vfe_clk_idx; uint32_t vfe_open_cnt; uint8_t vt_enable; - void __iomem *p_avtimer_msw; - void __iomem *p_avtimer_lsw; uint8_t ignore_error; }; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 4de3008c89a..9c37b734990 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -222,40 +222,38 @@ static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp) do_gettimeofday(&(time_stamp->event_time)); } -static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev, - struct msm_isp_timestamp *time_stamp) +#ifdef CONFIG_MSM_AVTIMER +static inline void msm_isp_get_avtimer_ts( + struct msm_isp_timestamp *time_stamp) { - uint64_t avtimer_msw_1st = 0, avtimer_lsw = 0; - uint64_t avtimer_msw_2nd = 0; - uint64_t avtimer_usec = 0; - uint64_t avtimer_sec = 0; - uint64_t vt_timestamp; - uint8_t iter = 0; - if (!vfe_dev->vfe_avtimer_base) { - pr_err("%s: ioremap failed\n", __func__); - return; - } - do { - avtimer_msw_1st = msm_camera_io_r(vfe_dev->vfe_avtimer_base + - VFE_AVTIMER_MSW); - avtimer_lsw = msm_camera_io_r(vfe_dev->vfe_avtimer_base + - VFE_AVTIMER_LSW); - avtimer_msw_2nd = msm_camera_io_r(vfe_dev->vfe_avtimer_base + - VFE_AVTIMER_MSW); - } while ((avtimer_msw_1st != avtimer_msw_2nd) - && (iter++ < AVTIMER_ITERATION_CTR)); - if (iter >= AVTIMER_ITERATION_CTR) { - pr_err("%s: AVTimer MSW TS did not converge !!!\n", __func__); - return; + int rc = 0; + uint32_t avtimer_usec = 0; + uint64_t avtimer_tick = 0; + + rc = avcs_core_query_timer(&avtimer_tick); + if (rc < 0) { + pr_err("%s: Error: Invalid AVTimer Tick, rc=%d\n", + __func__, rc); + /*In case of error return zero AVTimer Tick Value*/ + time_stamp->vt_time.tv_sec = 0; + time_stamp->vt_time.tv_usec = 0; + } else { + avtimer_usec = do_div(avtimer_tick, USEC_PER_SEC); + time_stamp->vt_time.tv_sec = (uint32_t)(avtimer_tick); + time_stamp->vt_time.tv_usec = avtimer_usec; + pr_debug("%s: AVTimer TS = %u:%u\n", __func__, + (uint32_t)(avtimer_tick), avtimer_usec); } - vt_timestamp = avtimer_msw_1st << 32 | avtimer_lsw; - avtimer_usec = do_div(vt_timestamp, USEC_PER_SEC * - AVTIMER_TICK_RES_PER_USEC); - avtimer_sec = vt_timestamp; - do_div(avtimer_usec, AVTIMER_TICK_RES_PER_USEC); - time_stamp->vt_time.tv_sec = (uint32_t)avtimer_sec; - time_stamp->vt_time.tv_usec = (uint32_t)avtimer_usec; } +#else +static inline void msm_isp_get_avtimer_ts( + struct msm_isp_timestamp *time_stamp) +{ + pr_err("%s: Error: AVTimer driver not available\n", __func__); + time_stamp->vt_time.tv_sec = 0; + time_stamp->vt_time.tv_usec = 0; +} +#endif int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub) @@ -554,28 +552,95 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, cmd_len); return -EINVAL; } + + /* Validate input parameters */ switch (reg_cfg_cmd->cmd_type) { - case VFE_WRITE: { - if (reg_cfg_cmd->u.rw_info.reg_offset < - resource_size(vfe_dev->vfe_mem)) { - uint32_t diff = 0; - diff = resource_size(vfe_dev->vfe_mem) - - reg_cfg_cmd->u.rw_info.reg_offset; - if (diff < reg_cfg_cmd->u.rw_info.len) { - pr_err("%s: VFE_WRITE: Invalid length\n", - __func__); + case VFE_WRITE: + case VFE_READ: + case VFE_WRITE_MB: { + if ((reg_cfg_cmd->u.rw_info.reg_offset > + (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || + ((reg_cfg_cmd->u.rw_info.reg_offset + + reg_cfg_cmd->u.rw_info.len) > + resource_size(vfe_dev->vfe_mem))) { + pr_err("%s:%d reg_offset %d len %d res %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.rw_info.reg_offset, + reg_cfg_cmd->u.rw_info.len, + (uint32_t)resource_size(vfe_dev->vfe_mem)); + return -EINVAL; + } + + if ((reg_cfg_cmd->u.rw_info.cmd_data_offset > + (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) || + ((reg_cfg_cmd->u.rw_info.cmd_data_offset + + reg_cfg_cmd->u.rw_info.len) > cmd_len)) { + pr_err("%s:%d cmd_data_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.rw_info.cmd_data_offset, + reg_cfg_cmd->u.rw_info.len, cmd_len); + return -EINVAL; + } + break; + } + + case VFE_WRITE_DMI_16BIT: + case VFE_WRITE_DMI_32BIT: + case VFE_WRITE_DMI_64BIT: + case VFE_READ_DMI_16BIT: + case VFE_READ_DMI_32BIT: + case VFE_READ_DMI_64BIT: { + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { + if ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset <= + reg_cfg_cmd->u.dmi_info.lo_tbl_offset) || + (reg_cfg_cmd->u.dmi_info.hi_tbl_offset - + reg_cfg_cmd->u.dmi_info.lo_tbl_offset != + (sizeof(uint32_t)))) { + pr_err("%s:%d hi %d lo %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset); + return -EINVAL; + } + if (reg_cfg_cmd->u.dmi_info.len <= sizeof(uint32_t)) { + pr_err("%s:%d len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.len); + return -EINVAL; + } + if (((UINT_MAX - + reg_cfg_cmd->u.dmi_info.hi_tbl_offset) < + (reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t))) || + ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset + + reg_cfg_cmd->u.dmi_info.len - + sizeof(uint32_t)) > cmd_len)) { + pr_err("%s:%d hi_tbl_offset %d len %d cmd %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.hi_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); return -EINVAL; } - } else { - pr_err("%s: VFE_WRITE: Invalid length\n", __func__); - return -EINVAL; } - if (resource_size(vfe_dev->vfe_mem) < - (reg_cfg_cmd->u.rw_info.reg_offset + - reg_cfg_cmd->u.rw_info.len)) { - pr_err("%s: VFE_WRITE: Invalid length\n", __func__); + if ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset > + (UINT_MAX - reg_cfg_cmd->u.dmi_info.len)) || + ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset + + reg_cfg_cmd->u.dmi_info.len) > cmd_len)) { + pr_err("%s:%d lo_tbl_offset %d len %d cmd_len %d\n", + __func__, __LINE__, + reg_cfg_cmd->u.dmi_info.lo_tbl_offset, + reg_cfg_cmd->u.dmi_info.len, cmd_len); return -EINVAL; } + break; + } + + default: + break; + } + + switch (reg_cfg_cmd->cmd_type) { + case VFE_WRITE: { msm_camera_io_memcpy(vfe_dev->vfe_base + reg_cfg_cmd->u.rw_info.reg_offset, cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, @@ -583,39 +648,27 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, break; } case VFE_WRITE_MB: { - uint32_t *data_ptr = cfg_data + - reg_cfg_cmd->u.rw_info.cmd_data_offset/4; - - if ((UINT_MAX - sizeof(*data_ptr) < - reg_cfg_cmd->u.rw_info.reg_offset) || - (resource_size(vfe_dev->vfe_mem) < - reg_cfg_cmd->u.rw_info.reg_offset + - sizeof(*data_ptr))) { - pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__); - return -EINVAL; - } - msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base + - reg_cfg_cmd->u.rw_info.reg_offset); + msm_camera_io_memcpy_mb(vfe_dev->vfe_base + + reg_cfg_cmd->u.rw_info.reg_offset, + cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4, + reg_cfg_cmd->u.rw_info.len); break; } case VFE_CFG_MASK: { uint32_t temp; - if (resource_size(vfe_dev->vfe_mem) < - reg_cfg_cmd->u.mask_info.reg_offset) - return -EINVAL; - temp = msm_camera_io_r(vfe_dev->vfe_base + - reg_cfg_cmd->u.mask_info.reg_offset); - - temp &= ~reg_cfg_cmd->u.mask_info.mask; - temp |= reg_cfg_cmd->u.mask_info.val; if ((UINT_MAX - sizeof(temp) < - reg_cfg_cmd->u.mask_info.reg_offset) || + reg_cfg_cmd->u.mask_info.reg_offset) || (resource_size(vfe_dev->vfe_mem) < reg_cfg_cmd->u.mask_info.reg_offset + sizeof(temp))) { pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__); return -EINVAL; } + temp = msm_camera_io_r(vfe_dev->vfe_base + + reg_cfg_cmd->u.mask_info.reg_offset); + + temp &= ~reg_cfg_cmd->u.mask_info.mask; + temp |= reg_cfg_cmd->u.mask_info.val; msm_camera_io_w(temp, vfe_dev->vfe_base + reg_cfg_cmd->u.mask_info.reg_offset); break; @@ -627,22 +680,9 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; uint32_t hi_val, lo_val, lo_val1; if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { - if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset < - reg_cfg_cmd->u.dmi_info.len) || - (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len)) { - pr_err("Invalid Hi Table out of bounds\n"); - return -EINVAL; - } hi_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; } - - if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Lo Table out of bounds\n"); - return -EINVAL; - } lo_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) @@ -675,31 +715,18 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL; uint32_t hi_val, lo_val, lo_val1; if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { - if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Hi Table out of bounds\n"); - return -EINVAL; - } hi_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4; } - if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset + - reg_cfg_cmd->u.dmi_info.len > cmd_len) { - pr_err("Invalid Lo Table out of bounds\n"); - return -EINVAL; - } lo_tbl_ptr = cfg_data + reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4; - for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { - hi_val = msm_camera_io_r(vfe_dev->vfe_base + - vfe_dev->hw_info->dmi_reg_offset); - *hi_tbl_ptr = hi_val; - hi_tbl_ptr += 2; - } + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) + reg_cfg_cmd->u.dmi_info.len = + reg_cfg_cmd->u.dmi_info.len / 2; + for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) { lo_val = msm_camera_io_r(vfe_dev->vfe_base + vfe_dev->hw_info->dmi_reg_offset + 0x4); @@ -709,8 +736,13 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, lo_val |= lo_val1 << 16; } *lo_tbl_ptr++ = lo_val; - if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) + if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { + hi_val = msm_camera_io_r(vfe_dev->vfe_base + + vfe_dev->hw_info->dmi_reg_offset); + *hi_tbl_ptr = hi_val; + hi_tbl_ptr += 2; lo_tbl_ptr++; + } } break; } @@ -722,7 +754,7 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, if ((data_ptr < cfg_data) || (UINT_MAX / sizeof(*data_ptr) < (data_ptr - cfg_data)) || - (sizeof(*data_ptr) * (data_ptr - cfg_data) > + (sizeof(*data_ptr) * (data_ptr - cfg_data) >= cmd_len)) return -EINVAL; *data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base + @@ -1231,7 +1263,7 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data) queue_cmd->vfeInterruptStatus1 = irq_status1; msm_isp_get_timestamp(&queue_cmd->ts); if (vfe_dev->vt_enable) - msm_isp_get_vt_tstamp(vfe_dev, &queue_cmd->ts); + msm_isp_get_avtimer_ts(&queue_cmd->ts); queue_cmd->cmd_used = 1; vfe_dev->taskletq_idx = (vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 626724c4af6..310bf93bc3e 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -699,9 +699,20 @@ static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif, rc = -EPERM; return rc; } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } for (i = 0; i < params->num; i++) { vfe_intf = params->entries[i].vfe_intf; + if (vfe_intf >= VFE_MAX) { + pr_err("%s: %d invalid i %d vfe_intf %d\n", __func__, + __LINE__, i, vfe_intf); + return -EINVAL; + } vfe_mask |= (1 << vfe_intf); } diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index 70055b0ae51..54890a65a89 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -51,6 +51,14 @@ static int msm_csid_cid_lut( return -EINVAL; } for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) { + if (csid_lut_params->vc_cfg[i]->cid >= + csid_lut_params->num_cid || + csid_lut_params->vc_cfg[i]->cid < 0) { + pr_err("%s: cid outside range %d\n", + __func__, csid_lut_params->vc_cfg[i]->cid); + return -EINVAL; + } + CDBG("%s lut params num_cid = %d, cid = %d\n", __func__, csid_lut_params->num_cid, diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c index dae20d66131..3b101cc513c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c @@ -107,6 +107,17 @@ void msm_camera_io_memcpy(void __iomem *dest_addr, msm_camera_io_dump(dest_addr, len); } +void msm_camera_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, u32 len) +{ + int i; + u32 *d = (u32 *) dest_addr; + u32 *s = (u32 *) src_addr; + + for (i = 0; i < (len / 4); i++) + msm_camera_io_w_mb(*s++, d++); +} + int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, struct msm_cam_clk_info *clk_src_info, int num_clk) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h index 0b71cd6e0a2..2074a1d4b7f 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h @@ -28,6 +28,8 @@ u32 msm_camera_io_r_mb(void __iomem *addr); void msm_camera_io_dump(void __iomem *addr, int size); void msm_camera_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len); +void msm_camera_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, u32 len); int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info, struct msm_cam_clk_info *clk_src_info, int num_clk); int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info, diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 6ce87a930be..143ede9f3b3 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -397,6 +397,14 @@ int32_t msm_sensor_driver_probe(void *setting) } size = slave_info->power_setting_array.size; + + /* Validate size */ + if (size > MAX_POWER_CONFIG) { + pr_err("failed: invalid number of power_up_setting %d\n", size); + rc = -EINVAL; + goto FREE_SLAVE_INFO; + } + /* Allocate memory for power up setting */ power_setting = kzalloc(sizeof(*power_setting) * size, GFP_KERNEL); if (!power_setting) { @@ -423,6 +431,12 @@ int32_t msm_sensor_driver_probe(void *setting) size_down = slave_info->power_setting_array.size_down; if (!size_down) size_down = size; + /* Validate size_down */ + if (size_down > MAX_POWER_CONFIG) { + pr_err("failed: invalid size_down %d", size_down); + rc = -EINVAL; + goto FREE_POWER_SETTING; + } /* Allocate memory for power down setting */ power_down_setting = kzalloc(sizeof(*power_setting) * size_down, GFP_KERNEL); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index f63edd4162f..7754ae2aab1 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -958,9 +958,23 @@ static int msm_venc_queue_setup(struct vb2_queue *q, } hdev = inst->core->device; + rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); + if (rc) { + dprintk(VIDC_ERR, "Failed to open instance\n"); + return rc; + } + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to get buffer requirements: %d\n", rc); + return rc; + } + switch (q->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: *num_planes = 1; + buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); if (buff_req) { *num_buffers = buff_req->buffer_count_actual = @@ -988,9 +1002,18 @@ static int msm_venc_queue_setup(struct vb2_queue *q, inst->fmts[CAPTURE_PORT]->num_planes = *num_planes; for (i = 0; i < *num_planes; i++) { + int extra_idx = EXTRADATA_IDX(*num_planes); + sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size( i, inst->prop.height[CAPTURE_PORT], inst->prop.width[CAPTURE_PORT]); + + if (extra_idx && i == extra_idx && + extra_idx < VIDEO_MAX_PLANES) { + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_OUTPUT); + sizes[i] = buff_req_buffer->buffer_size; + } } property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL; @@ -1000,26 +1023,18 @@ static int msm_venc_queue_setup(struct vb2_queue *q, property_id, &new_buf_count); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); - if (rc) { - dprintk(VIDC_ERR, "Failed to open instance\n"); - break; - } - rc = msm_comm_try_get_bufreqs(inst); - if (rc) { - dprintk(VIDC_ERR, - "Failed to get buffer requirements: %d\n", rc); - break; - } *num_planes = 1; + mutex_lock(&inst->lock); *num_buffers = inst->buff_req.buffer[0].buffer_count_actual = max(*num_buffers, inst->buff_req.buffer[0]. buffer_count_actual); mutex_unlock(&inst->lock); + property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL; new_buf_count.buffer_type = HAL_BUFFER_INPUT; new_buf_count.buffer_count_actual = *num_buffers; + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA); if (ctrl) @@ -1027,6 +1042,7 @@ static int msm_venc_queue_setup(struct vb2_queue *q, if (extradata == V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) *num_planes = *num_planes + 1; inst->fmts[OUTPUT_PORT]->num_planes = *num_planes; + rc = call_hfi_op(hdev, session_set_property, inst->session, property_id, &new_buf_count); dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n", @@ -1036,15 +1052,15 @@ static int msm_venc_queue_setup(struct vb2_queue *q, sizes[0] = inst->fmts[OUTPUT_PORT]->get_frame_size( 0, inst->prop.height[OUTPUT_PORT], inst->prop.width[OUTPUT_PORT]); + extra_idx = EXTRADATA_IDX(inst->fmts[OUTPUT_PORT]->num_planes); if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { buff_req_buffer = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_INPUT); - sizes[extra_idx] = - buff_req_buffer ? - buff_req_buffer->buffer_size : 0; + sizes[extra_idx] = buff_req_buffer->buffer_size; } + break; default: dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type); diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 86d67672806..91820365216 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -79,16 +79,6 @@ struct tzbsp_video_set_state_req { u32 spare; /*reserved for future, should be zero*/ }; -#define VENUS_SET_STATE(__device, __state) {\ - mutex_lock(&(__device)->write_lock); \ - mutex_lock(&(__device)->read_lock); \ - (__device)->state = __state; \ - mutex_unlock(&(__device)->write_lock); \ - mutex_unlock(&(__device)->read_lock); } - -#define IS_VENUS_IN_VALID_STATE(__device) (\ - (__device)->state != VENUS_STATE_DEINIT) - static void venus_hfi_pm_hndlr(struct work_struct *work); static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr); @@ -102,6 +92,22 @@ static inline int venus_hfi_prepare_enable_clks( static inline void venus_hfi_disable_unprepare_clks( struct venus_hfi_device *device); +static inline void venus_hfi_set_state(struct venus_hfi_device *device, + enum venus_hfi_state state) +{ + mutex_lock(&device->write_lock); + mutex_lock(&device->read_lock); + device->state = state; + mutex_unlock(&device->write_lock); + mutex_unlock(&device->read_lock); +} + +static inline bool venus_hfi_core_in_valid_state( + struct venus_hfi_device *device) +{ + return device->state != VENUS_STATE_DEINIT; +} + static void venus_hfi_dump_packet(u8 *packet) { u32 c = 0, packet_size = *(u32 *)packet; @@ -1252,6 +1258,18 @@ static int __unset_free_ocmem(struct venus_hfi_device *device) if (!device->res->ocmem_size) return rc; + mutex_lock(&device->write_lock); + mutex_lock(&device->read_lock); + rc = venus_hfi_core_in_valid_state(device); + mutex_unlock(&device->read_lock); + mutex_unlock(&device->write_lock); + + if (!rc) { + dprintk(VIDC_WARN, + "Core is in bad state, Skipping unset OCMEM\n"); + goto core_in_bad_state; + } + init_completion(&release_resources_done); rc = __unset_ocmem(device); if (rc) { @@ -1268,6 +1286,7 @@ static int __unset_free_ocmem(struct venus_hfi_device *device) goto release_resources_failed; } +core_in_bad_state: rc = __free_ocmem(device); if (rc) { dprintk(VIDC_ERR, "Failed to free OCMEM during PC\n"); @@ -1626,7 +1645,7 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device, WARN(!mutex_is_locked(&device->write_lock), "Cmd queue write lock must be acquired"); - if (!IS_VENUS_IN_VALID_STATE(device)) { + if (!venus_hfi_core_in_valid_state(device)) { dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__); result = -EINVAL; goto err_q_null; @@ -1695,8 +1714,8 @@ static int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt) return -EINVAL; } mutex_lock(&device->read_lock); - if (!IS_VENUS_IN_VALID_STATE(device)) { - dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__); + if (!venus_hfi_core_in_valid_state(device)) { + dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__); rc = -EINVAL; goto read_error_null; } @@ -1736,8 +1755,8 @@ static int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt) return -EINVAL; } mutex_lock(&device->read_lock); - if (!IS_VENUS_IN_VALID_STATE(device)) { - dprintk(VIDC_ERR, "%s - fw not in init state\n", __func__); + if (!venus_hfi_core_in_valid_state(device)) { + dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__); rc = -EINVAL; goto dbg_error_null; } @@ -2096,7 +2115,7 @@ static int venus_hfi_core_init(void *device) return -ENODEV; } - VENUS_SET_STATE(dev, VENUS_STATE_INIT); + venus_hfi_set_state(dev, VENUS_STATE_INIT); dev->intr_status = 0; INIT_LIST_HEAD(&dev->sess_head); @@ -2150,7 +2169,7 @@ static int venus_hfi_core_init(void *device) return rc; err_core_init: - VENUS_SET_STATE(dev, VENUS_STATE_DEINIT); + venus_hfi_set_state(dev, VENUS_STATE_DEINIT); disable_irq_nosync(dev->hal_data->irq); return rc; } @@ -2187,7 +2206,7 @@ static int venus_hfi_core_release(void *device) disable_irq_nosync(dev->hal_data->irq); dev->intr_status = 0; } - VENUS_SET_STATE(dev, VENUS_STATE_DEINIT); + venus_hfi_set_state(dev, VENUS_STATE_DEINIT); dprintk(VIDC_INFO, "HAL exited\n"); return 0; @@ -2898,6 +2917,19 @@ static void venus_hfi_pm_hndlr(struct work_struct *work) __func__); return; } + + mutex_lock(&device->write_lock); + mutex_lock(&device->read_lock); + rc = venus_hfi_core_in_valid_state(device); + mutex_unlock(&device->read_lock); + mutex_unlock(&device->write_lock); + + if (!rc) { + dprintk(VIDC_WARN, + "Core is in bad state, Skipping power collapse\n"); + return; + } + dprintk(VIDC_DBG, "Prepare for power collapse\n"); mutex_lock(&device->resource_lock); @@ -2990,6 +3022,9 @@ static void venus_hfi_process_msg_event_notify( (struct hfi_msg_event_notify_packet *)msg_hdr; if (event_pkt && event_pkt->event_id == HFI_EVENT_SYS_ERROR) { + + venus_hfi_set_state(device, VENUS_STATE_DEINIT); + vsfr = (struct hfi_sfr_struct *) device->sfr.align_virtual_addr; if (vsfr) { diff --git a/drivers/net/wireless/wcnss/wcnss_prealloc.c b/drivers/net/wireless/wcnss/wcnss_prealloc.c index d9ec8f20879..69cb556bfc3 100644 --- a/drivers/net/wireless/wcnss/wcnss_prealloc.c +++ b/drivers/net/wireless/wcnss/wcnss_prealloc.c @@ -87,6 +87,8 @@ static struct wcnss_prealloc wcnss_allocs[] = { {0, 32 * 1024, NULL}, {0, 64 * 1024, NULL}, {0, 64 * 1024, NULL}, + {0, 64 * 1024, NULL}, + {0, 64 * 1024, NULL}, {0, 76 * 1024, NULL}, }; diff --git a/drivers/usb/host/xhci-msm-hsic.c b/drivers/usb/host/xhci-msm-hsic.c index 9062c199c89..6e1f84d5702 100644 --- a/drivers/usb/host/xhci-msm-hsic.c +++ b/drivers/usb/host/xhci-msm-hsic.c @@ -1132,7 +1132,8 @@ static irqreturn_t mxhci_irq(struct usb_hcd *hcd) } spin_unlock(&xhci->lock); - tasklet_schedule(&mxhci->bh); + if (!mxhci->xhci_remove_flag) + tasklet_schedule(&mxhci->bh); return IRQ_HANDLED; } diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h index 68ed8be352c..b8c35122f59 100644 --- a/drivers/video/msm/mdss/mdss.h +++ b/drivers/video/msm/mdss/mdss.h @@ -128,6 +128,7 @@ struct mdss_data_type { u32 irq_mask; u32 irq_ena; u32 irq_buzy; + bool irq_wakeup_en; u32 has_bwc; u32 has_decimation; u32 wfd_mode; @@ -238,6 +239,7 @@ void mdss_disable_irq_nosync(struct mdss_hw *hw); void mdss_bus_bandwidth_ctrl(int enable); int mdss_iommu_ctrl(int enable); int mdss_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota); +void mdss_enable_irq_wake(bool enable); static inline struct ion_client *mdss_get_ionclient(void) { diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c index 5f54e57f495..60d4728cf3c 100644 --- a/drivers/video/msm/mdss/mdss_dsi.c +++ b/drivers/video/msm/mdss/mdss_dsi.c @@ -1617,6 +1617,8 @@ int dsi_panel_device_register(struct device_node *pan_node, pinfo->panel_power_state = MDSS_PANEL_POWER_OFF; } + pinfo->is_prim_panel = true; + rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data)); if (rc) { pr_err("%s: unable to register MIPI DSI panel\n", __func__); diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c index af553c62183..86b420c8840 100644 --- a/drivers/video/msm/mdss/mdss_edp.c +++ b/drivers/video/msm/mdss/mdss_edp.c @@ -795,6 +795,7 @@ static int mdss_edp_device_register(struct mdss_edp_drv_pdata *edp_drv) edp_drv->panel_data.panel_info.cont_splash_enabled = edp_drv->cont_splash; + edp_drv->panel_data.panel_info.is_prim_panel = true; ret = mdss_register_panel(edp_drv->pdev, &edp_drv->panel_data); if (ret) { diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index 5150339877d..05230162111 100644 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -3291,6 +3291,13 @@ int mdss_register_panel(struct platform_device *pdev, goto mdss_notfound; } + if (pdata && !pdata->panel_info.is_prim_panel && + !fbi_list_index) { + pr_err("%s %d panel deferred, first panel not prim\n", + __func__, pdata->panel_info.type); + return -EPROBE_DEFER; + } + fb_pdev = of_find_device_by_node(node); if (fb_pdev) { rc = mdss_fb_register_extra_panel(fb_pdev, pdata); @@ -3371,7 +3378,7 @@ module_init(mdss_fb_init); int mdss_fb_suspres_panel(struct device *dev, void *data) { struct msm_fb_data_type *mfd; - int rc; + int rc = 0; u32 event; if (!data) { @@ -3384,10 +3391,14 @@ int mdss_fb_suspres_panel(struct device *dev, void *data) event = *((bool *) data) ? MDSS_EVENT_RESUME : MDSS_EVENT_SUSPEND; - rc = mdss_fb_send_panel_event(mfd, event, NULL); - if (rc) - pr_warn("unable to %s fb%d (%d)\n", - event == MDSS_EVENT_RESUME ? "resume" : "suspend", - mfd->index, rc); + /* Do not send runtime suspend/resume for HDMI primary */ + if (!mdss_fb_is_hdmi_primary(mfd)) { + rc = mdss_fb_send_panel_event(mfd, event, NULL); + if (rc) + pr_warn("unable to %s fb%d (%d)\n", + event == MDSS_EVENT_RESUME ? + "resume" : "suspend", + mfd->index, rc); + } return rc; } diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h index d94e170b889..10b2158766c 100644 --- a/drivers/video/msm/mdss/mdss_fb.h +++ b/drivers/video/msm/mdss/mdss_fb.h @@ -300,6 +300,12 @@ static inline bool mdss_fb_is_power_on_lp(struct msm_fb_data_type *mfd) return mdss_panel_is_power_on_lp(mfd->panel_power_state); } +static inline bool mdss_fb_is_hdmi_primary(struct msm_fb_data_type *mfd) +{ + return (mfd && (mfd->index == 0) && + (mfd->panel_info->type == DTV_PANEL)); +} + int mdss_fb_get_phys_info(dma_addr_t *start, unsigned long *len, int fb_num); void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl); void mdss_fb_update_backlight(struct msm_fb_data_type *mfd); diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c index f3fd06e5352..323ef9f1928 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_cec.c +++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "mdss_hdmi_cec.h" @@ -25,6 +26,10 @@ #define RETRANSMIT_MAX_NUM 5 #define MAX_OPERAND_SIZE 15 +#define CEC_OP_SET_STREAM_PATH 0x86 +#define CEC_OP_KEY_PRESS 0x44 +#define CEC_OP_STANDBY 0x36 + /* * Ref. HDMI 1.4a: Supplement-1 CEC Section 6, 7 */ @@ -46,6 +51,8 @@ struct hdmi_cec_ctrl { bool cec_enabled; bool compliance_response_enabled; bool cec_engine_configed; + bool cec_wakeup_en; + bool tx_power_on; u8 cec_logical_addr; u32 cec_msg_wr_status; @@ -55,6 +62,7 @@ struct hdmi_cec_ctrl { struct work_struct cec_read_work; struct completion cec_msg_wr_done; struct hdmi_cec_init_data init_data; + struct input_dev *input; }; static int hdmi_cec_msg_send(struct hdmi_cec_ctrl *cec_ctrl, @@ -73,24 +81,25 @@ static void hdmi_cec_dump_msg(struct hdmi_cec_ctrl *cec_ctrl, } spin_lock_irqsave(&cec_ctrl->lock, flags); - DEV_DBG("=================%pS dump start =====================\n", + 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); + DEV_DBG("cec sender_id: %d\n", msg->sender_id); + DEV_DBG("cec recvr_id: %d\n", msg->recvr_id); if (msg->frame_size < 2) { - DEV_DBG("polling message"); + DEV_DBG("polling message\n"); spin_unlock_irqrestore(&cec_ctrl->lock, flags); return; } - DEV_DBG("opcode : %02x", msg->opcode); + DEV_DBG("cec opcode: %02x\n", msg->opcode); for (i = 0; i < msg->frame_size - 2; i++) - DEV_DBG("operand(%2d) : %02x", i + 1, msg->operand[i]); + DEV_DBG("cec operand(%2d) : %02x\n", i + 1, msg->operand[i]); - DEV_DBG("=================%pS dump end =====================\n", + DEV_DBG("==%pS dump end ==\n", __builtin_return_address(0)); + spin_unlock_irqrestore(&cec_ctrl->lock, flags); } /* hdmi_cec_dump_msg */ @@ -171,7 +180,6 @@ static int hdmi_cec_send_abort_opcode(struct hdmi_cec_ctrl *cec_ctrl, 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 */ @@ -311,7 +319,7 @@ static int hdmi_cec_msg_parser(struct hdmi_cec_ctrl *cec_ctrl, static int hdmi_cec_msg_send(struct hdmi_cec_ctrl *cec_ctrl, struct hdmi_cec_msg *msg) { - int i, line_check_retry = 10; + int i, line_check_retry = 10, rc = 0; u32 frame_retransmit = RETRANSMIT_MAX_NUM; bool frame_type; unsigned long flags; @@ -375,17 +383,53 @@ static int hdmi_cec_msg_send(struct hdmi_cec_ctrl *cec_ctrl, } spin_lock_irqsave(&cec_ctrl->lock, flags); - if (cec_ctrl->cec_msg_wr_status == CEC_STATUS_WR_ERROR) + if (cec_ctrl->cec_msg_wr_status == CEC_STATUS_WR_ERROR) { + rc = -ENXIO; DEV_ERR("%s: msg write failed.\n", __func__); - else + } 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; + return rc; } /* hdmi_cec_msg_send */ +static void hdmi_cec_init_input_event(struct hdmi_cec_ctrl *cec_ctrl) +{ + int rc = 0; + + /* Initialize CEC input events */ + if (!cec_ctrl->input) + cec_ctrl->input = input_allocate_device(); + if (!cec_ctrl->input) { + DEV_ERR("hdmi input device allocation failed\n"); + return; + } + + cec_ctrl->input->name = "HDMI CEC User or Deck Control"; + cec_ctrl->input->phys = "hdmi/input0"; + cec_ctrl->input->id.bustype = BUS_VIRTUAL; + + input_set_capability(cec_ctrl->input, EV_KEY, KEY_POWER); + + rc = input_register_device(cec_ctrl->input); + if (rc) { + DEV_ERR(KERN_ERR "cec input device registeration failed\n"); + input_free_device(cec_ctrl->input); + cec_ctrl->input = NULL; + return; + } +} + +static void hdmi_cec_deinit_input_event(struct hdmi_cec_ctrl *cec_ctrl) +{ + if (cec_ctrl->input) + input_unregister_device(cec_ctrl->input); + cec_ctrl->input = NULL; +} + static void hdmi_cec_msg_recv(struct work_struct *work) { int i; @@ -446,7 +490,32 @@ static void hdmi_cec_msg_recv(struct work_struct *work) DEV_DBG("%s: CEC read frame done\n", __func__); hdmi_cec_dump_msg(cec_ctrl, &msg_node->msg); + DEV_DBG("%s: opcode 0x%x, wakup_en %d, tx_power_on %d\n", __func__, + msg_node->msg.opcode, cec_ctrl->cec_wakeup_en, + cec_ctrl->tx_power_on); + spin_lock_irqsave(&cec_ctrl->lock, flags); + if ((msg_node->msg.opcode == CEC_OP_SET_STREAM_PATH || + msg_node->msg.opcode == CEC_OP_KEY_PRESS) && + cec_ctrl->input && cec_ctrl->cec_wakeup_en && + !cec_ctrl->tx_power_on) { + DEV_DBG("%s: Sending power on at wakeup\n", __func__); + input_report_key(cec_ctrl->input, KEY_POWER, 1); + input_sync(cec_ctrl->input); + input_report_key(cec_ctrl->input, KEY_POWER, 0); + input_sync(cec_ctrl->input); + } + + if ((msg_node->msg.opcode == CEC_OP_STANDBY) && + cec_ctrl->input && cec_ctrl->cec_wakeup_en && + cec_ctrl->tx_power_on) { + DEV_DBG("%s: Sending power off on standby\n", __func__); + input_report_key(cec_ctrl->input, KEY_POWER, 1); + input_sync(cec_ctrl->input); + input_report_key(cec_ctrl->input, KEY_POWER, 0); + input_sync(cec_ctrl->input); + } + if (cec_ctrl->compliance_response_enabled) { spin_unlock_irqrestore(&cec_ctrl->lock, flags); @@ -516,7 +585,9 @@ static ssize_t hdmi_wta_cec_enable(struct device *dev, DEV_ERR("%s: kstrtoint failed.\n", __func__); return -EPERM; } - cec_en = (val == 1) ? true : false; + cec_en = (val & 0x1) ? true : false; + /* bit 1 is used for wakeup feature */ + cec_ctrl->cec_wakeup_en = ((val & 0x3) == 0x3) ? true : false; spin_lock_irqsave(&cec_ctrl->lock, flags); if (cec_ctrl->cec_enabled == cec_en) { @@ -759,6 +830,13 @@ static ssize_t hdmi_wta_cec_msg(struct device *dev, __func__); return -EPERM; } + + if (!cec_ctrl->cec_engine_configed) { + spin_unlock_irqrestore(&cec_ctrl->lock, flags); + DEV_ERR("%s: CEC engine is not configed.\n", + __func__); + return -EPERM; + } spin_unlock_irqrestore(&cec_ctrl->lock, flags); if (msg->frame_size > MAX_OPERAND_SIZE) { @@ -781,7 +859,7 @@ static DEVICE_ATTR(enable_compliance, S_IRUGO | S_IWUSR, static DEVICE_ATTR(logical_addr, S_IRUSR | 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 DEVICE_ATTR(wr_msg, S_IWUSR | S_IRUSR, NULL, hdmi_wta_cec_msg); static struct attribute *hdmi_cec_fs_attrs[] = { &dev_attr_enable.attr, @@ -797,6 +875,16 @@ static struct attribute_group hdmi_cec_fs_attr_group = { .attrs = hdmi_cec_fs_attrs, }; +bool is_hdmi_cec_wakeup_en(void *input) +{ + struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input; + if (!cec_ctrl) { + DEV_ERR("%s: Invalid input\n", __func__); + return 0; + } + return cec_ctrl->cec_wakeup_en; +} /* is_hdmi_cec_wakeup_en */ + int hdmi_cec_isr(void *input) { int rc = 0; @@ -813,7 +901,6 @@ int hdmi_cec_isr(void *input) io = cec_ctrl->init_data.io; cec_intr = DSS_REG_R_ND(io, HDMI_CEC_INT); - DEV_DBG("%s: cec interrupt status is [0x%x]\n", __func__, cec_intr); if (!cec_ctrl->cec_enabled) { if (cec_intr) @@ -823,7 +910,6 @@ int hdmi_cec_isr(void *input) } 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__); @@ -869,6 +955,11 @@ int hdmi_cec_deconfig(void *input) return -EPERM; } + cec_ctrl->tx_power_on = false; + + if (cec_ctrl->cec_wakeup_en) + return 0; + hdmi_cec_disable(cec_ctrl); spin_lock_irqsave(&cec_ctrl->lock, flags); @@ -913,11 +1004,15 @@ int hdmi_cec_config(void *input) 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) + spin_lock_irqsave(&cec_ctrl->lock, flags); + if (cec_ctrl->cec_enabled) { + hdmi_cec_write_logical_addr(cec_ctrl, + cec_ctrl->cec_logical_addr); hdmi_cec_enable(cec_ctrl); + } - spin_lock_irqsave(&cec_ctrl->lock, flags); cec_ctrl->cec_engine_configed = true; + cec_ctrl->tx_power_on = true; spin_unlock_irqrestore(&cec_ctrl->lock, flags); return 0; @@ -938,6 +1033,8 @@ void hdmi_cec_deinit(void *input) sysfs_remove_group(cec_ctrl->init_data.sysfs_kobj, &hdmi_cec_fs_attr_group); + hdmi_cec_deinit_input_event(cec_ctrl); + kfree(cec_ctrl); } } /* hdmi_cec_deinit */ @@ -969,7 +1066,7 @@ void *hdmi_cec_init(struct hdmi_cec_init_data *init_data) 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); - + hdmi_cec_init_input_event(cec_ctrl); goto exit; error: diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.h b/drivers/video/msm/mdss/mdss_hdmi_cec.h index a554507af32..0386e058283 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_cec.h +++ b/drivers/video/msm/mdss/mdss_hdmi_cec.h @@ -26,4 +26,5 @@ 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); +bool is_hdmi_cec_wakeup_en(void *cec_ctrl); #endif /* __MDSS_HDMI_CEC_H__ */ diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c index 69726aa87b5..2147566f00d 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_edid.c +++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c @@ -33,6 +33,7 @@ * descriptors with each SAD being 3 bytes long. * Thus, the maximum length of the audio data block would be 30 bytes */ +#define MAX_NUMBER_ADB 5 #define MAX_AUDIO_DATA_BLOCK_SIZE 30 #define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3 @@ -77,7 +78,7 @@ struct hdmi_edid_ctrl { u16 audio_latency; u16 video_latency; u32 present_3d; - u8 audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE]; + u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE]; int adb_size; u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE]; int sadb_size; @@ -587,33 +588,48 @@ static void hdmi_edid_extract_3d_present(struct hdmi_edid_ctrl *edid_ctrl, static void hdmi_edid_extract_audio_data_blocks( struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf) { - u8 len, cnt = 0; + u8 len = 0; + u8 adb_max = 0; const u8 *adb = NULL; + u32 offset = DBC_START_OFFSET; if (!edid_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } - adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, AUDIO_DATA_BLOCK, - &len); - if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE)) { - DEV_DBG("%s: No/Invalid Audio Data Block\n", - __func__); - return; - } + edid_ctrl->adb_size = 0; - memcpy(edid_ctrl->audio_data_block, adb + 1, len); - edid_ctrl->adb_size = len; + memset(edid_ctrl->audio_data_block, 0, + sizeof(edid_ctrl->audio_data_block)); - while (len >= 3 && cnt < 16) { - DEV_DBG("%s: ch=%d fmt=%d sampling=0x%02x bitdepth=0x%02x\n", - __func__, (adb[1]&0x7)+1, adb[1]>>3, adb[2], adb[3]); + do { + len = 0; + adb = hdmi_edid_find_block(in_buf, offset, AUDIO_DATA_BLOCK, + &len); + + if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE || + adb_max >= MAX_NUMBER_ADB)) { + if (!edid_ctrl->adb_size) { + DEV_DBG("%s: No/Invalid Audio Data Block\n", + __func__); + return; + } else { + DEV_DBG("%s: No more valid ADB found\n", + __func__); + } + + continue; + } + + memcpy(edid_ctrl->audio_data_block + edid_ctrl->adb_size, + adb + 1, len); + offset = (adb - in_buf) + 1 + len; + + edid_ctrl->adb_size += len; + adb_max++; + } while (adb); - cnt++; - len -= 3; - adb += 3; - } } /* hdmi_edid_extract_audio_data_blocks */ static void hdmi_edid_extract_speaker_allocation_data( diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h index e8d1b7cd1d1..d14ae324244 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_edid.h +++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014, 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 @@ -13,7 +13,7 @@ #ifndef __HDMI_EDID_H__ #define __HDMI_EDID_H__ -#include +#include #include "mdss_hdmi_util.h" struct hdmi_edid_init_data { diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c index b527108ec25..38d97503a10 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c +++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c @@ -1236,36 +1236,6 @@ int hdmi_hdcp_authenticate(void *input) return 0; } /* hdmi_hdcp_authenticate */ -/* - * Only retries defined times then abort current authenticating process - * Send check_topology message to notify any hdcpmanager's client of non- - * hdcp authenticated data link so the client can tear down any active secure - * playback. - * Reduce hdcp link to regular hdmi data link with hdcp disabled so any - * un-secure like UI & menu still can be sent over HDMI and display. - */ -#define AUTH_RETRIES_TIME (30) -static int hdmi_msm_if_abort_reauth(struct hdmi_hdcp_ctrl *hdcp_ctrl) -{ - int ret = 0; - - if (!hdcp_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); - return -EINVAL; - } - - if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) { - mutex_lock(hdcp_ctrl->init_data.mutex); - hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE; - mutex_unlock(hdcp_ctrl->init_data.mutex); - - hdcp_ctrl->auth_retries = 0; - ret = -ERANGE; - } - - return ret; -} - int hdmi_hdcp_reauthenticate(void *input) { struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input; @@ -1310,13 +1280,6 @@ int hdmi_hdcp_reauthenticate(void *input) DSS_REG_R(hdcp_ctrl->init_data.core_io, HDMI_HPD_CTRL) | BIT(28)); - ret = hdmi_msm_if_abort_reauth(hdcp_ctrl); - - if (ret) { - DEV_ERR("%s: abort reauthentication!\n", __func__); - return ret; - } - /* Restart authentication attempt */ DEV_DBG("%s: %s: Scheduling work to start HDCP authentication", __func__, HDCP_STATE_NAME); diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c index 1b66c46e47f..9e7713c3a78 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_tx.c +++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c @@ -21,7 +21,6 @@ #include #include #include -#include #define REG_DUMP 0 @@ -56,6 +55,8 @@ #define AUDIO_POLL_SLEEP_US (5 * 1000) #define AUDIO_POLL_TIMEOUT_US (AUDIO_POLL_SLEEP_US * 1000) +#define LPA_DMA_IDLE_MAX 200 + #define IFRAME_CHECKSUM_32(d) \ ((d & 0xff) + ((d >> 8) & 0xff) + \ ((d >> 16) & 0xff) + ((d >> 24) & 0xff)) @@ -145,6 +146,11 @@ enum hdmi_tx_hpd_states { HPD_ENABLE }; +enum hdmi_tx_res_states { + RESOLUTION_UNCHANGED, + RESOLUTION_CHANGED +}; + /* parameters for clock regeneration */ struct hdmi_tx_audio_acr { u32 n; @@ -162,8 +168,6 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data); static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, int enable); -static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl, - int val, bool force); static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl); static void hdmi_tx_en_encryption(struct hdmi_tx_ctrl *hdmi_ctrl, u32 on); static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl); @@ -394,7 +398,15 @@ static bool hdmi_tx_is_cea_format(int mode) return cea_fmt; } -const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module) +static inline bool hdmi_tx_is_hdcp_enabled(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) + return true; + + return false; +} + +static const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module) { switch (module) { case HDMI_TX_HPD_PM: return "HDMI_TX_HPD_PM"; @@ -409,7 +421,6 @@ static const char *hdmi_tx_io_name(u32 type) { switch (type) { case HDMI_TX_CORE_IO: return "core_physical"; - case HDMI_TX_PHY_IO: return "phy_physical"; case HDMI_TX_QFPROM_IO: return "qfprom_physical"; default: return NULL; } @@ -475,26 +486,52 @@ static int hdmi_tx_get_vic_from_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl, return new_vic; } /* hdmi_tx_get_vic_from_panel_info */ +static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + return hdmi_edid_get_sink_mode( + hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1; +} /* hdmi_tx_is_dvi_mode */ + static inline void hdmi_tx_send_cable_notification( struct hdmi_tx_ctrl *hdmi_ctrl, int val) { + int state = hdmi_ctrl->sdev.state; + if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); return; } - if (hdmi_ctrl->sdev.state != val) - switch_set_state(&hdmi_ctrl->sdev, val); + switch_set_state(&hdmi_ctrl->sdev, val); + + DEV_INFO("%s: cable state %s %d\n", __func__, + hdmi_ctrl->sdev.state == state ? + "is same" : "switched to", + hdmi_ctrl->sdev.state); /* Notify all registered modules of cable connection status */ schedule_work(&hdmi_ctrl->cable_notify_work); } /* hdmi_tx_send_cable_notification */ -static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl) +static inline void hdmi_tx_set_audio_switch_node( + struct hdmi_tx_ctrl *hdmi_ctrl, int val) { - return hdmi_edid_get_sink_mode( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID]) ? 0 : 1; -} /* hdmi_tx_is_dvi_mode */ + int state = hdmi_ctrl->audio_sdev.state; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) { + switch_set_state(&hdmi_ctrl->audio_sdev, val); + + DEV_INFO("%s: audio state %s %d\n", __func__, + hdmi_ctrl->audio_sdev.state == state ? + "is same" : "switched to", + hdmi_ctrl->audio_sdev.state); + } +} /* hdmi_tx_set_audio_switch_node */ static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl) { @@ -687,13 +724,11 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false); if (hdmi_ctrl->panel_power_on && hdmi_ctrl->hpd_state) { - hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false); + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); } hdmi_tx_send_cable_notification(hdmi_ctrl, 0); - DEV_DBG("%s: Hdmi state switch to %d\n", __func__, - hdmi_ctrl->sdev.state); break; case HPD_ON: if (hdmi_ctrl->hpd_disabled == true) { @@ -1104,56 +1139,81 @@ static void hdmi_tx_sysfs_remove(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->kobj = NULL; } /* hdmi_tx_sysfs_remove */ -static inline void hdmi_tx_set_audio_switch_node(struct hdmi_tx_ctrl *hdmi_ctrl, - int val, bool force) +static int hdmi_tx_config_avmute(struct hdmi_tx_ctrl *hdmi_ctrl, bool set) { + struct dss_io_data *io; + u32 av_mute_status; + bool av_pkt_en = false; + if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); - return; + return -EINVAL; } - if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && - (force || (hdmi_ctrl->audio_sdev.state != val))) { - switch_set_state(&hdmi_ctrl->audio_sdev, val); - DEV_INFO("%s: hdmi_audio state switched to %d\n", __func__, - hdmi_ctrl->audio_sdev.state); + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; + if (!io->base) { + DEV_ERR("%s: Core io is not initialized\n", __func__); + return -EINVAL; } -} /* hdmi_tx_set_audio_switch_node */ -static int hdmi_tx_config_avmute(struct hdmi_tx_ctrl *hdmi_ctrl, int set) + av_mute_status = DSS_REG_R(io, HDMI_GC); + + if (set) { + if (!(av_mute_status & BIT(0))) { + DSS_REG_W(io, HDMI_GC, av_mute_status | BIT(0)); + av_pkt_en = true; + } + } else { + if (av_mute_status & BIT(0)) { + DSS_REG_W(io, HDMI_GC, av_mute_status & ~BIT(0)); + av_pkt_en = true; + } + } + + /* Enable AV Mute tranmission here */ + if (av_pkt_en) + DSS_REG_W(io, HDMI_VBI_PKT_CTRL, + DSS_REG_R(io, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5))); + + DEV_DBG("%s: AVMUTE %s\n", __func__, set ? "set" : "cleared"); + + return 0; +} /* hdmi_tx_config_avmute */ + +static bool hdmi_tx_is_encryption_set(struct hdmi_tx_ctrl *hdmi_ctrl) { struct dss_io_data *io; + bool enc_en = true; + u32 reg_val; if (!hdmi_ctrl) { DEV_ERR("%s: invalid input\n", __func__); - return -EINVAL; + goto end; } io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; if (!io->base) { DEV_ERR("%s: Core io is not initialized\n", __func__); - return -EINVAL; + goto end; } - if (set) - DSS_REG_W(io, HDMI_GC, - DSS_REG_R(io, HDMI_GC) | BIT(0)); - else - DSS_REG_W(io, HDMI_GC, - DSS_REG_R(io, HDMI_GC) & ~BIT(0)); + reg_val = DSS_REG_R_ND(io, HDMI_HDCP_CTRL2); + if ((reg_val & BIT(0)) && (reg_val & BIT(1))) + goto end; - /* Enable AV Mute tranmission here */ - DSS_REG_W(io, HDMI_VBI_PKT_CTRL, - DSS_REG_R(io, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5))); + if (DSS_REG_R_ND(io, HDMI_CTRL) & BIT(2)) + goto end; - DEV_DBG("%s: AVMUTE %s\n", __func__, set ? "set" : "cleared"); + return false; - return 0; -} /* hdmi_tx_config_avmute */ +end: + return enc_en; +} /* hdmi_tx_is_encryption_set */ void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status) { int rc = 0; + bool enc_en; struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)ptr; if (!hdmi_ctrl) { @@ -1169,23 +1229,15 @@ void hdmi_tx_hdcp_cb(void *ptr, enum hdmi_hdcp_state status) switch (status) { case HDCP_STATE_AUTHENTICATED: if (hdmi_ctrl->hpd_state) { - if (hdmi_ctrl->pdata.primary) - hdmi_tx_en_encryption(hdmi_ctrl, true); - else - /* Clear AV Mute */ - rc = hdmi_tx_config_avmute(hdmi_ctrl, 0); - hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false); + hdmi_tx_config_avmute(hdmi_ctrl, false); + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); } break; case HDCP_STATE_AUTH_FAIL: - hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false); - if (hdmi_ctrl->hpd_state) { - if (hdmi_ctrl->pdata.primary) - hdmi_tx_en_encryption(hdmi_ctrl, false); - else - /* Set AV Mute */ - rc = hdmi_tx_config_avmute(hdmi_ctrl, 1); + enc_en = hdmi_tx_is_encryption_set(hdmi_ctrl); + hdmi_tx_set_audio_switch_node(hdmi_ctrl, !enc_en); + hdmi_tx_config_avmute(hdmi_ctrl, enc_en); DEV_DBG("%s: Reauthenticating\n", __func__); rc = hdmi_hdcp_reauthenticate( @@ -1291,14 +1343,21 @@ static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl) return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0); } /* hdmi_tx_is_controller_on */ -static int hdmi_tx_init_panel_info(uint32_t resolution, - struct mdss_panel_info *pinfo) +static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl) { - const struct msm_hdmi_mode_timing_info *timing = - hdmi_get_supported_mode(resolution); + struct mdss_panel_info *pinfo; + const struct msm_hdmi_mode_timing_info *timing; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + timing = hdmi_get_supported_mode(hdmi_ctrl->video_resolution); + pinfo = &hdmi_ctrl->panel_data.panel_info; if (!timing || !pinfo) { - DEV_ERR("%s: invalid input.\n", __func__); + DEV_ERR("%s: invalid timing data\n", __func__); return -EINVAL; } @@ -1323,6 +1382,8 @@ static int hdmi_tx_init_panel_info(uint32_t resolution, pinfo->lcdc.underflow_clr = 0xff; /* blue */ pinfo->lcdc.hsync_skew = 0; + pinfo->cont_splash_enabled = hdmi_ctrl->pdata.cont_splash_enabled; + return 0; } /* hdmi_tx_init_panel_info */ @@ -1388,7 +1449,13 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) return; } io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; - DEV_DBG("%s: Got HPD interrupt\n", __func__); + DEV_DBG("%s: Got HPD %s interrupt\n", __func__, + hdmi_ctrl->hpd_state ? "connect" : "disconnect"); + + if (hdmi_ctrl->polarity_reset) { + hdmi_ctrl->polarity_reset = false; + hdmi_ctrl->hpd_state = 0; + } if (hdmi_ctrl->hpd_state) { /* @@ -1406,31 +1473,33 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) DEV_ERR("%s: Failed to enable ddc power\n", __func__); return; } + /* Enable SW DDC before EDID read */ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io, HDMI_DDC_ARBITRATION) & ~(BIT(4))); hdmi_tx_read_sink_info(hdmi_ctrl); - hdmi_tx_send_cable_notification(hdmi_ctrl, 1); - DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n", - __func__, hdmi_ctrl->sdev.state); + + if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false)) + DEV_ERR("%s: Failed to disable ddc power\n", __func__); + + hdmi_tx_send_cable_notification(hdmi_ctrl, true); } else { - hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false); - hdmi_tx_wait_for_audio_engine(hdmi_ctrl); + hdmi_tx_config_avmute(hdmi_ctrl, true); - if (!hdmi_ctrl->panel_power_on) { - if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, - false)) - DEV_WARN("%s: Failed to disable ddc power\n", - __func__); - } + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); + hdmi_tx_wait_for_audio_engine(hdmi_ctrl); +<<<<<<< HEAD if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false)) DEV_WARN("%s: Failed to disable ddc power\n", __func__); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n", __func__, hdmi_ctrl->sdev.state); +======= + hdmi_tx_send_cable_notification(hdmi_ctrl, false); +>>>>>>> AU_LINUX_ANDROID_LA.BF.2.1_RB1.05.00.00.173.031 } if (!completion_done(&hdmi_ctrl->hpd_done)) @@ -1483,6 +1552,7 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl, { int new_vic = -1; const struct msm_hdmi_mode_timing_info *timing = NULL; + int res_changed = RESOLUTION_UNCHANGED; if (!hdmi_ctrl || !pinfo) { DEV_ERR("%s: invalid input\n", __func__); @@ -1495,9 +1565,12 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl, return -EPERM; } - DEV_DBG("%s: switching from %s => %s", __func__, - msm_hdmi_mode_2string(hdmi_ctrl->video_resolution), - msm_hdmi_mode_2string(new_vic)); + if (hdmi_ctrl->video_resolution != new_vic) { + res_changed = RESOLUTION_CHANGED; + DEV_DBG("%s: switching from %s => %s", __func__, + msm_hdmi_mode_2string(hdmi_ctrl->video_resolution), + msm_hdmi_mode_2string(new_vic)); + } hdmi_ctrl->video_resolution = (u32)new_vic; @@ -1511,7 +1584,7 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl, hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], hdmi_ctrl->video_resolution); - return 0; + return res_changed; } /* hdmi_tx_set_video_fmt */ static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl, @@ -1843,28 +1916,6 @@ static void hdmi_tx_set_spd_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control); } /* hdmi_tx_set_spd_infoframe */ -static void hdmi_tx_en_encryption(struct hdmi_tx_ctrl *hdmi_ctrl, u32 on) -{ - u32 reg_val; - struct dss_io_data *io = NULL; - - if (!hdmi_ctrl->hdcp_feature_on || !hdmi_ctrl->present_hdcp) - return; - - io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; - - mutex_lock(&hdmi_ctrl->mutex); - reg_val = DSS_REG_R_ND(io, HDMI_CTRL); - - if (on) - reg_val |= BIT(2); - else - reg_val &= ~BIT(2); - DSS_REG_W(io, HDMI_CTRL, reg_val); - - mutex_unlock(&hdmi_ctrl->mutex); -} /* hdmi_tx_en_encryption */ - static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) { struct dss_io_data *io = NULL; @@ -1887,8 +1938,8 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) reg_val |= BIT(0); /* HDMI Encryption, if HDCP is enabled */ - if (hdmi_ctrl->hdcp_feature_on && - hdmi_ctrl->present_hdcp && !hdmi_ctrl->pdata.primary) + if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl) && + !hdmi_ctrl->pdata.primary) reg_val |= BIT(2); /* Set transmission mode to DVI based in EDID info */ @@ -1955,6 +2006,27 @@ static int hdmi_tx_config_power(struct hdmi_tx_ctrl *hdmi_ctrl, return rc; } /* hdmi_tx_config_power */ +static int hdmi_tx_vote_power(struct hdmi_tx_ctrl *hdmi_ctrl, + enum hdmi_tx_power_module_type module) +{ + struct dss_module_power *power_data = NULL; + + if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) { + DEV_ERR("%s: Error: invalid input\n", __func__); + return -EINVAL; + } + + power_data = &hdmi_ctrl->pdata.power_data[module]; + if (!power_data) { + DEV_ERR("%s: Error: invalid power data\n", __func__); + return -EINVAL; + } + + power_data->enable = true; + + return 0; +} + static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, int enable) { @@ -1974,7 +2046,7 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, goto error; } - if (enable) { + if (enable && !power_data->enable) { rc = msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 1); if (rc) { @@ -2006,13 +2078,17 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, __func__, hdmi_tx_pm_name(module), rc); goto disable_gpio; } - } else { + power_data->enable = true; + } else if (!enable && power_data->enable && + (!IS_CEC_WAKEUP_EN(hdmi_ctrl) || + ((module != HDMI_TX_HPD_PM) && (module != HDMI_TX_CEC_PM)))) { msm_dss_enable_clk(power_data->clk_config, power_data->num_clk, 0); msm_dss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0); msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0); + power_data->enable = false; } return rc; @@ -2108,49 +2184,6 @@ static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL); } /* hdmi_tx_phy_reset */ -static void hdmi_tx_init_phy(struct hdmi_tx_ctrl *hdmi_ctrl) -{ - struct dss_io_data *io = NULL; - - if (!hdmi_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); - return; - } - - io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO]; - if (!io->base) { - DEV_ERR("%s: phy io is not initialized\n", __func__); - return; - } - - DSS_REG_W_ND(io, HDMI_PHY_ANA_CFG0, 0x1B); - DSS_REG_W_ND(io, HDMI_PHY_ANA_CFG1, 0xF2); - DSS_REG_W_ND(io, HDMI_PHY_BIST_CFG0, 0x0); - DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN0, 0x0); - DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN1, 0x0); - DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN2, 0x0); - DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN3, 0x0); - - DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL1, 0x20); -} /* hdmi_tx_init_phy */ - -static void hdmi_tx_powerdown_phy(struct hdmi_tx_ctrl *hdmi_ctrl) -{ - struct dss_io_data *io = NULL; - - if (!hdmi_ctrl) { - DEV_ERR("%s: invalid input\n", __func__); - return; - } - io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO]; - if (!io->base) { - DEV_ERR("%s: phy io is not initialized\n", __func__); - return; - } - - DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL0, 0x7F); -} /* hdmi_tx_powerdown_phy */ - static int hdmi_tx_audio_acr_setup(struct hdmi_tx_ctrl *hdmi_ctrl, bool enabled) { @@ -2341,14 +2374,20 @@ static int hdmi_tx_audio_iframe_setup(struct hdmi_tx_ctrl *hdmi_ctrl, case MSM_HDMI_AUDIO_CHANNEL_2: break; case MSM_HDMI_AUDIO_CHANNEL_3: + channel_count = 2; + break; case MSM_HDMI_AUDIO_CHANNEL_4: channel_count = 3; break; case MSM_HDMI_AUDIO_CHANNEL_5: + channel_count = 4; + break; case MSM_HDMI_AUDIO_CHANNEL_6: channel_count = 5; break; case MSM_HDMI_AUDIO_CHANNEL_7: + channel_count = 6; + break; case MSM_HDMI_AUDIO_CHANNEL_8: channel_count = 7; break; @@ -2582,6 +2621,10 @@ int msm_hdmi_register_audio_codec(struct platform_device *pdev, ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk; ops->hdmi_cable_status = hdmi_tx_get_cable_status; + /* call back function to play short silent audio */ + hdmi_ctrl->play_short_silent_audio = ops->play_silent_audio_callback; + hdmi_ctrl->codec_data = ops->callback_data; + return 0; } /* hdmi_tx_audio_register */ EXPORT_SYMBOL(msm_hdmi_register_audio_codec); @@ -2664,7 +2707,6 @@ static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl) } hdmi_tx_set_mode(hdmi_ctrl, false); - hdmi_tx_init_phy(hdmi_ctrl); DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B); hdmi_tx_set_mode(hdmi_ctrl, true); @@ -2679,16 +2721,16 @@ static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl) if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && hdmi_tx_is_cea_format(hdmi_ctrl->video_resolution)) { - rc = hdmi_tx_audio_setup(hdmi_ctrl); - if (rc) { - DEV_ERR("%s: hdmi_msm_audio_setup failed. rc=%d\n", - __func__, rc); - hdmi_tx_set_mode(hdmi_ctrl, false); - return rc; - } + hdmi_tx_audio_setup(hdmi_ctrl); + + if (hdmi_ctrl->pdata.primary && + hdmi_ctrl->play_short_silent_audio) + hdmi_ctrl->play_short_silent_audio( + hdmi_ctrl->codec_data); - if (!hdmi_ctrl->hdcp_feature_on || !hdmi_ctrl->present_hdcp) - hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1, false); + if (!hdmi_tx_is_hdcp_enabled(hdmi_ctrl) && + !hdmi_tx_is_encryption_set(hdmi_ctrl)) + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); mutex_lock(&hdmi_ctrl->lut_lock); hdmi_tx_set_avi_infoframe(hdmi_ctrl); @@ -2697,7 +2739,8 @@ static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_tx_set_spd_infoframe(hdmi_ctrl); } - /* todo: CEC */ + if (!hdmi_tx_is_encryption_set(hdmi_ctrl)) + hdmi_tx_config_avmute(hdmi_ctrl, false); DEV_INFO("%s: HDMI Core: Initialized\n", __func__); @@ -2733,6 +2776,9 @@ static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl, if (cable_sense == polarity) { u32 reg_val = DSS_REG_R(io, HDMI_HPD_CTRL); + DEV_DBG("%s: reset HPD as cable sense and polarity same %d\n", + __func__, polarity); + /* Toggle HPD circuit to trigger HPD sense */ DSS_REG_W(io, HDMI_HPD_CTRL, reg_val & ~BIT(28)); DSS_REG_W(io, HDMI_HPD_CTRL, reg_val | BIT(28)); @@ -2759,8 +2805,6 @@ static void hdmi_tx_power_off_work(struct work_struct *work) if (!hdmi_tx_is_dvi_mode(hdmi_ctrl)) hdmi_tx_audio_off(hdmi_ctrl); - hdmi_tx_powerdown_phy(hdmi_ctrl); - hdmi_cec_deconfig(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]); hdmi_tx_core_off(hdmi_ctrl); @@ -2786,7 +2830,9 @@ static int hdmi_tx_power_off(struct mdss_panel_data *panel_data) struct hdmi_tx_ctrl *hdmi_ctrl = hdmi_tx_get_drvdata_from_panel_data(panel_data); - if (!hdmi_ctrl || !hdmi_ctrl->panel_power_on) { + if (!hdmi_ctrl || + (!panel_data->panel_info.cont_splash_enabled && + !hdmi_ctrl->panel_power_on)) { DEV_ERR("%s: invalid input\n", __func__); return -EINVAL; } @@ -2805,7 +2851,10 @@ static int hdmi_tx_power_off(struct mdss_panel_data *panel_data) static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) { int rc = 0; + u32 cable_sense; + int res_changed = RESOLUTION_UNCHANGED; struct dss_io_data *io = NULL; + struct mdss_panel_info *panel_info = NULL; struct hdmi_tx_ctrl *hdmi_ctrl = hdmi_tx_get_drvdata_from_panel_data(panel_data); @@ -2820,24 +2869,21 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) } if (!hdmi_ctrl->hpd_initialized) { - DEV_ERR("%s: HDMI on is not possible w/o cable detection.\n", - __func__); + DEV_ERR("%s: hpd not initialized\n", __func__); return -EPERM; } + panel_info = &panel_data->panel_info; + hdmi_ctrl->hdcp_feature_on = hdcp_feature_on; + /* If a power down is already underway, wait for it to finish */ flush_work(&hdmi_ctrl->power_off_work); - rc = hdmi_tx_set_video_fmt(hdmi_ctrl, &panel_data->panel_info); - if (rc) { - DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc); - return rc; - } - - hdmi_ctrl->hdcp_feature_on = hdcp_feature_on; + res_changed = hdmi_tx_set_video_fmt(hdmi_ctrl, panel_info); - DEV_INFO("power: ON (%s)\n", msm_hdmi_mode_2string( - hdmi_ctrl->video_resolution)); + DEV_DBG("%s: %dx%d%s\n", __func__, + panel_info->xres, panel_info->yres, + panel_info->cont_splash_enabled ? " (handoff underway)" : ""); rc = hdmi_tx_core_on(hdmi_ctrl); if (rc) { @@ -2851,8 +2897,30 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) hdmi_cec_config(hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]); + if (hdmi_ctrl->pdata.cont_splash_enabled) { + hdmi_ctrl->pdata.cont_splash_enabled = false; + panel_data->panel_info.cont_splash_enabled = false; + + if (res_changed == RESOLUTION_UNCHANGED) { + if (!hdmi_tx_is_hdcp_enabled(hdmi_ctrl) && + !hdmi_tx_is_encryption_set(hdmi_ctrl)) + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1); + + cable_sense = (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & + BIT(1)) >> 1; + + if (!cable_sense) { + hdmi_ctrl->polarity_reset = true; + hdmi_tx_hpd_polarity_setup(hdmi_ctrl, + HPD_CONNECT_POLARITY); + return 0; + } + + goto end; + } + } + if (hdmi_ctrl->hpd_state) { - DEV_DBG("%s: Turning HDMI on\n", __func__); rc = hdmi_tx_start(hdmi_ctrl); if (rc) { DEV_ERR("%s: hdmi_tx_start failed. rc=%d\n", @@ -2861,12 +2929,12 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data) return rc; } } - +end: dss_reg_dump(io->base, io->len, "HDMI-ON: ", REG_DUMP); - DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__, + DEV_DBG("%s: Tx: %s (%s mode)\n", __func__, hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" , - hdmi_tx_is_dvi_mode(hdmi_ctrl) ? "ON" : "OFF"); + hdmi_tx_is_dvi_mode(hdmi_ctrl) ? "DVI" : "HDMI"); hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_DISCONNECT_POLARITY); @@ -2904,9 +2972,12 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl) /* Turn off HPD interrupts */ DSS_REG_W(io, HDMI_HPD_INT_CTRL, 0); - mdss_disable_irq(&hdmi_tx_hw); - - hdmi_tx_set_mode(hdmi_ctrl, false); + if (IS_CEC_WAKEUP_EN(hdmi_ctrl)) { + mdss_enable_irq_wake(true); + } else { + mdss_disable_irq(&hdmi_tx_hw); + hdmi_tx_set_mode(hdmi_ctrl, false); + } if (hdmi_ctrl->hpd_state) { rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, 0); @@ -2919,12 +2990,13 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl) if (rc) DEV_INFO("%s: Failed to disable hpd power. Error=%d\n", __func__, rc); - spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags); hdmi_ctrl->hpd_state = false; spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags); hdmi_ctrl->hpd_initialized = false; + + DEV_DBG("%s\n", __func__); } /* hdmi_tx_hpd_off */ static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl) @@ -2956,12 +3028,17 @@ static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl) dss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP); - hdmi_tx_set_mode(hdmi_ctrl, false); - hdmi_tx_phy_reset(hdmi_ctrl); - hdmi_tx_set_mode(hdmi_ctrl, true); + if (!hdmi_ctrl->pdata.primary) { + hdmi_tx_set_mode(hdmi_ctrl, false); + hdmi_tx_phy_reset(hdmi_ctrl); + hdmi_tx_set_mode(hdmi_ctrl, true); + } DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B); + if (IS_CEC_WAKEUP_EN(hdmi_ctrl)) + mdss_enable_irq_wake(false); + mdss_enable_irq(&hdmi_tx_hw); hdmi_ctrl->hpd_initialized = true; @@ -2979,6 +3056,8 @@ static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY); } + DEV_DBG("%s\n", __func__); + return rc; } /* hdmi_tx_hpd_on */ @@ -3235,6 +3314,34 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl) return rc; } /* hdmi_tx_dev_init */ +static int hdmi_tx_start_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int rc; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled || + !hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) + return 0; + + if (hdmi_tx_is_encryption_set(hdmi_ctrl)) + hdmi_tx_config_avmute(hdmi_ctrl, true); + + if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, true)) { + DEV_ERR("%s: Failed to enable ddc power\n", __func__); + return -ENODEV; + } + + rc = hdmi_hdcp_authenticate(hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]); + if (rc) + DEV_ERR("%s: hdcp auth failed. rc=%d\n", __func__, rc); + + return rc; +} + static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, int event, void *arg) { @@ -3276,6 +3383,9 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, return rc; } else { hdmi_ctrl->hpd_feature_on = true; + hdmi_tx_send_cable_notification(hdmi_ctrl, + true); + hdmi_ctrl->hpd_state = true; } } @@ -3325,7 +3435,8 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, if (!timeout & !hdmi_ctrl->hpd_state) { DEV_INFO("%s: cable removed during suspend\n", __func__); - hdmi_tx_send_cable_notification(hdmi_ctrl, 0); + hdmi_tx_send_cable_notification(hdmi_ctrl, + false); rc = -EPERM; } else { DEV_DBG("%s: cable present after resume\n", @@ -3342,20 +3453,10 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, break; case MDSS_EVENT_PANEL_ON: - if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) { - /* Set AV Mute before starting authentication */ - if (hdmi_ctrl->pdata.primary) - hdmi_tx_en_encryption(hdmi_ctrl, false); - else - rc = hdmi_tx_config_avmute(hdmi_ctrl, 1); - - DEV_DBG("%s: Starting HDCP authentication\n", __func__); - rc = hdmi_hdcp_authenticate( - hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]); - if (rc) - DEV_ERR("%s: hdcp auth failed. rc=%d\n", - __func__, rc); - } + rc = hdmi_tx_start_hdcp(hdmi_ctrl); + if (rc) + DEV_ERR("%s: hdcp start failed rc=%d\n", __func__, rc); + hdmi_ctrl->timing_gen_on = true; break; @@ -3372,10 +3473,16 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, break; case MDSS_EVENT_BLANK: - if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) { + if (hdmi_tx_is_hdcp_enabled(hdmi_ctrl)) { DEV_DBG("%s: Turning off HDCP\n", __func__); hdmi_hdcp_off( hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]); + + rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, + false); + if (rc) + DEV_ERR("%s: Failed to disable ddc power\n", + __func__); } break; @@ -3393,9 +3500,14 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, break; case MDSS_EVENT_CLOSE: - if (hdmi_ctrl->hpd_feature_on) - hdmi_tx_hpd_polarity_setup(hdmi_ctrl, - HPD_CONNECT_POLARITY); + if (panel_data->panel_info.cont_splash_enabled) { + hdmi_tx_power_off(panel_data); + panel_data->panel_info.cont_splash_enabled = false; + } else { + if (hdmi_ctrl->hpd_feature_on) + hdmi_tx_hpd_polarity_setup(hdmi_ctrl, + HPD_CONNECT_POLARITY); + } break; } @@ -3413,14 +3525,10 @@ static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->panel_data.event_handler = hdmi_tx_panel_event_handler; - /* Default 1080p resolution for hdmi primary display */ - if (hdmi_ctrl->pdata.primary) - hdmi_ctrl->video_resolution = DEFAULT_HDMI_PRIMARY_RESOLUTION; - else + if (!hdmi_ctrl->pdata.primary) hdmi_ctrl->video_resolution = DEFAULT_VIDEO_RESOLUTION; - rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution, - &hdmi_ctrl->panel_data.panel_info); + rc = hdmi_tx_init_panel_info(hdmi_ctrl); if (rc) { DEV_ERR("%s: hdmi_init_panel_info failed\n", __func__); return rc; @@ -3923,6 +4031,8 @@ static int hdmi_tx_get_dt_data(struct platform_device *pdev, { int i, rc = 0; struct device_node *of_node = NULL; + struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev); + bool splash_en; if (!pdev || !pdata) { DEV_ERR("%s: invalid input\n", __func__); @@ -3972,16 +4082,19 @@ static int hdmi_tx_get_dt_data(struct platform_device *pdev, } } - if (of_find_property(pdev->dev.of_node, "qcom,primary_panel", NULL)) { - u32 tmp; - of_property_read_u32(pdev->dev.of_node, "qcom,primary_panel", - &tmp); - pdata->primary = tmp ? true : false; - } + if (!hdmi_ctrl->pdata.primary) + hdmi_ctrl->pdata.primary = of_property_read_bool( + pdev->dev.of_node, "qcom,primary_panel"); pdata->cond_power_on = of_property_read_bool(pdev->dev.of_node, "qcom,conditional-power-on"); + splash_en = of_property_read_bool(pdev->dev.of_node, + "qcom,cont_splash_enabled"); + + if (splash_en) + pdata->cont_splash_enabled = true; + return rc; error: @@ -3989,9 +4102,72 @@ static int hdmi_tx_get_dt_data(struct platform_device *pdev, return rc; } /* hdmi_tx_get_dt_data */ +static void hdmi_tx_audio_tear_down(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + struct dss_io_data *io; + u32 audio_pkt_ctrl; + u32 audio_eng_cfg; + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO]; + if (!io->base) { + DEV_ERR("%s: Core io is not initialized\n", __func__); + return; + } + + audio_pkt_ctrl = DSS_REG_R(io, HDMI_AUDIO_PKT_CTRL); + audio_eng_cfg = DSS_REG_R(io, HDMI_AUDIO_CFG); + + if ((audio_pkt_ctrl & BIT(0)) || (audio_eng_cfg & BIT(0))) { + u32 lpa_dma, i = 0; + + void __iomem *lpa_base = ioremap(LPASS_LPAIF_RDDMA_CTL0, 0xFF); + + lpa_dma = readl_relaxed(lpa_base + LPASS_LPAIF_RDDMA_PER_CNT0); + + /* Disable audio packet transmission */ + DSS_REG_W(io, HDMI_AUDIO_PKT_CTRL, + DSS_REG_R(io, HDMI_AUDIO_PKT_CTRL) & ~BIT(0)); + + /* Wait for LPA DMA Engine to be idle */ + while (i < LPA_DMA_IDLE_MAX) { + u32 val; + + /* + * sleep for minimum HW recommended time + * for HW status to update. + */ + msleep(20); + + val = readl_relaxed(lpa_base + + LPASS_LPAIF_RDDMA_PER_CNT0); + if (val == lpa_dma) + break; + + lpa_dma = val; + i++; + } + + DEV_DBG("%s: LPA DMA idle after %d ms\n", __func__, i * 20); + + /* Disable audio engine */ + DSS_REG_W(io, HDMI_AUDIO_CFG, + DSS_REG_R(io, HDMI_AUDIO_CFG) & ~BIT(0)); + + /* Disable LPA DMA Engine */ + writel_relaxed(readl_relaxed(lpa_base) & ~BIT(0), lpa_base); + + iounmap(lpa_base); + } +} + static int hdmi_tx_probe(struct platform_device *pdev) { - int rc = 0; + int rc = 0, i; struct device_node *of_node = pdev->dev.of_node; struct hdmi_tx_ctrl *hdmi_ctrl = NULL; struct mdss_panel_cfg *pan_cfg = NULL; @@ -4012,19 +4188,31 @@ static int hdmi_tx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi_ctrl); hdmi_ctrl->pdev = pdev; - rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata); - if (rc) { - DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n", - __func__, rc); - goto failed_dt_data; - } - pan_cfg = mdss_panel_intf_type(MDSS_PANEL_INTF_HDMI); if (IS_ERR(pan_cfg)) { return PTR_ERR(pan_cfg); } else if (pan_cfg) { - DEV_DBG("%s: HDMI is primary\n", __func__); + int vic; + + if (kstrtoint(pan_cfg->arg_cfg, 10, &vic)) + vic = DEFAULT_HDMI_PRIMARY_RESOLUTION; + hdmi_ctrl->pdata.primary = true; + hdmi_ctrl->panel_data.panel_info.is_prim_panel = true; + hdmi_ctrl->pdata.cont_splash_enabled = true; + + if (vic) + hdmi_ctrl->video_resolution = vic; + else + hdmi_ctrl->video_resolution = + DEFAULT_HDMI_PRIMARY_RESOLUTION; + } + + rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata); + if (rc) { + DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n", + __func__, rc); + goto failed_dt_data; } rc = hdmi_tx_init_resource(hdmi_ctrl); @@ -4060,6 +4248,26 @@ static int hdmi_tx_probe(struct platform_device *pdev) hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len)) DEV_WARN("%s: hdmi_tx debugfs register failed\n", __func__); + if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) { + for (i = 0; i < HDMI_TX_MAX_PM; i++) { + msm_dss_enable_vreg( + hdmi_ctrl->pdata.power_data[i].vreg_config, + hdmi_ctrl->pdata.power_data[i].num_vreg, 1); + + msm_dss_enable_gpio( + hdmi_ctrl->pdata.power_data[i].gpio_config, + hdmi_ctrl->pdata.power_data[i].num_gpio, 1); + + msm_dss_enable_clk( + hdmi_ctrl->pdata.power_data[i].clk_config, + hdmi_ctrl->pdata.power_data[i].num_clk, 1); + + hdmi_tx_vote_power(hdmi_ctrl, i); + } + + hdmi_tx_audio_tear_down(hdmi_ctrl); + } + return rc; failed_reg_panel: diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h index 2706d089f77..f6c274955c6 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_tx.h +++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h @@ -19,7 +19,6 @@ enum hdmi_tx_io_type { HDMI_TX_CORE_IO, - HDMI_TX_PHY_IO, HDMI_TX_QFPROM_IO, HDMI_TX_MAX_IO }; @@ -35,6 +34,7 @@ enum hdmi_tx_power_module_type { /* Data filled from device tree */ struct hdmi_tx_platform_data { bool primary; + bool cont_splash_enabled; bool cond_power_on; struct dss_io_data io[HDMI_TX_MAX_IO]; struct dss_module_power power_data[HDMI_TX_MAX_PM]; @@ -87,6 +87,7 @@ struct hdmi_tx_ctrl { bool hdcp_feature_on; bool hpd_disabled; bool ds_registered; + bool polarity_reset; u32 present_hdcp; u8 aksv[5]; enum hdmi_hdcp_state hdcp_status; @@ -100,6 +101,12 @@ struct hdmi_tx_ctrl { void *downstream_data; void *feature_data[HDMI_TX_FEAT_MAX]; + + void *codec_data; + u32 (*play_short_silent_audio) (void *codec_data); + bool power_enabled[HDMI_TX_MAX_PM]; }; +#define IS_CEC_WAKEUP_EN(ctrl) \ + is_hdmi_cec_wakeup_en((ctrl)->feature_data[HDMI_TX_FEAT_CEC]) #endif /* __MDSS_HDMI_TX_H__ */ diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h index 7dd5b8e5df4..48bad54bb2a 100644 --- a/drivers/video/msm/mdss/mdss_hdmi_util.h +++ b/drivers/video/msm/mdss/mdss_hdmi_util.h @@ -78,6 +78,7 @@ #define HDMI_RAMP_CTRL2 (0x00000100) #define HDMI_RAMP_CTRL3 (0x00000104) #define HDMI_CS_60958_2 (0x00000108) +#define HDMI_HDCP_CTRL2 (0x0000010C) #define HDMI_HDCP_CTRL (0x00000110) #define HDMI_HDCP_DEBUG_CTRL (0x00000114) #define HDMI_HDCP_INT_CTRL (0x00000118) @@ -228,6 +229,9 @@ #define FRAME_PACKING 0x20 #define SIDE_BY_SIDE_HALF 0x40 +#define LPASS_LPAIF_RDDMA_CTL0 (0xFE152000) +#define LPASS_LPAIF_RDDMA_PER_CNT0 (0x00000014) + enum hdmi_tx_feature_type { HDMI_TX_FEAT_EDID, HDMI_TX_FEAT_HDCP, diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c index 7b6b3c6f818..c5f4b19b102 100644 --- a/drivers/video/msm/mdss/mdss_mdp.c +++ b/drivers/video/msm/mdss/mdss_mdp.c @@ -313,6 +313,23 @@ void mdss_enable_irq(struct mdss_hw *hw) } EXPORT_SYMBOL(mdss_enable_irq); +void mdss_enable_irq_wake(bool enable) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdss_lock, irq_flags); + if (enable && !mdss_res->irq_wakeup_en && mdss_res->irq_mask) { + enable_irq_wake(mdss_res->irq); + mdss_res->irq_wakeup_en = true; + } else if (!enable && mdss_res->irq_wakeup_en) { + disable_irq_wake(mdss_res->irq); + mdss_res->irq_wakeup_en = false; + } + spin_unlock_irqrestore(&mdss_lock, irq_flags); + pr_debug("%s en=%d mask=%x irq_wakeup_en=%d", __func__, + enable, mdss_res->irq_mask, mdss_res->irq_wakeup_en); +} + void mdss_disable_irq(struct mdss_hw *hw) { unsigned long irq_flags; diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c index 8bcd4bbfb9c..53f9613aa8d 100644 --- a/drivers/video/msm/mdss/mdss_mdp_overlay.c +++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 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 @@ -526,10 +526,12 @@ static int __mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe) if ((rc == -EOVERFLOW) && (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)) { /* overflow on Qseed2 scaler is acceptable */ rc = 0; + } else if (rc == -EOVERFLOW) { + /* overflow expected and should fallback to GPU */ + rc = -ECANCELED; } else if (rc) { pr_err("Vertical scaling calculation failed=%d! %d->%d\n", rc, src, pipe->dst.h); - return rc; } return rc; } @@ -839,6 +841,7 @@ int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, req->priority = pipe->priority; pipe->req_data = *req; + mdss_mdp_pipe_sspp_term(pipe); if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) { memcpy(&pipe->pp_cfg, &req->overlay_pp_cfg, sizeof(struct mdp_overlay_pp_params)); diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c index 872651ef32b..c4867172200 100644 --- a/drivers/video/msm/mdss/mdss_mdp_pp.c +++ b/drivers/video/msm/mdss/mdss_mdp_pp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2015, 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 @@ -1085,7 +1085,8 @@ static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe) } if ((src_h != pipe->dst.h) || - (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) || + (pipe->src_fmt->is_yuv && + (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE)) || (chroma_sample == MDSS_MDP_CHROMA_420) || (chroma_sample == MDSS_MDP_CHROMA_H1V2) || (pipe->scale.enable_pxl_ext && (src_h != pipe->dst.h))) { @@ -1141,7 +1142,8 @@ static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe) } if ((src_w != pipe->dst.w) || - (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) || + (pipe->src_fmt->is_yuv && + (pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE)) || (chroma_sample == MDSS_MDP_CHROMA_420) || (chroma_sample == MDSS_MDP_CHROMA_H2V1) || (pipe->scale.enable_pxl_ext && (src_w != pipe->dst.w))) { diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h index f864572d4b8..5f60d0d9dcf 100644 --- a/drivers/video/msm/mdss/mdss_panel.h +++ b/drivers/video/msm/mdss/mdss_panel.h @@ -388,6 +388,7 @@ struct mdss_panel_info { uint32_t panel_dead; struct mdss_mdp_pp_tear_check te; + bool is_prim_panel; struct lcd_panel_info lcdc; struct fbc_panel_info fbc; diff --git a/drivers/video/msm/mdss/mdss_wb.c b/drivers/video/msm/mdss/mdss_wb.c index aa98b996213..93f914819c7 100644 --- a/drivers/video/msm/mdss/mdss_wb.c +++ b/drivers/video/msm/mdss/mdss_wb.c @@ -121,26 +121,11 @@ static int mdss_wb_probe(struct platform_device *pdev) { struct mdss_panel_data *pdata = NULL; struct mdss_wb_ctrl *wb_ctrl = NULL; - struct mdss_panel_cfg *pan_cfg = NULL; int rc = 0; if (!pdev->dev.of_node) return -ENODEV; - /* - * In case HDMI is configured as primary, do not configure - * WB. Currently there is no requirement for any other panel - * in case HDMI is primary. Will revisit if WB is needed with - * HDMI as primary. - */ - pan_cfg = mdss_panel_intf_type(MDSS_PANEL_INTF_HDMI); - if (IS_ERR(pan_cfg)) { - return PTR_ERR(pan_cfg); - } else if (pan_cfg) { - pr_debug("%s: HDMI is primary\n", __func__); - return -ENODEV; - } - wb_ctrl = devm_kzalloc(&pdev->dev, sizeof(*wb_ctrl), GFP_KERNEL); if (!wb_ctrl) return -ENOMEM; @@ -151,12 +136,12 @@ static int mdss_wb_probe(struct platform_device *pdev) rc = !mdss_wb_parse_dt(pdev, pdata); if (!rc) - return rc; + goto error_no_mem; rc = mdss_wb_dev_init(wb_ctrl); if (rc) { dev_err(&pdev->dev, "unable to set up device nodes for writeback panel\n"); - return rc; + goto error_no_mem; } pdata->panel_info.type = WRITEBACK_PANEL; @@ -170,10 +155,16 @@ static int mdss_wb_probe(struct platform_device *pdev) rc = mdss_register_panel(pdev, pdata); if (rc) { dev_err(&pdev->dev, "unable to register writeback panel\n"); - return rc; + goto error_init; } return rc; + +error_init: + mdss_wb_dev_uninit(wb_ctrl); +error_no_mem: + devm_kfree(&pdev->dev, wb_ctrl); + return rc; } static int mdss_wb_remove(struct platform_device *pdev) diff --git a/include/linux/mdss_io_util.h b/include/linux/mdss_io_util.h index 6ad21e88787..45614fa3a81 100644 --- a/include/linux/mdss_io_util.h +++ b/include/linux/mdss_io_util.h @@ -86,6 +86,7 @@ struct dss_module_power { struct dss_gpio *gpio_config; unsigned num_clk; struct dss_clk *clk_config; + bool enable; }; int msm_dss_ioremap_byname(struct platform_device *pdev, diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h index 70fae94f888..e4e7fc84e49 100644 --- a/include/linux/msm_hdmi.h +++ b/include/linux/msm_hdmi.h @@ -14,6 +14,9 @@ #ifndef _MSM_HDMI_H_ #define _MSM_HDMI_H_ +#include +#include + /* * HDMI cable notify handler sturcture. * link A link for the linked list @@ -26,6 +29,25 @@ struct hdmi_cable_notify { void (*hpd_notify) (struct hdmi_cable_notify *h); }; +struct msm_hdmi_audio_edid_blk { + u8 *audio_data_blk; + unsigned int audio_data_blk_size; /* in bytes */ + u8 *spk_alloc_data_blk; + unsigned int spk_alloc_data_blk_size; /* in bytes */ +}; + +struct msm_hdmi_audio_codec_ops { + int (*audio_info_setup)(struct platform_device *pdev, + u32 sample_rate, u32 num_of_channels, + u32 channel_allocation, u32 level_shift, + bool down_mix); + int (*get_audio_edid_blk) (struct platform_device *pdev, + struct msm_hdmi_audio_edid_blk *blk); + int (*hdmi_cable_status) (struct platform_device *pdev, u32 vote); + void *callback_data; + u32 (*play_silent_audio_callback) (void *callback_data); +}; + #ifdef CONFIG_FB_MSM_MDSS_HDMI_PANEL /* * Register for HDMI cable connect or disconnect notification. @@ -42,16 +64,25 @@ int register_hdmi_cable_notification( */ int unregister_hdmi_cable_notification( struct hdmi_cable_notify *handler); + +int msm_hdmi_register_audio_codec(struct platform_device *pdev, + struct msm_hdmi_audio_codec_ops *ops); + #else -int register_hdmi_cable_notification( +static inline int register_hdmi_cable_notification( struct hdmi_cable_notify *handler) { return 0; } -int unregister_hdmi_cable_notification( +static inline int unregister_hdmi_cable_notification( struct hdmi_cable_notify *handler) { return 0; } + +static inline int msm_hdmi_register_audio_codec(struct platform_device *pdev, + struct msm_hdmi_audio_codec_ops *ops) { + return 0; +} #endif /* CONFIG_FB_MSM_MDSS_HDMI_PANEL */ #endif /*_MSM_HDMI_H_*/ diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h index 7a74b1cfcfd..c857b807727 100644 --- a/include/media/msm_cam_sensor.h +++ b/include/media/msm_cam_sensor.h @@ -54,6 +54,7 @@ #define MAX_NUMBER_OF_STEPS 47 #define MAX_LED_TRIGGERS 3 +#define MAX_POWER_CONFIG 12 enum sensor_stats_type { YRGB, diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index 13ddb7f16fa..311d52a28a6 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -218,4 +218,5 @@ void afe_clear_config(enum afe_config_type config); bool afe_has_config(enum afe_config_type config); void afe_set_aanc_info(struct aanc_data *aanc_info); +int afe_short_silence(u32 duration); #endif /* __Q6AFE_V2_H__ */ diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c index 4a14061ef34..e6613a6d016 100644 --- a/sound/soc/codecs/msm_hdmi_codec_rx.c +++ b/sound/soc/codecs/msm_hdmi_codec_rx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 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 @@ -17,7 +17,8 @@ #include #include #include -#include +#include +#include #define MSM_HDMI_PCM_RATES SNDRV_PCM_RATE_48000 @@ -205,6 +206,23 @@ static struct snd_soc_dai_ops msm_hdmi_audio_codec_rx_dai_ops = { .shutdown = msm_hdmi_audio_codec_rx_dai_shutdown }; +static u32 msm_hdmi_audio_codec_silent_play(void *data) +{ + int rc; + + struct msm_hdmi_audio_codec_rx_data *codec_data = + (struct msm_hdmi_audio_codec_rx_data *) data; + + rc = codec_data->hdmi_ops.audio_info_setup( + codec_data->hdmi_core_pdev, 48000, 2, 0, 0, 0); + if (IS_ERR_VALUE(rc)) + return rc; + + afe_short_silence(100); + + return 0; +} + static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) { struct msm_hdmi_audio_codec_rx_data *codec_data; @@ -234,6 +252,10 @@ static int msm_hdmi_audio_codec_rx_probe(struct snd_soc_codec *codec) return -ENODEV; } + codec_data->hdmi_ops.play_silent_audio_callback = + msm_hdmi_audio_codec_silent_play; + codec_data->hdmi_ops.callback_data = codec_data; + if (msm_hdmi_register_audio_codec(codec_data->hdmi_core_pdev, &codec_data->hdmi_ops)) { dev_err(codec->dev, "%s(): can't register with hdmi core", diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c index 19d7ac33899..a2309cdaf5b 100644 --- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c @@ -1177,11 +1177,9 @@ static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, prtd->cmd_interrupt = 0; return rc; default: - pr_err("%s: Invalid ioctl %d\n", __func__, cmd); - rc = -ENOTTY; break; } - return rc; + return snd_pcm_lib_ioctl(substream, cmd, arg); } static int msm_compr_ioctl(struct snd_pcm_substream *substream, diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-common.h b/sound/soc/msm/qdsp6v2/msm-dolby-common.h index c34a95f78e4..f874b6972fa 100644 --- a/sound/soc/msm/qdsp6v2/msm-dolby-common.h +++ b/sound/soc/msm/qdsp6v2/msm-dolby-common.h @@ -254,11 +254,9 @@ enum { USB_ACCESSORY = 0x2000, USB_DEVICE = 0x4000, REMOTE_SUBMIX = 0x8000, - ANC_HEADSET = 0x10000, - ANC_HEADPHONE = 0x20000, - PROXY = 0x40000, - FM = 0x80000, - FM_TX = 0x100000, + PROXY = 0x2000000, + FM = 0x100000, + FM_TX = 0x1000000, DEVICE_OUT_DEFAULT = 0x40000000, DEVICE_OUT_ALL = 0x403FFFFF, }; diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c index 3f6fd1a6b7e..7f371f53e5e 100644 --- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c @@ -175,22 +175,6 @@ const struct dolby_dap_endp_params_s DOLBY_ENDDEP_PARAM_VMB_OFFSET}, {-320, -320, 144} }, - {ANC_HEADSET, 2, DOLBY_ENDP_HEADPHONES, - {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB}, - {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH, - DOLBY_ENDDEP_PARAM_VMB_LENGTH}, - {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET, - DOLBY_ENDDEP_PARAM_VMB_OFFSET}, - {-320, -320, 144} - }, - {ANC_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES, - {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB}, - {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH, - DOLBY_ENDDEP_PARAM_VMB_LENGTH}, - {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET, - DOLBY_ENDDEP_PARAM_VMB_OFFSET}, - {-320, -320, 144} - }, {PROXY, 2, DOLBY_ENDP_EXT_SPEAKERS, {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB}, {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH, diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h index 4190ee384b4..b1d20009062 100644 --- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h +++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h @@ -18,7 +18,7 @@ #ifdef CONFIG_DOLBY_DAP /* DOLBY DOLBY GUIDS */ #define DOLBY_ADM_COPP_TOPOLOGY_ID 0x0001033B -#define NUM_DOLBY_ENDP_DEVICE 23 +#define NUM_DOLBY_ENDP_DEVICE 21 #define DOLBY_NUM_ENDP_DEPENDENT_PARAMS 3 #define DOLBY_ENDDEP_PARAM_DVLO_OFFSET 0 diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c index 1401ce0eb3a..71f08ddffd8 100644 --- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c @@ -181,7 +181,7 @@ static struct ds2_dap_params_states_s ds2_dap_params_states = {true, false, static int all_supported_devices = EARPIECE|SPEAKER|WIRED_HEADSET| WIRED_HEADPHONE|BLUETOOTH_SCO|AUX_DIGITAL| ANLG_DOCK_HEADSET|DGTL_DOCK_HEADSET| - REMOTE_SUBMIX|ANC_HEADSET|ANC_HEADPHONE| + REMOTE_SUBMIX| PROXY|FM|FM_TX|DEVICE_NONE| BLUETOOTH_SCO_HEADSET|BLUETOOTH_SCO_CARKIT; @@ -711,8 +711,6 @@ static int msm_ds2_dap_map_device_to_dolby_cache_devices(int32_t device_id) case WIRED_HEADPHONE: case ANLG_DOCK_HEADSET: case DGTL_DOCK_HEADSET: - case ANC_HEADSET: - case ANC_HEADPHONE: case BLUETOOTH_SCO: case BLUETOOTH_SCO_HEADSET: case BLUETOOTH_SCO_CARKIT: @@ -776,10 +774,6 @@ static int msm_ds2_dap_update_num_devices(struct dolby_param_data *dolby_data, dev_arr[idx++] = DGTL_DOCK_HEADSET; if ((idx < array_size) && (supported_devices & REMOTE_SUBMIX)) dev_arr[idx++] = REMOTE_SUBMIX; - if ((idx < array_size) && (supported_devices & ANC_HEADSET)) - dev_arr[idx++] = ANC_HEADSET; - if ((idx < array_size) && (supported_devices & ANC_HEADPHONE)) - dev_arr[idx++] = ANC_HEADPHONE; if ((idx < array_size) && (supported_devices & PROXY)) dev_arr[idx++] = PROXY; if ((idx < array_size) && (supported_devices & FM)) diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h index 772a1e21249..31fd36c2dcb 100644 --- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h +++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.h @@ -22,7 +22,7 @@ #define DS2_MODULE_ID 0x00010775 #define DS2_DSP_SUPPORTED_ENDP_DEVICE 17 -#define DS2_DEVICES_ALL 22 +#define DS2_DEVICES_ALL 32 /* enum val is 4 bytes */ enum { diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index ed8ce9ae0c2..4df9b894e58 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,6 +33,10 @@ enum { MAX_AFE_CAL_TYPES }; +enum { + STATUS_PORT_STARTED, /* track if AFE port has started */ + STATUS_MAX +}; struct afe_ctl { void *apr; @@ -60,6 +66,14 @@ struct afe_ctl { static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX]; static unsigned long afe_configured_cmd; +struct msm_dai_q6_hdmi_dai_data { + DECLARE_BITMAP(status_mask, STATUS_MAX); + u32 rate; + u32 channels; + union afe_port_config port_config; +}; + +static atomic_t hdmi_port_start; static struct afe_ctl this_afe; #define TIMEOUT_MS 1000 @@ -1636,6 +1650,7 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; case HDMI_RX: + atomic_set(&hdmi_port_start, 1); cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; case VOICE_PLAYBACK_TX: @@ -1709,6 +1724,8 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, ret = afe_send_cmd_port_start(port_id); fail_cmd: + if (port_id == HDMI_RX) + atomic_set(&hdmi_port_start, 0); mutex_unlock(&this_afe.afe_cmd_lock); return ret; } @@ -1782,6 +1799,29 @@ int afe_get_port_index(u16 port_id) } } +int afe_short_silence(u32 duration) +{ + struct msm_dai_q6_hdmi_dai_data dai_data; + u16 bit_width = 16; + if (atomic_read(&hdmi_port_start) == 1) + return 0; + + dai_data.rate = 48000; + dai_data.channels = 2; + dai_data.port_config.hdmi_multi_ch.bit_width = bit_width; + dai_data.port_config.hdmi_multi_ch.channel_allocation = 0; + + afe_port_start(HDMI_RX, &dai_data.port_config, + dai_data.rate); + + msleep(duration); + + afe_close(HDMI_RX); + + return 0; +} +EXPORT_SYMBOL(afe_short_silence); + int afe_open(u16 port_id, union afe_port_config *afe_config, int rate) { @@ -3332,6 +3372,8 @@ int afe_close(int port_id) if (ret) pr_err("%s: AFE close failed %d\n", __func__, ret); + if (port_id == HDMI_RX) + atomic_set(&hdmi_port_start, 0); fail_cmd: return ret; }