aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvamsi k <x0093442@ti.com>2012-01-24 19:08:15 +0530
committerDan Murphy <dmurphy@ti.com>2012-02-15 11:18:03 -0600
commite5493a63c6e84a0066796c81477b92829363450b (patch)
tree327b8924d76b3d1a384d045c82dd7ecc2a115294
parent2f1f998ad774c137d9a381ab3644e31bae3cf96f (diff)
downloadkernel_samsung_espresso10-e5493a63c6e84a0066796c81477b92829363450b.zip
kernel_samsung_espresso10-e5493a63c6e84a0066796c81477b92829363450b.tar.gz
kernel_samsung_espresso10-e5493a63c6e84a0066796c81477b92829363450b.tar.bz2
OMAP4: HDMI workaround excessive ACR packet reduction
Add support for enabling HDMI ACR WA. OMAP4430 ES2.0, ES2.1 and ES2.2, will send excessive ACR packets which lead to AVR inter-op issues and to "CTS Interval" compliance failures. This SW WA is implemented to overcome HW bug. Change-Id: Icde7ef8a04e5a8cba39ce9a045b81bb0c7cce290 Signed-off-by: vamsi krishna k <x0093442@ti.com> Signed-off-by: Axel Castaneda Gonzalez <x0055901@ti.com>
-rw-r--r--drivers/video/hdmi_ti_4xxx_ip.c166
-rw-r--r--drivers/video/hdmi_ti_4xxx_ip.h2
2 files changed, 167 insertions, 1 deletions
diff --git a/drivers/video/hdmi_ti_4xxx_ip.c b/drivers/video/hdmi_ti_4xxx_ip.c
index 99091ed..2f19785 100644
--- a/drivers/video/hdmi_ti_4xxx_ip.c
+++ b/drivers/video/hdmi_ti_4xxx_ip.c
@@ -29,9 +29,153 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/omapfb.h>
+#include <linux/rpmsg.h>
+#include <linux/remoteproc.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
#include "hdmi_ti_4xxx_ip.h"
+static bool hdmi_acrwa_registered;
+struct omap_chip_id audio_must_use_tclk;
+
+struct payload_data {
+ u32 cts_interval;
+ u32 acr_rate;
+ u32 sys_ck_rate;
+ u32 trigger;
+} hdmi_payload;
+
+static void hdmi_acrwa_cb(struct rpmsg_channel *rpdev, void *data, int len,
+ void *priv, u32 src)
+{
+ struct rproc *rproc;
+ struct payload_data *payload = data;
+ int err = 0;
+
+ if (!payload)
+ pr_err("HDMI ACRWA: No payload received (src: 0x%x)\n", src);
+
+ pr_info("HDMI ACRWA: ACRrate %d, CTSInterval %d, sys_clk %d,"
+ "(src: 0x%x)\n", payload->acr_rate,
+ payload->cts_interval, payload->sys_ck_rate, src);
+
+ if (payload && payload->cts_interval == hdmi_payload.cts_interval &&
+ payload->acr_rate == hdmi_payload.acr_rate &&
+ payload->sys_ck_rate == hdmi_payload.sys_ck_rate &&
+ payload->acr_rate && payload->sys_ck_rate &&
+ payload->cts_interval) {
+
+ hdmi_payload.trigger = 1;
+ err = rpmsg_send(rpdev, &hdmi_payload, sizeof(hdmi_payload));
+ if (err) {
+ pr_err("HDMI ACRWA: rpmsg trigger start"
+ "send failed: %d\n", err);
+ hdmi_payload.trigger = 0;
+ return;
+ }
+ /* Disable hibernation before Start HDMI ACRWA */
+ rproc = rproc_get("ipu");
+ pm_runtime_disable(rproc->dev);
+ rproc_put(rproc);
+
+ } else {
+ pr_err("HDMI ACRWA: Wrong payload received\n");
+ }
+}
+
+static int hdmi_acrwa_probe(struct rpmsg_channel *rpdev)
+{
+ int err = 0;
+ struct clk *sys_ck;
+
+ /* Sys clk rate is require to calculate cts_interval in ticks */
+ sys_ck = clk_get(NULL, "sys_clkin_ck");
+
+ if (IS_ERR(sys_ck)) {
+ pr_err("HDMI ACRWA: Not able to obtain sys_clk\n");
+ return -EINVAL;
+ }
+
+ hdmi_payload.sys_ck_rate = clk_get_rate(sys_ck);
+ hdmi_payload.trigger = 0;
+
+ /* send a message to our remote processor */
+ pr_info("HDMI ACRWA: Send START msg from:0x%x to:0x%x\n",
+ rpdev->src, rpdev->dst);
+ err = rpmsg_send(rpdev, &hdmi_payload, sizeof(hdmi_payload));
+ if (err)
+ pr_err("HDMI ACRWA: rpmsg payload send failed: %d\n", err);
+
+ return err;
+}
+
+static void __devexit hdmi_acrwa_remove(struct rpmsg_channel *rpdev)
+{
+ struct rproc *rproc;
+
+ if (hdmi_payload.trigger) {
+ hdmi_payload.cts_interval = 0;
+ hdmi_payload.acr_rate = 0;
+ hdmi_payload.sys_ck_rate = 0;
+ hdmi_payload.trigger = 0;
+
+ pr_info("HDMI ACRWA:Send STOP msg from:0x%x to:0x%x\n",
+ rpdev->src, rpdev->dst);
+ /* send a message to our remote processor */
+ rpmsg_send(rpdev, &hdmi_payload, sizeof(hdmi_payload));
+
+ /* Reenable hibernation after HDMI ACRWA stopped */
+ rproc = rproc_get("ipu");
+ pm_runtime_enable(rproc->dev);
+ rproc_put(rproc);
+ }
+}
+
+static struct rpmsg_device_id hdmi_acrwa_id_table[] = {
+ {
+ .name = "rpmsg-hdmiwa"
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, hdmi_acrwa_id_table);
+
+static struct rpmsg_driver hdmi_acrwa_driver = {
+ .drv.name = KBUILD_MODNAME,
+ .drv.owner = THIS_MODULE,
+ .id_table = hdmi_acrwa_id_table,
+ .probe = hdmi_acrwa_probe,
+ .callback = hdmi_acrwa_cb,
+ .remove = __devexit_p(hdmi_acrwa_remove),
+};
+
+int hdmi_lib_start_acr_wa(void)
+{
+ int ret = 0;
+
+ if (omap_chip_is(audio_must_use_tclk)) {
+ if (!hdmi_acrwa_registered) {
+ ret = register_rpmsg_driver(&hdmi_acrwa_driver);
+ if (ret) {
+ pr_err("Error creating hdmi_acrwa driver\n");
+ return ret;
+ }
+
+ hdmi_acrwa_registered = true;
+ }
+ }
+ return ret;
+}
+void hdmi_lib_stop_acr_wa(void)
+{
+ if (omap_chip_is(audio_must_use_tclk)) {
+ if (hdmi_acrwa_registered) {
+ unregister_rpmsg_driver(&hdmi_acrwa_driver);
+ hdmi_acrwa_registered = false;
+ }
+ }
+}
+
static inline void hdmi_write_reg(void __iomem *base_addr,
const struct hdmi_reg idx, u32 val)
{
@@ -281,6 +425,7 @@ int hdmi_ti_4xxx_phy_init(struct hdmi_ip_data *ip_data)
void hdmi_ti_4xxx_phy_off(struct hdmi_ip_data *ip_data, bool set_mode)
{
+ hdmi_lib_stop_acr_wa();
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF, set_mode);
}
EXPORT_SYMBOL(hdmi_ti_4xxx_phy_init);
@@ -1097,7 +1242,7 @@ int hdmi_ti_4xxx_config_audio_acr(struct hdmi_ip_data *ip_data,
{
u32 r;
u32 deep_color = 0;
-
+ u32 cts_interval_qtt, cts_interval_res, n_val, cts_interval;
if (n == NULL || cts == NULL)
return -EINVAL;
@@ -1148,6 +1293,22 @@ int hdmi_ti_4xxx_config_audio_acr(struct hdmi_ip_data *ip_data,
/* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
*cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+ if (omap_chip_is(audio_must_use_tclk)) {
+ n_val = *n;
+ cts_interval = 0;
+ if (pclk && deep_color) {
+ cts_interval_qtt = 1000000 /
+ ((pclk * deep_color) / 100);
+ cts_interval_res = 1000000 %
+ ((pclk * deep_color) / 100);
+ cts_interval = (cts_interval_res * n_val) /
+ ((pclk * deep_color) / 100);
+ cts_interval += cts_interval_qtt * n_val;
+ }
+ hdmi_payload.cts_interval = cts_interval;
+ hdmi_payload.acr_rate = 128 * sample_freq / n_val;
+ }
+
return 0;
}
EXPORT_SYMBOL(hdmi_ti_4xxx_config_audio_acr);
@@ -1387,6 +1548,9 @@ EXPORT_SYMBOL(hdmi_ti_4xx_check_aksv_data);
static int __init hdmi_ti_4xxx_init(void)
{
+ audio_must_use_tclk.oc = CHIP_IS_OMAP4430ES2 |
+ CHIP_IS_OMAP4430ES2_1 | CHIP_IS_OMAP4430ES2_2;
+ hdmi_acrwa_registered = false;
return 0;
}
diff --git a/drivers/video/hdmi_ti_4xxx_ip.h b/drivers/video/hdmi_ti_4xxx_ip.h
index 74607fa..793f957 100644
--- a/drivers/video/hdmi_ti_4xxx_ip.h
+++ b/drivers/video/hdmi_ti_4xxx_ip.h
@@ -342,4 +342,6 @@ struct hdmi_video_interface {
int tm; /* Timing mode */
};
+int hdmi_lib_start_acr_wa(void);
+void hdmi_lib_stop_acr_wa(void);
#endif