diff options
author | vamsi k <x0093442@ti.com> | 2012-01-24 19:08:15 +0530 |
---|---|---|
committer | Dan Murphy <dmurphy@ti.com> | 2012-02-15 11:18:03 -0600 |
commit | e5493a63c6e84a0066796c81477b92829363450b (patch) | |
tree | 327b8924d76b3d1a384d045c82dd7ecc2a115294 | |
parent | 2f1f998ad774c137d9a381ab3644e31bae3cf96f (diff) | |
download | kernel_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.c | 166 | ||||
-rw-r--r-- | drivers/video/hdmi_ti_4xxx_ip.h | 2 |
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 |