platform_device_register(&rk29xx_device_spi0m);
#endif
}
+
+#ifdef CONFIG_HDMI_RK2928
+static struct resource resource_hdmi[] = {
+ [0] = {
+ .start = RK2928_HDMI_PHYS,
+ .end = RK2928_HDMI_PHYS + RK2928_HDMI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_HDMI,
+ .end = IRQ_HDMI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device device_hdmi = {
+ .name = "rk2928-hdmi",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resource_hdmi),
+ .resource = resource_hdmi,
+};
+#endif
#ifdef CONFIG_RGA_RK30
static struct resource resource_rga[] = {
[0] = {
source "drivers/video/backlight/Kconfig"
source "drivers/video/display/Kconfig"
+
+if !LCDC_RK30 && !LCDC_RK2928
source "drivers/video/hdmi/Kconfig"
+endif
+
source "drivers/video/rockchip/Kconfig"
if VT
obj-$(CONFIG_LCDC_RK2928) += chips/rk2928_lcdc.o
obj-$(CONFIG_LCDC_RK31) += chips/rk31_lcdc.o
obj-$(CONFIG_RGA_RK30) += rga/
-obj-$(CONFIG_HDMI_RK30) += hdmi/
+obj-$(CONFIG_RK_HDMI) += hdmi/
-menuconfig HDMI_RK30
- bool "RK30 HDMI support"
- depends on LCDC_RK30
- select FB_MODE_HELPERS
- help
- Support rk30 hdmi if you say y here
+menu "RK_HDMI"
+config RK_HDMI
+ bool "RK_HDMI support"
+
+if RK_HDMI
+source "drivers/video/rockchip/hdmi/chips/Kconfig"
+endif
-config HDMI_RK30_CTL_CODEC
- bool "Mute Codec When HDMI Actived"
- depends on HDMI_RK30
- default n
- help
- If you say y heres, Codec will be mute when hdmi inserted,
- and unmute when removed.
-
-config HDMI_RK30_DEBUG
- bool "RK30 HDMI Debugging"
- depends on HDMI_RK30 && LCDC_RK30
- default n
- help
- Enableds verbose debugging the the HDMI drivers
-
-source "drivers/video/rockchip/hdmi/hdcp/Kconfig"
\ No newline at end of file
+endmenu
# Makefile for HDMI linux kernel module.
#
-ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG
+ccflags-$(CONFIG_RK_HDMI_DEBUG) = -DDEBUG -DHDMI_DEBUG
-obj-$(CONFIG_HDMI_RK30) += rk30_hdmi_hw.o rk30_hdmi_edid.o rk30_hdmi_lcdc.o rk30_hdmi_task.o rk30_hdmi_sysfs.o rk30_hdmi.o
-obj-$(CONFIG_HDCP_RK30) += hdcp/
+obj-$(CONFIG_RK_HDMI) += rk_hdmi_edid.o rk_hdmi_lcdc.o rk_hdmi_task.o rk_hdmi_sysfs.o
+obj-$(CONFIG_RK_HDMI) += chips/
--- /dev/null
+choice
+ prompt "HDMI chips select"
+config HDMI_RK30
+ bool "RK30 HDMI support"
+ depends on LCDC_RK30
+ select FB_MODE_HELPERS
+ help
+ Support rk30 hdmi if you say y here
+config HDMI_RK2928
+ bool "RK2928 HDMI support"
+ depends on LCDC_RK2928
+ select FB_MODE_HELPERS
+ help
+ Support rk2928 hdmi if you say y here
+endchoice
+
+if HDMI_RK30
+source "drivers/video/rockchip/hdmi/chips/rk30/Kconfig"
+endif
+
+if HDMI_RK2928
+source "drivers/video/rockchip/hdmi/chips/rk2928/Kconfig"
+endif
--- /dev/null
+#
+# Makefile for HDMI linux kernel module.
+#
+
+ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG
+
+obj-$(CONFIG_HDMI_RK30) += rk30/
+obj-$(CONFIG_HDMI_RK2928) += rk2928/
--- /dev/null
+#
+# Makefile for HDMI linux kernel module.
+#
+
+ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG
+
+obj-y += rk2928_hdmi_hw.o rk2928_hdmi.o
+obj-$(CONFIG_HDCP_RK2928) += hdcp/
--- /dev/null
+config HDCP_RK30
+ bool "RK30 HDCP support"
+ depends on LCDC_RK30 && HDMI_RK30
+ default n
+ help
+ HDCP Interface. This adds the High Definition Content Protection Interface.
+ See http://www.digital-cp.com/ for HDCP specification.
+
+config HDCP_RK30_DEBUG
+ bool "RK30 HDCP Debugging"
+ depends on HDCP_RK30
+ default n
+ help
+ Enableds verbose debugging the the HDCP drivers
--- /dev/null
+#
+# Makefile for HDCP linux kernel module.
+#
+
+ccflags-$(CONFIG_HDCP_RK30_DEBUG) = -DDEBUG -DHDCP_DEBUG
+
+obj-$(CONFIG_HDCP_RK30) += hdcp.o
+hdcp-y := rk30_hdcp.o rk30_hdmi_hdcp.o
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include "../rk30_hdmi.h"
+#include "../rk30_hdmi_hw.h"
+#include "rk30_hdmi_hdcp.h"
+
+struct hdcp *hdcp = NULL;
+
+static void hdcp_work_queue(struct work_struct *work);
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_submit_work
+ *-----------------------------------------------------------------------------
+ */
+static struct delayed_work *hdcp_submit_work(int event, int delay)
+{
+ struct hdcp_delayed_work *work;
+
+ DBG("%s event %04x delay %d", __FUNCTION__, event, delay);
+
+ work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC);
+
+ if (work) {
+ INIT_DELAYED_WORK(&work->work, hdcp_work_queue);
+ work->event = event;
+ queue_delayed_work(hdcp->workqueue,
+ &work->work,
+ msecs_to_jiffies(delay));
+ } else {
+ printk(KERN_WARNING "HDCP: Cannot allocate memory to "
+ "create work\n");
+ return 0;
+ }
+
+ return &work->work;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_cancel_work
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_cancel_work(struct delayed_work **work)
+{
+ int ret = 0;
+
+ if (*work) {
+ ret = cancel_delayed_work(*work);
+ if (ret != 1) {
+ ret = cancel_work_sync(&((*work)->work));
+ printk(KERN_INFO "Canceling work failed - "
+ "cancel_work_sync done %d\n", ret);
+ }
+ kfree(*work);
+ *work = 0;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_authentication_failure
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_authentication_failure(void)
+{
+ if (hdcp->hdmi_state == HDMI_STOPPED) {
+ return;
+ }
+
+ rk30_hdcp_disable();
+ rk30_hdmi_control_output(false);
+
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+
+ if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) {
+ if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) {
+ hdcp->retry_cnt--;
+ printk(KERN_INFO "HDCP: authentication failed - "
+ "retrying, attempts=%d\n",
+ hdcp->retry_cnt);
+ } else
+ printk(KERN_INFO "HDCP: authentication failed - "
+ "retrying\n");
+
+ hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+
+ hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT,
+ HDCP_REAUTH_DELAY);
+ } else {
+ printk(KERN_INFO "HDCP: authentication failed - "
+ "HDCP disabled\n");
+ hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+ }
+
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_start_authentication
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_start_authentication(void)
+{
+ int status = HDCP_OK;
+
+ hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+
+ DBG("HDCP: authentication start");
+
+ status = rk30_hdcp_start_authentication();
+
+ if (status != HDCP_OK) {
+ DBG("HDCP: authentication failed");
+ hdcp_wq_authentication_failure();
+ } else {
+ hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_check_bksv
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_check_bksv(void)
+{
+ int status = HDCP_OK;
+
+ DBG("Check BKSV start");
+
+ status = rk30_hdcp_check_bksv();
+
+ if (status != HDCP_OK) {
+ printk(KERN_INFO "HDCP: Check BKSV failed");
+ hdcp->retry_cnt = 0;
+ hdcp_wq_authentication_failure();
+ }
+ else {
+ DBG("HDCP: Check BKSV successful");
+
+ hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
+
+ /* Restore retry counter */
+ if(hdcp->retry_times == 0)
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+ else
+ hdcp->retry_cnt = hdcp->retry_times;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_authentication_sucess
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_authentication_sucess(void)
+{
+ printk(KERN_INFO "HDCP: authentication pass");
+ rk30_hdmi_control_output(true);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_disable
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_disable(int event)
+{
+ printk(KERN_INFO "HDCP: disabled");
+
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+ rk30_hdcp_disable();
+ if(event == HDCP_DISABLE_CTL) {
+ hdcp->hdcp_state = HDCP_DISABLED;
+ if(hdcp->hdmi_state == HDMI_STARTED)
+ rk30_hdmi_control_output(true);
+ }
+ else if(event == HDCP_STOP_FRAME_EVENT)
+ hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_work_queue
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_work_queue(struct work_struct *work)
+{
+ struct hdcp_delayed_work *hdcp_w =
+ container_of(work, struct hdcp_delayed_work, work.work);
+ int event = hdcp_w->event;
+
+ mutex_lock(&hdcp->lock);
+
+ DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d",
+ jiffies_to_msecs(jiffies),
+ hdcp->hdmi_state,
+ hdcp->hdcp_state,
+ (event & 0xFF00) >> 8,
+ event & 0xFF);
+
+ if(event == HDCP_STOP_FRAME_EVENT) {
+ hdcp->hdmi_state = HDMI_STOPPED;
+ }
+
+ if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) {
+ hdcp_wq_disable(event);
+ }
+
+ if (event & HDCP_WORKQUEUE_SRC)
+ hdcp->pending_wq_event = 0;
+
+ /* First handle HDMI state */
+ if (event == HDCP_START_FRAME_EVENT) {
+ hdcp->pending_start = 0;
+ hdcp->hdmi_state = HDMI_STARTED;
+ }
+
+ /**********************/
+ /* HDCP state machine */
+ /**********************/
+ switch (hdcp->hdcp_state) {
+ case HDCP_DISABLED:
+ /* HDCP enable control or re-authentication event */
+ if (event == HDCP_ENABLE_CTL) {
+ if(hdcp->retry_times == 0)
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+ else
+ hdcp->retry_cnt = hdcp->retry_times;
+ if (hdcp->hdmi_state == HDMI_STARTED)
+ hdcp_wq_start_authentication();
+ else
+ hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+ }
+ break;
+
+ case HDCP_ENABLE_PENDING:
+ /* HDMI start frame event */
+ if (event == HDCP_START_FRAME_EVENT)
+ hdcp_wq_start_authentication();
+
+ break;
+
+ case HDCP_AUTHENTICATION_START:
+ /* Re-authentication */
+ if (event == HDCP_AUTH_REATT_EVENT)
+ hdcp_wq_start_authentication();
+
+ break;
+
+ case HDCP_WAIT_KSV_LIST:
+ /* KSV failure */
+ if (event == HDCP_FAIL_EVENT) {
+ printk(KERN_INFO "HDCP: KSV switch failure\n");
+
+ hdcp_wq_authentication_failure();
+ }
+ /* KSV list ready event */
+ else if (event == HDCP_KSV_LIST_RDY_EVENT)
+ hdcp_wq_check_bksv();
+ break;
+
+ case HDCP_LINK_INTEGRITY_CHECK:
+ /* Ri failure */
+ if (event == HDCP_FAIL_EVENT) {
+ printk(KERN_INFO "HDCP: Ri check failure\n");
+ hdcp_wq_authentication_failure();
+ }
+ else if(event == HDCP_AUTH_PASS_EVENT)
+ hdcp_wq_authentication_sucess();
+ break;
+
+ default:
+ printk(KERN_WARNING "HDCP: error - unknow HDCP state\n");
+ break;
+ }
+
+ kfree(hdcp_w);
+ if(event == HDCP_STOP_FRAME_EVENT)
+ complete(&hdcp->complete);
+
+ mutex_unlock(&hdcp->lock);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_start_frame_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_start_frame_cb(void)
+{
+ DBG("hdcp_start_frame_cb()");
+
+ /* Cancel any pending work */
+ if (hdcp->pending_start)
+ hdcp_cancel_work(&hdcp->pending_start);
+ if (hdcp->pending_wq_event)
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+
+ hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT,
+ HDCP_ENABLE_DELAY);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_irq_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_irq_cb(int interrupt)
+{
+ int value;
+ DBG("%s 0x%x", __FUNCTION__, interrupt);
+ if(interrupt & m_INT_HDCP_ERR)
+ {
+ value = HDMIRdReg(HDCP_ERROR);
+ HDMIWrReg(HDCP_ERROR, value);
+ printk(KERN_INFO "HDCP: Error 0x%02x\n", value);
+
+ if( (hdcp->hdcp_state != HDCP_DISABLED) &&
+ (hdcp->hdcp_state != HDCP_ENABLE_PENDING) )
+ {
+ hdcp_submit_work(HDCP_FAIL_EVENT, 0);
+ }
+ }
+ else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY))
+ hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0);
+ else if(interrupt & m_INT_AUTH_DONE)
+ hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_on_cb
+ *-----------------------------------------------------------------------------
+ */
+static int hdcp_power_on_cb(void)
+{
+ DBG("%s", __FUNCTION__);
+ return rk30_hdcp_load_key2mem(hdcp->keys);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_off_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_power_off_cb(void)
+{
+ DBG("%s", __FUNCTION__);
+ if(!hdcp->enable)
+ return;
+
+ hdcp_cancel_work(&hdcp->pending_start);
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+ init_completion(&hdcp->complete);
+ /* Post event to workqueue */
+ if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0))
+ wait_for_completion_interruptible_timeout(&hdcp->complete,
+ msecs_to_jiffies(2000));
+}
+
+// Load HDCP key to external HDCP memory
+static void hdcp_load_keys_cb(const struct firmware *fw, void *context)
+{
+ if (!fw) {
+ pr_err("HDCP: failed to load keys\n");
+ return;
+ }
+
+ if(fw->size < HDCP_KEY_SIZE) {
+ pr_err("HDCP: firmware wrong size %d\n", fw->size);
+ return;
+ }
+
+ hdcp->keys = kmalloc(HDCP_KEY_SIZE, GFP_KERNEL);
+ if(hdcp->keys == NULL) {
+ pr_err("HDCP: can't allocated space for keys\n");
+ return;
+ }
+
+ memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE);
+
+ rk30_hdcp_load_key2mem(hdcp->keys);
+ printk(KERN_INFO "HDCP: loaded hdcp key success\n");
+
+ if(fw->size > HDCP_KEY_SIZE) {
+ DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE);
+ if((fw->size - HDCP_KEY_SIZE) % 5) {
+ pr_err("HDCP: failed to load invalid keys\n");
+ return;
+ }
+ hdcp->invalidkeys = kmalloc(fw->size - HDCP_KEY_SIZE, GFP_KERNEL);
+ if(hdcp->invalidkeys == NULL) {
+ pr_err("HDCP: can't allocated space for invalid keys\n");
+ return;
+ }
+ memcpy(hdcp->invalidkeys, fw->data + HDCP_KEY_SIZE, fw->size - HDCP_KEY_SIZE);
+ hdcp->invalidkey = (fw->size - HDCP_KEY_SIZE)/5;
+ printk(KERN_INFO "HDCP: loaded hdcp invalid key success\n");
+ }
+}
+
+static ssize_t hdcp_enable_read(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ int enable = 0;
+
+ if(hdcp)
+ enable = hdcp->enable;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", enable);
+}
+
+static ssize_t hdcp_enable_write(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int enable;
+
+ if(hdcp == NULL)
+ return -EINVAL;
+
+ sscanf(buf, "%d", &enable);
+ if(hdcp->enable != enable)
+ {
+ /* Post event to workqueue */
+ if(enable) {
+ if (hdcp_submit_work(HDCP_ENABLE_CTL, 0) == 0)
+ return -EFAULT;
+ }
+ else {
+ hdcp_cancel_work(&hdcp->pending_start);
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+
+ /* Post event to workqueue */
+ if (hdcp_submit_work(HDCP_DISABLE_CTL, 0) == 0)
+ return -EFAULT;
+ }
+ hdcp->enable = enable;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, hdcp_enable_read, hdcp_enable_write);
+
+static ssize_t hdcp_trytimes_read(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ int trytimes = 0;
+
+ if(hdcp)
+ trytimes = hdcp->retry_times;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", trytimes);
+}
+
+static ssize_t hdcp_trytimes_wrtie(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int trytimes;
+
+ if(hdcp == NULL)
+ return -EINVAL;
+
+ sscanf(buf, "%d", &trytimes);
+ if(hdcp->retry_times != trytimes)
+ hdcp->retry_times = trytimes;
+
+ return count;
+}
+
+
+static DEVICE_ATTR(trytimes, S_IRUGO|S_IWUSR, hdcp_trytimes_read, hdcp_trytimes_wrtie);
+
+
+static struct miscdevice mdev;
+
+static int __init rk30_hdcp_init(void)
+{
+ int ret;
+
+ DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies));
+
+ hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL);
+ if(!hdcp)
+ {
+ printk(KERN_ERR ">>HDCP: kmalloc fail!");
+ ret = -ENOMEM;
+ goto error0;
+ }
+ memset(hdcp, 0, sizeof(struct hdcp));
+ mutex_init(&hdcp->lock);
+
+ mdev.minor = MISC_DYNAMIC_MINOR;
+ mdev.name = "hdcp";
+ mdev.mode = 0666;
+ if (misc_register(&mdev)) {
+ printk(KERN_ERR "HDCP: Could not add character driver\n");
+ ret = HDMI_ERROR_FALSE;
+ goto error1;
+ }
+ ret = device_create_file(mdev.this_device, &dev_attr_enable);
+ if(ret)
+ {
+ printk(KERN_ERR "HDCP: Could not add sys file enable\n");
+ ret = -EINVAL;
+ goto error2;
+ }
+
+ ret = device_create_file(mdev.this_device, &dev_attr_trytimes);
+ if(ret)
+ {
+ printk(KERN_ERR "HDCP: Could not add sys file trytimes\n");
+ ret = -EINVAL;
+ goto error3;
+ }
+
+ hdcp->workqueue = create_singlethread_workqueue("hdcp");
+ if (hdcp->workqueue == NULL) {
+ printk(KERN_ERR "HDCP,: create workqueue failed.\n");
+ goto error4;
+ }
+
+
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ "hdcp.keys", mdev.this_device, GFP_KERNEL,
+ hdcp, hdcp_load_keys_cb);
+ if (ret < 0) {
+ printk(KERN_ERR "HDCP: request_firmware_nowait failed: %d\n", ret);
+ goto error5;
+ }
+
+ rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb,
+ hdcp_irq_cb,
+ hdcp_power_on_cb,
+ hdcp_power_off_cb);
+
+ DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies));
+ return 0;
+
+error5:
+ destroy_workqueue(hdcp->workqueue);
+error4:
+ device_remove_file(mdev.this_device, &dev_attr_trytimes);
+error3:
+ device_remove_file(mdev.this_device, &dev_attr_enable);
+error2:
+ misc_deregister(&mdev);
+error1:
+ if(hdcp->keys)
+ kfree(hdcp->keys);
+ if(hdcp->invalidkeys)
+ kfree(hdcp->invalidkeys);
+ kfree(hdcp);
+error0:
+ return ret;
+}
+
+static void __exit rk30_hdcp_exit(void)
+{
+ if(hdcp) {
+ mutex_lock(&hdcp->lock);
+ rk30_hdmi_register_hdcp_callbacks(0, 0, 0, 0);
+ device_remove_file(mdev.this_device, &dev_attr_enable);
+ misc_deregister(&mdev);
+ destroy_workqueue(hdcp->workqueue);
+ if(hdcp->keys)
+ kfree(hdcp->keys);
+ if(hdcp->invalidkeys)
+ kfree(hdcp->invalidkeys);
+ mutex_unlock(&hdcp->lock);
+ kfree(hdcp);
+ }
+}
+
+module_init(rk30_hdcp_init);
+module_exit(rk30_hdcp_exit);
\ No newline at end of file
--- /dev/null
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <mach/io.h>
+#include "../rk30_hdmi.h"
+#include "../rk30_hdmi_hw.h"
+#include "rk30_hdmi_hdcp.h"
+
+static void rk30_hdcp_write_mem(int addr_8, char value)
+{
+ int temp;
+ int addr_32 = addr_8 - addr_8%4;
+ int shift = (addr_8%4) * 8;
+
+ temp = HDMIRdReg(addr_32);
+ temp &= ~(0xff << shift);
+ temp |= value << shift;
+// printk("temp is %08x\n", temp);
+ HDMIWrReg(addr_32, temp);
+}
+
+int rk30_hdcp_load_key2mem(struct hdcp_keys *key)
+{
+ int i;
+
+ if(key == NULL) return HDMI_ERROR_FALSE;
+
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
+
+ for(i = 0; i < 7; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV1 + i, key->KSV[i]);
+ for(i = 0; i < 7; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV2 + i, key->KSV[i]);
+ for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + i, key->DeviceKey[i]);
+ for(i = 0; i < HDCP_KEY_SHA_SIZE; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + HDCP_PRIVATE_KEY_SIZE + i, key->sha1[i]);
+
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV | 0x20);
+ return HDCP_OK;
+}
+
+void rk30_hdcp_disable(void)
+{
+ int temp;
+ // Diable HDCP Interrupt
+ HDMIWrReg(INTR_MASK2, 0x00);
+ // Stop and Reset HDCP
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET,
+ v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) );
+}
+
+static int rk30_hdcp_load_key(void)
+{
+ int value, temp = 0;
+
+ if(hdcp->keys == NULL) {
+ pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__);
+ return HDCP_KEY_ERR;
+ }
+
+ value = HDMIRdReg(HDCP_KEY_MEM_CTRL);
+ //Check HDCP key loaded from external HDCP memory
+ while((value & (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) != (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) {
+ if(temp > 10) {
+ pr_err("[%s] loaded hdcp key is incorrectable %02x\n", __FUNCTION__, value & 0xFF);
+ return HDCP_KEY_ERR;
+ }
+ //Load HDCP Key from external HDCP memory
+ HDMIWrReg(HDCP_KEY_ACCESS_CTRL2, m_LOAD_HDCP_KEY);
+ msleep(1);
+ value = HDMIRdReg(HDCP_KEY_MEM_CTRL);
+ temp++;
+ }
+
+ return HDCP_OK;
+}
+
+
+int rk30_hdcp_start_authentication(void)
+{
+ int rc, temp;
+
+ rc = rk30_hdcp_load_key();
+ if(rc != HDCP_OK)
+ return rc;
+
+ // Set 100ms & 5 sec timer
+ switch(hdmi->vic)
+ {
+ case HDMI_720x576p_50Hz_4_3:
+ case HDMI_720x576p_50Hz_16_9:
+ case HDMI_1280x720p_50Hz:
+ case HDMI_1920x1080i_50Hz:
+ case HDMI_720x576i_50Hz_4_3:
+ case HDMI_720x576i_50Hz_16_9:
+ case HDMI_1920x1080p_50Hz:
+ HDMIWrReg(HDCP_TIMER_100MS, 5);
+ HDMIWrReg(HDCP_TIMER_5S, 250);
+ break;
+
+ default:
+ HDMIWrReg(HDCP_TIMER_100MS, 0x26);
+ HDMIWrReg(HDCP_TIMER_5S, 0x2c);
+ break;
+ }
+ // Config DDC Clock
+ temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4;
+ HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF);
+ HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF);
+ // Enable HDCP Interrupt
+ HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY);
+ // Start HDCP
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0));
+
+ return HDCP_OK;
+}
+
+int rk30_hdcp_check_bksv(void)
+{
+ int i, temp;
+ char bksv[5];
+ char *invalidkey;
+
+ temp = HDMIRdReg(HDCP_BCAPS);
+ DBG("Receiver capacity is 0x%02x", temp);
+
+#ifdef DEBUG
+ if(temp & m_HDMI_RECEIVED)
+ DBG("Receiver support HDMI");
+ if(temp & m_REPEATER)
+ DBG("Receiver is a repeater");
+ if(temp & m_DDC_FAST)
+ DBG("Receiver support 400K DDC");
+ if(temp & m_1_1_FEATURE)
+ DBG("Receiver support 1.1 features, such as advanced cipher, EESS.");
+ if(temp & m_FAST_REAUTHENTICATION)
+ DBG("Receiver support fast reauthentication.");
+#endif
+
+ for(i = 0; i < 5; i++) {
+ bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF;
+ }
+
+ DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
+
+ for(i = 0; i < hdcp->invalidkey; i++)
+ {
+ invalidkey = hdcp->invalidkeys + i *5;
+ if(memcmp(bksv, invalidkey, 5) == 0) {
+ printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0));
+ return HDCP_KSV_ERR;
+ }
+ }
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1));
+ return HDCP_OK;
+}
--- /dev/null
+#ifndef __RK30_HDMI_HDCP_H__
+#define __RK30_HDMI_HDCP_H__
+
+/***************************/
+/* Definitions */
+/***************************/
+
+/* Status / error codes */
+#define HDCP_OK 0
+#define HDCP_KEY_ERR 1
+#define HDCP_KSV_ERR 2
+
+/* Delays */
+#define HDCP_ENABLE_DELAY 300
+#define HDCP_REAUTH_DELAY 100
+
+/* Event source */
+#define HDCP_SRC_SHIFT 8
+#define HDCP_IOCTL_SRC (0x1 << HDCP_SRC_SHIFT)
+#define HDCP_HDMI_SRC (0x2 << HDCP_SRC_SHIFT)
+#define HDCP_IRQ_SRC (0x4 << HDCP_SRC_SHIFT)
+#define HDCP_WORKQUEUE_SRC (0x8 << HDCP_SRC_SHIFT)
+
+/* Event */
+#define HDCP_ENABLE_CTL (HDCP_IOCTL_SRC | 0)
+#define HDCP_DISABLE_CTL (HDCP_IOCTL_SRC | 1)
+#define HDCP_START_FRAME_EVENT (HDCP_HDMI_SRC | 2)
+#define HDCP_STOP_FRAME_EVENT (HDCP_HDMI_SRC | 3)
+#define HDCP_KSV_LIST_RDY_EVENT (HDCP_IRQ_SRC | 4)
+#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 5)
+#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 6)
+#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 7)
+
+/* Key size */
+#define HDCP_KEY_SIZE 308
+
+/* Authentication retry times */
+#define HDCP_INFINITE_REAUTH 0x100
+
+enum hdcp_states {
+ HDCP_DISABLED,
+ HDCP_ENABLE_PENDING,
+ HDCP_AUTHENTICATION_START,
+ HDCP_WAIT_KSV_LIST,
+ HDCP_LINK_INTEGRITY_CHECK,
+};
+
+enum hdmi_states {
+ HDMI_STOPPED,
+ HDMI_STARTED
+};
+
+#define HDCP_PRIVATE_KEY_SIZE 280
+#define HDCP_KEY_SHA_SIZE 20
+#define HDCP_DDC_CLK 100000
+
+struct hdcp_keys{
+ u8 KSV[8];
+ u8 DeviceKey[HDCP_PRIVATE_KEY_SIZE];
+ u8 sha1[HDCP_KEY_SHA_SIZE];
+};
+
+struct hdcp_delayed_work {
+ struct delayed_work work;
+ int event;
+};
+
+struct hdcp {
+ int enable;
+ int retry_times;
+ struct hdcp_keys *keys;
+ int invalidkey;
+ char *invalidkeys;
+ struct mutex lock;
+ struct completion complete;
+ struct workqueue_struct *workqueue;
+
+ enum hdmi_states hdmi_state;
+ enum hdcp_states hdcp_state;
+
+ struct delayed_work *pending_start;
+ struct delayed_work *pending_wq_event;
+ int retry_cnt;
+};
+
+extern struct hdcp *hdcp;
+
+#ifdef HDCP_DEBUG
+#define DBG(format, ...) \
+ printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+extern void rk30_hdcp_disable(void);
+extern int rk30_hdcp_start_authentication(void);
+extern int rk30_hdcp_check_bksv(void);
+extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key);
+#endif /* __RK30_HDMI_HDCP_H__ */
\ No newline at end of file
--- /dev/null
+#include <linux/module.h>\r
+#include <linux/kernel.h>\r
+#include <linux/errno.h>\r
+#include <linux/string.h>\r
+#include <linux/mm.h>\r
+#include <linux/slab.h>\r
+#include <linux/delay.h>\r
+#include <linux/device.h>\r
+#include <linux/init.h>\r
+#include <linux/dma-mapping.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/clk.h>\r
+\r
+#include <mach/board.h>\r
+#include <mach/io.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include "rk2928_hdmi.h"\r
+#include "rk2928_hdmi_hw.h"\r
+\r
+struct hdmi *hdmi = NULL;\r
+\r
+extern irqreturn_t hdmi_irq(int irq, void *priv);\r
+extern void hdmi_work(struct work_struct *work);\r
+extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);\r
+extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);\r
+extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);\r
+\r
+int rk2928_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),\r
+ void (*hdcp_irq_cb)(int status),\r
+ int (*hdcp_power_on_cb)(void),\r
+ void (*hdcp_power_off_cb)(void))\r
+{\r
+ if(hdmi == NULL)\r
+ return HDMI_ERROR_FALSE;\r
+\r
+ hdmi->hdcp_cb = hdcp_cb;\r
+ hdmi->hdcp_irq_cb = hdcp_irq_cb;\r
+ hdmi->hdcp_power_on_cb = hdcp_power_on_cb;\r
+ hdmi->hdcp_power_off_cb = hdcp_power_off_cb;\r
+ \r
+ return HDMI_ERROR_SUCESS;\r
+}\r
+\r
+#ifdef CONFIG_HAS_EARLYSUSPEND\r
+static void hdmi_early_suspend(struct early_suspend *h)\r
+{\r
+ hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
+ flush_delayed_work(&hdmi->delay_work); \r
+ mutex_lock(&hdmi->enable_mutex);\r
+ hdmi->suspend = 1;\r
+ if(!hdmi->enable) {\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ return;\r
+ }\r
+ disable_irq(hdmi->irq);\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ hdmi->command = HDMI_CONFIG_ENABLE;\r
+ init_completion(&hdmi->complete);\r
+ hdmi->wait = 1;\r
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);\r
+ wait_for_completion_interruptible_timeout(&hdmi->complete,\r
+ msecs_to_jiffies(5000));\r
+ flush_delayed_work(&hdmi->delay_work);\r
+ // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced\r
+ // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO.\r
+// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_GPIO0A7);\r
+// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_GPIO0A6);\r
+ return;\r
+}\r
+\r
+static void hdmi_early_resume(struct early_suspend *h)\r
+{\r
+ hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");\r
+ mutex_lock(&hdmi->enable_mutex);\r
+ \r
+// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA);\r
+// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL);\r
+ \r
+ hdmi->suspend = 0;\r
+ rk2928_hdmi_initial();\r
+ if(hdmi->enable) {\r
+ enable_irq(hdmi->irq);\r
+ }\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ return;\r
+}\r
+#endif\r
+\r
+static inline void hdmi_io_remap(void)\r
+{\r
+ unsigned int value;\r
+ \r
+ // Remap HDMI IO Pin\r
+// rk2928_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA);\r
+// rk2928_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL);\r
+// rk2928_mux_api_set(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B_HDMI_HOTPLUGIN);\r
+ \r
+ // Select LCDC0 as video source and enabled.\r
+// value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);\r
+// writel(value, GRF_SOC_CON0 + rk2928_GRF_BASE);\r
+}\r
+\r
+static int __devinit rk2928_hdmi_probe (struct platform_device *pdev)\r
+{\r
+ int ret;\r
+ struct resource *res;\r
+ struct resource *mem;\r
+ \r
+ hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);\r
+ if(!hdmi)\r
+ {\r
+ dev_err(&pdev->dev, ">>rk30 hdmi kmalloc fail!");\r
+ return -ENOMEM;\r
+ }\r
+ memset(hdmi, 0, sizeof(struct hdmi));\r
+ hdmi->dev = &pdev->dev;\r
+ platform_set_drvdata(pdev, hdmi);\r
+\r
+ if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)\r
+ hdmi->lcdc = rk_get_lcdc_drv("lcdc0");\r
+ else\r
+ hdmi->lcdc = rk_get_lcdc_drv("lcdc1");\r
+ if(hdmi->lcdc == NULL)\r
+ {\r
+ dev_err(hdmi->dev, "can not connect to video source lcdc\n");\r
+ ret = -ENXIO;\r
+ goto err0;\r
+ }\r
+ hdmi->xscale = 95;\r
+ hdmi->yscale = 95;\r
+ \r
+ hdmi->hclk = clk_get(NULL,"hclk_hdmi");\r
+ if(IS_ERR(hdmi->hclk))\r
+ {\r
+ dev_err(hdmi->dev, "Unable to get hdmi hclk\n");\r
+ ret = -ENXIO;\r
+ goto err0;\r
+ }\r
+ clk_enable(hdmi->hclk);\r
+ \r
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+ if (!res) {\r
+ dev_err(hdmi->dev, "Unable to get register resource\n");\r
+ ret = -ENXIO;\r
+ goto err0;\r
+ }\r
+ hdmi->regbase_phy = res->start;\r
+ hdmi->regsize_phy = (res->end - res->start) + 1;\r
+ mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name);\r
+ if (!mem)\r
+ {\r
+ dev_err(hdmi->dev, "failed to request mem region for hdmi\n");\r
+ ret = -ENOENT;\r
+ goto err0;\r
+ }\r
+\r
+ \r
+ hdmi->regbase = (int)ioremap(res->start, (res->end - res->start) + 1);\r
+ if (!hdmi->regbase) {\r
+ dev_err(hdmi->dev, "cannot ioremap registers\n");\r
+ ret = -ENXIO;\r
+ goto err1;\r
+ }\r
+ \r
+ ret = rk2928_hdmi_initial();\r
+ if(ret != HDMI_ERROR_SUCESS)\r
+ goto err1;\r
+ \r
+ hdmi_io_remap();\r
+ hdmi_sys_init();\r
+ \r
+ hdmi->workqueue = create_singlethread_workqueue("hdmi");\r
+ INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);\r
+\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ hdmi->early_suspend.suspend = hdmi_early_suspend;\r
+ hdmi->early_suspend.resume = hdmi_early_resume;\r
+ hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;\r
+ register_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ \r
+ hdmi_register_display_sysfs(hdmi, NULL);\r
+ #ifdef CONFIG_SWITCH\r
+ hdmi->switch_hdmi.name="hdmi";\r
+ switch_dev_register(&(hdmi->switch_hdmi));\r
+ #endif\r
+ \r
+ spin_lock_init(&hdmi->irq_lock);\r
+ mutex_init(&hdmi->enable_mutex);\r
+ \r
+ /* get the IRQ */\r
+ hdmi->irq = platform_get_irq(pdev, 0);\r
+ if(hdmi->irq <= 0) {\r
+ dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq);\r
+ ret = -ENXIO;\r
+ goto err2;\r
+ }\r
+\r
+ /* request the IRQ */\r
+ ret = request_irq(hdmi->irq, hdmi_irq, 0, dev_name(&pdev->dev), hdmi);\r
+ if (ret)\r
+ {\r
+ dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret);\r
+ goto err2;\r
+ }\r
+\r
+ hdmi_dbg(hdmi->dev, "rk30 hdmi probe sucess.\n");\r
+ return 0;\r
+err2:\r
+ #ifdef CONFIG_SWITCH\r
+ switch_dev_unregister(&(hdmi->switch_hdmi));\r
+ #endif\r
+ hdmi_unregister_display_sysfs(hdmi);\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ unregister_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ iounmap((void*)hdmi->regbase);\r
+err1:\r
+ release_mem_region(res->start,(res->end - res->start) + 1);\r
+ clk_disable(hdmi->hclk);\r
+err0:\r
+ hdmi_dbg(hdmi->dev, "rk30 hdmi probe error.\n");\r
+ kfree(hdmi);\r
+ hdmi = NULL;\r
+ return ret;\r
+}\r
+\r
+static int __devexit rk2928_hdmi_remove(struct platform_device *pdev)\r
+{\r
+ if(hdmi) {\r
+ mutex_lock(&hdmi->enable_mutex);\r
+ if(!hdmi->suspend && hdmi->enable)\r
+ disable_irq(hdmi->irq);\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ free_irq(hdmi->irq, NULL);\r
+ flush_workqueue(hdmi->workqueue);\r
+ destroy_workqueue(hdmi->workqueue);\r
+ #ifdef CONFIG_SWITCH\r
+ switch_dev_unregister(&(hdmi->switch_hdmi));\r
+ #endif\r
+ hdmi_unregister_display_sysfs(hdmi);\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ unregister_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ iounmap((void*)hdmi->regbase);\r
+ release_mem_region(hdmi->regbase_phy, hdmi->regsize_phy);\r
+ clk_disable(hdmi->hclk);\r
+ fb_destroy_modelist(&hdmi->edid.modelist);\r
+ if(hdmi->edid.audio)\r
+ kfree(hdmi->edid.audio);\r
+ if(hdmi->edid.specs)\r
+ {\r
+ if(hdmi->edid.specs->modedb)\r
+ kfree(hdmi->edid.specs->modedb);\r
+ kfree(hdmi->edid.specs);\r
+ }\r
+ kfree(hdmi);\r
+ hdmi = NULL;\r
+ }\r
+ printk(KERN_INFO "rk30 hdmi removed.\n");\r
+ return 0;\r
+}\r
+\r
+static void rk2928_hdmi_shutdown(struct platform_device *pdev)\r
+{\r
+ if(hdmi) {\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ unregister_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ }\r
+ printk(KERN_INFO "rk30 hdmi shut down.\n");\r
+}\r
+\r
+static struct platform_driver rk2928_hdmi_driver = {\r
+ .probe = rk2928_hdmi_probe,\r
+ .remove = __devexit_p(rk2928_hdmi_remove),\r
+ .driver = {\r
+ .name = "rk30-hdmi",\r
+ .owner = THIS_MODULE,\r
+ },\r
+ .shutdown = rk2928_hdmi_shutdown,\r
+};\r
+\r
+static int __init rk2928_hdmi_init(void)\r
+{\r
+ return platform_driver_register(&rk2928_hdmi_driver);\r
+}\r
+\r
+static void __exit rk2928_hdmi_exit(void)\r
+{\r
+ platform_driver_unregister(&rk2928_hdmi_driver);\r
+}\r
+\r
+\r
+//fs_initcall(rk2928_hdmi_init);\r
+module_init(rk2928_hdmi_init);\r
+module_exit(rk2928_hdmi_exit);\r
--- /dev/null
+#ifndef __RK30_HDMI_H__
+#define __RK30_HDMI_H__
+
+#include "../../rk_hdmi.h"
+
+
+extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
+ void (*hdcp_irq_cb)(int status),
+ int (*hdcp_power_on_cb)(void),
+ void (*hdcp_power_off_cb)(void));
+#endif /* __RK30_HDMI_H__ */
--- /dev/null
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <mach/io.h>
+#include "rk2928_hdmi.h"
+#include "rk2928_hdmi_hw.h"
+
+static char edid_result = 0;
+static bool analog_sync = 0;
+
+static inline void delay100us(void)
+{
+ msleep(1);
+}
+
+
+static void rk2928_hdmi_av_mute(bool enable)
+{
+ HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(enable) | v_VIDEO_MUTE(enable));
+}
+
+static void rk2928_hdmi_sys_power_up(void)
+{
+ hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__);
+ HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_ON | v_INT_POL_HIGH);
+}
+static void rk2928_hdmi_sys_power_down(void)
+{
+ hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__);
+ HDMIWrReg(SYS_CTRL, v_REG_CLK_SOURCE_IIS | v_PWR_OFF | v_INT_POL_HIGH);
+}
+
+
+
+static void rk2928_hdmi_set_pwr_mode(int mode)
+{
+ hdmi_dbg(hdmi->dev,"%s \n",__FUNCTION__);
+ if(hdmi->pwr_mode == mode)
+ return;
+ switch(mode){
+ case NORMAL:
+ rk2928_hdmi_sys_power_down();
+ HDMIWrReg(0xe3, 0x82);
+ HDMIWrReg(0xe5, 0x00);
+ HDMIWrReg(0xe4, 0x00);
+ HDMIWrReg(0xe7, 0x00);
+ HDMIWrReg(0xe1, 0x8e);
+ HDMIWrReg(0xce, 0x00);
+ HDMIWrReg(0xce, 0x01);
+ rk2928_hdmi_av_mute(1);
+ rk2928_hdmi_sys_power_up();
+ analog_sync = 1;
+ break;
+ case LOWER_PWR:
+ rk2928_hdmi_av_mute(0);
+ rk2928_hdmi_sys_power_down();
+ HDMIWrReg(0xe3, 0x02);
+ HDMIWrReg(0xe5, 0x1c);
+ HDMIWrReg(0xe1, 0x8c);
+ HDMIWrReg(0xe7, 0x04);
+ HDMIWrReg(0xe4, 0x03);
+ break;
+ default:
+ hdmi_dbg(hdmi->dev,"unkown rk2928 hdmi pwr mode %d\n",mode);
+ }
+ hdmi->pwr_mode = mode;
+}
+
+
+int rk2928_hdmi_detect_hotplug(void)
+{
+ int value = HDMIRdReg(HDMI_STATUS);
+
+ hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value);
+ value &= m_HOTPLUG;
+ if(value == m_HOTPLUG)
+ return HDMI_HPD_ACTIVED;
+ else if(value)
+ return HDMI_HPD_INSERT;
+ else
+ return HDMI_HPD_REMOVED;
+}
+
+#define HDMI_SYS_FREG_CLK 11289600
+#define HDMI_SCL_RATE (100*1000)
+#define HDMI_DDC_CONFIG (HDMI_SYS_FREG_CLK>>2)/HDMI_SCL_RATE
+#define DDC_BUS_FREQ_L 0x4b
+#define DDC_BUS_FREQ_H 0x4c
+
+int rk2928_hdmi_read_edid(int block, unsigned char *buff)
+{
+ int value, ret = -1, ddc_bus_freq = 0;
+ char interrupt = 0, trytime = 2;
+ unsigned long flags;
+
+ hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block);
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+ edid_result = 0;
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+ //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 30MHz.
+ //Set DDC I2C CLK which devided from DDC_CLK to 100KHz.
+
+ ddc_bus_freq = HDMI_DDC_CONFIG;
+ HDMIWrReg(DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
+ HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
+
+ // Enable edid interrupt
+ HDMIWrReg(INTERRUPT_MASK1, m_INT_HOTPLUG | m_INT_EDID_READY);
+
+ while(trytime--) {
+ // Config EDID block and segment addr
+ HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80);
+ HDMIWrReg(EDID_SEGMENT_POINTER, block/2);
+
+ value = 10;
+ while(value--)
+ {
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+ interrupt = edid_result;
+ edid_result = 0;
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+ if(interrupt & (m_INT_EDID_READY))
+ break;
+ msleep(10);
+ }
+ hdmi_dbg(hdmi->dev, "[%s] edid read value %d\n", __FUNCTION__, value);
+ if(interrupt & m_INT_EDID_READY)
+ {
+ for(value = 0; value < HDMI_EDID_BLOCK_SIZE; value++)
+ buff[value] = HDMIRdReg(EDID_FIFO_ADDR);
+ ret = 0;
+
+ hdmi_dbg(hdmi->dev, "[%s] edid read sucess\n", __FUNCTION__);
+#ifdef HDMI_DEBUG
+ for(value = 0; value < 128; value++) {
+ printk("%02x ,", buff[value]);
+ if( (value + 1) % 16 == 0)
+ printk("\n");
+ }
+#endif
+ break;
+ }else
+ hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__);
+
+ }
+ // Disable edid interrupt
+ HDMIWrReg(INTERRUPT_MASK1, m_INT_HOTPLUG);
+// msleep(100);
+ return ret;
+}
+
+static void rk2928_hdmi_config_avi(unsigned char vic, unsigned char output_color)
+{
+ int i;
+ char info[SIZE_AVI_INFOFRAME];
+
+ memset(info, 0, SIZE_AVI_INFOFRAME);
+ HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
+ info[0] = 0x82;
+ info[1] = 0x02;
+ info[2] = 0x0D;
+ info[3] = info[0] + info[1] + info[2];
+ info[4] = (AVI_COLOR_MODE_RGB << 5);
+ info[5] = (AVI_COLORIMETRY_NO_DATA << 6) | (AVI_CODED_FRAME_ASPECT_NO_DATA << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME;
+ info[6] = 0;
+ info[7] = vic;
+ info[8] = 0;
+
+ // Calculate AVI InfoFrame ChecKsum
+ for (i = 4; i < SIZE_AVI_INFOFRAME; i++)
+ {
+ info[3] += info[i];
+ }
+ info[3] = 0x100 - info[3];
+
+ for(i = 0; i < SIZE_AVI_INFOFRAME; i++)
+ HDMIWrReg(CONTROL_PACKET_ADDR + i, info[i]);
+}
+
+static int rk2928_hdmi_config_video(struct hdmi_video_para *vpara)
+{
+ int value;
+ struct fb_videomode *mode;
+
+ hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__);
+ if(vpara == NULL) {
+ hdmi_err(hdmi->dev, "[%s] input parameter error\n", __FUNCTION__);
+ return -1;
+ }
+
+ if(hdmi->hdcp_power_off_cb)
+ hdmi->hdcp_power_off_cb();
+ // Diable video and audio output
+ HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
+
+ // Input video mode is SDR RGB24bit, Data enable signal from external
+ HDMIWrReg(VIDEO_CONTRL1, v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444) | v_DE_EXTERNAL);
+ HDMIWrReg(VIDEO_CONTRL2, v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) | (vpara->output_color & 0xFF));
+
+ // Set HDMI Mode
+ HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(vpara->output_mode));
+
+ // Enable or disalbe color space convert
+ if(vpara->input_color != vpara->output_color) {
+ value = v_SOF_DISABLE | v_CSC_ENABLE;
+ }
+ else
+ value = v_SOF_DISABLE;
+ HDMIWrReg(VIDEO_CONTRL3, value);
+
+ // Set ext video
+#if 1
+ HDMIWrReg(VIDEO_TIMING_CTL, 0);
+ mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);
+ if(mode == NULL)
+ {
+ hdmi_err(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic);
+ return -ENOENT;
+ }
+ hdmi->tmdsclk = mode->pixclock;
+#else
+ value = v_EXTERANL_VIDEO(1) | v_INETLACE(mode->vmode);
+ if(mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ value |= v_HSYNC_POLARITY(1);
+ if(mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ value |= v_VSYNC_POLARITY(1);
+ HDMIWrReg(VIDEO_TIMING_CTL, value);
+
+ value = mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len;
+ HDMIWrReg(VIDEO_EXT_HTOTAL_L, value & 0xFF);
+ HDMIWrReg(VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
+
+ value = mode->left_margin + mode->right_margin + mode->hsync_len;
+ HDMIWrReg(VIDEO_EXT_HBLANK_L, value & 0xFF);
+ HDMIWrReg(VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
+
+ value = mode->left_margin + mode->hsync_len;
+ HDMIWrReg(VIDEO_EXT_HDELAY_L, value & 0xFF);
+ HDMIWrReg(VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
+
+ value = mode->hsync_len;
+ HDMIWrReg(VIDEO_EXT_HDURATION_L, value & 0xFF);
+ HDMIWrReg(VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
+
+ value = mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len;
+ HDMIWrReg(VIDEO_EXT_VTOTAL_L, value & 0xFF);
+ HDMIWrReg(VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
+
+ value = mode->upper_margin + mode->vsync_len + mode->lower_margin;
+ HDMIWrReg(VIDEO_EXT_VBLANK, value & 0xFF);
+
+ if(vpara->vic == HDMI_720x480p_60Hz_4_3 || vpara->vic == HDMI_720x480p_60Hz_16_9)
+ value = 42;
+ else
+ value = mode->upper_margin + mode->vsync_len;
+
+ HDMIWrReg(VIDEO_EXT_VDELAY, value & 0xFF);
+
+ value = mode->vsync_len;
+ HDMIWrReg(VIDEO_EXT_VDURATION, value & 0xFF);
+#endif
+
+ if(vpara->output_mode == OUTPUT_HDMI) {
+ rk2928_hdmi_config_avi(vpara->vic, vpara->output_color);
+ hdmi_dbg(hdmi->dev, "[%s] sucess output HDMI.\n", __FUNCTION__);
+ }
+ else {
+ hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__);
+ }
+ // Power on TMDS
+ HDMIWrReg(PHY_PRE_EMPHASIS, v_PRE_EMPHASIS(0) | v_TMDS_PWRDOWN(0)); // TMDS power on
+
+ // Enable TMDS
+ value = HDMIRdReg(PHY_DRIVER);
+ value |= v_TX_ENABLE(1);
+ HDMIWrReg(PHY_DRIVER, value);
+
+ return 0;
+}
+
+static void rk2928_hdmi_config_aai(void)
+{
+ int i;
+ char info[SIZE_AUDIO_INFOFRAME];
+
+ memset(info, 0, SIZE_AUDIO_INFOFRAME);
+
+ info[0] = 0x84;
+ info[1] = 0x01;
+ info[2] = 0x0A;
+
+ info[3] = info[0] + info[1] + info[2];
+ for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)
+ info[3] += info[i];
+
+ info[3] = 0x100 - info[3];
+
+ HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI);
+ for(i = 0; i < SIZE_AUDIO_INFOFRAME; i++)
+ HDMIWrReg(CONTROL_PACKET_ADDR + i, info[i]);
+}
+
+static int rk2928_hdmi_config_audio(struct hdmi_audio *audio)
+{
+ int rate, N, channel, mclk_fs;
+
+ if(audio->channel < 3)
+ channel = I2S_CHANNEL_1_2;
+ else if(audio->channel < 5)
+ channel = I2S_CHANNEL_3_4;
+ else if(audio->channel < 7)
+ channel = I2S_CHANNEL_5_6;
+ else
+ channel = I2S_CHANNEL_7_8;
+
+ switch(audio->rate)
+ {
+ case HDMI_AUDIO_FS_32000:
+ rate = AUDIO_32K;
+ N = N_32K;
+ mclk_fs = MCLK_384FS;
+ break;
+ case HDMI_AUDIO_FS_44100:
+ rate = AUDIO_441K;
+ N = N_441K;
+ mclk_fs = MCLK_256FS;
+ break;
+ case HDMI_AUDIO_FS_48000:
+ rate = AUDIO_48K;
+ N = N_48K;
+ mclk_fs = MCLK_256FS;
+ break;
+ case HDMI_AUDIO_FS_88200:
+ rate = AUDIO_882K;
+ N = N_882K;
+ mclk_fs = MCLK_128FS;
+ break;
+ case HDMI_AUDIO_FS_96000:
+ rate = AUDIO_96K;
+ N = N_96K;
+ mclk_fs = MCLK_128FS;
+ break;
+ case HDMI_AUDIO_FS_176400:
+ rate = AUDIO_1764K;
+ N = N_1764K;
+ mclk_fs = MCLK_128FS;
+ break;
+ case HDMI_AUDIO_FS_192000:
+ rate = AUDIO_192K;
+ N = N_192K;
+ mclk_fs = MCLK_128FS;
+ break;
+ default:
+ dev_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate);
+ return -ENOENT;
+ }
+
+ //set_audio source I2S
+ HDMIWrReg(AUDIO_CTRL1, 0x00); //internal CTS, disable down sample, i2s input, disable MCLK
+ HDMIWrReg(AUDIO_SAMPLE_RATE, rate);
+ HDMIWrReg(AUDIO_I2S_MODE, v_I2S_MODE(I2S_STANDARD) | v_I2S_CHANNEL(channel) );
+ HDMIWrReg(AUDIO_I2S_MAP, 0x00);
+ HDMIWrReg(AUDIO_I2S_SWAPS_SPDIF, 0); // no swap
+
+ //Set N value
+ HDMIWrReg(AUDIO_N_H, (N >> 16) & 0x0F);
+ HDMIWrReg(AUDIO_N_M, (N >> 8) & 0xFF);
+ HDMIWrReg(AUDIO_N_L, N & 0xFF);
+ rk2928_hdmi_config_aai();
+
+ return 0;
+}
+
+static void rk2928_hdmi_control_output(int enable)
+{
+ char mutestatus = 0;
+
+ if(enable) {
+ mutestatus = HDMIRdReg(AV_MUTE);
+ if(mutestatus && (m_AUDIO_MUTE | m_VIDEO_BLACK)) {
+ HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
+ rk2928_hdmi_sys_power_up();
+ rk2928_hdmi_sys_power_down();
+ rk2928_hdmi_sys_power_up();
+ if(analog_sync){
+ HDMIWrReg(0xce, 0x00);
+ delay100us();
+ HDMIWrReg(0xce, 0x01);
+ analog_sync = 0;
+ }
+ }
+ }
+ else {
+ HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
+ }
+}
+
+int rk2928_hdmi_removed(void)
+{
+
+ dev_printk(KERN_INFO , hdmi->dev , "Removed.\n");
+ rk2928_hdmi_set_pwr_mode(LOWER_PWR);
+
+ return HDMI_ERROR_SUCESS;
+}
+
+
+irqreturn_t hdmi_irq(int irq, void *priv)
+{
+ char interrupt1 = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&hdmi->irq_lock,flags);
+ interrupt1 = HDMIRdReg(INTERRUPT_STATUS1);
+ HDMIWrReg(INTERRUPT_STATUS1, interrupt1);
+#if 1
+ hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x \n",\
+ __FUNCTION__, interrupt1, interrupt2);
+#endif
+ if(interrupt1 & m_INT_HOTPLUG ){
+ if(hdmi->state == HDMI_SLEEP)
+ hdmi->state = WAIT_HOTPLUG;
+ if(hdmi->pwr_mode == LOWER_PWR)
+ rk2928_hdmi_set_pwr_mode(NORMAL);
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
+ }else if(interrupt1 & m_INT_EDID_READY) {
+ edid_result = interrupt1;
+ }else if(hdmi->state == HDMI_SLEEP) {
+ hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n");
+ rk2928_hdmi_set_pwr_mode(LOWER_PWR);
+ }
+#if 0
+ if(hdmi->hdcp_irq_cb)
+ hdmi->hdcp_irq_cb(interrupt2);
+#endif
+ spin_unlock_irqrestore(&hdmi->irq_lock,flags);
+ return IRQ_HANDLED;
+}
+
+int rk2928_hdmi_initial(void)
+{
+ int rc = HDMI_ERROR_SUCESS;
+
+ hdmi->pwr_mode = NORMAL;
+ hdmi->hdmi_removed = rk2928_hdmi_removed ;
+ hdmi->control_output = rk2928_hdmi_control_output;
+ hdmi->config_video = rk2928_hdmi_config_video;
+ hdmi->config_audio = rk2928_hdmi_config_audio;
+ hdmi->detect_hotplug = rk2928_hdmi_detect_hotplug;
+ hdmi->read_edid = rk2928_hdmi_read_edid;
+ // internal hclk = hdmi_hclk/20
+ //HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
+
+ if(hdmi->hdcp_power_on_cb)
+ rc = hdmi->hdcp_power_on_cb();
+
+ return rc;
+}
--- /dev/null
+#ifndef _RK2928_HDMI_HW_H
+#define _RK2928_HDMI_HW_H
+
+enum PWR_MODE{
+ NORMAL,
+ LOWER_PWR,
+};
+enum {
+ OUTPUT_DVI = 0,
+ OUTPUT_HDMI
+ };
+#define SYS_CTRL 0x00
+ #define m_INT_POL (1 << 0)
+ #define m_POWER (1 << 1)
+ #define m_REG_CLK_SOURCE (1 << 2)
+ #define v_INT_POL_HIGH 1
+ #define v_INT_POL_LOW 0
+ #define v_PWR_ON (0 << 1)
+ #define v_PWR_OFF (1 << 1)
+ #define v_REG_CLK_SOURCE_TMDS (0 << 2)
+ #define v_REG_CLK_SOURCE_IIS (1 << 2)
+#define VIDEO_CONTRL1 0x01
+ #define m_VIDEO_INPUT_FORMAT (7 << 1)
+ #define m_DE_SOURCE (1 << 0)
+ enum {
+ VIDEO_INPUT_SDR_RGB444 = 0,
+ VIDEO_INPUT_DDR_RGB444 = 5,
+ VIDEO_INPUT_DDR_YCBCR422 = 6
+ };
+ #define v_VIDEO_INPUT_FORMAT(n) (n << 1)
+ #define v_DE_EXTERNAL 1
+ #define v_DE_INTERANL 0
+
+#define VIDEO_CONTRL2 0x02
+ #define m_VIDEO_OUTPUT_FORMAT (3 << 6)
+ #define m_VIDEO_INPUT_BITS (3 << 4)
+ #define v_VIDEO_OUTPUT_FORMAT(n)(n << 6)
+ #define v_VIDEO_INPUT_BITS(n) (n << 4)
+ enum{
+ VIDEO_INPUT_12BITS = 0,
+ VIDEO_INPUT_10BITS,
+ VIDEO_INPUT_8BITS
+ };
+#define VIDEO_CONTRL3 0x04
+ #define m_SOF (1 << 3)
+ #define m_CSC (1 << 0)
+ #define v_SOF_ENABLE (0 << 3)
+ #define v_SOF_DISABLE (1 << 3)
+ #define v_CSC_ENABLE 1
+ #define v_CSC_DISABLE 0
+
+#define AV_MUTE 0x05
+ #define m_AVMUTE_CLEAR (1 << 7)
+ #define m_AVMUTE_ENABLE (1 << 6)
+ #define m_AUDIO_MUTE (1 << 1)
+ #define m_VIDEO_BLACK (1 << 0)
+ #define v_AUDIO_MUTE(n) (n << 1)
+ #define v_VIDEO_MUTE(n) (n << 0)
+
+#define VIDEO_TIMING_CTL 0x08
+ #define v_HSYNC_POLARITY(n) (n << 3)
+ #define v_VSYNC_POLARITY(n) (n << 2)
+ #define v_INETLACE(n) (n << 1)
+ #define v_EXTERANL_VIDEO(n) (n << 0)
+
+#define VIDEO_EXT_HTOTAL_L 0x09
+#define VIDEO_EXT_HTOTAL_H 0x0a
+#define VIDEO_EXT_HBLANK_L 0x0b
+#define VIDEO_EXT_HBLANK_H 0x0c
+#define VIDEO_EXT_HDELAY_L 0x0d
+#define VIDEO_EXT_HDELAY_H 0x0e
+#define VIDEO_EXT_HDURATION_L 0x0f
+#define VIDEO_EXT_HDURATION_H 0x10
+#define VIDEO_EXT_VTOTAL_L 0x11
+#define VIDEO_EXT_VTOTAL_H 0x12
+#define VIDEO_EXT_VBLANK 0x13
+#define VIDEO_EXT_VDELAY 0x14
+#define VIDEO_EXT_VDURATION 0x15
+
+#define AUDIO_CTRL1 0x35
+ enum {
+ CTS_SOURCE_INTERNAL = 0,
+ CTS_SOURCE_EXTERNAL
+ };
+ #define v_CTS_SOURCE(n) (n << 7)
+ enum {
+ DOWNSAMPLE_DISABLE = 0,
+ DOWNSAMPLE_1_2,
+ DOWNSAMPLE_1_4
+ };
+ #define v_DOWN_SAMPLE(n) (n << 5)
+ enum {
+ AUDIO_SOURCE_IIS = 0,
+ AUDIO_SOURCE_SPDIF
+ };
+ #define v_AUDIO_SOURCE(n) (n << 3)
+ #define v_MCLK_ENABLE(n) (n << 2)
+ enum {
+ MCLK_128FS = 0,
+ MCLK_256FS,
+ MCLK_384FS,
+ MCLK_512FS
+ };
+ #define v_MCLK_RATIO(n) (n)
+
+#define AUDIO_SAMPLE_RATE 0x37
+ enum {
+ AUDIO_32K = 0x3,
+ AUDIO_441K = 0x0,
+ AUDIO_48K = 0x2,
+ AUDIO_882K = 0x8,
+ AUDIO_96K = 0xa,
+ AUDIO_1764K = 0xc,
+ AUDIO_192K = 0xe,
+ };
+
+#define AUDIO_I2S_MODE 0x38
+ enum {
+ I2S_CHANNEL_1_2 = 1,
+ I2S_CHANNEL_3_4 = 3,
+ I2S_CHANNEL_5_6 = 7,
+ I2S_CHANNEL_7_8 = 0xf
+ };
+ #define v_I2S_CHANNEL(n) ((n) << 2)
+ enum {
+ I2S_STANDARD = 0,
+ I2S_LEFT_JUSTIFIED,
+ I2S_RIGHT_JUSTIFIED
+ };
+ #define v_I2S_MODE(n) (n)
+
+#define AUDIO_I2S_MAP 0x39
+#define AUDIO_I2S_SWAPS_SPDIF 0x3a
+ #define v_SPIDF_FREQ(n) (n)
+
+#define N_32K 0x1000
+#define N_441K 0x1880
+#define N_882K 0x3100
+#define N_1764K 0x6200
+#define N_48K 0x1800
+#define N_96K 0x3000
+#define N_192K 0x6000
+
+#define AUDIO_N_H 0x3f
+#define AUDIO_N_M 0x40
+#define AUDIO_N_L 0x41
+
+#define AUDIO_CTS_H 0x45
+#define AUDIO_CTS_M 0x46
+#define AUDIO_CTS_L 0x47
+
+
+#define DDC_CLK_L 0x4b
+#define DDC_CLK_H 0x4c
+
+#define EDID_SEGMENT_POINTER 0x4d
+#define EDID_WORD_ADDR 0x4e
+#define EDID_FIFO_OFFSET 0x4f
+#define EDID_FIFO_ADDR 0x50
+
+/* CONTROL_PACKET_BUF_INDEX */
+#define CONTROL_PACKET_BUF_INDEX 0x9f
+enum {
+ INFOFRAME_AVI = 0x06,
+ INFOFRAME_AAI = 0x08
+};
+#define CONTROL_PACKET_ADDR 0xa0
+
+
+#define SIZE_AVI_INFOFRAME 0x11 // 14 bytes
+#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes
+enum {
+ AVI_COLOR_MODE_RGB = 0,
+ AVI_COLOR_MODE_YCBCR422,
+ AVI_COLOR_MODE_YCBCR444
+};
+enum {
+ AVI_COLORIMETRY_NO_DATA = 0,
+ AVI_COLORIMETRY_SMPTE_170M,
+ AVI_COLORIMETRY_ITU709,
+ AVI_COLORIMETRY_EXTENDED
+};
+enum {
+ AVI_CODED_FRAME_ASPECT_NO_DATA,
+ AVI_CODED_FRAME_ASPECT_4_3,
+ AVI_CODED_FRAME_ASPECT_16_9
+};
+enum {
+ ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
+ ACTIVE_ASPECT_RATE_4_3,
+ ACTIVE_ASPECT_RATE_16_9,
+ ACTIVE_ASPECT_RATE_14_9
+};
+
+#define HDCP_CTRL 0x52
+ #define m_HDMI_DVI (1 << 1)
+ #define v_HDMI_DVI(n) (n << 1)
+
+#define INTERRUPT_MASK1 0xc0
+#define INTERRUPT_STATUS1 0xc1
+ #define m_INT_HOTPLUG (1 << 7)
+ #define m_INT_ACTIVE_VSYNC (1 << 6)
+ #define m_INT_EDID_READY (1 << 2)
+
+#define INTERRUPT_MASK2 0xc2
+#define INTERRUPT_STATUS2 0xc3
+ #define m_INT_HDCP_ERR (1 << 7)
+ #define m_INT_BKSV_FLAG (1 << 6)
+ #define m_INT_HDCP_OK (1 << 4)
+
+#define HDMI_STATUS 0xc8
+ #define m_HOTPLUG (1 << 7)
+ #define m_DDC_SDA (1 << 5)
+ #define m_DDC_SDC (1 << 4)
+
+#define PHY_SYNC 0xce //sync phy parameter
+
+#define PHY_DRIVER 0xe1
+ #define v_MAIN_DRIVER(n) (n << 4)
+ #define v_PRE_DRIVER(n) (n << 2)
+ #define v_TX_ENABLE(n) (n << 1)
+
+#define PHY_PRE_EMPHASIS 0xe2
+ #define v_PRE_EMPHASIS(n) (n << 4)
+ #define v_TMDS_PWRDOWN(n) (n)
+
+#define PHY_PLL_TEST 0xe3
+#define PHY_BANDGAP_PWR 0xe4
+ #define v_BANDGAP_PWR_DOWN 0x03
+ #define v_BANDGAP_PWR_UP 0
+
+#define PHY_PLL_CTRL 0xe5
+ #define v_PLL_DISABLE(n) (n << 4)
+ #define v_PLL_RESET(n) (n << 3)
+ #define v_TMDS_RESET(n) (n << 2)
+
+#define PHY_PLL_LDO_PWR 0xe7
+ #define v_LDO_PWR_DOWN(n) (n << 2)
+
+#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr)
+#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr);
+#define HDMIMskReg(temp, addr, msk, val) \
+ temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \
+ __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr);
+
+extern int rk2928_hdmi_initial(void);
+
+#endif
--- /dev/null
+#ifndef __RK2928_HDMI_HW_H__
+#define __RK2928_HDMI_HW_H__
+
+
+//0x00
+#define INT_POL 1
+#define SYS_PWR_ON 0
+#define SYS_PWR_OFF 1
+#define PHY_CLK 0
+#define SYS_CLK 1
+
+#define MCLK_FS 0x01 //256fs
+//0x01
+// INPUT_VIDEO_FORMAT
+#define RGB_YUV444 0x00
+#define DDR_RGB444_YUV444 0x05
+#define DDR_YUV422 0x06
+
+//0x02
+//video output format
+#define RGB444 0x00
+#define YUV444 0x01
+#define YUV422 0x02
+
+//DATA WIDTH
+#define DATA_12BIT 0X00
+#define DATA_10BIT 0X01
+#define DATA_8BIT 0X03
+
+//0X04
+//1:after 0:not After 1st sof for external DE sample
+#define DE_AFTER_SOF 0
+#define DE_NOAFTER_SOF 1
+
+#define CSC_ENABLE 0
+#define CSC_DISABLE 1
+
+//0X05
+#define CLEAR_AVMUTE(x) (x)<<7
+#define SET_AVMUTE(x) (x)<<6
+#define AUDIO_MUTE(x) (x)<<1
+#define VIDEO_BLACK(x) (x)<<0 //1:black 0:normal
+
+//0x08
+#define VSYNC_POL(x) (x)<<3 //0:Negative 1:Positive
+#define HSYNC_POL(x) (x)<<2 //0:Negative 1:Positive
+#define INTER_PROGRESSIVE(x) (x)<<1 //0: progressive 1:interlace
+#define VIDEO_SET_ENABLE(x) (x)<<0 //0:disable 1: enable
+
+/* 0xe1 */
+//Main-driver strength :0000~1111: the strength from low to high
+#define M_DRIVER_STR(x) (((x)&0xf)<<4)
+//Pre-driver strength :00~11: the strength from low to high
+#define P_DRIVER_STR(x) (((x)&3)<<2)
+//TX driver enable 1: enable 0: disable
+#define TX_DRIVER_EN(x) (((x)&1)<<1)
+/* 0xe2 */
+//Pre-emphasis strength 00~11: the strength from 0 to high
+#define P_EMPHASIS_STR(x) (((x)&3)<<4)
+//Power down TMDS driver 1: power down. 0: not
+#define PWR_DOWN_TMDS(x) (((x)&1)<<0)
+/* 0xe3 */
+//PLL out enable. Just for test. need set to 1’b0
+#define PLL_OUT_EN(x) (((x)&1)<<7)
+/* 0xe4 */
+// Band-Gap power down 11: power down 00: not
+#define BAND_PWR(x) (((x)&3)<<0)
+/* 0xe5 */
+//PLL disable 1: disable 0: enable
+#define PLL_PWR(x) (((x)&1)<<4)
+// PLL reset 1: reset 0: not
+#define PLL_RST(x) (((x)&1)<<3)
+//PHY TMDS channels reset 1: reset 0: not
+#define TMDS_RST(x) (((x)&1)<<2)
+/* 0xe7 */
+// PLL LDO power down 1: power down 0: not
+#define PLL_LDO_PWR(x) (((x)&1)<<2)
+
+enum PWR_MODE{
+ NORMAL,
+ LOWER_PWR,
+};
+
+#if 0
+/* HDMI_SYS_CONTROL */
+#define SYS_CTRL 0x0
+
+enum {
+ PWR_SAVE_MODE_A = 1,
+ PWR_SAVE_MODE_B = 2,
+ PWR_SAVE_MODE_D = 4,
+ PWR_SAVE_MODE_E = 8
+};
+#define m_PWR_SAVE_MODE 0xF0
+#define v_PWR_SAVE_MODE(n) (n << 4)
+#define PLL_B_RESET (1 << 3)
+
+#define N_32K 0x1000
+#define N_441K 0x1880
+#define N_882K 0x3100
+#define N_1764K 0x6200
+#define N_48K 0x1800
+#define N_96K 0x3000
+#define N_192K 0x6000
+
+#define LR_SWAP_N3 0x04
+#define N_2 0x08
+#define N_1 0x0c
+
+#define AUDIO_CTRL1 0x28
+#define AUDIO_CTRL2 0x2c
+#define I2S_AUDIO_CTRL 0x30
+enum {
+ I2S_MODE_STANDARD = 0,
+ I2S_MODE_RIGHT_JUSTIFIED,
+ I2S_MODE_LEFT_JUSTIFIED
+};
+#define v_I2S_MODE(n) n
+enum {
+ I2S_CHANNEL_1_2 = 1,
+ I2S_CHANNEL_3_4 = 3,
+ I2S_CHANNEL_5_6 = 7,
+ I2S_CHANNEL_7_8 = 0xf
+};
+#define v_I2S_CHANNEL(n) ( (n) << 2 )
+
+#define I2S_INPUT_SWAP 0x40
+
+#define SRC_NUM_AUDIO_LEN 0x50
+
+/* HDMI_AV_CTRL1*/
+#define AV_CTRL1 0x54
+enum {
+ AUDIO_32K = 0x3,
+ AUDIO_441K = 0x0,
+ AUDIO_48K = 0x2,
+ AUDIO_882K = 0x8,
+ AUDIO_96K = 0xa,
+ AUDIO_1764K = 0xc,
+ AUDIO_192K = 0xe,
+};
+#define m_AUDIO_SAMPLE_RATE 0xF0
+#define v_AUDIO_SAMPLE_RATE(n) (n << 4)
+#define m_INPUT_VIDEO_MODE (7 << 1)
+#define v_INPUT_VIDEO_MODE(n) (n << 1)
+enum {
+ INTERNAL_DE = 0,
+ EXTERNAL_DE
+};
+#define m_DE_SIGNAL_SELECT (1 << 0)
+
+/* HDMI_AV_CTRL2 */
+#define AV_CTRL2 0xec
+#define m_CSC_ENABLE (1 << 0)
+#define v_CSC_ENABLE(n) (n)
+
+/* HDMI_VIDEO_CTRL1 */
+#define VIDEO_CTRL1 0x58
+
+#define m_VIDEO_OUTPUT_MODE (0x3 << 6)
+#define v_VIDEO_OUTPUT_MODE(n) (n << 6)
+enum {
+ VIDEO_INPUT_DEPTH_12BIT = 0,
+ VIDEO_INPUT_DEPTH_10BIT = 0x1,
+ VIDEO_INPUT_DEPTH_8BIT = 0x3
+};
+#define m_VIDEO_INPUT_DEPTH (3 << 4)
+#define v_VIDEO_INPUT_DEPTH(n) (n << 4)
+enum {
+ VIDEO_EMBEDDED_SYNC_LOCATION_0 = 0,
+ VIDEO_EMBEDDED_SYNC_LOCATION_1,
+ VIDEO_EMBEDDED_SYNC_LOCATION_2
+};
+#define m_VIDEO_EMBEDDED_SYNC_LOCATION (3 << 2)
+#define VIDEO_EMBEDDED_SYNC_LOCATION(n) (n << 2)
+#define m_VIDEO_INPUT_COLOR_MODE (1 << 0)
+
+/* DEEP_COLOR_MODE */
+#define DEEP_COLOR_MODE 0x5c
+enum{
+ TMDS_CLOCK_MODE_8BIT = 0,
+ TMDS_CLOKK_MODE_10BIT,
+ TMDS_CLOKK_MODE_12BIT
+};
+#define TMDS_CLOCK_MODE_MASK 0x3 << 6
+#define TMDS_CLOCK_MODE(n) (n) << 6
+
+/* VIDEO_CTRL2 */
+#define VIDEO_SETTING2 0x114
+#define m_UNMUTE (1 << 7)
+#define m_MUTE (1 << 6)
+#define m_AUDIO_RESET (1 << 2)
+#define m_NOT_SEND_AUDIO (1 << 1)
+#define m_NOT_SEND_VIDEO (1 << 0)
+#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data
+#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data
+#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode.
+#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data
+#define NOT_SEND_VIDEO (1 << 0) // Send black video data
+
+/* Color Space Convertion Parameter*/
+#define CSC_PARA_C0_H 0x60
+#define CSC_PARA_C0_L 0x64
+#define CSC_PARA_C1_H 0x68
+#define CSC_PARA_C1_L 0x6c
+#define CSC_PARA_C2_H 0x70
+#define CSC_PARA_C2_L 0x74
+#define CSC_PARA_C3_H 0x78
+#define CSC_PARA_C3_L 0x7c
+#define CSC_PARA_C4_H 0x80
+#define CSC_PARA_C4_L 0x84
+#define CSC_PARA_C5_H 0x88
+#define CSC_PARA_C5_L 0x8c
+#define CSC_PARA_C6_H 0x90
+#define CSC_PARA_C6_L 0x94
+#define CSC_PARA_C7_H 0x98
+#define CSC_PARA_C7_L 0x9c
+#define CSC_PARA_C8_H 0xa0
+#define CSC_PARA_C8_L 0xa4
+#define CSC_PARA_C9_H 0xa8
+#define CSC_PARA_C9_L 0xac
+#define CSC_PARA_C10_H 0xac
+#define CSC_PARA_C10_L 0xb4
+#define CSC_PARA_C11_H 0xb8
+#define CSC_PARA_C11_L 0xbc
+
+#define CSC_CONFIG1 0x34c
+#define m_CSC_MODE (1 << 7)
+#define m_CSC_COEF_MODE (0xF << 3) //Only used in auto csc mode
+#define m_CSC_STATUS (1 << 2)
+#define m_CSC_VID_SELECT (1 << 1)
+#define m_CSC_BRSWAP_DIABLE (1)
+
+enum {
+ CSC_MODE_MANUAL = 0,
+ CSC_MODE_AUTO
+};
+#define v_CSC_MODE(n) (n << 7)
+enum {
+ COE_SDTV_LIMITED_RANGE = 0x08,
+ COE_SDTV_FULL_RANGE = 0x04,
+ COE_HDTV_60Hz = 0x2,
+ COE_HDTV_50Hz = 0x1
+};
+#define v_CSC_COE_MODE(n) (n << 3)
+enum {
+ CSC_INPUT_VID_5_19 = 0,
+ CSC_INPUT_VID_28_29
+};
+#define v_CSC_VID_SELECT(n) (n << 1)
+#define v_CSC_BRSWAP_DIABLE(n) (n)
+#endif
+/* CONTROL_PACKET_BUF_INDEX */
+#define CONTROL_PACKET_BUF_INDEX 0x17c
+enum {
+ INFOFRAME_AVI = 0x06,
+ INFOFRAME_AAI = 0x08
+};
+#define CONTROL_PACKET_HB0 0x180
+#define CONTROL_PACKET_HB1 0x184
+#define CONTROL_PACKET_HB2 0x188
+#define CONTROL_PACKET_PB_ADDR 0x18c
+#define SIZE_AVI_INFOFRAME 0x11 // 17 bytes
+#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes
+enum {
+ AVI_COLOR_MODE_RGB = 0,
+ AVI_COLOR_MODE_YCBCR422,
+ AVI_COLOR_MODE_YCBCR444
+};
+enum {
+ AVI_COLORIMETRY_NO_DATA = 0,
+ AVI_COLORIMETRY_SMPTE_170M,
+ AVI_COLORIMETRY_ITU709,
+ AVI_COLORIMETRY_EXTENDED
+};
+enum {
+ AVI_CODED_FRAME_ASPECT_NO_DATA,
+ AVI_CODED_FRAME_ASPECT_4_3,
+ AVI_CODED_FRAME_ASPECT_16_9
+};
+enum {
+ ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
+ ACTIVE_ASPECT_RATE_4_3,
+ ACTIVE_ASPECT_RATE_16_9,
+ ACTIVE_ASPECT_RATE_14_9
+};
+#if 0
+/* External Video Parameter Setting*/
+#define EXT_VIDEO_PARA 0xC0
+#define m_VSYNC_OFFSET (0xF << 4)
+#define m_VSYNC_POLARITY (1 << 3)
+#define m_HSYNC_POLARITY (1 << 2)
+#define m_INTERLACE (1 << 1)
+#define m_EXT_VIDEO_ENABLE (1 << 0)
+
+#define v_VSYNC_OFFSET(n) (n << 4)
+#define v_VSYNC_POLARITY(n) (n << 3)
+#define v_HSYNC_POLARITY(n) (n << 2)
+#define v_INTERLACE(n) (n << 1)
+#define v_EXT_VIDEO_ENABLE(n) (n << 0)
+
+#define EXT_VIDEO_PARA_HTOTAL_L 0xC4
+#define EXT_VIDEO_PARA_HTOTAL_H 0xC8
+#define EXT_VIDEO_PARA_HBLANK_L 0xCC
+#define EXT_VIDEO_PARA_HBLANK_H 0xD0
+#define EXT_VIDEO_PARA_HDELAY_L 0xD4
+#define EXT_VIDEO_PARA_HDELAY_H 0xD8
+#define EXT_VIDEO_PARA_HSYNCWIDTH_L 0xDC
+#define EXT_VIDEO_PARA_HSYNCWIDTH_H 0xE0
+
+#define EXT_VIDEO_PARA_VTOTAL_L 0xE4
+#define EXT_VIDEO_PARA_VTOTAL_H 0xE8
+#define EXT_VIDEO_PARA_VBLANK_L 0xF4
+#define EXT_VIDEO_PARA_VDELAY 0xF8
+#define EXT_VIDEO_PARA_VSYNCWIDTH 0xFC
+
+#define PHY_PLL_SPEED 0x158
+ #define v_TEST_EN(n) (n << 6)
+ #define v_PLLA_BYPASS(n) (n << 4)
+ #define v_PLLB_SPEED(n) (n << 2)
+ #define v_PLLA_SPEED(n) (n)
+ enum {
+ PLL_SPEED_LOWEST = 0,
+ PLL_SPEED_MIDLOW,
+ PLL_SPEED_MIDHIGH,
+ PLL_SPEED_HIGHEST
+ };
+
+#define PHY_PLL_17 0x15c // PLL A & B config bit 17
+ #define v_PLLA_BIT17(n) (n << 2)
+ #define v_PLLB_BIT17(n) (n << 1)
+
+#define PHY_BGR 0x160
+ #define v_BGR_DISCONNECT(n) (n << 7)
+ #define v_BGR_V_OFFSET(n) (n << 4)
+ #define v_BGR_I_OFFSET(n) (n)
+
+#define PHY_PLLA_1 0x164
+#define PHY_PLLA_2 0x168
+#define PHY_PLLB_1 0x16c
+#define PHY_PLLB_2 0x170
+
+#define PHY_DRIVER_PREEMPHASIS 0x174
+ #define v_TMDS_SWING(n) (n << 4)
+ #define v_PRE_EMPHASIS(n) (n)
+
+#define PHY_PLL_16_AML 0x178 // PLL A & B config bit 16 and AML control
+ #define v_PLLA_BIT16(n) (n << 5)
+ #define v_PLLB_BIT16(n) (n << 4)
+ #define v_AML(n) (n)
+#endif
+/* Interrupt Setting */
+#define INTR_MASK1 0xc0
+#define INTR_STATUS1 0xc1
+ #define m_INT_HOTPLUG (1 << 7)
+ #define m_INT_VSYNC (1 << 5)
+ #define m_INT_EDID_READY (1 << 2)
+
+#define INTR_MASK2 0xc2
+#define INTR_STATUS2 0xc3
+ #define m_INT_HDCP_ERR (1 << 7) // HDCP error detected
+ #define m_INT_BKSV_RPRDY (1 << 6) // BKSV list ready from repeater
+ #define m_INT_AUTH_DONE (1 << 4) // HDCP authentication done
+
+#if 0
+#define DDC_READ_FIFO_ADDR 0x200
+#define DDC_BUS_FREQ_L 0x204
+#define DDC_BUS_FREQ_H 0x208
+#define DDC_BUS_CTRL 0x2dc
+#define DDC_I2C_LEN 0x278
+#define DDC_I2C_OFFSET 0x280
+#define DDC_I2C_CTRL 0x284
+#define DDC_I2C_READ_BUF0 0x288
+#define DDC_I2C_READ_BUF1 0x28c
+#define DDC_I2C_READ_BUF2 0x290
+#define DDC_I2C_READ_BUF3 0x294
+#define DDC_I2C_WRITE_BUF0 0x298
+#define DDC_I2C_WRITE_BUF1 0x29c
+#define DDC_I2C_WRITE_BUF2 0x2a0
+#define DDC_I2C_WRITE_BUF3 0x2a4
+#define DDC_I2C_WRITE_BUF4 0x2ac
+#define DDC_I2C_WRITE_BUF5 0x2b0
+#define DDC_I2C_WRITE_BUF6 0x2b4
+
+#endif
+#define EDID_SEGMENT_POINTER 0x4d
+#define EDID_WORD_ADDR 0x4e
+#define EDID_FIFO_ADDR 0x4f
+
+#define PIN_STATUS 0xc8
+#define m_HOTPLUG_STATUS (1 << 7)
+#define m_DDCSDA_STATUS (1 << 5)
+#define m_DDCSCL_STATUS (1 << 4)
+#if 0
+/* HDCP_CTRL */
+#define HDCP_CTRL 0x2bc
+ enum {
+ OUTPUT_DVI = 0,
+ OUTPUT_HDMI
+ };
+ #define m_HDCP_AUTH_START (1 << 7) // start hdcp
+ #define m_HDCP_BKSV_PASS (1 << 6) // bksv valid
+ #define m_HDCP_BKSV_FAILED (1 << 5) // bksv invalid
+ #define m_HDCP_FRAMED_ENCRYPED (1 << 4)
+ #define m_HDCP_AUTH_STOP (1 << 3) // stop hdcp
+ #define m_HDCP_ADV_CIPHER (1 << 2) // advanced cipher mode
+ #define m_HDMI_DVI (1 << 1)
+ #define m_HDCP_RESET (1 << 0) // reset hdcp
+ #define v_HDCP_AUTH_START(n) (n << 7)
+ #define v_HDCP_BKSV_PASS(n) (n << 6)
+ #define v_HDCP_BKSV_FAILED(n) (n << 5)
+ #define v_HDCP_FRAMED_ENCRYPED(n) (n << 4)
+ #define v_HDCP_AUTH_STOP(n) (n << 3)
+ #define v_HDCP_ADV_CIPHER(n) (n << 2)
+ #define v_HDMI_DVI(n) (n << 1)
+ #define v_HDCP_RESET(n) (n << 0)
+#define HDCP_CTRL2 0x340
+
+/* HDCP Key Memory Access Control */
+#define HDCP_KEY_ACCESS_CTRL1 0x338
+#define HDCP_KEY_ACCESS_CTRL2 0x33c
+ #define m_LOAD_FACSIMILE_HDCP_KEY (1 << 1)
+ #define m_LOAD_HDCP_KEY (1 << 0)
+/* HDCP Key Memory Control */
+#define HDCP_KEY_MEM_CTRL 0x348
+ #define m_USE_KEY1 (1 << 6)
+ #define m_USE_KEY2 (1 << 5)
+ #define m_LOAD_AKSV (1 << 4)
+ #define m_KSV_SELECTED (1 << 3)
+ #define m_KSV_VALID (1 << 2)
+ #define m_KEY_VALID (1 << 1)
+ #define m_KEY_READY (1 << 0)
+ #define v_USE_KEY1(n) (n << 6)
+ #define v_USE_KEY2(n) (n << 5)
+ #define v_LOAD_AKSV(n) (n << 4)
+
+/* HDCP B device capacity */
+#define HDCP_BCAPS 0x2f8
+ #define m_HDMI_RECEIVED (1 << 7) //If HDCP receiver support HDMI, this bit must be 1.
+ #define m_REPEATER (1 << 6)
+ #define m_KSV_FIFO_READY (1 << 5)
+ #define m_DDC_FAST (1 << 4)
+ #define m_1_1_FEATURE (1 << 1)
+ #define m_FAST_REAUTHENTICATION (1 << 0) //For HDMI, this function is supported whether this bit is enabled or not.
+
+/* HDCP KSV Value */
+#define HDCP_KSV_BYTE0 0x2fc
+#define HDCP_KSV_BYTE1 0x300
+#define HDCP_KSV_BYTE2 0x304
+#define HDCP_KSV_BYTE3 0x308
+#define HDCP_KSV_BYTE4 0x30c
+
+/* HDCP error status */
+#define HDCP_ERROR 0x320
+
+/* HDCP 100 ms timer */
+#define HDCP_TIMER_100MS 0x324
+/* HDCP 5s timer */
+#define HDCP_TIMER_5S 0x328
+
+/* HDCP Key ram address */
+#define HDCP_RAM_KEY_KSV1 0x400
+#define HDCP_RAM_KEY_KSV2 0x407
+#define HDCP_RAM_KEY_PRIVATE 0x40e
+#define HDCP_KEY_LENGTH 0x13C
+
+
+#define HDCP_ENABLE_HW_AUTH // Enable hardware authentication mode
+#define HDMI_INTERANL_CLK_DIV 0x19
+
+#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr)
+#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr);
+#define HDMIMskReg(temp, addr, msk, val) \
+ temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \
+ __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr);
+
+
+
+/* Color Space Convertion Mode */
+enum {
+ CSC_RGB_0_255_TO_ITU601_16_235 = 0, //RGB 0-255 input to YCbCr 16-235 output according BT601
+ CSC_RGB_0_255_TO_ITU709_16_235, //RGB 0-255 input to YCbCr 16-235 output accroding BT709
+ CSC_ITU601_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT601
+ CSC_ITU709_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT709
+ CSC_ITU601_16_235_TO_RGB_0_255, //YCbCr 16-235 input to RGB 0-255 output according BT601
+ CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709
+};
+#endif
+extern int rk2928_hdmi_initial(void);
+extern int rk2928_hdmi_detect_hotplug(void);
+extern int rk2928_hdmi_read_edid(int block, unsigned char *buff);
+extern int rk2928_hdmi_removed(void);
+extern int rk2928_hdmi_config_video(struct hdmi_video_para *vpara);
+extern int rk2928_hdmi_config_audio(struct hdmi_audio *audio);
+extern void rk2928_hdmi_control_output(int enable);
+
+#endif
--- /dev/null
+config HDMI_RK30_CTL_CODEC
+ bool "Mute Codec When HDMI Actived"
+ depends on HDMI_RK30
+ default n
+ help
+ If you say y heres, Codec will be mute when hdmi inserted,
+ and unmute when removed.
+
+config HDMI_RK30_DEBUG
+ bool "RK30 HDMI Debugging"
+ depends on HDMI_RK30 && LCDC_RK30
+ default n
+ help
+ Enableds verbose debugging the the HDMI drivers
+
--- /dev/null
+#
+# Makefile for HDMI linux kernel module.
+#
+
+ccflags-$(CONFIG_HDMI_RK30_DEBUG) = -DDEBUG -DHDMI_DEBUG
+
+obj-$(CONFIG_HDMI_RK30) += rk30_hdmi_hw.o rk30_hdmi.o
+obj-$(CONFIG_HDCP_RK30) += hdcp/
--- /dev/null
+config HDCP_RK30
+ bool "RK30 HDCP support"
+ depends on LCDC_RK30 && HDMI_RK30
+ default n
+ help
+ HDCP Interface. This adds the High Definition Content Protection Interface.
+ See http://www.digital-cp.com/ for HDCP specification.
+
+config HDCP_RK30_DEBUG
+ bool "RK30 HDCP Debugging"
+ depends on HDCP_RK30
+ default n
+ help
+ Enableds verbose debugging the the HDCP drivers
--- /dev/null
+#
+# Makefile for HDCP linux kernel module.
+#
+
+ccflags-$(CONFIG_HDCP_RK30_DEBUG) = -DDEBUG -DHDCP_DEBUG
+
+obj-$(CONFIG_HDCP_RK30) += hdcp.o
+hdcp-y := rk30_hdcp.o rk30_hdmi_hdcp.o
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+#include "../rk30_hdmi.h"
+#include "../rk30_hdmi_hw.h"
+#include "rk30_hdmi_hdcp.h"
+
+struct hdcp *hdcp = NULL;
+
+static void hdcp_work_queue(struct work_struct *work);
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_submit_work
+ *-----------------------------------------------------------------------------
+ */
+static struct delayed_work *hdcp_submit_work(int event, int delay)
+{
+ struct hdcp_delayed_work *work;
+
+ DBG("%s event %04x delay %d", __FUNCTION__, event, delay);
+
+ work = kmalloc(sizeof(struct hdcp_delayed_work), GFP_ATOMIC);
+
+ if (work) {
+ INIT_DELAYED_WORK(&work->work, hdcp_work_queue);
+ work->event = event;
+ queue_delayed_work(hdcp->workqueue,
+ &work->work,
+ msecs_to_jiffies(delay));
+ } else {
+ printk(KERN_WARNING "HDCP: Cannot allocate memory to "
+ "create work\n");
+ return 0;
+ }
+
+ return &work->work;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_cancel_work
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_cancel_work(struct delayed_work **work)
+{
+ int ret = 0;
+
+ if (*work) {
+ ret = cancel_delayed_work(*work);
+ if (ret != 1) {
+ ret = cancel_work_sync(&((*work)->work));
+ printk(KERN_INFO "Canceling work failed - "
+ "cancel_work_sync done %d\n", ret);
+ }
+ kfree(*work);
+ *work = 0;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_authentication_failure
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_authentication_failure(void)
+{
+ if (hdcp->hdmi_state == HDMI_STOPPED) {
+ return;
+ }
+
+ rk30_hdcp_disable();
+ rk30_hdmi_control_output(false);
+
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+
+ if (hdcp->retry_cnt && (hdcp->hdmi_state != HDMI_STOPPED)) {
+ if (hdcp->retry_cnt < HDCP_INFINITE_REAUTH) {
+ hdcp->retry_cnt--;
+ printk(KERN_INFO "HDCP: authentication failed - "
+ "retrying, attempts=%d\n",
+ hdcp->retry_cnt);
+ } else
+ printk(KERN_INFO "HDCP: authentication failed - "
+ "retrying\n");
+
+ hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+
+ hdcp->pending_wq_event = hdcp_submit_work(HDCP_AUTH_REATT_EVENT,
+ HDCP_REAUTH_DELAY);
+ } else {
+ printk(KERN_INFO "HDCP: authentication failed - "
+ "HDCP disabled\n");
+ hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+ }
+
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_start_authentication
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_start_authentication(void)
+{
+ int status = HDCP_OK;
+
+ hdcp->hdcp_state = HDCP_AUTHENTICATION_START;
+
+ DBG("HDCP: authentication start");
+
+ status = rk30_hdcp_start_authentication();
+
+ if (status != HDCP_OK) {
+ DBG("HDCP: authentication failed");
+ hdcp_wq_authentication_failure();
+ } else {
+ hdcp->hdcp_state = HDCP_WAIT_KSV_LIST;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_check_bksv
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_check_bksv(void)
+{
+ int status = HDCP_OK;
+
+ DBG("Check BKSV start");
+
+ status = rk30_hdcp_check_bksv();
+
+ if (status != HDCP_OK) {
+ printk(KERN_INFO "HDCP: Check BKSV failed");
+ hdcp->retry_cnt = 0;
+ hdcp_wq_authentication_failure();
+ }
+ else {
+ DBG("HDCP: Check BKSV successful");
+
+ hdcp->hdcp_state = HDCP_LINK_INTEGRITY_CHECK;
+
+ /* Restore retry counter */
+ if(hdcp->retry_times == 0)
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+ else
+ hdcp->retry_cnt = hdcp->retry_times;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_authentication_sucess
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_authentication_sucess(void)
+{
+ printk(KERN_INFO "HDCP: authentication pass");
+ rk30_hdmi_control_output(true);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_wq_disable
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_wq_disable(int event)
+{
+ printk(KERN_INFO "HDCP: disabled");
+
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+ rk30_hdcp_disable();
+ if(event == HDCP_DISABLE_CTL) {
+ hdcp->hdcp_state = HDCP_DISABLED;
+ if(hdcp->hdmi_state == HDMI_STARTED)
+ rk30_hdmi_control_output(true);
+ }
+ else if(event == HDCP_STOP_FRAME_EVENT)
+ hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_work_queue
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_work_queue(struct work_struct *work)
+{
+ struct hdcp_delayed_work *hdcp_w =
+ container_of(work, struct hdcp_delayed_work, work.work);
+ int event = hdcp_w->event;
+
+ mutex_lock(&hdcp->lock);
+
+ DBG("hdcp_work_queue() - START - %u hdmi=%d hdcp=%d evt= %x %d",
+ jiffies_to_msecs(jiffies),
+ hdcp->hdmi_state,
+ hdcp->hdcp_state,
+ (event & 0xFF00) >> 8,
+ event & 0xFF);
+
+ if(event == HDCP_STOP_FRAME_EVENT) {
+ hdcp->hdmi_state = HDMI_STOPPED;
+ }
+
+ if (event == HDCP_DISABLE_CTL || event == HDCP_STOP_FRAME_EVENT) {
+ hdcp_wq_disable(event);
+ }
+
+ if (event & HDCP_WORKQUEUE_SRC)
+ hdcp->pending_wq_event = 0;
+
+ /* First handle HDMI state */
+ if (event == HDCP_START_FRAME_EVENT) {
+ hdcp->pending_start = 0;
+ hdcp->hdmi_state = HDMI_STARTED;
+ }
+
+ /**********************/
+ /* HDCP state machine */
+ /**********************/
+ switch (hdcp->hdcp_state) {
+ case HDCP_DISABLED:
+ /* HDCP enable control or re-authentication event */
+ if (event == HDCP_ENABLE_CTL) {
+ if(hdcp->retry_times == 0)
+ hdcp->retry_cnt = HDCP_INFINITE_REAUTH;
+ else
+ hdcp->retry_cnt = hdcp->retry_times;
+ if (hdcp->hdmi_state == HDMI_STARTED)
+ hdcp_wq_start_authentication();
+ else
+ hdcp->hdcp_state = HDCP_ENABLE_PENDING;
+ }
+ break;
+
+ case HDCP_ENABLE_PENDING:
+ /* HDMI start frame event */
+ if (event == HDCP_START_FRAME_EVENT)
+ hdcp_wq_start_authentication();
+
+ break;
+
+ case HDCP_AUTHENTICATION_START:
+ /* Re-authentication */
+ if (event == HDCP_AUTH_REATT_EVENT)
+ hdcp_wq_start_authentication();
+
+ break;
+
+ case HDCP_WAIT_KSV_LIST:
+ /* KSV failure */
+ if (event == HDCP_FAIL_EVENT) {
+ printk(KERN_INFO "HDCP: KSV switch failure\n");
+
+ hdcp_wq_authentication_failure();
+ }
+ /* KSV list ready event */
+ else if (event == HDCP_KSV_LIST_RDY_EVENT)
+ hdcp_wq_check_bksv();
+ break;
+
+ case HDCP_LINK_INTEGRITY_CHECK:
+ /* Ri failure */
+ if (event == HDCP_FAIL_EVENT) {
+ printk(KERN_INFO "HDCP: Ri check failure\n");
+ hdcp_wq_authentication_failure();
+ }
+ else if(event == HDCP_AUTH_PASS_EVENT)
+ hdcp_wq_authentication_sucess();
+ break;
+
+ default:
+ printk(KERN_WARNING "HDCP: error - unknow HDCP state\n");
+ break;
+ }
+
+ kfree(hdcp_w);
+ if(event == HDCP_STOP_FRAME_EVENT)
+ complete(&hdcp->complete);
+
+ mutex_unlock(&hdcp->lock);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_start_frame_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_start_frame_cb(void)
+{
+ DBG("hdcp_start_frame_cb()");
+
+ /* Cancel any pending work */
+ if (hdcp->pending_start)
+ hdcp_cancel_work(&hdcp->pending_start);
+ if (hdcp->pending_wq_event)
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+
+ hdcp->pending_start = hdcp_submit_work(HDCP_START_FRAME_EVENT,
+ HDCP_ENABLE_DELAY);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_irq_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_irq_cb(int interrupt)
+{
+ int value;
+ DBG("%s 0x%x", __FUNCTION__, interrupt);
+ if(interrupt & m_INT_HDCP_ERR)
+ {
+ value = HDMIRdReg(HDCP_ERROR);
+ HDMIWrReg(HDCP_ERROR, value);
+ printk(KERN_INFO "HDCP: Error 0x%02x\n", value);
+
+ if( (hdcp->hdcp_state != HDCP_DISABLED) &&
+ (hdcp->hdcp_state != HDCP_ENABLE_PENDING) )
+ {
+ hdcp_submit_work(HDCP_FAIL_EVENT, 0);
+ }
+ }
+ else if(interrupt & (m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY))
+ hdcp_submit_work(HDCP_KSV_LIST_RDY_EVENT, 0);
+ else if(interrupt & m_INT_AUTH_DONE)
+ hdcp_submit_work(HDCP_AUTH_PASS_EVENT, 0);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_on_cb
+ *-----------------------------------------------------------------------------
+ */
+static int hdcp_power_on_cb(void)
+{
+ DBG("%s", __FUNCTION__);
+ return rk30_hdcp_load_key2mem(hdcp->keys);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: hdcp_power_off_cb
+ *-----------------------------------------------------------------------------
+ */
+static void hdcp_power_off_cb(void)
+{
+ DBG("%s", __FUNCTION__);
+ if(!hdcp->enable)
+ return;
+
+ hdcp_cancel_work(&hdcp->pending_start);
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+ init_completion(&hdcp->complete);
+ /* Post event to workqueue */
+ if (hdcp_submit_work(HDCP_STOP_FRAME_EVENT, 0))
+ wait_for_completion_interruptible_timeout(&hdcp->complete,
+ msecs_to_jiffies(2000));
+}
+
+// Load HDCP key to external HDCP memory
+static void hdcp_load_keys_cb(const struct firmware *fw, void *context)
+{
+ if (!fw) {
+ pr_err("HDCP: failed to load keys\n");
+ return;
+ }
+
+ if(fw->size < HDCP_KEY_SIZE) {
+ pr_err("HDCP: firmware wrong size %d\n", fw->size);
+ return;
+ }
+
+ hdcp->keys = kmalloc(HDCP_KEY_SIZE, GFP_KERNEL);
+ if(hdcp->keys == NULL) {
+ pr_err("HDCP: can't allocated space for keys\n");
+ return;
+ }
+
+ memcpy(hdcp->keys, fw->data, HDCP_KEY_SIZE);
+
+ rk30_hdcp_load_key2mem(hdcp->keys);
+ printk(KERN_INFO "HDCP: loaded hdcp key success\n");
+
+ if(fw->size > HDCP_KEY_SIZE) {
+ DBG("%s invalid key size %d", __FUNCTION__, fw->size - HDCP_KEY_SIZE);
+ if((fw->size - HDCP_KEY_SIZE) % 5) {
+ pr_err("HDCP: failed to load invalid keys\n");
+ return;
+ }
+ hdcp->invalidkeys = kmalloc(fw->size - HDCP_KEY_SIZE, GFP_KERNEL);
+ if(hdcp->invalidkeys == NULL) {
+ pr_err("HDCP: can't allocated space for invalid keys\n");
+ return;
+ }
+ memcpy(hdcp->invalidkeys, fw->data + HDCP_KEY_SIZE, fw->size - HDCP_KEY_SIZE);
+ hdcp->invalidkey = (fw->size - HDCP_KEY_SIZE)/5;
+ printk(KERN_INFO "HDCP: loaded hdcp invalid key success\n");
+ }
+}
+
+static ssize_t hdcp_enable_read(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ int enable = 0;
+
+ if(hdcp)
+ enable = hdcp->enable;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", enable);
+}
+
+static ssize_t hdcp_enable_write(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int enable;
+
+ if(hdcp == NULL)
+ return -EINVAL;
+
+ sscanf(buf, "%d", &enable);
+ if(hdcp->enable != enable)
+ {
+ /* Post event to workqueue */
+ if(enable) {
+ if (hdcp_submit_work(HDCP_ENABLE_CTL, 0) == 0)
+ return -EFAULT;
+ }
+ else {
+ hdcp_cancel_work(&hdcp->pending_start);
+ hdcp_cancel_work(&hdcp->pending_wq_event);
+
+ /* Post event to workqueue */
+ if (hdcp_submit_work(HDCP_DISABLE_CTL, 0) == 0)
+ return -EFAULT;
+ }
+ hdcp->enable = enable;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, hdcp_enable_read, hdcp_enable_write);
+
+static ssize_t hdcp_trytimes_read(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ int trytimes = 0;
+
+ if(hdcp)
+ trytimes = hdcp->retry_times;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", trytimes);
+}
+
+static ssize_t hdcp_trytimes_wrtie(struct device *device,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int trytimes;
+
+ if(hdcp == NULL)
+ return -EINVAL;
+
+ sscanf(buf, "%d", &trytimes);
+ if(hdcp->retry_times != trytimes)
+ hdcp->retry_times = trytimes;
+
+ return count;
+}
+
+
+static DEVICE_ATTR(trytimes, S_IRUGO|S_IWUSR, hdcp_trytimes_read, hdcp_trytimes_wrtie);
+
+
+static struct miscdevice mdev;
+
+static int __init rk30_hdcp_init(void)
+{
+ int ret;
+
+ DBG("[%s] %u", __FUNCTION__, jiffies_to_msecs(jiffies));
+
+ hdcp = kmalloc(sizeof(struct hdcp), GFP_KERNEL);
+ if(!hdcp)
+ {
+ printk(KERN_ERR ">>HDCP: kmalloc fail!");
+ ret = -ENOMEM;
+ goto error0;
+ }
+ memset(hdcp, 0, sizeof(struct hdcp));
+ mutex_init(&hdcp->lock);
+
+ mdev.minor = MISC_DYNAMIC_MINOR;
+ mdev.name = "hdcp";
+ mdev.mode = 0666;
+ if (misc_register(&mdev)) {
+ printk(KERN_ERR "HDCP: Could not add character driver\n");
+ ret = HDMI_ERROR_FALSE;
+ goto error1;
+ }
+ ret = device_create_file(mdev.this_device, &dev_attr_enable);
+ if(ret)
+ {
+ printk(KERN_ERR "HDCP: Could not add sys file enable\n");
+ ret = -EINVAL;
+ goto error2;
+ }
+
+ ret = device_create_file(mdev.this_device, &dev_attr_trytimes);
+ if(ret)
+ {
+ printk(KERN_ERR "HDCP: Could not add sys file trytimes\n");
+ ret = -EINVAL;
+ goto error3;
+ }
+
+ hdcp->workqueue = create_singlethread_workqueue("hdcp");
+ if (hdcp->workqueue == NULL) {
+ printk(KERN_ERR "HDCP,: create workqueue failed.\n");
+ goto error4;
+ }
+
+
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
+ "hdcp.keys", mdev.this_device, GFP_KERNEL,
+ hdcp, hdcp_load_keys_cb);
+ if (ret < 0) {
+ printk(KERN_ERR "HDCP: request_firmware_nowait failed: %d\n", ret);
+ goto error5;
+ }
+
+ rk30_hdmi_register_hdcp_callbacks( hdcp_start_frame_cb,
+ hdcp_irq_cb,
+ hdcp_power_on_cb,
+ hdcp_power_off_cb);
+
+ DBG("%s success %u", __FUNCTION__, jiffies_to_msecs(jiffies));
+ return 0;
+
+error5:
+ destroy_workqueue(hdcp->workqueue);
+error4:
+ device_remove_file(mdev.this_device, &dev_attr_trytimes);
+error3:
+ device_remove_file(mdev.this_device, &dev_attr_enable);
+error2:
+ misc_deregister(&mdev);
+error1:
+ if(hdcp->keys)
+ kfree(hdcp->keys);
+ if(hdcp->invalidkeys)
+ kfree(hdcp->invalidkeys);
+ kfree(hdcp);
+error0:
+ return ret;
+}
+
+static void __exit rk30_hdcp_exit(void)
+{
+ if(hdcp) {
+ mutex_lock(&hdcp->lock);
+ rk30_hdmi_register_hdcp_callbacks(0, 0, 0, 0);
+ device_remove_file(mdev.this_device, &dev_attr_enable);
+ misc_deregister(&mdev);
+ destroy_workqueue(hdcp->workqueue);
+ if(hdcp->keys)
+ kfree(hdcp->keys);
+ if(hdcp->invalidkeys)
+ kfree(hdcp->invalidkeys);
+ mutex_unlock(&hdcp->lock);
+ kfree(hdcp);
+ }
+}
+
+module_init(rk30_hdcp_init);
+module_exit(rk30_hdcp_exit);
\ No newline at end of file
--- /dev/null
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <mach/io.h>
+#include "../rk30_hdmi.h"
+#include "../rk30_hdmi_hw.h"
+#include "rk30_hdmi_hdcp.h"
+
+static void rk30_hdcp_write_mem(int addr_8, char value)
+{
+ int temp;
+ int addr_32 = addr_8 - addr_8%4;
+ int shift = (addr_8%4) * 8;
+
+ temp = HDMIRdReg(addr_32);
+ temp &= ~(0xff << shift);
+ temp |= value << shift;
+// printk("temp is %08x\n", temp);
+ HDMIWrReg(addr_32, temp);
+}
+
+int rk30_hdcp_load_key2mem(struct hdcp_keys *key)
+{
+ int i;
+
+ if(key == NULL) return HDMI_ERROR_FALSE;
+
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
+
+ for(i = 0; i < 7; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV1 + i, key->KSV[i]);
+ for(i = 0; i < 7; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_KSV2 + i, key->KSV[i]);
+ for(i = 0; i < HDCP_PRIVATE_KEY_SIZE; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + i, key->DeviceKey[i]);
+ for(i = 0; i < HDCP_KEY_SHA_SIZE; i++)
+ rk30_hdcp_write_mem(HDCP_RAM_KEY_PRIVATE + HDCP_PRIVATE_KEY_SIZE + i, key->sha1[i]);
+
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV | 0x20);
+ return HDCP_OK;
+}
+
+void rk30_hdcp_disable(void)
+{
+ int temp;
+ // Diable HDCP Interrupt
+ HDMIWrReg(INTR_MASK2, 0x00);
+ // Stop and Reset HDCP
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_FRAMED_ENCRYPED | m_HDCP_AUTH_STOP | m_HDCP_RESET,
+ v_HDCP_FRAMED_ENCRYPED(0) | v_HDCP_AUTH_STOP(1) | v_HDCP_RESET(1) );
+}
+
+static int rk30_hdcp_load_key(void)
+{
+ int value, temp = 0;
+
+ if(hdcp->keys == NULL) {
+ pr_err("[%s] HDCP key not loaded.\n", __FUNCTION__);
+ return HDCP_KEY_ERR;
+ }
+
+ value = HDMIRdReg(HDCP_KEY_MEM_CTRL);
+ //Check HDCP key loaded from external HDCP memory
+ while((value & (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) != (m_KSV_VALID | m_KEY_VALID | m_KEY_READY)) {
+ if(temp > 10) {
+ pr_err("[%s] loaded hdcp key is incorrectable %02x\n", __FUNCTION__, value & 0xFF);
+ return HDCP_KEY_ERR;
+ }
+ //Load HDCP Key from external HDCP memory
+ HDMIWrReg(HDCP_KEY_ACCESS_CTRL2, m_LOAD_HDCP_KEY);
+ msleep(1);
+ value = HDMIRdReg(HDCP_KEY_MEM_CTRL);
+ temp++;
+ }
+
+ return HDCP_OK;
+}
+
+
+int rk30_hdcp_start_authentication(void)
+{
+ int rc, temp;
+
+ rc = rk30_hdcp_load_key();
+ if(rc != HDCP_OK)
+ return rc;
+
+ // Set 100ms & 5 sec timer
+ switch(hdmi->vic)
+ {
+ case HDMI_720x576p_50Hz_4_3:
+ case HDMI_720x576p_50Hz_16_9:
+ case HDMI_1280x720p_50Hz:
+ case HDMI_1920x1080i_50Hz:
+ case HDMI_720x576i_50Hz_4_3:
+ case HDMI_720x576i_50Hz_16_9:
+ case HDMI_1920x1080p_50Hz:
+ HDMIWrReg(HDCP_TIMER_100MS, 5);
+ HDMIWrReg(HDCP_TIMER_5S, 250);
+ break;
+
+ default:
+ HDMIWrReg(HDCP_TIMER_100MS, 0x26);
+ HDMIWrReg(HDCP_TIMER_5S, 0x2c);
+ break;
+ }
+ // Config DDC Clock
+ temp = (hdmi->tmdsclk/HDCP_DDC_CLK)/4;
+ HDMIWrReg(DDC_BUS_FREQ_L, temp & 0xFF);
+ HDMIWrReg(DDC_BUS_FREQ_H, (temp >> 8) & 0xFF);
+ // Enable HDCP Interrupt
+ HDMIWrReg(INTR_MASK2, m_INT_HDCP_ERR | m_INT_BKSV_RPRDY | m_INT_BKSV_RCRDY | m_INT_AUTH_DONE | m_INT_AUTH_READY);
+ // Start HDCP
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_AUTH_START | m_HDCP_FRAMED_ENCRYPED, v_HDCP_AUTH_START(1) | v_HDCP_FRAMED_ENCRYPED(0));
+
+ return HDCP_OK;
+}
+
+int rk30_hdcp_check_bksv(void)
+{
+ int i, temp;
+ char bksv[5];
+ char *invalidkey;
+
+ temp = HDMIRdReg(HDCP_BCAPS);
+ DBG("Receiver capacity is 0x%02x", temp);
+
+#ifdef DEBUG
+ if(temp & m_HDMI_RECEIVED)
+ DBG("Receiver support HDMI");
+ if(temp & m_REPEATER)
+ DBG("Receiver is a repeater");
+ if(temp & m_DDC_FAST)
+ DBG("Receiver support 400K DDC");
+ if(temp & m_1_1_FEATURE)
+ DBG("Receiver support 1.1 features, such as advanced cipher, EESS.");
+ if(temp & m_FAST_REAUTHENTICATION)
+ DBG("Receiver support fast reauthentication.");
+#endif
+
+ for(i = 0; i < 5; i++) {
+ bksv[i] = HDMIRdReg(HDCP_KSV_BYTE0 + (4 - i)*4) & 0xFF;
+ }
+
+ DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
+
+ for(i = 0; i < hdcp->invalidkey; i++)
+ {
+ invalidkey = hdcp->invalidkeys + i *5;
+ if(memcmp(bksv, invalidkey, 5) == 0) {
+ printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_FAILED | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_FAILED(1) | v_HDCP_FRAMED_ENCRYPED(0));
+ return HDCP_KSV_ERR;
+ }
+ }
+ HDMIMskReg(temp, HDCP_CTRL, m_HDCP_BKSV_PASS | m_HDCP_FRAMED_ENCRYPED, v_HDCP_BKSV_PASS(1) | v_HDCP_FRAMED_ENCRYPED(1));
+ return HDCP_OK;
+}
--- /dev/null
+#ifndef __RK30_HDMI_HDCP_H__
+#define __RK30_HDMI_HDCP_H__
+
+/***************************/
+/* Definitions */
+/***************************/
+
+/* Status / error codes */
+#define HDCP_OK 0
+#define HDCP_KEY_ERR 1
+#define HDCP_KSV_ERR 2
+
+/* Delays */
+#define HDCP_ENABLE_DELAY 300
+#define HDCP_REAUTH_DELAY 100
+
+/* Event source */
+#define HDCP_SRC_SHIFT 8
+#define HDCP_IOCTL_SRC (0x1 << HDCP_SRC_SHIFT)
+#define HDCP_HDMI_SRC (0x2 << HDCP_SRC_SHIFT)
+#define HDCP_IRQ_SRC (0x4 << HDCP_SRC_SHIFT)
+#define HDCP_WORKQUEUE_SRC (0x8 << HDCP_SRC_SHIFT)
+
+/* Event */
+#define HDCP_ENABLE_CTL (HDCP_IOCTL_SRC | 0)
+#define HDCP_DISABLE_CTL (HDCP_IOCTL_SRC | 1)
+#define HDCP_START_FRAME_EVENT (HDCP_HDMI_SRC | 2)
+#define HDCP_STOP_FRAME_EVENT (HDCP_HDMI_SRC | 3)
+#define HDCP_KSV_LIST_RDY_EVENT (HDCP_IRQ_SRC | 4)
+#define HDCP_FAIL_EVENT (HDCP_IRQ_SRC | 5)
+#define HDCP_AUTH_PASS_EVENT (HDCP_IRQ_SRC | 6)
+#define HDCP_AUTH_REATT_EVENT (HDCP_WORKQUEUE_SRC | 7)
+
+/* Key size */
+#define HDCP_KEY_SIZE 308
+
+/* Authentication retry times */
+#define HDCP_INFINITE_REAUTH 0x100
+
+enum hdcp_states {
+ HDCP_DISABLED,
+ HDCP_ENABLE_PENDING,
+ HDCP_AUTHENTICATION_START,
+ HDCP_WAIT_KSV_LIST,
+ HDCP_LINK_INTEGRITY_CHECK,
+};
+
+enum hdmi_states {
+ HDMI_STOPPED,
+ HDMI_STARTED
+};
+
+#define HDCP_PRIVATE_KEY_SIZE 280
+#define HDCP_KEY_SHA_SIZE 20
+#define HDCP_DDC_CLK 100000
+
+struct hdcp_keys{
+ u8 KSV[8];
+ u8 DeviceKey[HDCP_PRIVATE_KEY_SIZE];
+ u8 sha1[HDCP_KEY_SHA_SIZE];
+};
+
+struct hdcp_delayed_work {
+ struct delayed_work work;
+ int event;
+};
+
+struct hdcp {
+ int enable;
+ int retry_times;
+ struct hdcp_keys *keys;
+ int invalidkey;
+ char *invalidkeys;
+ struct mutex lock;
+ struct completion complete;
+ struct workqueue_struct *workqueue;
+
+ enum hdmi_states hdmi_state;
+ enum hdcp_states hdcp_state;
+
+ struct delayed_work *pending_start;
+ struct delayed_work *pending_wq_event;
+ int retry_cnt;
+};
+
+extern struct hdcp *hdcp;
+
+#ifdef HDCP_DEBUG
+#define DBG(format, ...) \
+ printk(KERN_INFO "HDCP: " format "\n", ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+extern void rk30_hdcp_disable(void);
+extern int rk30_hdcp_start_authentication(void);
+extern int rk30_hdcp_check_bksv(void);
+extern int rk30_hdcp_load_key2mem(struct hdcp_keys *key);
+#endif /* __RK30_HDMI_HDCP_H__ */
\ No newline at end of file
--- /dev/null
+#include <linux/module.h>\r
+#include <linux/kernel.h>\r
+#include <linux/errno.h>\r
+#include <linux/string.h>\r
+#include <linux/mm.h>\r
+#include <linux/slab.h>\r
+#include <linux/delay.h>\r
+#include <linux/device.h>\r
+#include <linux/init.h>\r
+#include <linux/dma-mapping.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/clk.h>\r
+\r
+#include <mach/board.h>\r
+#include <mach/io.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include "rk30_hdmi.h"\r
+#include "rk30_hdmi_hw.h"\r
+\r
+struct hdmi *hdmi = NULL;\r
+\r
+extern irqreturn_t hdmi_irq(int irq, void *priv);\r
+extern void hdmi_work(struct work_struct *work);\r
+extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);\r
+extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);\r
+extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);\r
+\r
+int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),\r
+ void (*hdcp_irq_cb)(int status),\r
+ int (*hdcp_power_on_cb)(void),\r
+ void (*hdcp_power_off_cb)(void))\r
+{\r
+ if(hdmi == NULL)\r
+ return HDMI_ERROR_FALSE;\r
+\r
+ hdmi->hdcp_cb = hdcp_cb;\r
+ hdmi->hdcp_irq_cb = hdcp_irq_cb;\r
+ hdmi->hdcp_power_on_cb = hdcp_power_on_cb;\r
+ hdmi->hdcp_power_off_cb = hdcp_power_off_cb;\r
+ \r
+ return HDMI_ERROR_SUCESS;\r
+}\r
+\r
+#ifdef CONFIG_HAS_EARLYSUSPEND\r
+static void hdmi_early_suspend(struct early_suspend *h)\r
+{\r
+ hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
+ flush_delayed_work(&hdmi->delay_work); \r
+ mutex_lock(&hdmi->enable_mutex);\r
+ hdmi->suspend = 1;\r
+ if(!hdmi->enable) {\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ return;\r
+ }\r
+ disable_irq(hdmi->irq);\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ hdmi->command = HDMI_CONFIG_ENABLE;\r
+ init_completion(&hdmi->complete);\r
+ hdmi->wait = 1;\r
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);\r
+ wait_for_completion_interruptible_timeout(&hdmi->complete,\r
+ msecs_to_jiffies(5000));\r
+ flush_delayed_work(&hdmi->delay_work);\r
+ // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced\r
+ // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO.\r
+ rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_GPIO0A2);\r
+ rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_GPIO0A1);\r
+ return;\r
+}\r
+\r
+static void hdmi_early_resume(struct early_suspend *h)\r
+{\r
+ hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");\r
+ mutex_lock(&hdmi->enable_mutex);\r
+ \r
+ rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_HDMI_I2C_SDA);\r
+ rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_HDMI_I2C_SCL);\r
+ \r
+ hdmi->suspend = 0;\r
+ rk30_hdmi_initial();\r
+ if(hdmi->enable) {\r
+ enable_irq(hdmi->irq);\r
+ }\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ return;\r
+}\r
+#endif\r
+\r
+static inline void hdmi_io_remap(void)\r
+{\r
+ unsigned int value;\r
+ \r
+ // Remap HDMI IO Pin\r
+ rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_HDMI_I2C_SDA);\r
+ rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_HDMI_I2C_SCL);\r
+ rk30_mux_api_set(GPIO0A0_HDMIHOTPLUGIN_NAME, GPIO0A_HDMI_HOT_PLUG_IN);\r
+ \r
+ // Select LCDC0 as video source and enabled.\r
+ value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);\r
+ writel(value, GRF_SOC_CON0 + RK30_GRF_BASE);\r
+}\r
+\r
+static int __devinit rk30_hdmi_probe (struct platform_device *pdev)\r
+{\r
+ int ret;\r
+ struct resource *res;\r
+ struct resource *mem;\r
+ \r
+ hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);\r
+ if(!hdmi)\r
+ {\r
+ dev_err(&pdev->dev, ">>rk30 hdmi kmalloc fail!");\r
+ return -ENOMEM;\r
+ }\r
+ memset(hdmi, 0, sizeof(struct hdmi));\r
+ hdmi->dev = &pdev->dev;\r
+ platform_set_drvdata(pdev, hdmi);\r
+\r
+ if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)\r
+ hdmi->lcdc = rk_get_lcdc_drv("lcdc0");\r
+ else\r
+ hdmi->lcdc = rk_get_lcdc_drv("lcdc1");\r
+ if(hdmi->lcdc == NULL)\r
+ {\r
+ dev_err(hdmi->dev, "can not connect to video source lcdc\n");\r
+ ret = -ENXIO;\r
+ goto err0;\r
+ }\r
+ hdmi->xscale = 95;\r
+ hdmi->yscale = 95;\r
+ \r
+ hdmi->hclk = clk_get(NULL,"hclk_hdmi");\r
+ if(IS_ERR(hdmi->hclk))\r
+ {\r
+ dev_err(hdmi->dev, "Unable to get hdmi hclk\n");\r
+ ret = -ENXIO;\r
+ goto err0;\r
+ }\r
+ clk_enable(hdmi->hclk);\r
+ \r
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
+ if (!res) {\r
+ dev_err(hdmi->dev, "Unable to get register resource\n");\r
+ ret = -ENXIO;\r
+ goto err0;\r
+ }\r
+ hdmi->regbase_phy = res->start;\r
+ hdmi->regsize_phy = (res->end - res->start) + 1;\r
+ mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name);\r
+ if (!mem)\r
+ {\r
+ dev_err(hdmi->dev, "failed to request mem region for hdmi\n");\r
+ ret = -ENOENT;\r
+ goto err0;\r
+ }\r
+\r
+ \r
+ hdmi->regbase = (int)ioremap(res->start, (res->end - res->start) + 1);\r
+ if (!hdmi->regbase) {\r
+ dev_err(hdmi->dev, "cannot ioremap registers\n");\r
+ ret = -ENXIO;\r
+ goto err1;\r
+ }\r
+ \r
+ ret = rk30_hdmi_initial();\r
+ if(ret != HDMI_ERROR_SUCESS)\r
+ goto err1;\r
+ \r
+ hdmi_io_remap();\r
+ hdmi_sys_init();\r
+ \r
+ hdmi->workqueue = create_singlethread_workqueue("hdmi");\r
+ INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);\r
+\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ hdmi->early_suspend.suspend = hdmi_early_suspend;\r
+ hdmi->early_suspend.resume = hdmi_early_resume;\r
+ hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;\r
+ register_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ \r
+ hdmi_register_display_sysfs(hdmi, NULL);\r
+ #ifdef CONFIG_SWITCH\r
+ hdmi->switch_hdmi.name="hdmi";\r
+ switch_dev_register(&(hdmi->switch_hdmi));\r
+ #endif\r
+ \r
+ spin_lock_init(&hdmi->irq_lock);\r
+ mutex_init(&hdmi->enable_mutex);\r
+ \r
+ /* get the IRQ */\r
+ hdmi->irq = platform_get_irq(pdev, 0);\r
+ if(hdmi->irq <= 0) {\r
+ dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq);\r
+ ret = -ENXIO;\r
+ goto err2;\r
+ }\r
+\r
+ /* request the IRQ */\r
+ ret = request_irq(hdmi->irq, hdmi_irq, 0, dev_name(&pdev->dev), hdmi);\r
+ if (ret)\r
+ {\r
+ dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret);\r
+ goto err2;\r
+ }\r
+\r
+ hdmi_dbg(hdmi->dev, "rk30 hdmi probe sucess.\n");\r
+ return 0;\r
+err2:\r
+ #ifdef CONFIG_SWITCH\r
+ switch_dev_unregister(&(hdmi->switch_hdmi));\r
+ #endif\r
+ hdmi_unregister_display_sysfs(hdmi);\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ unregister_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ iounmap((void*)hdmi->regbase);\r
+err1:\r
+ release_mem_region(res->start,(res->end - res->start) + 1);\r
+ clk_disable(hdmi->hclk);\r
+err0:\r
+ hdmi_dbg(hdmi->dev, "rk30 hdmi probe error.\n");\r
+ kfree(hdmi);\r
+ hdmi = NULL;\r
+ return ret;\r
+}\r
+\r
+static int __devexit rk30_hdmi_remove(struct platform_device *pdev)\r
+{\r
+ if(hdmi) {\r
+ mutex_lock(&hdmi->enable_mutex);\r
+ if(!hdmi->suspend && hdmi->enable)\r
+ disable_irq(hdmi->irq);\r
+ mutex_unlock(&hdmi->enable_mutex);\r
+ free_irq(hdmi->irq, NULL);\r
+ flush_workqueue(hdmi->workqueue);\r
+ destroy_workqueue(hdmi->workqueue);\r
+ #ifdef CONFIG_SWITCH\r
+ switch_dev_unregister(&(hdmi->switch_hdmi));\r
+ #endif\r
+ hdmi_unregister_display_sysfs(hdmi);\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ unregister_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ iounmap((void*)hdmi->regbase);\r
+ release_mem_region(hdmi->regbase_phy, hdmi->regsize_phy);\r
+ clk_disable(hdmi->hclk);\r
+ fb_destroy_modelist(&hdmi->edid.modelist);\r
+ if(hdmi->edid.audio)\r
+ kfree(hdmi->edid.audio);\r
+ if(hdmi->edid.specs)\r
+ {\r
+ if(hdmi->edid.specs->modedb)\r
+ kfree(hdmi->edid.specs->modedb);\r
+ kfree(hdmi->edid.specs);\r
+ }\r
+ kfree(hdmi);\r
+ hdmi = NULL;\r
+ }\r
+ printk(KERN_INFO "rk30 hdmi removed.\n");\r
+ return 0;\r
+}\r
+\r
+static void rk30_hdmi_shutdown(struct platform_device *pdev)\r
+{\r
+ if(hdmi) {\r
+ #ifdef CONFIG_HAS_EARLYSUSPEND\r
+ unregister_early_suspend(&hdmi->early_suspend);\r
+ #endif\r
+ }\r
+ printk(KERN_INFO "rk30 hdmi shut down.\n");\r
+}\r
+\r
+static struct platform_driver rk30_hdmi_driver = {\r
+ .probe = rk30_hdmi_probe,\r
+ .remove = __devexit_p(rk30_hdmi_remove),\r
+ .driver = {\r
+ .name = "rk30-hdmi",\r
+ .owner = THIS_MODULE,\r
+ },\r
+ .shutdown = rk30_hdmi_shutdown,\r
+};\r
+\r
+static int __init rk30_hdmi_init(void)\r
+{\r
+ return platform_driver_register(&rk30_hdmi_driver);\r
+}\r
+\r
+static void __exit rk30_hdmi_exit(void)\r
+{\r
+ platform_driver_unregister(&rk30_hdmi_driver);\r
+}\r
+\r
+\r
+//fs_initcall(rk30_hdmi_init);\r
+module_init(rk30_hdmi_init);\r
+module_exit(rk30_hdmi_exit);\r
--- /dev/null
+#ifndef __RK30_HDMI_H__
+#define __RK30_HDMI_H__
+
+#include "../../rk_hdmi.h"
+
+
+extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
+ void (*hdcp_irq_cb)(int status),
+ int (*hdcp_power_on_cb)(void),
+ void (*hdcp_power_off_cb)(void));
+#endif /* __RK30_HDMI_H__ */
--- /dev/null
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <mach/io.h>
+#include "rk30_hdmi.h"
+#include "rk30_hdmi_hw.h"
+
+static char edid_result = 0;
+
+static inline void delay100us(void)
+{
+ msleep(1);
+}
+
+int rk30_hdmi_initial(void)
+{
+ int rc = HDMI_ERROR_SUCESS;
+
+ hdmi->pwr_mode = PWR_SAVE_MODE_A;
+ hdmi->hdmi_removed = rk30_hdmi_removed ;
+ hdmi->control_output = rk30_hdmi_control_output;
+ hdmi->config_video = rk30_hdmi_config_video;
+ hdmi->config_audio = rk30_hdmi_config_audio;
+ hdmi->detect_hotplug = rk30_hdmi_detect_hotplug;
+ hdmi->read_edid = rk30_hdmi_read_edid;
+ // internal hclk = hdmi_hclk/20
+ HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
+
+ if(hdmi->hdcp_power_on_cb)
+ rc = hdmi->hdcp_power_on_cb();
+
+ return rc;
+}
+
+static void rk30_hdmi_set_pwr_mode(int mode)
+{
+ if(hdmi->pwr_mode == mode)
+ return;
+ hdmi_dbg(hdmi->dev, "[%s] mode %d\n", __FUNCTION__, mode);
+ switch(mode)
+ {
+ case PWR_SAVE_MODE_A:
+ HDMIWrReg(SYS_CTRL, 0x10);
+ break;
+ case PWR_SAVE_MODE_B:
+ HDMIWrReg(SYS_CTRL, 0x20);
+ break;
+ case PWR_SAVE_MODE_D:
+ // reset PLL A&B
+ HDMIWrReg(SYS_CTRL, 0x4C);
+ delay100us();
+ // release PLL A reset
+ HDMIWrReg(SYS_CTRL, 0x48);
+ delay100us();
+ // release PLL B reset
+ HDMIWrReg(SYS_CTRL, 0x40);
+ break;
+ case PWR_SAVE_MODE_E:
+ HDMIWrReg(SYS_CTRL, 0x80);
+ break;
+ }
+ hdmi->pwr_mode = mode;
+ if(mode != PWR_SAVE_MODE_A)
+ msleep(10);
+ hdmi_dbg(hdmi->dev, "[%s] curmode %02x\n", __FUNCTION__, HDMIRdReg(SYS_CTRL));
+}
+
+int rk30_hdmi_detect_hotplug(void)
+{
+ int value = HDMIRdReg(HPD_MENS_STA);
+
+ hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value);
+ value &= m_HOTPLUG_STATUS | m_MSEN_STATUS;
+ if(value == (m_HOTPLUG_STATUS | m_MSEN_STATUS) )
+ return HDMI_HPD_ACTIVED;
+ else if(value)
+ return HDMI_HPD_INSERT;
+ else
+ return HDMI_HPD_REMOVED;
+}
+
+#define HDMI_EDID_DDC_CLK 90000
+int rk30_hdmi_read_edid(int block, unsigned char *buff)
+{
+ int value, ret = -1, ddc_bus_freq = 0;
+ char interrupt = 0, trytime = 2;
+ unsigned long flags;
+
+ hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block);
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+ edid_result = 0;
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+ //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 30MHz.
+ //Set DDC I2C CLK which devided from DDC_CLK to 100KHz.
+ ddc_bus_freq = (30000000/HDMI_EDID_DDC_CLK)/4;
+ HDMIWrReg(DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
+ HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
+
+ // Enable edid interrupt
+ HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS | m_INT_EDID_ERR | m_INT_EDID_READY);
+
+ while(trytime--) {
+ // Config EDID block and segment addr
+ HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80);
+ HDMIWrReg(EDID_SEGMENT_POINTER, block/2);
+
+ value = 100;
+ while(value--)
+ {
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+ interrupt = edid_result;
+ edid_result = 0;
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+ if(interrupt & (m_INT_EDID_ERR | m_INT_EDID_READY))
+ break;
+ msleep(10);
+ }
+ hdmi_dbg(hdmi->dev, "[%s] edid read value %d\n", __FUNCTION__, value);
+ if(interrupt & m_INT_EDID_READY)
+ {
+ for(value = 0; value < HDMI_EDID_BLOCK_SIZE; value++)
+ buff[value] = HDMIRdReg(DDC_READ_FIFO_ADDR);
+ ret = 0;
+
+ hdmi_dbg(hdmi->dev, "[%s] edid read sucess\n", __FUNCTION__);
+#ifdef HDMI_DEBUG
+ for(value = 0; value < 128; value++) {
+ printk("%02x ,", buff[value]);
+ if( (value + 1) % 16 == 0)
+ printk("\n");
+ }
+#endif
+ break;
+ }
+ if(interrupt & m_INT_EDID_ERR)
+ hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__);
+
+ }
+ // Disable edid interrupt
+ HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
+// msleep(100);
+ return ret;
+}
+
+static inline void rk30_hdmi_config_phy_reg(int reg, int value)
+{
+ HDMIWrReg(reg, value);
+ HDMIWrReg(SYS_CTRL, 0x2C);
+ delay100us();
+ HDMIWrReg(SYS_CTRL, 0x20);
+ msleep(1);
+}
+
+static void rk30_hdmi_config_phy(unsigned char vic)
+{
+ HDMIWrReg(DEEP_COLOR_MODE, 0x22); // tmds frequency same as input dlck
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
+ switch(vic)
+ {
+ case HDMI_1920x1080p_60Hz:
+ case HDMI_1920x1080p_50Hz:
+ rk30_hdmi_config_phy_reg(0x158, 0x0E);
+ rk30_hdmi_config_phy_reg(0x15c, 0x00);
+ rk30_hdmi_config_phy_reg(0x160, 0x60);
+ rk30_hdmi_config_phy_reg(0x164, 0x00);
+ rk30_hdmi_config_phy_reg(0x168, 0xDA);
+ rk30_hdmi_config_phy_reg(0x16c, 0xA1);
+ rk30_hdmi_config_phy_reg(0x170, 0x0e);
+ rk30_hdmi_config_phy_reg(0x174, 0x22);
+ rk30_hdmi_config_phy_reg(0x178, 0x00);
+ break;
+
+ case HDMI_1920x1080i_60Hz:
+ case HDMI_1920x1080i_50Hz:
+ case HDMI_1280x720p_60Hz:
+ case HDMI_1280x720p_50Hz:
+ rk30_hdmi_config_phy_reg(0x158, 0x06);
+ rk30_hdmi_config_phy_reg(0x15c, 0x00);
+ rk30_hdmi_config_phy_reg(0x160, 0x60);
+ rk30_hdmi_config_phy_reg(0x164, 0x00);
+ rk30_hdmi_config_phy_reg(0x168, 0xCA);
+ rk30_hdmi_config_phy_reg(0x16c, 0xA3);
+ rk30_hdmi_config_phy_reg(0x170, 0x0e);
+ rk30_hdmi_config_phy_reg(0x174, 0x20);
+ rk30_hdmi_config_phy_reg(0x178, 0x00);
+ break;
+
+ case HDMI_720x576p_50Hz_4_3:
+ case HDMI_720x576p_50Hz_16_9:
+ case HDMI_720x480p_60Hz_4_3:
+ case HDMI_720x480p_60Hz_16_9:
+ rk30_hdmi_config_phy_reg(0x158, 0x02);
+ rk30_hdmi_config_phy_reg(0x15c, 0x00);
+ rk30_hdmi_config_phy_reg(0x160, 0x60);
+ rk30_hdmi_config_phy_reg(0x164, 0x00);
+ rk30_hdmi_config_phy_reg(0x168, 0xC2);
+ rk30_hdmi_config_phy_reg(0x16c, 0xA2);
+ rk30_hdmi_config_phy_reg(0x170, 0x0e);
+ rk30_hdmi_config_phy_reg(0x174, 0x20);
+ rk30_hdmi_config_phy_reg(0x178, 0x00);
+ break;
+ default:
+ hdmi_err(hdmi->dev, "not support such vic %d\n", vic);
+ break;
+ }
+}
+
+static void rk30_hdmi_config_avi(unsigned char vic, unsigned char output_color)
+{
+ int i, clolorimetry, aspect_ratio;
+ char info[SIZE_AVI_INFOFRAME];
+
+ memset(info, 0, SIZE_AVI_INFOFRAME);
+ HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
+ info[0] = 0x82;
+ info[1] = 0x02;
+ info[2] = 0x0D;
+ info[3] = info[0] + info[1] + info[2];
+
+ if(output_color == VIDEO_OUTPUT_YCBCR444)
+ info[4] = (AVI_COLOR_MODE_YCBCR444 << 5);
+ else if(output_color == VIDEO_OUTPUT_YCBCR422)
+ info[4] = (AVI_COLOR_MODE_YCBCR422 << 5);
+ else
+ info[4] = (AVI_COLOR_MODE_RGB << 5);
+ info[4] |= (1 << 4); //Enable active format data bits is present in info[2]
+
+ switch(vic)
+ {
+ case HDMI_720x480i_60Hz_4_3:
+ case HDMI_720x576i_50Hz_4_3:
+ case HDMI_720x480p_60Hz_4_3:
+ case HDMI_720x576p_50Hz_4_3:
+ aspect_ratio = AVI_CODED_FRAME_ASPECT_4_3;
+ clolorimetry = AVI_COLORIMETRY_SMPTE_170M;
+ break;
+ case HDMI_720x480i_60Hz_16_9:
+ case HDMI_720x576i_50Hz_16_9:
+ case HDMI_720x480p_60Hz_16_9:
+ case HDMI_720x576p_50Hz_16_9:
+ aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9;
+ clolorimetry = AVI_COLORIMETRY_SMPTE_170M;
+ break;
+ default:
+ aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9;
+ clolorimetry = AVI_COLORIMETRY_ITU709;
+ }
+
+ if(output_color == VIDEO_OUTPUT_RGB444)
+ clolorimetry = AVI_COLORIMETRY_NO_DATA;
+
+ info[5] = (clolorimetry << 6) | (aspect_ratio << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME;
+ info[6] = 0;
+ info[7] = vic;
+ info[8] = 0;
+
+ // Calculate AVI InfoFrame ChecKsum
+ for (i = 4; i < SIZE_AVI_INFOFRAME; i++)
+ {
+ info[3] += info[i];
+ }
+ info[3] = 0x100 - info[3];
+
+ for(i = 0; i < SIZE_AVI_INFOFRAME; i++)
+ HDMIWrReg(CONTROL_PACKET_HB0 + i*4, info[i]);
+}
+
+static char coeff_csc[][24] = {
+ //G B R Bias
+ { //CSC_RGB_0_255_TO_ITU601_16_235
+ 0x11, 0xb6, 0x02, 0x0b, 0x10, 0x55, 0x00, 0x80, //Cr
+ 0x02, 0x59, 0x01, 0x32, 0x00, 0x75, 0x00, 0x10, //Y
+ 0x11, 0x5b, 0x10, 0xb0, 0x02, 0x0b, 0x00, 0x80, //Cb
+ },
+ { //CSC_RGB_0_255_TO_ITU709_16_235
+ 0x11, 0xdb, 0x02, 0x0b, 0x10, 0x30, 0x00, 0x80, //Cr
+ 0x02, 0xdc, 0x00, 0xda, 0x00, 0x4a, 0x00, 0x10, //Y
+ 0x11, 0x93, 0x10, 0x78, 0x02, 0x0b, 0x00, 0x80, //Cb
+ },
+ //Y Cr Cb Bias
+ { //CSC_ITU601_16_235_TO_RGB_16_235
+ 0x04, 0x00, 0x05, 0x7c, 0x00, 0x00, 0x02, 0xaf, //R
+ 0x04, 0x00, 0x12, 0xcb, 0x11, 0x58, 0x00, 0x84, //G
+ 0x04, 0x00, 0x00, 0x00, 0x06, 0xee, 0x02, 0xde, //B
+ },
+ { //CSC_ITU709_16_235_TO_RGB_16_235
+ 0x04, 0x00, 0x06, 0x29, 0x00, 0x00, 0x02, 0xc5, //R
+ 0x04, 0x00, 0x11, 0xd6, 0x10, 0xbb, 0x00, 0x52, //G
+ 0x04, 0x00, 0x00, 0x00, 0x07, 0x44, 0x02, 0xe8, //B
+ },
+ { //CSC_ITU601_16_235_TO_RGB_0_255
+ 0x04, 0xa8, 0x05, 0x7c, 0x00, 0x00, 0x02, 0xc2, //R
+ 0x04, 0xa8, 0x12, 0xcb, 0x11, 0x58, 0x00, 0x72, //G
+ 0x04, 0xa8, 0x00, 0x00, 0x06, 0xee, 0x02, 0xf0, //B
+ },
+ { //CSC_ITU709_16_235_TO_RGB_0_255
+ 0x04, 0xa8, 0x06, 0x29, 0x00, 0x00, 0x02, 0xd8, //R
+ 0x04, 0xa8, 0x11, 0xd6, 0x10, 0xbb, 0x00, 0x40, //G
+ 0x04, 0xa8, 0x00, 0x00, 0x07, 0x44, 0x02, 0xfb, //B
+ },
+
+};
+
+static void rk30_hdmi_config_csc(struct hdmi_video_para *vpara)
+{
+ int i, mode;
+ char *coeff = NULL;
+
+ if( ((vpara->input_color == VIDEO_INPUT_COLOR_RGB) && (vpara->output_color == VIDEO_OUTPUT_RGB444)) ||
+ ((vpara->input_color == VIDEO_INPUT_COLOR_YCBCR) && (vpara->output_color != VIDEO_OUTPUT_RGB444) ))
+ {
+ return;
+ }
+ switch(vpara->vic)
+ {
+ case HDMI_720x480i_60Hz_4_3:
+ case HDMI_720x576i_50Hz_4_3:
+ case HDMI_720x480p_60Hz_4_3:
+ case HDMI_720x576p_50Hz_4_3:
+ case HDMI_720x480i_60Hz_16_9:
+ case HDMI_720x576i_50Hz_16_9:
+ case HDMI_720x480p_60Hz_16_9:
+ case HDMI_720x576p_50Hz_16_9:
+ if(vpara->input_color == VIDEO_INPUT_COLOR_RGB)
+ mode = CSC_RGB_0_255_TO_ITU601_16_235;
+ else if(vpara->output_mode == OUTPUT_HDMI)
+ mode = CSC_ITU601_16_235_TO_RGB_16_235;
+ else
+ mode = CSC_ITU601_16_235_TO_RGB_0_255;
+ break;
+ default:
+ if(vpara->input_color == VIDEO_INPUT_COLOR_RGB)
+ mode = CSC_RGB_0_255_TO_ITU709_16_235;
+ else if(vpara->output_mode == OUTPUT_HDMI)
+ mode = CSC_ITU709_16_235_TO_RGB_16_235;
+ else
+ mode = CSC_ITU709_16_235_TO_RGB_0_255;
+ break;
+ }
+
+ coeff = coeff_csc[mode];
+
+ HDMIWrReg(CSC_CONFIG1, v_CSC_MODE(CSC_MODE_MANUAL) | v_CSC_BRSWAP_DIABLE(1));
+
+ for(i = 0; i < 24; i++)
+ HDMIWrReg(CSC_PARA_C0_H + i*4, coeff[i]);
+
+ HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(1));
+}
+
+int rk30_hdmi_config_video(struct hdmi_video_para *vpara)
+{
+ int value;
+ struct fb_videomode *mode;
+
+ hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__);
+ if(vpara == NULL) {
+ hdmi_err(hdmi->dev, "[%s] input parameter error\n", __FUNCTION__);
+ return -1;
+ }
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_E)
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_D || hdmi->pwr_mode == PWR_SAVE_MODE_A)
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
+
+ if(hdmi->hdcp_power_off_cb)
+ hdmi->hdcp_power_off_cb();
+
+ // Input video mode is RGB24bit, Data enable signal from external
+ HDMIMskReg(value, AV_CTRL1, m_INPUT_VIDEO_MODE | m_DE_SIGNAL_SELECT, \
+ v_INPUT_VIDEO_MODE(vpara->input_mode) | EXTERNAL_DE)
+ HDMIMskReg(value, VIDEO_CTRL1, m_VIDEO_OUTPUT_MODE | m_VIDEO_INPUT_DEPTH | m_VIDEO_INPUT_COLOR_MODE, \
+ v_VIDEO_OUTPUT_MODE(vpara->output_color) | v_VIDEO_INPUT_DEPTH(VIDEO_INPUT_DEPTH_8BIT) | vpara->input_color)
+ HDMIWrReg(DEEP_COLOR_MODE, 0x20);
+ // color space convert
+ rk30_hdmi_config_csc(vpara);
+ // Set HDMI Mode
+ HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(vpara->output_mode));
+
+ // Set ext video
+ mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);
+ if(mode == NULL)
+ {
+ hdmi_err(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic);
+ return -ENOENT;
+ }
+ hdmi->tmdsclk = mode->pixclock;
+
+ if( (vpara->vic == HDMI_720x480p_60Hz_4_3) || (vpara->vic == HDMI_720x480p_60Hz_16_9) )
+ value = v_VSYNC_OFFSET(6);
+ else
+ value = v_VSYNC_OFFSET(0);
+ value |= v_EXT_VIDEO_ENABLE(1) | v_INTERLACE(mode->vmode);
+ if(mode->sync & FB_SYNC_HOR_HIGH_ACT)
+ value |= v_HSYNC_POLARITY(1);
+ if(mode->sync & FB_SYNC_VERT_HIGH_ACT)
+ value |= v_VSYNC_POLARITY(1);
+ HDMIWrReg(EXT_VIDEO_PARA, value);
+ value = mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len;
+ HDMIWrReg(EXT_VIDEO_PARA_HTOTAL_L, value & 0xFF);
+ HDMIWrReg(EXT_VIDEO_PARA_HTOTAL_H, (value >> 8) & 0xFF);
+
+ value = mode->left_margin + mode->right_margin + mode->hsync_len;
+ HDMIWrReg(EXT_VIDEO_PARA_HBLANK_L, value & 0xFF);
+ HDMIWrReg(EXT_VIDEO_PARA_HBLANK_H, (value >> 8) & 0xFF);
+
+ value = mode->left_margin + mode->hsync_len;
+ HDMIWrReg(EXT_VIDEO_PARA_HDELAY_L, value & 0xFF);
+ HDMIWrReg(EXT_VIDEO_PARA_HDELAY_H, (value >> 8) & 0xFF);
+
+ value = mode->hsync_len;
+ HDMIWrReg(EXT_VIDEO_PARA_HSYNCWIDTH_L, value & 0xFF);
+ HDMIWrReg(EXT_VIDEO_PARA_HSYNCWIDTH_H, (value >> 8) & 0xFF);
+
+ value = mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len;
+ HDMIWrReg(EXT_VIDEO_PARA_VTOTAL_L, value & 0xFF);
+ HDMIWrReg(EXT_VIDEO_PARA_VTOTAL_H, (value >> 8) & 0xFF);
+
+ value = mode->upper_margin + mode->vsync_len + mode->lower_margin;
+ HDMIWrReg(EXT_VIDEO_PARA_VBLANK_L, value & 0xFF);
+
+ if(vpara->vic == HDMI_720x480p_60Hz_4_3 || vpara->vic == HDMI_720x480p_60Hz_16_9)
+ value = 42;
+ else
+ value = mode->upper_margin + mode->vsync_len;
+
+ HDMIWrReg(EXT_VIDEO_PARA_VDELAY, value & 0xFF);
+
+ value = mode->vsync_len;
+ HDMIWrReg(EXT_VIDEO_PARA_VSYNCWIDTH, value & 0xFF);
+
+ if(vpara->output_mode == OUTPUT_HDMI) {
+ rk30_hdmi_config_avi(vpara->vic, vpara->output_color);
+ hdmi_dbg(hdmi->dev, "[%s] sucess output HDMI.\n", __FUNCTION__);
+ }
+ else {
+ hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__);
+ }
+
+ rk30_hdmi_config_phy(vpara->vic);
+ rk30_hdmi_control_output(0);
+ return 0;
+}
+
+static void rk30_hdmi_config_aai(void)
+{
+ int i;
+ char info[SIZE_AUDIO_INFOFRAME];
+
+ memset(info, 0, SIZE_AUDIO_INFOFRAME);
+
+ info[0] = 0x84;
+ info[1] = 0x01;
+ info[2] = 0x0A;
+
+ info[3] = info[0] + info[1] + info[2];
+ for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)
+ info[3] += info[i];
+
+ info[3] = 0x100 - info[3];
+
+ HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI);
+ for(i = 0; i < SIZE_AUDIO_INFOFRAME; i++)
+ HDMIWrReg(CONTROL_PACKET_HB0 + i*4, info[i]);
+}
+
+int rk30_hdmi_config_audio(struct hdmi_audio *audio)
+{
+ int value, rate, N;
+ char word_length, channel;
+
+ if(audio->channel < 3)
+ channel = I2S_CHANNEL_1_2;
+ else if(audio->channel < 5)
+ channel = I2S_CHANNEL_3_4;
+ else if(audio->channel < 7)
+ channel = I2S_CHANNEL_5_6;
+ else
+ channel = I2S_CHANNEL_7_8;
+
+ switch(audio->rate)
+ {
+ case HDMI_AUDIO_FS_32000:
+ rate = AUDIO_32K;
+ N = N_32K;
+ break;
+ case HDMI_AUDIO_FS_44100:
+ rate = AUDIO_441K;
+ N = N_441K;
+ break;
+ case HDMI_AUDIO_FS_48000:
+ rate = AUDIO_48K;
+ N = N_48K;
+ break;
+ case HDMI_AUDIO_FS_88200:
+ rate = AUDIO_882K;
+ N = N_882K;
+ break;
+ case HDMI_AUDIO_FS_96000:
+ rate = AUDIO_96K;
+ N = N_96K;
+ break;
+ case HDMI_AUDIO_FS_176400:
+ rate = AUDIO_1764K;
+ N = N_1764K;
+ break;
+ case HDMI_AUDIO_FS_192000:
+ rate = AUDIO_192K;
+ N = N_192K;
+ break;
+ default:
+ hdmi_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate);
+ return -ENOENT;
+ }
+// switch(audio->word_length)
+// {
+// case HDMI_AUDIO_WORD_LENGTH_16bit:
+// word_length = 0x02;
+// break;
+// case HDMI_AUDIO_WORD_LENGTH_20bit:
+// word_length = 0x0a;
+// break;
+// case HDMI_AUDIO_WORD_LENGTH_24bit:
+// word_length = 0x0b;
+// break;
+// default:
+// hdmi_err(hdmi->dev, "[%s] not support such word length %d\n", __FUNCTION__, audio->word_length);
+// return -ENOENT;
+// }
+ //set_audio_if I2S
+ HDMIWrReg(AUDIO_CTRL1, 0x00); //internal CTS, disable down sample, i2s input, disable MCLK
+ HDMIWrReg(AUDIO_CTRL2, 0x40);
+ HDMIWrReg(I2S_AUDIO_CTRL, v_I2S_MODE(I2S_MODE_STANDARD) | v_I2S_CHANNEL(channel) );
+ HDMIWrReg(I2S_INPUT_SWAP, 0x00); //no swap
+ HDMIMskReg(value, AV_CTRL1, m_AUDIO_SAMPLE_RATE, v_AUDIO_SAMPLE_RATE(rate))
+// HDMIWrReg(SRC_NUM_AUDIO_LEN, word_length);
+
+ //Set N value 6144, fs=48kHz
+ HDMIWrReg(N_1, N & 0xFF);
+ HDMIWrReg(N_2, (N >> 8) & 0xFF);
+ HDMIWrReg(LR_SWAP_N3, (N >> 16) & 0x0F);
+
+ rk30_hdmi_config_aai();
+ return 0;
+}
+
+static void rk30_hdmi_audio_reset(void)
+{
+ int value;
+
+ HDMIMskReg(value, VIDEO_SETTING2, m_AUDIO_RESET, AUDIO_CAPTURE_RESET)
+ msleep(1);
+ HDMIMskReg(value, VIDEO_SETTING2, m_AUDIO_RESET, 0)
+}
+
+void rk30_hdmi_control_output(int enable)
+{
+ hdmi_dbg(hdmi->dev, "[%s] %d\n", __FUNCTION__, enable);
+ if(enable == 0) {
+ HDMIWrReg(AV_MUTE, v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1));
+ }
+ else {
+ HDMIWrReg(VIDEO_SETTING2, 0x03);
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_B) {
+ // Switch to power save mode_d
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
+ }
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_D) {
+ // Switch to power save mode_e
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_E);
+ }
+ HDMIWrReg(VIDEO_SETTING2, 0x00);
+ rk30_hdmi_audio_reset();
+ }
+}
+
+int rk30_hdmi_removed(void)
+{
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_E)
+ {
+ HDMIWrReg(VIDEO_SETTING2, 0x00);
+ rk30_hdmi_audio_reset();
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
+ }
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_D)
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_B && hdmi->state == HDMI_SLEEP)
+ {
+ HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
+ HDMIWrReg(INTR_MASK2, 0);
+ HDMIWrReg(INTR_MASK3, 0);
+ HDMIWrReg(INTR_MASK4, 0);
+ // Disable color space convertion
+ HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(0));
+ HDMIWrReg(CSC_CONFIG1, v_CSC_MODE(CSC_MODE_AUTO) | v_CSC_BRSWAP_DIABLE(1));
+ if(hdmi->hdcp_power_off_cb)
+ hdmi->hdcp_power_off_cb();
+ rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_A);
+ }
+ dev_printk(KERN_INFO , hdmi->dev , "Removed.\n");
+ return HDMI_ERROR_SUCESS;
+}
+
+
+irqreturn_t hdmi_irq(int irq, void *priv)
+{
+ char interrupt1 = 0, interrupt2 = 0, interrupt3 = 0, interrupt4 = 0;
+
+ if(hdmi->pwr_mode == PWR_SAVE_MODE_A)
+ {
+ HDMIWrReg(SYS_CTRL, 0x20);
+ hdmi->pwr_mode = PWR_SAVE_MODE_B;
+
+ hdmi_dbg(hdmi->dev, "hdmi irq wake up\n");
+ // HDMI was inserted when system is sleeping, irq was triggered only once
+ // when wake up. So we need to check hotplug status.
+ if(HDMIRdReg(HPD_MENS_STA) & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) {
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
+ }
+ }
+ else
+ {
+ interrupt1 = HDMIRdReg(INTR_STATUS1);
+ interrupt2 = HDMIRdReg(INTR_STATUS2);
+ interrupt3 = HDMIRdReg(INTR_STATUS3);
+ interrupt4 = HDMIRdReg(INTR_STATUS4);
+ HDMIWrReg(INTR_STATUS1, interrupt1);
+ HDMIWrReg(INTR_STATUS2, interrupt2);
+ HDMIWrReg(INTR_STATUS3, interrupt3);
+ HDMIWrReg(INTR_STATUS4, interrupt4);
+#if 0
+ hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x interrupt3 %02x interrupt4 %02x\n",\
+ __FUNCTION__, interrupt1, interrupt2, interrupt3, interrupt4);
+#endif
+ if(interrupt1 & (m_INT_HOTPLUG | m_INT_MSENS))
+ {
+ if(hdmi->state == HDMI_SLEEP)
+ hdmi->state = WAIT_HOTPLUG;
+ interrupt1 &= ~(m_INT_HOTPLUG | m_INT_MSENS);
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
+ }
+ else if(interrupt1 & (m_INT_EDID_READY | m_INT_EDID_ERR)) {
+ spin_lock(&hdmi->irq_lock);
+ edid_result = interrupt1;
+ spin_unlock(&hdmi->irq_lock);
+ }
+ else if(hdmi->state == HDMI_SLEEP) {
+ hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n");
+ HDMIWrReg(SYS_CTRL, 0x10);
+ hdmi->pwr_mode = PWR_SAVE_MODE_A;
+ }
+ if(interrupt2 && hdmi->hdcp_irq_cb)
+ hdmi->hdcp_irq_cb(interrupt2);
+ }
+ return IRQ_HANDLED;
+}
+
--- /dev/null
+#ifndef __RK30_HDMI_HW_H__
+#define __RK30_HDMI_HW_H__
+
+/* HDMI_SYS_CONTROL */
+#define SYS_CTRL 0x0
+
+enum {
+ PWR_SAVE_MODE_A = 1,
+ PWR_SAVE_MODE_B = 2,
+ PWR_SAVE_MODE_D = 4,
+ PWR_SAVE_MODE_E = 8
+};
+#define m_PWR_SAVE_MODE 0xF0
+#define v_PWR_SAVE_MODE(n) (n << 4)
+#define PLL_B_RESET (1 << 3)
+
+#define N_32K 0x1000
+#define N_441K 0x1880
+#define N_882K 0x3100
+#define N_1764K 0x6200
+#define N_48K 0x1800
+#define N_96K 0x3000
+#define N_192K 0x6000
+
+#define LR_SWAP_N3 0x04
+#define N_2 0x08
+#define N_1 0x0c
+
+#define AUDIO_CTRL1 0x28
+#define AUDIO_CTRL2 0x2c
+#define I2S_AUDIO_CTRL 0x30
+enum {
+ I2S_MODE_STANDARD = 0,
+ I2S_MODE_RIGHT_JUSTIFIED,
+ I2S_MODE_LEFT_JUSTIFIED
+};
+#define v_I2S_MODE(n) n
+enum {
+ I2S_CHANNEL_1_2 = 1,
+ I2S_CHANNEL_3_4 = 3,
+ I2S_CHANNEL_5_6 = 7,
+ I2S_CHANNEL_7_8 = 0xf
+};
+#define v_I2S_CHANNEL(n) ( (n) << 2 )
+
+#define I2S_INPUT_SWAP 0x40
+
+#define SRC_NUM_AUDIO_LEN 0x50
+
+/* HDMI_AV_CTRL1*/
+#define AV_CTRL1 0x54
+enum {
+ AUDIO_32K = 0x3,
+ AUDIO_441K = 0x0,
+ AUDIO_48K = 0x2,
+ AUDIO_882K = 0x8,
+ AUDIO_96K = 0xa,
+ AUDIO_1764K = 0xc,
+ AUDIO_192K = 0xe,
+};
+#define m_AUDIO_SAMPLE_RATE 0xF0
+#define v_AUDIO_SAMPLE_RATE(n) (n << 4)
+#define m_INPUT_VIDEO_MODE (7 << 1)
+#define v_INPUT_VIDEO_MODE(n) (n << 1)
+enum {
+ INTERNAL_DE = 0,
+ EXTERNAL_DE
+};
+#define m_DE_SIGNAL_SELECT (1 << 0)
+
+/* HDMI_AV_CTRL2 */
+#define AV_CTRL2 0xec
+#define m_CSC_ENABLE (1 << 0)
+#define v_CSC_ENABLE(n) (n)
+
+/* HDMI_VIDEO_CTRL1 */
+#define VIDEO_CTRL1 0x58
+
+#define m_VIDEO_OUTPUT_MODE (0x3 << 6)
+#define v_VIDEO_OUTPUT_MODE(n) (n << 6)
+enum {
+ VIDEO_INPUT_DEPTH_12BIT = 0,
+ VIDEO_INPUT_DEPTH_10BIT = 0x1,
+ VIDEO_INPUT_DEPTH_8BIT = 0x3
+};
+#define m_VIDEO_INPUT_DEPTH (3 << 4)
+#define v_VIDEO_INPUT_DEPTH(n) (n << 4)
+enum {
+ VIDEO_EMBEDDED_SYNC_LOCATION_0 = 0,
+ VIDEO_EMBEDDED_SYNC_LOCATION_1,
+ VIDEO_EMBEDDED_SYNC_LOCATION_2
+};
+#define m_VIDEO_EMBEDDED_SYNC_LOCATION (3 << 2)
+#define VIDEO_EMBEDDED_SYNC_LOCATION(n) (n << 2)
+#define m_VIDEO_INPUT_COLOR_MODE (1 << 0)
+
+/* DEEP_COLOR_MODE */
+#define DEEP_COLOR_MODE 0x5c
+enum{
+ TMDS_CLOCK_MODE_8BIT = 0,
+ TMDS_CLOKK_MODE_10BIT,
+ TMDS_CLOKK_MODE_12BIT
+};
+#define TMDS_CLOCK_MODE_MASK 0x3 << 6
+#define TMDS_CLOCK_MODE(n) (n) << 6
+
+/* VIDEO_CTRL2 */
+#define VIDEO_SETTING2 0x114
+#define m_UNMUTE (1 << 7)
+#define m_MUTE (1 << 6)
+#define m_AUDIO_RESET (1 << 2)
+#define m_NOT_SEND_AUDIO (1 << 1)
+#define m_NOT_SEND_VIDEO (1 << 0)
+#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data
+#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data
+#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode.
+#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data
+#define NOT_SEND_VIDEO (1 << 0) // Send black video data
+
+/* Color Space Convertion Parameter*/
+#define CSC_PARA_C0_H 0x60
+#define CSC_PARA_C0_L 0x64
+#define CSC_PARA_C1_H 0x68
+#define CSC_PARA_C1_L 0x6c
+#define CSC_PARA_C2_H 0x70
+#define CSC_PARA_C2_L 0x74
+#define CSC_PARA_C3_H 0x78
+#define CSC_PARA_C3_L 0x7c
+#define CSC_PARA_C4_H 0x80
+#define CSC_PARA_C4_L 0x84
+#define CSC_PARA_C5_H 0x88
+#define CSC_PARA_C5_L 0x8c
+#define CSC_PARA_C6_H 0x90
+#define CSC_PARA_C6_L 0x94
+#define CSC_PARA_C7_H 0x98
+#define CSC_PARA_C7_L 0x9c
+#define CSC_PARA_C8_H 0xa0
+#define CSC_PARA_C8_L 0xa4
+#define CSC_PARA_C9_H 0xa8
+#define CSC_PARA_C9_L 0xac
+#define CSC_PARA_C10_H 0xac
+#define CSC_PARA_C10_L 0xb4
+#define CSC_PARA_C11_H 0xb8
+#define CSC_PARA_C11_L 0xbc
+
+#define CSC_CONFIG1 0x34c
+#define m_CSC_MODE (1 << 7)
+#define m_CSC_COEF_MODE (0xF << 3) //Only used in auto csc mode
+#define m_CSC_STATUS (1 << 2)
+#define m_CSC_VID_SELECT (1 << 1)
+#define m_CSC_BRSWAP_DIABLE (1)
+
+enum {
+ CSC_MODE_MANUAL = 0,
+ CSC_MODE_AUTO
+};
+#define v_CSC_MODE(n) (n << 7)
+enum {
+ COE_SDTV_LIMITED_RANGE = 0x08,
+ COE_SDTV_FULL_RANGE = 0x04,
+ COE_HDTV_60Hz = 0x2,
+ COE_HDTV_50Hz = 0x1
+};
+#define v_CSC_COE_MODE(n) (n << 3)
+enum {
+ CSC_INPUT_VID_5_19 = 0,
+ CSC_INPUT_VID_28_29
+};
+#define v_CSC_VID_SELECT(n) (n << 1)
+#define v_CSC_BRSWAP_DIABLE(n) (n)
+
+/* CONTROL_PACKET_BUF_INDEX */
+#define CONTROL_PACKET_BUF_INDEX 0x17c
+enum {
+ INFOFRAME_AVI = 0x06,
+ INFOFRAME_AAI = 0x08
+};
+#define CONTROL_PACKET_HB0 0x180
+#define CONTROL_PACKET_HB1 0x184
+#define CONTROL_PACKET_HB2 0x188
+#define CONTROL_PACKET_PB_ADDR 0x18c
+#define SIZE_AVI_INFOFRAME 0x11 // 17 bytes
+#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes
+enum {
+ AVI_COLOR_MODE_RGB = 0,
+ AVI_COLOR_MODE_YCBCR422,
+ AVI_COLOR_MODE_YCBCR444
+};
+enum {
+ AVI_COLORIMETRY_NO_DATA = 0,
+ AVI_COLORIMETRY_SMPTE_170M,
+ AVI_COLORIMETRY_ITU709,
+ AVI_COLORIMETRY_EXTENDED
+};
+enum {
+ AVI_CODED_FRAME_ASPECT_NO_DATA,
+ AVI_CODED_FRAME_ASPECT_4_3,
+ AVI_CODED_FRAME_ASPECT_16_9
+};
+enum {
+ ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
+ ACTIVE_ASPECT_RATE_4_3,
+ ACTIVE_ASPECT_RATE_16_9,
+ ACTIVE_ASPECT_RATE_14_9
+};
+
+/* External Video Parameter Setting*/
+#define EXT_VIDEO_PARA 0xC0
+#define m_VSYNC_OFFSET (0xF << 4)
+#define m_VSYNC_POLARITY (1 << 3)
+#define m_HSYNC_POLARITY (1 << 2)
+#define m_INTERLACE (1 << 1)
+#define m_EXT_VIDEO_ENABLE (1 << 0)
+
+#define v_VSYNC_OFFSET(n) (n << 4)
+#define v_VSYNC_POLARITY(n) (n << 3)
+#define v_HSYNC_POLARITY(n) (n << 2)
+#define v_INTERLACE(n) (n << 1)
+#define v_EXT_VIDEO_ENABLE(n) (n << 0)
+
+#define EXT_VIDEO_PARA_HTOTAL_L 0xC4
+#define EXT_VIDEO_PARA_HTOTAL_H 0xC8
+#define EXT_VIDEO_PARA_HBLANK_L 0xCC
+#define EXT_VIDEO_PARA_HBLANK_H 0xD0
+#define EXT_VIDEO_PARA_HDELAY_L 0xD4
+#define EXT_VIDEO_PARA_HDELAY_H 0xD8
+#define EXT_VIDEO_PARA_HSYNCWIDTH_L 0xDC
+#define EXT_VIDEO_PARA_HSYNCWIDTH_H 0xE0
+
+#define EXT_VIDEO_PARA_VTOTAL_L 0xE4
+#define EXT_VIDEO_PARA_VTOTAL_H 0xE8
+#define EXT_VIDEO_PARA_VBLANK_L 0xF4
+#define EXT_VIDEO_PARA_VDELAY 0xF8
+#define EXT_VIDEO_PARA_VSYNCWIDTH 0xFC
+
+#define PHY_PLL_SPEED 0x158
+ #define v_TEST_EN(n) (n << 6)
+ #define v_PLLA_BYPASS(n) (n << 4)
+ #define v_PLLB_SPEED(n) (n << 2)
+ #define v_PLLA_SPEED(n) (n)
+ enum {
+ PLL_SPEED_LOWEST = 0,
+ PLL_SPEED_MIDLOW,
+ PLL_SPEED_MIDHIGH,
+ PLL_SPEED_HIGHEST
+ };
+
+#define PHY_PLL_17 0x15c // PLL A & B config bit 17
+ #define v_PLLA_BIT17(n) (n << 2)
+ #define v_PLLB_BIT17(n) (n << 1)
+
+#define PHY_BGR 0x160
+ #define v_BGR_DISCONNECT(n) (n << 7)
+ #define v_BGR_V_OFFSET(n) (n << 4)
+ #define v_BGR_I_OFFSET(n) (n)
+
+#define PHY_PLLA_1 0x164
+#define PHY_PLLA_2 0x168
+#define PHY_PLLB_1 0x16c
+#define PHY_PLLB_2 0x170
+
+#define PHY_DRIVER_PREEMPHASIS 0x174
+ #define v_TMDS_SWING(n) (n << 4)
+ #define v_PRE_EMPHASIS(n) (n)
+
+#define PHY_PLL_16_AML 0x178 // PLL A & B config bit 16 and AML control
+ #define v_PLLA_BIT16(n) (n << 5)
+ #define v_PLLB_BIT16(n) (n << 4)
+ #define v_AML(n) (n)
+
+/* Interrupt Setting */
+#define INTR_MASK1 0x248
+#define INTR_STATUS1 0x250
+ #define m_INT_HOTPLUG (1 << 7)
+ #define m_INT_MSENS (1 << 6)
+ #define m_INT_VSYNC (1 << 5)
+ #define m_INT_AUDIO_FIFO_FULL (1 << 4)
+ #define m_INT_EDID_READY (1 << 2)
+ #define m_INT_EDID_ERR (1 << 1)
+#define INTR_MASK2 0x24c
+#define INTR_STATUS2 0x254
+ #define m_INT_HDCP_ERR (1 << 7) // HDCP error detected
+ #define m_INT_BKSV_RPRDY (1 << 6) // BKSV list ready from repeater
+ #define m_INT_BKSV_RCRDY (1 << 5) // BKSV list ready from receiver
+ #define m_INT_AUTH_DONE (1 << 4) // HDCP authentication done
+ #define m_INT_AUTH_READY (1 << 3) // HDCP authentication ready
+#define INTR_MASK3 0x258
+#define INTR_STATUS3 0x260
+
+#define INTR_MASK4 0x25c
+#define INTR_STATUS4 0x264
+
+#define DDC_READ_FIFO_ADDR 0x200
+#define DDC_BUS_FREQ_L 0x204
+#define DDC_BUS_FREQ_H 0x208
+#define DDC_BUS_CTRL 0x2dc
+#define DDC_I2C_LEN 0x278
+#define DDC_I2C_OFFSET 0x280
+#define DDC_I2C_CTRL 0x284
+#define DDC_I2C_READ_BUF0 0x288
+#define DDC_I2C_READ_BUF1 0x28c
+#define DDC_I2C_READ_BUF2 0x290
+#define DDC_I2C_READ_BUF3 0x294
+#define DDC_I2C_WRITE_BUF0 0x298
+#define DDC_I2C_WRITE_BUF1 0x29c
+#define DDC_I2C_WRITE_BUF2 0x2a0
+#define DDC_I2C_WRITE_BUF3 0x2a4
+#define DDC_I2C_WRITE_BUF4 0x2ac
+#define DDC_I2C_WRITE_BUF5 0x2b0
+#define DDC_I2C_WRITE_BUF6 0x2b4
+
+#define EDID_SEGMENT_POINTER 0x310
+#define EDID_WORD_ADDR 0x314
+#define EDID_FIFO_ADDR 0x318
+
+#define HPD_MENS_STA 0x37c
+#define m_HOTPLUG_STATUS (1 << 7)
+#define m_MSEN_STATUS (1 << 6)
+
+/* HDCP_CTRL */
+#define HDCP_CTRL 0x2bc
+ enum {
+ OUTPUT_DVI = 0,
+ OUTPUT_HDMI
+ };
+ #define m_HDCP_AUTH_START (1 << 7) // start hdcp
+ #define m_HDCP_BKSV_PASS (1 << 6) // bksv valid
+ #define m_HDCP_BKSV_FAILED (1 << 5) // bksv invalid
+ #define m_HDCP_FRAMED_ENCRYPED (1 << 4)
+ #define m_HDCP_AUTH_STOP (1 << 3) // stop hdcp
+ #define m_HDCP_ADV_CIPHER (1 << 2) // advanced cipher mode
+ #define m_HDMI_DVI (1 << 1)
+ #define m_HDCP_RESET (1 << 0) // reset hdcp
+ #define v_HDCP_AUTH_START(n) (n << 7)
+ #define v_HDCP_BKSV_PASS(n) (n << 6)
+ #define v_HDCP_BKSV_FAILED(n) (n << 5)
+ #define v_HDCP_FRAMED_ENCRYPED(n) (n << 4)
+ #define v_HDCP_AUTH_STOP(n) (n << 3)
+ #define v_HDCP_ADV_CIPHER(n) (n << 2)
+ #define v_HDMI_DVI(n) (n << 1)
+ #define v_HDCP_RESET(n) (n << 0)
+#define HDCP_CTRL2 0x340
+
+/* HDCP Key Memory Access Control */
+#define HDCP_KEY_ACCESS_CTRL1 0x338
+#define HDCP_KEY_ACCESS_CTRL2 0x33c
+ #define m_LOAD_FACSIMILE_HDCP_KEY (1 << 1)
+ #define m_LOAD_HDCP_KEY (1 << 0)
+/* HDCP Key Memory Control */
+#define HDCP_KEY_MEM_CTRL 0x348
+ #define m_USE_KEY1 (1 << 6)
+ #define m_USE_KEY2 (1 << 5)
+ #define m_LOAD_AKSV (1 << 4)
+ #define m_KSV_SELECTED (1 << 3)
+ #define m_KSV_VALID (1 << 2)
+ #define m_KEY_VALID (1 << 1)
+ #define m_KEY_READY (1 << 0)
+ #define v_USE_KEY1(n) (n << 6)
+ #define v_USE_KEY2(n) (n << 5)
+ #define v_LOAD_AKSV(n) (n << 4)
+
+/* HDCP B device capacity */
+#define HDCP_BCAPS 0x2f8
+ #define m_HDMI_RECEIVED (1 << 7) //If HDCP receiver support HDMI, this bit must be 1.
+ #define m_REPEATER (1 << 6)
+ #define m_KSV_FIFO_READY (1 << 5)
+ #define m_DDC_FAST (1 << 4)
+ #define m_1_1_FEATURE (1 << 1)
+ #define m_FAST_REAUTHENTICATION (1 << 0) //For HDMI, this function is supported whether this bit is enabled or not.
+
+/* HDCP KSV Value */
+#define HDCP_KSV_BYTE0 0x2fc
+#define HDCP_KSV_BYTE1 0x300
+#define HDCP_KSV_BYTE2 0x304
+#define HDCP_KSV_BYTE3 0x308
+#define HDCP_KSV_BYTE4 0x30c
+
+/* HDCP error status */
+#define HDCP_ERROR 0x320
+
+/* HDCP 100 ms timer */
+#define HDCP_TIMER_100MS 0x324
+/* HDCP 5s timer */
+#define HDCP_TIMER_5S 0x328
+
+/* HDCP Key ram address */
+#define HDCP_RAM_KEY_KSV1 0x400
+#define HDCP_RAM_KEY_KSV2 0x407
+#define HDCP_RAM_KEY_PRIVATE 0x40e
+#define HDCP_KEY_LENGTH 0x13C
+
+
+#define HDCP_ENABLE_HW_AUTH // Enable hardware authentication mode
+#define HDMI_INTERANL_CLK_DIV 0x19
+
+#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr)
+#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr);
+#define HDMIMskReg(temp, addr, msk, val) \
+ temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \
+ __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr);
+
+
+
+/* Color Space Convertion Mode */
+enum {
+ CSC_RGB_0_255_TO_ITU601_16_235 = 0, //RGB 0-255 input to YCbCr 16-235 output according BT601
+ CSC_RGB_0_255_TO_ITU709_16_235, //RGB 0-255 input to YCbCr 16-235 output accroding BT709
+ CSC_ITU601_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT601
+ CSC_ITU709_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT709
+ CSC_ITU601_16_235_TO_RGB_0_255, //YCbCr 16-235 input to RGB 0-255 output according BT601
+ CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709
+};
+
+extern int rk30_hdmi_initial(void);
+extern int rk30_hdmi_detect_hotplug(void);
+extern int rk30_hdmi_read_edid(int block, unsigned char *buff);
+extern int rk30_hdmi_removed(void);
+extern int rk30_hdmi_config_video(struct hdmi_video_para *vpara);
+extern int rk30_hdmi_config_audio(struct hdmi_audio *audio);
+extern void rk30_hdmi_control_output(int enable);
+
+#endif
+++ /dev/null
-#include <linux/module.h>\r
-#include <linux/kernel.h>\r
-#include <linux/errno.h>\r
-#include <linux/string.h>\r
-#include <linux/mm.h>\r
-#include <linux/slab.h>\r
-#include <linux/delay.h>\r
-#include <linux/device.h>\r
-#include <linux/init.h>\r
-#include <linux/dma-mapping.h>\r
-#include <linux/interrupt.h>\r
-#include <linux/platform_device.h>\r
-#include <linux/clk.h>\r
-\r
-#include <mach/board.h>\r
-#include <mach/io.h>\r
-#include <mach/gpio.h>\r
-#include <mach/iomux.h>\r
-#include "rk30_hdmi.h"\r
-#include "rk30_hdmi_hw.h"\r
-\r
-struct hdmi *hdmi = NULL;\r
-\r
-extern irqreturn_t hdmi_irq(int irq, void *priv);\r
-extern void hdmi_work(struct work_struct *work);\r
-extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);\r
-extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);\r
-extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);\r
-\r
-int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),\r
- void (*hdcp_irq_cb)(int status),\r
- int (*hdcp_power_on_cb)(void),\r
- void (*hdcp_power_off_cb)(void))\r
-{\r
- if(hdmi == NULL)\r
- return HDMI_ERROR_FALSE;\r
-\r
- hdmi->hdcp_cb = hdcp_cb;\r
- hdmi->hdcp_irq_cb = hdcp_irq_cb;\r
- hdmi->hdcp_power_on_cb = hdcp_power_on_cb;\r
- hdmi->hdcp_power_off_cb = hdcp_power_off_cb;\r
- \r
- return HDMI_ERROR_SUCESS;\r
-}\r
-\r
-#ifdef CONFIG_HAS_EARLYSUSPEND\r
-static void hdmi_early_suspend(struct early_suspend *h)\r
-{\r
- hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);\r
- flush_delayed_work(&hdmi->delay_work); \r
- mutex_lock(&hdmi->enable_mutex);\r
- hdmi->suspend = 1;\r
- if(!hdmi->enable) {\r
- mutex_unlock(&hdmi->enable_mutex);\r
- return;\r
- }\r
- disable_irq(hdmi->irq);\r
- mutex_unlock(&hdmi->enable_mutex);\r
- hdmi->command = HDMI_CONFIG_ENABLE;\r
- init_completion(&hdmi->complete);\r
- hdmi->wait = 1;\r
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);\r
- wait_for_completion_interruptible_timeout(&hdmi->complete,\r
- msecs_to_jiffies(5000));\r
- flush_delayed_work(&hdmi->delay_work);\r
- // When HDMI 1.1V and 2.5V power off, DDC channel will be pull down, current is produced\r
- // from VCC_IO which is pull up outside soc. We need to switch DDC IO to GPIO.\r
- rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_GPIO0A2);\r
- rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_GPIO0A1);\r
- return;\r
-}\r
-\r
-static void hdmi_early_resume(struct early_suspend *h)\r
-{\r
- hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");\r
- mutex_lock(&hdmi->enable_mutex);\r
- \r
- rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_HDMI_I2C_SDA);\r
- rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_HDMI_I2C_SCL);\r
- \r
- hdmi->suspend = 0;\r
- rk30_hdmi_initial();\r
- if(hdmi->enable) {\r
- enable_irq(hdmi->irq);\r
- }\r
- mutex_unlock(&hdmi->enable_mutex);\r
- return;\r
-}\r
-#endif\r
-\r
-static inline void hdmi_io_remap(void)\r
-{\r
- unsigned int value;\r
- \r
- // Remap HDMI IO Pin\r
- rk30_mux_api_set(GPIO0A2_HDMII2CSDA_NAME, GPIO0A_HDMI_I2C_SDA);\r
- rk30_mux_api_set(GPIO0A1_HDMII2CSCL_NAME, GPIO0A_HDMI_I2C_SCL);\r
- rk30_mux_api_set(GPIO0A0_HDMIHOTPLUGIN_NAME, GPIO0A_HDMI_HOT_PLUG_IN);\r
- \r
- // Select LCDC0 as video source and enabled.\r
- value = (HDMI_SOURCE_DEFAULT << 14) | (1 << 30);\r
- writel(value, GRF_SOC_CON0 + RK30_GRF_BASE);\r
-}\r
-\r
-static int __devinit rk30_hdmi_probe (struct platform_device *pdev)\r
-{\r
- int ret;\r
- struct resource *res;\r
- struct resource *mem;\r
- \r
- hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);\r
- if(!hdmi)\r
- {\r
- dev_err(&pdev->dev, ">>rk30 hdmi kmalloc fail!");\r
- return -ENOMEM;\r
- }\r
- memset(hdmi, 0, sizeof(struct hdmi));\r
- hdmi->dev = &pdev->dev;\r
- platform_set_drvdata(pdev, hdmi);\r
-\r
- if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)\r
- hdmi->lcdc = rk_get_lcdc_drv("lcdc0");\r
- else\r
- hdmi->lcdc = rk_get_lcdc_drv("lcdc1");\r
- if(hdmi->lcdc == NULL)\r
- {\r
- dev_err(hdmi->dev, "can not connect to video source lcdc\n");\r
- ret = -ENXIO;\r
- goto err0;\r
- }\r
- hdmi->xscale = 95;\r
- hdmi->yscale = 95;\r
- \r
- hdmi->hclk = clk_get(NULL,"hclk_hdmi");\r
- if(IS_ERR(hdmi->hclk))\r
- {\r
- dev_err(hdmi->dev, "Unable to get hdmi hclk\n");\r
- ret = -ENXIO;\r
- goto err0;\r
- }\r
- clk_enable(hdmi->hclk);\r
- \r
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);\r
- if (!res) {\r
- dev_err(hdmi->dev, "Unable to get register resource\n");\r
- ret = -ENXIO;\r
- goto err0;\r
- }\r
- hdmi->regbase_phy = res->start;\r
- hdmi->regsize_phy = (res->end - res->start) + 1;\r
- mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name);\r
- if (!mem)\r
- {\r
- dev_err(hdmi->dev, "failed to request mem region for hdmi\n");\r
- ret = -ENOENT;\r
- goto err0;\r
- }\r
-\r
- \r
- hdmi->regbase = (int)ioremap(res->start, (res->end - res->start) + 1);\r
- if (!hdmi->regbase) {\r
- dev_err(hdmi->dev, "cannot ioremap registers\n");\r
- ret = -ENXIO;\r
- goto err1;\r
- }\r
- \r
- ret = rk30_hdmi_initial();\r
- if(ret != HDMI_ERROR_SUCESS)\r
- goto err1;\r
- \r
- hdmi_io_remap();\r
- hdmi_sys_init();\r
- \r
- hdmi->workqueue = create_singlethread_workqueue("hdmi");\r
- INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);\r
-\r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- hdmi->early_suspend.suspend = hdmi_early_suspend;\r
- hdmi->early_suspend.resume = hdmi_early_resume;\r
- hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;\r
- register_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- \r
- hdmi_register_display_sysfs(hdmi, NULL);\r
- #ifdef CONFIG_SWITCH\r
- hdmi->switch_hdmi.name="hdmi";\r
- switch_dev_register(&(hdmi->switch_hdmi));\r
- #endif\r
- \r
- spin_lock_init(&hdmi->irq_lock);\r
- mutex_init(&hdmi->enable_mutex);\r
- \r
- /* get the IRQ */\r
- hdmi->irq = platform_get_irq(pdev, 0);\r
- if(hdmi->irq <= 0) {\r
- dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq);\r
- ret = -ENXIO;\r
- goto err2;\r
- }\r
-\r
- /* request the IRQ */\r
- ret = request_irq(hdmi->irq, hdmi_irq, 0, dev_name(&pdev->dev), hdmi);\r
- if (ret)\r
- {\r
- dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret);\r
- goto err2;\r
- }\r
-\r
- hdmi_dbg(hdmi->dev, "rk30 hdmi probe sucess.\n");\r
- return 0;\r
-err2:\r
- #ifdef CONFIG_SWITCH\r
- switch_dev_unregister(&(hdmi->switch_hdmi));\r
- #endif\r
- hdmi_unregister_display_sysfs(hdmi);\r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- unregister_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- iounmap((void*)hdmi->regbase);\r
-err1:\r
- release_mem_region(res->start,(res->end - res->start) + 1);\r
- clk_disable(hdmi->hclk);\r
-err0:\r
- hdmi_dbg(hdmi->dev, "rk30 hdmi probe error.\n");\r
- kfree(hdmi);\r
- hdmi = NULL;\r
- return ret;\r
-}\r
-\r
-static int __devexit rk30_hdmi_remove(struct platform_device *pdev)\r
-{\r
- if(hdmi) {\r
- mutex_lock(&hdmi->enable_mutex);\r
- if(!hdmi->suspend && hdmi->enable)\r
- disable_irq(hdmi->irq);\r
- mutex_unlock(&hdmi->enable_mutex);\r
- free_irq(hdmi->irq, NULL);\r
- flush_workqueue(hdmi->workqueue);\r
- destroy_workqueue(hdmi->workqueue);\r
- #ifdef CONFIG_SWITCH\r
- switch_dev_unregister(&(hdmi->switch_hdmi));\r
- #endif\r
- hdmi_unregister_display_sysfs(hdmi);\r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- unregister_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- iounmap((void*)hdmi->regbase);\r
- release_mem_region(hdmi->regbase_phy, hdmi->regsize_phy);\r
- clk_disable(hdmi->hclk);\r
- fb_destroy_modelist(&hdmi->edid.modelist);\r
- if(hdmi->edid.audio)\r
- kfree(hdmi->edid.audio);\r
- if(hdmi->edid.specs)\r
- {\r
- if(hdmi->edid.specs->modedb)\r
- kfree(hdmi->edid.specs->modedb);\r
- kfree(hdmi->edid.specs);\r
- }\r
- kfree(hdmi);\r
- hdmi = NULL;\r
- }\r
- printk(KERN_INFO "rk30 hdmi removed.\n");\r
- return 0;\r
-}\r
-\r
-static void rk30_hdmi_shutdown(struct platform_device *pdev)\r
-{\r
- if(hdmi) {\r
- #ifdef CONFIG_HAS_EARLYSUSPEND\r
- unregister_early_suspend(&hdmi->early_suspend);\r
- #endif\r
- }\r
- printk(KERN_INFO "rk30 hdmi shut down.\n");\r
-}\r
-\r
-static struct platform_driver rk30_hdmi_driver = {\r
- .probe = rk30_hdmi_probe,\r
- .remove = __devexit_p(rk30_hdmi_remove),\r
- .driver = {\r
- .name = "rk30-hdmi",\r
- .owner = THIS_MODULE,\r
- },\r
- .shutdown = rk30_hdmi_shutdown,\r
-};\r
-\r
-static int __init rk30_hdmi_init(void)\r
-{\r
- return platform_driver_register(&rk30_hdmi_driver);\r
-}\r
-\r
-static void __exit rk30_hdmi_exit(void)\r
-{\r
- platform_driver_unregister(&rk30_hdmi_driver);\r
-}\r
-\r
-\r
-//fs_initcall(rk30_hdmi_init);\r
-module_init(rk30_hdmi_init);\r
-module_exit(rk30_hdmi_exit);\r
+++ /dev/null
-#ifndef __RK30_HDMI_H__
-#define __RK30_HDMI_H__
-
-#include <linux/kernel.h>
-#include <linux/fb.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/display-sys.h>
-#ifdef CONFIG_SWITCH
-#include <linux/switch.h>
-#endif
-#ifdef CONFIG_HAS_EARLYSUSPEND
-#include <linux/earlysuspend.h>
-#endif
-#include <asm/atomic.h>
-#include<linux/rk_screen.h>
-#include <linux/rk_fb.h>
-#include "rk_hdmi.h"
-
-// HDMI video source
-enum {
- HDMI_SOURCE_LCDC0 = 0,
- HDMI_SOURCE_LCDC1 = 1
-};
-
-/* default HDMI video source */
-#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1
-
-/* If HDMI_ENABLE, system will auto configure output mode according to EDID
- * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE
- */
-#define HDMI_AUTO_CONFIGURE HDMI_ENABLE
-
-/* default HDMI output video mode */
-#define HDMI_VIDEO_DEFAULT_MODE HDMI_1280x720p_60Hz//HDMI_1920x1080p_60Hz
-/* default HDMI output audio mode */
-#define HDMI_AUDIO_DEFAULT_CHANNEL 2
-#define HDMI_AUDIO_DEFAULT_RATE HDMI_AUDIO_FS_44100
-#define HDMI_AUDIO_DEFAULT_WORD_LENGTH HDMI_AUDIO_WORD_LENGTH_16bit
-
-struct hdmi {
- struct device *dev;
- struct clk *hclk; //HDMI AHP clk
- int regbase;
- int irq;
- int regbase_phy;
- int regsize_phy;
- struct rk_lcdc_device_driver *lcdc;
-
- #ifdef CONFIG_SWITCH
- struct switch_dev switch_hdmi;
- #endif
-
- struct workqueue_struct *workqueue;
- struct delayed_work delay_work;
-
- spinlock_t irq_lock;
- struct mutex enable_mutex;
-
- int wait;
- struct completion complete;
-
- int suspend;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- struct early_suspend early_suspend;
-#endif
-
- struct hdmi_edid edid;
- int enable; // Enable HDMI output or not
- int vic; // HDMI output video mode code
- struct hdmi_audio audio; // HDMI output audio type.
-
- int pwr_mode; // power mode
- int hotplug; // hot plug status
- int state; // hdmi state machine status
- int autoconfig; // if true, auto config hdmi output mode according to EDID.
- int command; // HDMI configuration command
- int display; // HDMI display status
- int xscale; // x direction scale value
- int yscale; // y directoon scale value
- int tmdsclk; // TDMS Clock frequency
- // call back for hdcp operatoion
- void (*hdcp_cb)(void);
- void (*hdcp_irq_cb)(int);
- int (*hdcp_power_on_cb)(void);
- void (*hdcp_power_off_cb)(void);
-};
-
-extern struct hdmi *hdmi;
-
-extern int hdmi_sys_init(void);
-extern int hdmi_sys_parse_edid(struct hdmi* hdmi);
-extern const char *hdmi_get_video_mode_name(unsigned char vic);
-extern int hdmi_videomode_to_vic(struct fb_videomode *vmode);
-extern const struct fb_videomode* hdmi_vic_to_videomode(int vic);
-extern int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head);
-extern struct hdmi_video_timing * hdmi_find_mode(int vic);
-extern int hdmi_find_best_mode(struct hdmi* hdmi, int vic);
-extern int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok);
-extern int hdmi_switch_fb(struct hdmi *hdmi, int vic);
-extern void hdmi_sys_remove(void);
-extern int rk30_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
- void (*hdcp_irq_cb)(int status),
- int (*hdcp_power_on_cb)(void),
- void (*hdcp_power_off_cb)(void));
-#endif /* __RK30_HDMI_H__ */
+++ /dev/null
-#include "rk30_hdmi.h"\r
-#include "rk30_hdmi_hw.h"\r
-#include "../../edid.h"\r
-\r
-#define hdmi_edid_error(fmt, ...) \\r
- printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)\r
-\r
-#if 0\r
-#define hdmi_edid_debug(fmt, ...) \\r
- printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)\r
-#else\r
-#define hdmi_edid_debug(fmt, ...) \r
-#endif\r
-\r
-typedef enum HDMI_EDID_ERRORCODE\r
-{\r
- E_HDMI_EDID_SUCCESS = 0,\r
- E_HDMI_EDID_PARAM,\r
- E_HDMI_EDID_HEAD,\r
- E_HDMI_EDID_CHECKSUM,\r
- E_HDMI_EDID_VERSION,\r
- E_HDMI_EDID_UNKOWNDATA,\r
- E_HDMI_EDID_NOMEMORY\r
-}HDMI_EDID_ErrorCode;\r
-\r
-static const unsigned int double_aspect_vic[] = {3, 7, 9, 11, 13, 15, 18, 22, 24, 26, 28, 30, 36, 38, 43, 45, 49, 51, 53, 55, 57, 59};\r
-static int hdmi_edid_checksum(unsigned char *buf)\r
-{\r
- int i;\r
- int checksum = 0;\r
- \r
- for(i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)\r
- checksum += buf[i]; \r
- \r
- checksum &= 0xff;\r
- \r
- if(checksum == 0)\r
- return E_HDMI_EDID_SUCCESS;\r
- else\r
- return E_HDMI_EDID_CHECKSUM;\r
-}\r
-\r
-/*\r
- @Des Parse Detail Timing Descriptor.\r
- @Param buf : pointer to DTD data.\r
- @Param pvic: VIC of DTD descripted.\r
- */\r
-static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)\r
-{\r
- mode->xres = H_ACTIVE;\r
- mode->yres = V_ACTIVE;\r
- mode->pixclock = PIXEL_CLOCK;\r
-// mode->pixclock /= 1000;\r
-// mode->pixclock = KHZ2PICOS(mode->pixclock);\r
- mode->right_margin = H_SYNC_OFFSET;\r
- mode->left_margin = (H_ACTIVE + H_BLANKING) -\r
- (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);\r
- mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -\r
- V_SYNC_WIDTH;\r
- mode->lower_margin = V_SYNC_OFFSET;\r
- mode->hsync_len = H_SYNC_WIDTH;\r
- mode->vsync_len = V_SYNC_WIDTH;\r
- if (HSYNC_POSITIVE)\r
- mode->sync |= FB_SYNC_HOR_HIGH_ACT;\r
- if (VSYNC_POSITIVE)\r
- mode->sync |= FB_SYNC_VERT_HIGH_ACT;\r
- mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *\r
- (V_ACTIVE + V_BLANKING));\r
- if (INTERLACED) {\r
- mode->yres *= 2;\r
- mode->upper_margin *= 2;\r
- mode->lower_margin *= 2;\r
- mode->vsync_len *= 2;\r
- mode->vmode |= FB_VMODE_INTERLACED;\r
- }\r
- mode->flag = FB_MODE_IS_DETAILED;\r
-\r
- hdmi_edid_debug("<<<<<<<<Detailed Time>>>>>>>>>\n");\r
- hdmi_edid_debug("%d KHz Refresh %d Hz", PIXEL_CLOCK/1000, mode->refresh);\r
- hdmi_edid_debug("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,\r
- H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);\r
- hdmi_edid_debug("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,\r
- V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);\r
- hdmi_edid_debug("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",\r
- (VSYNC_POSITIVE) ? "+" : "-");\r
- return E_HDMI_EDID_SUCCESS;\r
-}\r
-\r
-static int hdmi_edid_parse_base(unsigned char *buf, int *extend_num, struct hdmi_edid *pedid)\r
-{\r
- int rc, i;\r
- \r
- if(buf == NULL || extend_num == NULL)\r
- return E_HDMI_EDID_PARAM;\r
- \r
- #ifdef DEBUG \r
- for(i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)\r
- {\r
- hdmi_edid_debug("%02x ", buf[i]&0xff);\r
- if((i+1) % 16 == 0)\r
- hdmi_edid_debug("\n");\r
- }\r
- #endif\r
- \r
- // Check first 8 byte to ensure it is an edid base block.\r
- if( buf[0] != 0x00 ||\r
- buf[1] != 0xFF ||\r
- buf[2] != 0xFF ||\r
- buf[3] != 0xFF ||\r
- buf[4] != 0xFF ||\r
- buf[5] != 0xFF ||\r
- buf[6] != 0xFF ||\r
- buf[7] != 0x00)\r
- {\r
- hdmi_edid_error("[EDID] check header error\n");\r
- return E_HDMI_EDID_HEAD;\r
- }\r
- \r
- *extend_num = buf[0x7e];\r
- #ifdef DEBUG\r
- hdmi_edid_debug("[EDID] extend block num is %d\n", buf[0x7e]);\r
- #endif\r
- \r
- // Checksum\r
- rc = hdmi_edid_checksum(buf);\r
- if( rc != E_HDMI_EDID_SUCCESS)\r
- {\r
- hdmi_edid_error("[EDID] base block checksum error\n");\r
- return E_HDMI_EDID_CHECKSUM;\r
- }\r
-\r
- pedid->specs = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);\r
- if(pedid->specs == NULL)\r
- return E_HDMI_EDID_NOMEMORY;\r
- \r
- fb_edid_to_monspecs(buf, pedid->specs);\r
- \r
- return E_HDMI_EDID_SUCCESS;\r
-}\r
-\r
-// Parse CEA Short Video Descriptor\r
-static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)\r
-{\r
- const struct fb_videomode *mode;\r
- int count, i, j, vic;\r
-\r
- count = buf[0] & 0x1F;\r
- for(i = 0; i < count; i++)\r
- {\r
- hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);\r
- vic = buf[1 + i] & 0x7f;\r
- for(j = 0; j < ARRAY_SIZE(double_aspect_vic); j++)\r
- {\r
- if(vic == double_aspect_vic[j])\r
- { \r
- vic--;\r
- break;\r
- }\r
- }\r
- if(vic)\r
- {\r
- mode = hdmi_vic_to_videomode(vic);\r
- if(mode)\r
- { \r
- hdmi_add_videomode(mode, &pedid->modelist);\r
- }\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-// Parse CEA Short Audio Descriptor\r
-static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)\r
-{\r
- int i, count;\r
- \r
- count = buf[0] & 0x1F;\r
- pedid->audio = kmalloc((count/3)*sizeof(struct hdmi_audio), GFP_KERNEL);\r
- if(pedid->audio == NULL)\r
- return E_HDMI_EDID_NOMEMORY;\r
- pedid->audio_num = count/3;\r
- for(i = 0; i < pedid->audio_num; i++)\r
- {\r
- pedid->audio[i].type = (buf[1 + i*3] >> 3) & 0x0F;\r
- pedid->audio[i].channel = (buf[1 + i*3] & 0x07) + 1;\r
- pedid->audio[i].rate = buf[1 + i*3 + 1];\r
- if(pedid->audio[i].type == HDMI_AUDIO_LPCM)//LPCM \r
- {\r
- pedid->audio[i].word_length = buf[1 + i*3 + 2];\r
- }\r
-// printk("[EDID-CEA] type %d channel %d rate %d word length %d\n", \r
-// pedid->audio[i].type, pedid->audio[i].channel, pedid->audio[i].rate, pedid->audio[i].word_length);\r
- }\r
- return E_HDMI_EDID_SUCCESS;\r
-}\r
-// Parse CEA 861 Serial Extension.\r
-static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *pedid)\r
-{\r
- unsigned int ddc_offset, native_dtd_num, cur_offset = 4;\r
- unsigned int underscan_support, baseaudio_support;\r
- unsigned int tag, IEEEOUI = 0;\r
-// unsigned int supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444;\r
-// unsigned char vic;\r
- \r
- if(buf == NULL)\r
- return E_HDMI_EDID_PARAM;\r
- \r
- // Check ces extension version\r
- if(buf[1] != 3)\r
- {\r
- hdmi_edid_error("[EDID-CEA] error version.\n");\r
- return E_HDMI_EDID_VERSION;\r
- }\r
- \r
- ddc_offset = buf[2];\r
- underscan_support = (buf[3] >> 7) & 0x01;\r
- baseaudio_support = (buf[3] >> 6) & 0x01;\r
- pedid->ycbcr444 = (buf[3] >> 5) & 0x01;\r
- pedid->ycbcr422 = (buf[3] >> 4) & 0x01;\r
- native_dtd_num = buf[3] & 0x0F;\r
-// hdmi_edid_debug("[EDID-CEA] ddc_offset %d underscan_support %d baseaudio_support %d yuv_support %d native_dtd_num %d\n", ddc_offset, underscan_support, baseaudio_support, yuv_support, native_dtd_num);\r
- // Parse data block\r
- while(cur_offset < ddc_offset)\r
- {\r
- tag = buf[cur_offset] >> 5;\r
- switch(tag)\r
- {\r
- case 0x02: // Video Data Block\r
- hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");\r
- hdmi_edid_get_cea_svd(buf + cur_offset, pedid);\r
- break;\r
- case 0x01: // Audio Data Block\r
- hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");\r
- hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);\r
- break;\r
- case 0x04: // Speaker Allocation Data Block\r
- hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocatio Data Block.\n");\r
- break;\r
- case 0x03: // Vendor Specific Data Block\r
- hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");\r
-\r
- IEEEOUI = buf[cur_offset + 2 + 1];\r
- IEEEOUI <<= 8;\r
- IEEEOUI += buf[cur_offset + 1 + 1];\r
- IEEEOUI <<= 8;\r
- IEEEOUI += buf[cur_offset + 1];\r
- hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);\r
- if(IEEEOUI == 0x0c03)\r
- pedid->sink_hdmi = 1;\r
-// if(count > 5)\r
-// {\r
-// pedid->deepcolor = (buf[cur_offset + 5] >> 3) & 0x0F;\r
-// supports_ai = buf[cur_offset + 5] >> 7;\r
-// dc_48bit = (buf[cur_offset + 5] >> 6) & 0x1;\r
-// dc_36bit = (buf[cur_offset + 5] >> 5) & 0x1;\r
-// dc_30bit = (buf[cur_offset + 5] >> 4) & 0x1;\r
-// dc_y444 = (buf[cur_offset + 5] >> 3) & 0x1;\r
-// hdmi_edid_debug("[EDID-CEA] supports_ai %d dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d \n", supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444);\r
-// }\r
-// if(count > 6)\r
-// pedid->maxtmdsclock = buf[cur_offset + 6] * 5000000;\r
-// if(count > 7)\r
-// {\r
-// pedid->latency_fields_present = (buf[cur_offset + 7] & 0x80) ? 1:0;\r
-// pedid->i_latency_fields_present = (buf[cur_offset + 7] & 0x40) ? 1:0;\r
-// }\r
-// if(count > 9 && pedid->latency_fields_present)\r
-// {\r
-// pedid->video_latency = buf[cur_offset + 8];\r
-// pedid->audio_latency = buf[cur_offset + 9];\r
-// }\r
-// if(count > 11 && pedid->i_latency_fields_present)\r
-// {\r
-// pedid->interlaced_video_latency = buf[cur_offset + 10];\r
-// pedid->interlaced_audio_latency = buf[cur_offset + 11];\r
-// }\r
- break; \r
- case 0x05: // VESA DTC Data Block\r
- hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");\r
- break;\r
- case 0x07: // Use Extended Tag\r
- hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");\r
- break;\r
- default:\r
- hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");\r
- break;\r
- }\r
- cur_offset += (buf[cur_offset] & 0x1F) + 1;\r
- }\r
-#if 1 \r
-{\r
- // Parse DTD\r
- struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);\r
- if(vmode == NULL)\r
- return E_HDMI_EDID_SUCCESS; \r
- while(ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) //buf[126] = 0 and buf[127] = checksum\r
- {\r
- if(!buf[ddc_offset] && !buf[ddc_offset + 1])\r
- break;\r
- memset(vmode, 0, sizeof(struct fb_videomode));\r
- hdmi_edid_parse_dtd(buf + ddc_offset, vmode);\r
- hdmi_add_videomode(vmode, &pedid->modelist);\r
- ddc_offset += 18;\r
- }\r
- kfree(vmode);\r
-}\r
-#endif\r
- return E_HDMI_EDID_SUCCESS;\r
-}\r
-\r
-static int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedid)\r
-{\r
- int rc;\r
- \r
- if(buf == NULL || pedid == NULL)\r
- return E_HDMI_EDID_PARAM;\r
- \r
- // Checksum\r
- rc = hdmi_edid_checksum(buf);\r
- if( rc != E_HDMI_EDID_SUCCESS)\r
- {\r
- hdmi_edid_error("[EDID] extensions block checksum error\n");\r
- return E_HDMI_EDID_CHECKSUM;\r
- }\r
- \r
- switch(buf[0])\r
- {\r
- case 0xF0:\r
- hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");\r
- break;\r
- case 0x02:\r
- hdmi_edid_debug("[EDID-EXTEND] It is a CEA 861 Series Extension.\n");\r
- hdmi_edid_parse_extensions_cea(buf, pedid);\r
- break;\r
- case 0x10:\r
- hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");\r
- break;\r
- case 0x40:\r
- hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");\r
- break;\r
- case 0x50:\r
- hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");\r
- break;\r
- case 0x60:\r
- hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");\r
- break;\r
- default:\r
- hdmi_edid_debug("[EDID-EXTEND] Unkowned extension.\n");\r
- break;\r
- }\r
- \r
- return E_HDMI_EDID_SUCCESS;\r
-}\r
-\r
-\r
-int hdmi_sys_parse_edid(struct hdmi* hdmi)\r
-{\r
- struct hdmi_edid *pedid;\r
- unsigned char *buff = NULL;\r
- int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;\r
- \r
- if(hdmi == NULL)\r
- return HDMI_ERROR_FALSE;\r
-\r
- pedid = &(hdmi->edid);\r
- memset(pedid, 0, sizeof(struct hdmi_edid));\r
- INIT_LIST_HEAD(&pedid->modelist);\r
- \r
- buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);\r
- if(buff == NULL)\r
- { \r
- hdmi_dbg(hdmi->dev, "[%s] can not allocate memory for edid buff.\n", __FUNCTION__);\r
- return -1;\r
- }\r
- // Read base block edid.\r
- memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);\r
- rc = rk30_hdmi_read_edid(0, buff);\r
- if(rc)\r
- {\r
- dev_err(hdmi->dev, "[HDMI] read edid base block error\n");\r
- goto out;\r
- }\r
- rc = hdmi_edid_parse_base(buff, &extendblock, pedid);\r
- if(rc)\r
- {\r
- dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");\r
- goto out;\r
- }\r
- for(i = 1; i < extendblock + 1; i++)\r
- {\r
- memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);\r
- rc = rk30_hdmi_read_edid(i, buff);\r
- if(rc)\r
- {\r
- printk("[HDMI] read edid block %d error\n", i); \r
- goto out;\r
- }\r
- rc = hdmi_edid_parse_extensions(buff, pedid);\r
- if(rc)\r
- {\r
- dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n", i);\r
- continue;\r
- }\r
- }\r
-out:\r
- if(buff)\r
- kfree(buff);\r
- rc = hdmi_ouputmode_select(hdmi, rc);\r
- return rc;\r
-}
\ No newline at end of file
+++ /dev/null
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <mach/io.h>
-#include "rk30_hdmi.h"
-#include "rk30_hdmi_hw.h"
-
-static char edid_result = 0;
-
-static inline void delay100us(void)
-{
- msleep(1);
-}
-
-int rk30_hdmi_initial(void)
-{
- int rc = HDMI_ERROR_SUCESS;
- // internal hclk = hdmi_hclk/20
- HDMIWrReg(0x800, HDMI_INTERANL_CLK_DIV);
-
- if(hdmi->hdcp_power_on_cb)
- rc = hdmi->hdcp_power_on_cb();
-
- return rc;
-}
-
-static void rk30_hdmi_set_pwr_mode(int mode)
-{
- if(hdmi->pwr_mode == mode)
- return;
- hdmi_dbg(hdmi->dev, "[%s] mode %d\n", __FUNCTION__, mode);
- switch(mode)
- {
- case PWR_SAVE_MODE_A:
- HDMIWrReg(SYS_CTRL, 0x10);
- break;
- case PWR_SAVE_MODE_B:
- HDMIWrReg(SYS_CTRL, 0x20);
- break;
- case PWR_SAVE_MODE_D:
- // reset PLL A&B
- HDMIWrReg(SYS_CTRL, 0x4C);
- delay100us();
- // release PLL A reset
- HDMIWrReg(SYS_CTRL, 0x48);
- delay100us();
- // release PLL B reset
- HDMIWrReg(SYS_CTRL, 0x40);
- break;
- case PWR_SAVE_MODE_E:
- HDMIWrReg(SYS_CTRL, 0x80);
- break;
- }
- hdmi->pwr_mode = mode;
- if(mode != PWR_SAVE_MODE_A)
- msleep(10);
- hdmi_dbg(hdmi->dev, "[%s] curmode %02x\n", __FUNCTION__, HDMIRdReg(SYS_CTRL));
-}
-
-int rk30_hdmi_detect_hotplug(void)
-{
- int value = HDMIRdReg(HPD_MENS_STA);
-
- hdmi_dbg(hdmi->dev, "[%s] value %02x\n", __FUNCTION__, value);
- value &= m_HOTPLUG_STATUS | m_MSEN_STATUS;
- if(value == (m_HOTPLUG_STATUS | m_MSEN_STATUS) )
- return HDMI_HPD_ACTIVED;
- else if(value)
- return HDMI_HPD_INSERT;
- else
- return HDMI_HPD_REMOVED;
-}
-
-#define HDMI_EDID_DDC_CLK 90000
-int rk30_hdmi_read_edid(int block, unsigned char *buff)
-{
- int value, ret = -1, ddc_bus_freq = 0;
- char interrupt = 0, trytime = 2;
- unsigned long flags;
-
- hdmi_dbg(hdmi->dev, "[%s] block %d\n", __FUNCTION__, block);
- spin_lock_irqsave(&hdmi->irq_lock, flags);
- edid_result = 0;
- spin_unlock_irqrestore(&hdmi->irq_lock, flags);
- //Before Phy parameter was set, DDC_CLK is equal to PLLA freq which is 30MHz.
- //Set DDC I2C CLK which devided from DDC_CLK to 100KHz.
- ddc_bus_freq = (30000000/HDMI_EDID_DDC_CLK)/4;
- HDMIWrReg(DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
- HDMIWrReg(DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
-
- // Enable edid interrupt
- HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS | m_INT_EDID_ERR | m_INT_EDID_READY);
-
- while(trytime--) {
- // Config EDID block and segment addr
- HDMIWrReg(EDID_WORD_ADDR, (block%2) * 0x80);
- HDMIWrReg(EDID_SEGMENT_POINTER, block/2);
-
- value = 100;
- while(value--)
- {
- spin_lock_irqsave(&hdmi->irq_lock, flags);
- interrupt = edid_result;
- edid_result = 0;
- spin_unlock_irqrestore(&hdmi->irq_lock, flags);
- if(interrupt & (m_INT_EDID_ERR | m_INT_EDID_READY))
- break;
- msleep(10);
- }
- hdmi_dbg(hdmi->dev, "[%s] edid read value %d\n", __FUNCTION__, value);
- if(interrupt & m_INT_EDID_READY)
- {
- for(value = 0; value < HDMI_EDID_BLOCK_SIZE; value++)
- buff[value] = HDMIRdReg(DDC_READ_FIFO_ADDR);
- ret = 0;
-
- hdmi_dbg(hdmi->dev, "[%s] edid read sucess\n", __FUNCTION__);
-#ifdef HDMI_DEBUG
- for(value = 0; value < 128; value++) {
- printk("%02x ,", buff[value]);
- if( (value + 1) % 16 == 0)
- printk("\n");
- }
-#endif
- break;
- }
- if(interrupt & m_INT_EDID_ERR)
- hdmi_err(hdmi->dev, "[%s] edid read error\n", __FUNCTION__);
-
- }
- // Disable edid interrupt
- HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
-// msleep(100);
- return ret;
-}
-
-static inline void rk30_hdmi_config_phy_reg(int reg, int value)
-{
- HDMIWrReg(reg, value);
- HDMIWrReg(SYS_CTRL, 0x2C);
- delay100us();
- HDMIWrReg(SYS_CTRL, 0x20);
- msleep(1);
-}
-
-static void rk30_hdmi_config_phy(unsigned char vic)
-{
- HDMIWrReg(DEEP_COLOR_MODE, 0x22); // tmds frequency same as input dlck
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
- switch(vic)
- {
- case HDMI_1920x1080p_60Hz:
- case HDMI_1920x1080p_50Hz:
- rk30_hdmi_config_phy_reg(0x158, 0x0E);
- rk30_hdmi_config_phy_reg(0x15c, 0x00);
- rk30_hdmi_config_phy_reg(0x160, 0x60);
- rk30_hdmi_config_phy_reg(0x164, 0x00);
- rk30_hdmi_config_phy_reg(0x168, 0xDA);
- rk30_hdmi_config_phy_reg(0x16c, 0xA1);
- rk30_hdmi_config_phy_reg(0x170, 0x0e);
- rk30_hdmi_config_phy_reg(0x174, 0x22);
- rk30_hdmi_config_phy_reg(0x178, 0x00);
- break;
-
- case HDMI_1920x1080i_60Hz:
- case HDMI_1920x1080i_50Hz:
- case HDMI_1280x720p_60Hz:
- case HDMI_1280x720p_50Hz:
- rk30_hdmi_config_phy_reg(0x158, 0x06);
- rk30_hdmi_config_phy_reg(0x15c, 0x00);
- rk30_hdmi_config_phy_reg(0x160, 0x60);
- rk30_hdmi_config_phy_reg(0x164, 0x00);
- rk30_hdmi_config_phy_reg(0x168, 0xCA);
- rk30_hdmi_config_phy_reg(0x16c, 0xA3);
- rk30_hdmi_config_phy_reg(0x170, 0x0e);
- rk30_hdmi_config_phy_reg(0x174, 0x20);
- rk30_hdmi_config_phy_reg(0x178, 0x00);
- break;
-
- case HDMI_720x576p_50Hz_4_3:
- case HDMI_720x576p_50Hz_16_9:
- case HDMI_720x480p_60Hz_4_3:
- case HDMI_720x480p_60Hz_16_9:
- rk30_hdmi_config_phy_reg(0x158, 0x02);
- rk30_hdmi_config_phy_reg(0x15c, 0x00);
- rk30_hdmi_config_phy_reg(0x160, 0x60);
- rk30_hdmi_config_phy_reg(0x164, 0x00);
- rk30_hdmi_config_phy_reg(0x168, 0xC2);
- rk30_hdmi_config_phy_reg(0x16c, 0xA2);
- rk30_hdmi_config_phy_reg(0x170, 0x0e);
- rk30_hdmi_config_phy_reg(0x174, 0x20);
- rk30_hdmi_config_phy_reg(0x178, 0x00);
- break;
- default:
- hdmi_err(hdmi->dev, "not support such vic %d\n", vic);
- break;
- }
-}
-
-static void rk30_hdmi_config_avi(unsigned char vic, unsigned char output_color)
-{
- int i, clolorimetry, aspect_ratio;
- char info[SIZE_AVI_INFOFRAME];
-
- memset(info, 0, SIZE_AVI_INFOFRAME);
- HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
- info[0] = 0x82;
- info[1] = 0x02;
- info[2] = 0x0D;
- info[3] = info[0] + info[1] + info[2];
-
- if(output_color == VIDEO_OUTPUT_YCBCR444)
- info[4] = (AVI_COLOR_MODE_YCBCR444 << 5);
- else if(output_color == VIDEO_OUTPUT_YCBCR422)
- info[4] = (AVI_COLOR_MODE_YCBCR422 << 5);
- else
- info[4] = (AVI_COLOR_MODE_RGB << 5);
- info[4] |= (1 << 4); //Enable active format data bits is present in info[2]
-
- switch(vic)
- {
- case HDMI_720x480i_60Hz_4_3:
- case HDMI_720x576i_50Hz_4_3:
- case HDMI_720x480p_60Hz_4_3:
- case HDMI_720x576p_50Hz_4_3:
- aspect_ratio = AVI_CODED_FRAME_ASPECT_4_3;
- clolorimetry = AVI_COLORIMETRY_SMPTE_170M;
- break;
- case HDMI_720x480i_60Hz_16_9:
- case HDMI_720x576i_50Hz_16_9:
- case HDMI_720x480p_60Hz_16_9:
- case HDMI_720x576p_50Hz_16_9:
- aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9;
- clolorimetry = AVI_COLORIMETRY_SMPTE_170M;
- break;
- default:
- aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9;
- clolorimetry = AVI_COLORIMETRY_ITU709;
- }
-
- if(output_color == VIDEO_OUTPUT_RGB444)
- clolorimetry = AVI_COLORIMETRY_NO_DATA;
-
- info[5] = (clolorimetry << 6) | (aspect_ratio << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME;
- info[6] = 0;
- info[7] = vic;
- info[8] = 0;
-
- // Calculate AVI InfoFrame ChecKsum
- for (i = 4; i < SIZE_AVI_INFOFRAME; i++)
- {
- info[3] += info[i];
- }
- info[3] = 0x100 - info[3];
-
- for(i = 0; i < SIZE_AVI_INFOFRAME; i++)
- HDMIWrReg(CONTROL_PACKET_HB0 + i*4, info[i]);
-}
-
-static char coeff_csc[][24] = {
- //G B R Bias
- { //CSC_RGB_0_255_TO_ITU601_16_235
- 0x11, 0xb6, 0x02, 0x0b, 0x10, 0x55, 0x00, 0x80, //Cr
- 0x02, 0x59, 0x01, 0x32, 0x00, 0x75, 0x00, 0x10, //Y
- 0x11, 0x5b, 0x10, 0xb0, 0x02, 0x0b, 0x00, 0x80, //Cb
- },
- { //CSC_RGB_0_255_TO_ITU709_16_235
- 0x11, 0xdb, 0x02, 0x0b, 0x10, 0x30, 0x00, 0x80, //Cr
- 0x02, 0xdc, 0x00, 0xda, 0x00, 0x4a, 0x00, 0x10, //Y
- 0x11, 0x93, 0x10, 0x78, 0x02, 0x0b, 0x00, 0x80, //Cb
- },
- //Y Cr Cb Bias
- { //CSC_ITU601_16_235_TO_RGB_16_235
- 0x04, 0x00, 0x05, 0x7c, 0x00, 0x00, 0x02, 0xaf, //R
- 0x04, 0x00, 0x12, 0xcb, 0x11, 0x58, 0x00, 0x84, //G
- 0x04, 0x00, 0x00, 0x00, 0x06, 0xee, 0x02, 0xde, //B
- },
- { //CSC_ITU709_16_235_TO_RGB_16_235
- 0x04, 0x00, 0x06, 0x29, 0x00, 0x00, 0x02, 0xc5, //R
- 0x04, 0x00, 0x11, 0xd6, 0x10, 0xbb, 0x00, 0x52, //G
- 0x04, 0x00, 0x00, 0x00, 0x07, 0x44, 0x02, 0xe8, //B
- },
- { //CSC_ITU601_16_235_TO_RGB_0_255
- 0x04, 0xa8, 0x05, 0x7c, 0x00, 0x00, 0x02, 0xc2, //R
- 0x04, 0xa8, 0x12, 0xcb, 0x11, 0x58, 0x00, 0x72, //G
- 0x04, 0xa8, 0x00, 0x00, 0x06, 0xee, 0x02, 0xf0, //B
- },
- { //CSC_ITU709_16_235_TO_RGB_0_255
- 0x04, 0xa8, 0x06, 0x29, 0x00, 0x00, 0x02, 0xd8, //R
- 0x04, 0xa8, 0x11, 0xd6, 0x10, 0xbb, 0x00, 0x40, //G
- 0x04, 0xa8, 0x00, 0x00, 0x07, 0x44, 0x02, 0xfb, //B
- },
-
-};
-
-static void rk30_hdmi_config_csc(struct rk30_hdmi_video_para *vpara)
-{
- int i, mode;
- char *coeff = NULL;
-
- if( ((vpara->input_color == VIDEO_INPUT_COLOR_RGB) && (vpara->output_color == VIDEO_OUTPUT_RGB444)) ||
- ((vpara->input_color == VIDEO_INPUT_COLOR_YCBCR) && (vpara->output_color != VIDEO_OUTPUT_RGB444) ))
- {
- return;
- }
- switch(vpara->vic)
- {
- case HDMI_720x480i_60Hz_4_3:
- case HDMI_720x576i_50Hz_4_3:
- case HDMI_720x480p_60Hz_4_3:
- case HDMI_720x576p_50Hz_4_3:
- case HDMI_720x480i_60Hz_16_9:
- case HDMI_720x576i_50Hz_16_9:
- case HDMI_720x480p_60Hz_16_9:
- case HDMI_720x576p_50Hz_16_9:
- if(vpara->input_color == VIDEO_INPUT_COLOR_RGB)
- mode = CSC_RGB_0_255_TO_ITU601_16_235;
- else if(vpara->output_mode == OUTPUT_HDMI)
- mode = CSC_ITU601_16_235_TO_RGB_16_235;
- else
- mode = CSC_ITU601_16_235_TO_RGB_0_255;
- break;
- default:
- if(vpara->input_color == VIDEO_INPUT_COLOR_RGB)
- mode = CSC_RGB_0_255_TO_ITU709_16_235;
- else if(vpara->output_mode == OUTPUT_HDMI)
- mode = CSC_ITU709_16_235_TO_RGB_16_235;
- else
- mode = CSC_ITU709_16_235_TO_RGB_0_255;
- break;
- }
-
- coeff = coeff_csc[mode];
-
- HDMIWrReg(CSC_CONFIG1, v_CSC_MODE(CSC_MODE_MANUAL) | v_CSC_BRSWAP_DIABLE(1));
-
- for(i = 0; i < 24; i++)
- HDMIWrReg(CSC_PARA_C0_H + i*4, coeff[i]);
-
- HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(1));
-}
-
-int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara)
-{
- int value;
- struct fb_videomode *mode;
-
- hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__);
- if(vpara == NULL) {
- hdmi_err(hdmi->dev, "[%s] input parameter error\n", __FUNCTION__);
- return -1;
- }
- if(hdmi->pwr_mode == PWR_SAVE_MODE_E)
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
- if(hdmi->pwr_mode == PWR_SAVE_MODE_D || hdmi->pwr_mode == PWR_SAVE_MODE_A)
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
-
- if(hdmi->hdcp_power_off_cb)
- hdmi->hdcp_power_off_cb();
-
- // Input video mode is RGB24bit, Data enable signal from external
- HDMIMskReg(value, AV_CTRL1, m_INPUT_VIDEO_MODE | m_DE_SIGNAL_SELECT, \
- v_INPUT_VIDEO_MODE(vpara->input_mode) | EXTERNAL_DE)
- HDMIMskReg(value, VIDEO_CTRL1, m_VIDEO_OUTPUT_MODE | m_VIDEO_INPUT_DEPTH | m_VIDEO_INPUT_COLOR_MODE, \
- v_VIDEO_OUTPUT_MODE(vpara->output_color) | v_VIDEO_INPUT_DEPTH(VIDEO_INPUT_DEPTH_8BIT) | vpara->input_color)
- HDMIWrReg(DEEP_COLOR_MODE, 0x20);
- // color space convert
- rk30_hdmi_config_csc(vpara);
- // Set HDMI Mode
- HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(vpara->output_mode));
-
- // Set ext video
- mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);
- if(mode == NULL)
- {
- hdmi_err(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic);
- return -ENOENT;
- }
- hdmi->tmdsclk = mode->pixclock;
-
- if( (vpara->vic == HDMI_720x480p_60Hz_4_3) || (vpara->vic == HDMI_720x480p_60Hz_16_9) )
- value = v_VSYNC_OFFSET(6);
- else
- value = v_VSYNC_OFFSET(0);
- value |= v_EXT_VIDEO_ENABLE(1) | v_INTERLACE(mode->vmode);
- if(mode->sync & FB_SYNC_HOR_HIGH_ACT)
- value |= v_HSYNC_POLARITY(1);
- if(mode->sync & FB_SYNC_VERT_HIGH_ACT)
- value |= v_VSYNC_POLARITY(1);
- HDMIWrReg(EXT_VIDEO_PARA, value);
- value = mode->left_margin + mode->xres + mode->right_margin + mode->hsync_len;
- HDMIWrReg(EXT_VIDEO_PARA_HTOTAL_L, value & 0xFF);
- HDMIWrReg(EXT_VIDEO_PARA_HTOTAL_H, (value >> 8) & 0xFF);
-
- value = mode->left_margin + mode->right_margin + mode->hsync_len;
- HDMIWrReg(EXT_VIDEO_PARA_HBLANK_L, value & 0xFF);
- HDMIWrReg(EXT_VIDEO_PARA_HBLANK_H, (value >> 8) & 0xFF);
-
- value = mode->left_margin + mode->hsync_len;
- HDMIWrReg(EXT_VIDEO_PARA_HDELAY_L, value & 0xFF);
- HDMIWrReg(EXT_VIDEO_PARA_HDELAY_H, (value >> 8) & 0xFF);
-
- value = mode->hsync_len;
- HDMIWrReg(EXT_VIDEO_PARA_HSYNCWIDTH_L, value & 0xFF);
- HDMIWrReg(EXT_VIDEO_PARA_HSYNCWIDTH_H, (value >> 8) & 0xFF);
-
- value = mode->upper_margin + mode->yres + mode->lower_margin + mode->vsync_len;
- HDMIWrReg(EXT_VIDEO_PARA_VTOTAL_L, value & 0xFF);
- HDMIWrReg(EXT_VIDEO_PARA_VTOTAL_H, (value >> 8) & 0xFF);
-
- value = mode->upper_margin + mode->vsync_len + mode->lower_margin;
- HDMIWrReg(EXT_VIDEO_PARA_VBLANK_L, value & 0xFF);
-
- if(vpara->vic == HDMI_720x480p_60Hz_4_3 || vpara->vic == HDMI_720x480p_60Hz_16_9)
- value = 42;
- else
- value = mode->upper_margin + mode->vsync_len;
-
- HDMIWrReg(EXT_VIDEO_PARA_VDELAY, value & 0xFF);
-
- value = mode->vsync_len;
- HDMIWrReg(EXT_VIDEO_PARA_VSYNCWIDTH, value & 0xFF);
-
- if(vpara->output_mode == OUTPUT_HDMI) {
- rk30_hdmi_config_avi(vpara->vic, vpara->output_color);
- hdmi_dbg(hdmi->dev, "[%s] sucess output HDMI.\n", __FUNCTION__);
- }
- else {
- hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__);
- }
-
- rk30_hdmi_config_phy(vpara->vic);
- rk30_hdmi_control_output(0);
- return 0;
-}
-
-static void rk30_hdmi_config_aai(void)
-{
- int i;
- char info[SIZE_AUDIO_INFOFRAME];
-
- memset(info, 0, SIZE_AUDIO_INFOFRAME);
-
- info[0] = 0x84;
- info[1] = 0x01;
- info[2] = 0x0A;
-
- info[3] = info[0] + info[1] + info[2];
- for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)
- info[3] += info[i];
-
- info[3] = 0x100 - info[3];
-
- HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI);
- for(i = 0; i < SIZE_AUDIO_INFOFRAME; i++)
- HDMIWrReg(CONTROL_PACKET_HB0 + i*4, info[i]);
-}
-
-int rk30_hdmi_config_audio(struct hdmi_audio *audio)
-{
- int value, rate, N;
- char word_length, channel;
-
- if(audio->channel < 3)
- channel = I2S_CHANNEL_1_2;
- else if(audio->channel < 5)
- channel = I2S_CHANNEL_3_4;
- else if(audio->channel < 7)
- channel = I2S_CHANNEL_5_6;
- else
- channel = I2S_CHANNEL_7_8;
-
- switch(audio->rate)
- {
- case HDMI_AUDIO_FS_32000:
- rate = AUDIO_32K;
- N = N_32K;
- break;
- case HDMI_AUDIO_FS_44100:
- rate = AUDIO_441K;
- N = N_441K;
- break;
- case HDMI_AUDIO_FS_48000:
- rate = AUDIO_48K;
- N = N_48K;
- break;
- case HDMI_AUDIO_FS_88200:
- rate = AUDIO_882K;
- N = N_882K;
- break;
- case HDMI_AUDIO_FS_96000:
- rate = AUDIO_96K;
- N = N_96K;
- break;
- case HDMI_AUDIO_FS_176400:
- rate = AUDIO_1764K;
- N = N_1764K;
- break;
- case HDMI_AUDIO_FS_192000:
- rate = AUDIO_192K;
- N = N_192K;
- break;
- default:
- hdmi_err(hdmi->dev, "[%s] not support such sample rate %d\n", __FUNCTION__, audio->rate);
- return -ENOENT;
- }
-// switch(audio->word_length)
-// {
-// case HDMI_AUDIO_WORD_LENGTH_16bit:
-// word_length = 0x02;
-// break;
-// case HDMI_AUDIO_WORD_LENGTH_20bit:
-// word_length = 0x0a;
-// break;
-// case HDMI_AUDIO_WORD_LENGTH_24bit:
-// word_length = 0x0b;
-// break;
-// default:
-// hdmi_err(hdmi->dev, "[%s] not support such word length %d\n", __FUNCTION__, audio->word_length);
-// return -ENOENT;
-// }
- //set_audio_if I2S
- HDMIWrReg(AUDIO_CTRL1, 0x00); //internal CTS, disable down sample, i2s input, disable MCLK
- HDMIWrReg(AUDIO_CTRL2, 0x40);
- HDMIWrReg(I2S_AUDIO_CTRL, v_I2S_MODE(I2S_MODE_STANDARD) | v_I2S_CHANNEL(channel) );
- HDMIWrReg(I2S_INPUT_SWAP, 0x00); //no swap
- HDMIMskReg(value, AV_CTRL1, m_AUDIO_SAMPLE_RATE, v_AUDIO_SAMPLE_RATE(rate))
-// HDMIWrReg(SRC_NUM_AUDIO_LEN, word_length);
-
- //Set N value 6144, fs=48kHz
- HDMIWrReg(N_1, N & 0xFF);
- HDMIWrReg(N_2, (N >> 8) & 0xFF);
- HDMIWrReg(LR_SWAP_N3, (N >> 16) & 0x0F);
-
- rk30_hdmi_config_aai();
- return 0;
-}
-
-static void rk30_hdmi_audio_reset(void)
-{
- int value;
-
- HDMIMskReg(value, VIDEO_SETTING2, m_AUDIO_RESET, AUDIO_CAPTURE_RESET)
- msleep(1);
- HDMIMskReg(value, VIDEO_SETTING2, m_AUDIO_RESET, 0)
-}
-
-void rk30_hdmi_control_output(int enable)
-{
- hdmi_dbg(hdmi->dev, "[%s] %d\n", __FUNCTION__, enable);
- if(enable == 0) {
- HDMIWrReg(VIDEO_SETTING2, 0x03);
- }
- else {
- if(hdmi->pwr_mode == PWR_SAVE_MODE_B) {
- // Switch to power save mode_d
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
- }
- if(hdmi->pwr_mode == PWR_SAVE_MODE_D) {
- // Switch to power save mode_e
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_E);
- }
- HDMIWrReg(VIDEO_SETTING2, 0x00);
- rk30_hdmi_audio_reset();
- }
-}
-
-int rk30_hdmi_removed(void)
-{
- if(hdmi->pwr_mode == PWR_SAVE_MODE_E)
- {
- HDMIWrReg(VIDEO_SETTING2, 0x00);
- rk30_hdmi_audio_reset();
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D);
- }
- if(hdmi->pwr_mode == PWR_SAVE_MODE_D)
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_B);
- if(hdmi->pwr_mode == PWR_SAVE_MODE_B && hdmi->state == HDMI_SLEEP)
- {
- HDMIWrReg(INTR_MASK1, m_INT_HOTPLUG | m_INT_MSENS);
- HDMIWrReg(INTR_MASK2, 0);
- HDMIWrReg(INTR_MASK3, 0);
- HDMIWrReg(INTR_MASK4, 0);
- // Disable color space convertion
- HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(0));
- HDMIWrReg(CSC_CONFIG1, v_CSC_MODE(CSC_MODE_AUTO) | v_CSC_BRSWAP_DIABLE(1));
- if(hdmi->hdcp_power_off_cb)
- hdmi->hdcp_power_off_cb();
- rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_A);
- }
- dev_printk(KERN_INFO , hdmi->dev , "Removed.\n");
- return HDMI_ERROR_SUCESS;
-}
-
-
-irqreturn_t hdmi_irq(int irq, void *priv)
-{
- char interrupt1 = 0, interrupt2 = 0, interrupt3 = 0, interrupt4 = 0;
-
- if(hdmi->pwr_mode == PWR_SAVE_MODE_A)
- {
- HDMIWrReg(SYS_CTRL, 0x20);
- hdmi->pwr_mode = PWR_SAVE_MODE_B;
-
- hdmi_dbg(hdmi->dev, "hdmi irq wake up\n");
- // HDMI was inserted when system is sleeping, irq was triggered only once
- // when wake up. So we need to check hotplug status.
- if(HDMIRdReg(HPD_MENS_STA) & (m_HOTPLUG_STATUS | m_MSEN_STATUS)) {
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
- }
- }
- else
- {
- interrupt1 = HDMIRdReg(INTR_STATUS1);
- interrupt2 = HDMIRdReg(INTR_STATUS2);
- interrupt3 = HDMIRdReg(INTR_STATUS3);
- interrupt4 = HDMIRdReg(INTR_STATUS4);
- HDMIWrReg(INTR_STATUS1, interrupt1);
- HDMIWrReg(INTR_STATUS2, interrupt2);
- HDMIWrReg(INTR_STATUS3, interrupt3);
- HDMIWrReg(INTR_STATUS4, interrupt4);
-#if 0
- hdmi_dbg(hdmi->dev, "[%s] interrupt1 %02x interrupt2 %02x interrupt3 %02x interrupt4 %02x\n",\
- __FUNCTION__, interrupt1, interrupt2, interrupt3, interrupt4);
-#endif
- if(interrupt1 & (m_INT_HOTPLUG | m_INT_MSENS))
- {
- if(hdmi->state == HDMI_SLEEP)
- hdmi->state = WAIT_HOTPLUG;
- interrupt1 &= ~(m_INT_HOTPLUG | m_INT_MSENS);
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));
- }
- else if(interrupt1 & (m_INT_EDID_READY | m_INT_EDID_ERR)) {
- spin_lock(&hdmi->irq_lock);
- edid_result = interrupt1;
- spin_unlock(&hdmi->irq_lock);
- }
- else if(hdmi->state == HDMI_SLEEP) {
- hdmi_dbg(hdmi->dev, "hdmi return to sleep mode\n");
- HDMIWrReg(SYS_CTRL, 0x10);
- hdmi->pwr_mode = PWR_SAVE_MODE_A;
- }
- if(interrupt2 && hdmi->hdcp_irq_cb)
- hdmi->hdcp_irq_cb(interrupt2);
- }
- return IRQ_HANDLED;
-}
-
+++ /dev/null
-#ifndef __RK30_HDMI_HW_H__
-#define __RK30_HDMI_HW_H__
-
-/* HDMI_SYS_CONTROL */
-#define SYS_CTRL 0x0
-
-enum {
- PWR_SAVE_MODE_A = 1,
- PWR_SAVE_MODE_B = 2,
- PWR_SAVE_MODE_D = 4,
- PWR_SAVE_MODE_E = 8
-};
-#define m_PWR_SAVE_MODE 0xF0
-#define v_PWR_SAVE_MODE(n) (n << 4)
-#define PLL_B_RESET (1 << 3)
-
-#define N_32K 0x1000
-#define N_441K 0x1880
-#define N_882K 0x3100
-#define N_1764K 0x6200
-#define N_48K 0x1800
-#define N_96K 0x3000
-#define N_192K 0x6000
-
-#define LR_SWAP_N3 0x04
-#define N_2 0x08
-#define N_1 0x0c
-
-#define AUDIO_CTRL1 0x28
-#define AUDIO_CTRL2 0x2c
-#define I2S_AUDIO_CTRL 0x30
-enum {
- I2S_MODE_STANDARD = 0,
- I2S_MODE_RIGHT_JUSTIFIED,
- I2S_MODE_LEFT_JUSTIFIED
-};
-#define v_I2S_MODE(n) n
-enum {
- I2S_CHANNEL_1_2 = 1,
- I2S_CHANNEL_3_4 = 3,
- I2S_CHANNEL_5_6 = 7,
- I2S_CHANNEL_7_8 = 0xf
-};
-#define v_I2S_CHANNEL(n) ( (n) << 2 )
-
-#define I2S_INPUT_SWAP 0x40
-
-#define SRC_NUM_AUDIO_LEN 0x50
-
-/* HDMI_AV_CTRL1*/
-#define AV_CTRL1 0x54
-enum {
- AUDIO_32K = 0x3,
- AUDIO_441K = 0x0,
- AUDIO_48K = 0x2,
- AUDIO_882K = 0x8,
- AUDIO_96K = 0xa,
- AUDIO_1764K = 0xc,
- AUDIO_192K = 0xe,
-};
-#define m_AUDIO_SAMPLE_RATE 0xF0
-#define v_AUDIO_SAMPLE_RATE(n) (n << 4)
-enum {
- VIDEO_INPUT_RGB_YCBCR_444 = 0,
- VIDEO_INPUT_YCBCR422,
- VIDEO_INPUT_YCBCR422_EMBEDDED_SYNC,
- VIDEO_INPUT_2X_CLOCK,
- VIDEO_INPUT_2X_CLOCK_EMBEDDED_SYNC,
- VIDEO_INPUT_RGB444_DDR,
- VIDEO_INPUT_YCBCR422_DDR
-};
-#define m_INPUT_VIDEO_MODE (7 << 1)
-#define v_INPUT_VIDEO_MODE(n) (n << 1)
-enum {
- INTERNAL_DE = 0,
- EXTERNAL_DE
-};
-#define m_DE_SIGNAL_SELECT (1 << 0)
-
-/* HDMI_AV_CTRL2 */
-#define AV_CTRL2 0xec
-#define m_CSC_ENABLE (1 << 0)
-#define v_CSC_ENABLE(n) (n)
-
-/* HDMI_VIDEO_CTRL1 */
-#define VIDEO_CTRL1 0x58
-enum {
- VIDEO_OUTPUT_RGB444 = 0,
- VIDEO_OUTPUT_YCBCR444,
- VIDEO_OUTPUT_YCBCR422
-};
-#define m_VIDEO_OUTPUT_MODE (0x3 << 6)
-#define v_VIDEO_OUTPUT_MODE(n) (n << 6)
-enum {
- VIDEO_INPUT_DEPTH_12BIT = 0,
- VIDEO_INPUT_DEPTH_10BIT = 0x1,
- VIDEO_INPUT_DEPTH_8BIT = 0x3
-};
-#define m_VIDEO_INPUT_DEPTH (3 << 4)
-#define v_VIDEO_INPUT_DEPTH(n) (n << 4)
-enum {
- VIDEO_EMBEDDED_SYNC_LOCATION_0 = 0,
- VIDEO_EMBEDDED_SYNC_LOCATION_1,
- VIDEO_EMBEDDED_SYNC_LOCATION_2
-};
-#define m_VIDEO_EMBEDDED_SYNC_LOCATION (3 << 2)
-#define VIDEO_EMBEDDED_SYNC_LOCATION(n) (n << 2)
-enum {
- VIDEO_INPUT_COLOR_RGB = 0,
- VIDEO_INPUT_COLOR_YCBCR
-};
-#define m_VIDEO_INPUT_COLOR_MODE (1 << 0)
-
-/* DEEP_COLOR_MODE */
-#define DEEP_COLOR_MODE 0x5c
-enum{
- TMDS_CLOCK_MODE_8BIT = 0,
- TMDS_CLOKK_MODE_10BIT,
- TMDS_CLOKK_MODE_12BIT
-};
-#define TMDS_CLOCK_MODE_MASK 0x3 << 6
-#define TMDS_CLOCK_MODE(n) (n) << 6
-
-/* VIDEO_CTRL2 */
-#define VIDEO_SETTING2 0x114
-#define m_UNMUTE (1 << 7)
-#define m_MUTE (1 << 6)
-#define m_AUDIO_RESET (1 << 2)
-#define m_NOT_SEND_AUDIO (1 << 1)
-#define m_NOT_SEND_VIDEO (1 << 0)
-#define AV_UNMUTE (1 << 7) // Unmute video and audio, send normal video and audio data
-#define AV_MUTE (1 << 6) // Mute video and audio, send black video data and silent audio data
-#define AUDIO_CAPTURE_RESET (1 << 2) // Reset audio process logic, only available in pwr_e mode.
-#define NOT_SEND_AUDIO (1 << 1) // Send silent audio data
-#define NOT_SEND_VIDEO (1 << 0) // Send black video data
-
-/* Color Space Convertion Parameter*/
-#define CSC_PARA_C0_H 0x60
-#define CSC_PARA_C0_L 0x64
-#define CSC_PARA_C1_H 0x68
-#define CSC_PARA_C1_L 0x6c
-#define CSC_PARA_C2_H 0x70
-#define CSC_PARA_C2_L 0x74
-#define CSC_PARA_C3_H 0x78
-#define CSC_PARA_C3_L 0x7c
-#define CSC_PARA_C4_H 0x80
-#define CSC_PARA_C4_L 0x84
-#define CSC_PARA_C5_H 0x88
-#define CSC_PARA_C5_L 0x8c
-#define CSC_PARA_C6_H 0x90
-#define CSC_PARA_C6_L 0x94
-#define CSC_PARA_C7_H 0x98
-#define CSC_PARA_C7_L 0x9c
-#define CSC_PARA_C8_H 0xa0
-#define CSC_PARA_C8_L 0xa4
-#define CSC_PARA_C9_H 0xa8
-#define CSC_PARA_C9_L 0xac
-#define CSC_PARA_C10_H 0xac
-#define CSC_PARA_C10_L 0xb4
-#define CSC_PARA_C11_H 0xb8
-#define CSC_PARA_C11_L 0xbc
-
-#define CSC_CONFIG1 0x34c
-#define m_CSC_MODE (1 << 7)
-#define m_CSC_COEF_MODE (0xF << 3) //Only used in auto csc mode
-#define m_CSC_STATUS (1 << 2)
-#define m_CSC_VID_SELECT (1 << 1)
-#define m_CSC_BRSWAP_DIABLE (1)
-
-enum {
- CSC_MODE_MANUAL = 0,
- CSC_MODE_AUTO
-};
-#define v_CSC_MODE(n) (n << 7)
-enum {
- COE_SDTV_LIMITED_RANGE = 0x08,
- COE_SDTV_FULL_RANGE = 0x04,
- COE_HDTV_60Hz = 0x2,
- COE_HDTV_50Hz = 0x1
-};
-#define v_CSC_COE_MODE(n) (n << 3)
-enum {
- CSC_INPUT_VID_5_19 = 0,
- CSC_INPUT_VID_28_29
-};
-#define v_CSC_VID_SELECT(n) (n << 1)
-#define v_CSC_BRSWAP_DIABLE(n) (n)
-
-/* CONTROL_PACKET_BUF_INDEX */
-#define CONTROL_PACKET_BUF_INDEX 0x17c
-enum {
- INFOFRAME_AVI = 0x06,
- INFOFRAME_AAI = 0x08
-};
-#define CONTROL_PACKET_HB0 0x180
-#define CONTROL_PACKET_HB1 0x184
-#define CONTROL_PACKET_HB2 0x188
-#define CONTROL_PACKET_PB_ADDR 0x18c
-#define SIZE_AVI_INFOFRAME 0x11 // 17 bytes
-#define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes
-enum {
- AVI_COLOR_MODE_RGB = 0,
- AVI_COLOR_MODE_YCBCR422,
- AVI_COLOR_MODE_YCBCR444
-};
-enum {
- AVI_COLORIMETRY_NO_DATA = 0,
- AVI_COLORIMETRY_SMPTE_170M,
- AVI_COLORIMETRY_ITU709,
- AVI_COLORIMETRY_EXTENDED
-};
-enum {
- AVI_CODED_FRAME_ASPECT_NO_DATA,
- AVI_CODED_FRAME_ASPECT_4_3,
- AVI_CODED_FRAME_ASPECT_16_9
-};
-enum {
- ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME = 0x08,
- ACTIVE_ASPECT_RATE_4_3,
- ACTIVE_ASPECT_RATE_16_9,
- ACTIVE_ASPECT_RATE_14_9
-};
-
-/* External Video Parameter Setting*/
-#define EXT_VIDEO_PARA 0xC0
-#define m_VSYNC_OFFSET (0xF << 4)
-#define m_VSYNC_POLARITY (1 << 3)
-#define m_HSYNC_POLARITY (1 << 2)
-#define m_INTERLACE (1 << 1)
-#define m_EXT_VIDEO_ENABLE (1 << 0)
-
-#define v_VSYNC_OFFSET(n) (n << 4)
-#define v_VSYNC_POLARITY(n) (n << 3)
-#define v_HSYNC_POLARITY(n) (n << 2)
-#define v_INTERLACE(n) (n << 1)
-#define v_EXT_VIDEO_ENABLE(n) (n << 0)
-
-#define EXT_VIDEO_PARA_HTOTAL_L 0xC4
-#define EXT_VIDEO_PARA_HTOTAL_H 0xC8
-#define EXT_VIDEO_PARA_HBLANK_L 0xCC
-#define EXT_VIDEO_PARA_HBLANK_H 0xD0
-#define EXT_VIDEO_PARA_HDELAY_L 0xD4
-#define EXT_VIDEO_PARA_HDELAY_H 0xD8
-#define EXT_VIDEO_PARA_HSYNCWIDTH_L 0xDC
-#define EXT_VIDEO_PARA_HSYNCWIDTH_H 0xE0
-
-#define EXT_VIDEO_PARA_VTOTAL_L 0xE4
-#define EXT_VIDEO_PARA_VTOTAL_H 0xE8
-#define EXT_VIDEO_PARA_VBLANK_L 0xF4
-#define EXT_VIDEO_PARA_VDELAY 0xF8
-#define EXT_VIDEO_PARA_VSYNCWIDTH 0xFC
-
-#define PHY_PLL_SPEED 0x158
- #define v_TEST_EN(n) (n << 6)
- #define v_PLLA_BYPASS(n) (n << 4)
- #define v_PLLB_SPEED(n) (n << 2)
- #define v_PLLA_SPEED(n) (n)
- enum {
- PLL_SPEED_LOWEST = 0,
- PLL_SPEED_MIDLOW,
- PLL_SPEED_MIDHIGH,
- PLL_SPEED_HIGHEST
- };
-
-#define PHY_PLL_17 0x15c // PLL A & B config bit 17
- #define v_PLLA_BIT17(n) (n << 2)
- #define v_PLLB_BIT17(n) (n << 1)
-
-#define PHY_BGR 0x160
- #define v_BGR_DISCONNECT(n) (n << 7)
- #define v_BGR_V_OFFSET(n) (n << 4)
- #define v_BGR_I_OFFSET(n) (n)
-
-#define PHY_PLLA_1 0x164
-#define PHY_PLLA_2 0x168
-#define PHY_PLLB_1 0x16c
-#define PHY_PLLB_2 0x170
-
-#define PHY_DRIVER_PREEMPHASIS 0x174
- #define v_TMDS_SWING(n) (n << 4)
- #define v_PRE_EMPHASIS(n) (n)
-
-#define PHY_PLL_16_AML 0x178 // PLL A & B config bit 16 and AML control
- #define v_PLLA_BIT16(n) (n << 5)
- #define v_PLLB_BIT16(n) (n << 4)
- #define v_AML(n) (n)
-
-/* Interrupt Setting */
-#define INTR_MASK1 0x248
-#define INTR_STATUS1 0x250
- #define m_INT_HOTPLUG (1 << 7)
- #define m_INT_MSENS (1 << 6)
- #define m_INT_VSYNC (1 << 5)
- #define m_INT_AUDIO_FIFO_FULL (1 << 4)
- #define m_INT_EDID_READY (1 << 2)
- #define m_INT_EDID_ERR (1 << 1)
-#define INTR_MASK2 0x24c
-#define INTR_STATUS2 0x254
- #define m_INT_HDCP_ERR (1 << 7) // HDCP error detected
- #define m_INT_BKSV_RPRDY (1 << 6) // BKSV list ready from repeater
- #define m_INT_BKSV_RCRDY (1 << 5) // BKSV list ready from receiver
- #define m_INT_AUTH_DONE (1 << 4) // HDCP authentication done
- #define m_INT_AUTH_READY (1 << 3) // HDCP authentication ready
-#define INTR_MASK3 0x258
-#define INTR_STATUS3 0x260
-
-#define INTR_MASK4 0x25c
-#define INTR_STATUS4 0x264
-
-#define DDC_READ_FIFO_ADDR 0x200
-#define DDC_BUS_FREQ_L 0x204
-#define DDC_BUS_FREQ_H 0x208
-#define DDC_BUS_CTRL 0x2dc
-#define DDC_I2C_LEN 0x278
-#define DDC_I2C_OFFSET 0x280
-#define DDC_I2C_CTRL 0x284
-#define DDC_I2C_READ_BUF0 0x288
-#define DDC_I2C_READ_BUF1 0x28c
-#define DDC_I2C_READ_BUF2 0x290
-#define DDC_I2C_READ_BUF3 0x294
-#define DDC_I2C_WRITE_BUF0 0x298
-#define DDC_I2C_WRITE_BUF1 0x29c
-#define DDC_I2C_WRITE_BUF2 0x2a0
-#define DDC_I2C_WRITE_BUF3 0x2a4
-#define DDC_I2C_WRITE_BUF4 0x2ac
-#define DDC_I2C_WRITE_BUF5 0x2b0
-#define DDC_I2C_WRITE_BUF6 0x2b4
-
-#define EDID_SEGMENT_POINTER 0x310
-#define EDID_WORD_ADDR 0x314
-#define EDID_FIFO_ADDR 0x318
-
-#define HPD_MENS_STA 0x37c
-#define m_HOTPLUG_STATUS (1 << 7)
-#define m_MSEN_STATUS (1 << 6)
-
-/* HDCP_CTRL */
-#define HDCP_CTRL 0x2bc
- enum {
- OUTPUT_DVI = 0,
- OUTPUT_HDMI
- };
- #define m_HDCP_AUTH_START (1 << 7) // start hdcp
- #define m_HDCP_BKSV_PASS (1 << 6) // bksv valid
- #define m_HDCP_BKSV_FAILED (1 << 5) // bksv invalid
- #define m_HDCP_FRAMED_ENCRYPED (1 << 4)
- #define m_HDCP_AUTH_STOP (1 << 3) // stop hdcp
- #define m_HDCP_ADV_CIPHER (1 << 2) // advanced cipher mode
- #define m_HDMI_DVI (1 << 1)
- #define m_HDCP_RESET (1 << 0) // reset hdcp
- #define v_HDCP_AUTH_START(n) (n << 7)
- #define v_HDCP_BKSV_PASS(n) (n << 6)
- #define v_HDCP_BKSV_FAILED(n) (n << 5)
- #define v_HDCP_FRAMED_ENCRYPED(n) (n << 4)
- #define v_HDCP_AUTH_STOP(n) (n << 3)
- #define v_HDCP_ADV_CIPHER(n) (n << 2)
- #define v_HDMI_DVI(n) (n << 1)
- #define v_HDCP_RESET(n) (n << 0)
-#define HDCP_CTRL2 0x340
-
-/* HDCP Key Memory Access Control */
-#define HDCP_KEY_ACCESS_CTRL1 0x338
-#define HDCP_KEY_ACCESS_CTRL2 0x33c
- #define m_LOAD_FACSIMILE_HDCP_KEY (1 << 1)
- #define m_LOAD_HDCP_KEY (1 << 0)
-/* HDCP Key Memory Control */
-#define HDCP_KEY_MEM_CTRL 0x348
- #define m_USE_KEY1 (1 << 6)
- #define m_USE_KEY2 (1 << 5)
- #define m_LOAD_AKSV (1 << 4)
- #define m_KSV_SELECTED (1 << 3)
- #define m_KSV_VALID (1 << 2)
- #define m_KEY_VALID (1 << 1)
- #define m_KEY_READY (1 << 0)
- #define v_USE_KEY1(n) (n << 6)
- #define v_USE_KEY2(n) (n << 5)
- #define v_LOAD_AKSV(n) (n << 4)
-
-/* HDCP B device capacity */
-#define HDCP_BCAPS 0x2f8
- #define m_HDMI_RECEIVED (1 << 7) //If HDCP receiver support HDMI, this bit must be 1.
- #define m_REPEATER (1 << 6)
- #define m_KSV_FIFO_READY (1 << 5)
- #define m_DDC_FAST (1 << 4)
- #define m_1_1_FEATURE (1 << 1)
- #define m_FAST_REAUTHENTICATION (1 << 0) //For HDMI, this function is supported whether this bit is enabled or not.
-
-/* HDCP KSV Value */
-#define HDCP_KSV_BYTE0 0x2fc
-#define HDCP_KSV_BYTE1 0x300
-#define HDCP_KSV_BYTE2 0x304
-#define HDCP_KSV_BYTE3 0x308
-#define HDCP_KSV_BYTE4 0x30c
-
-/* HDCP error status */
-#define HDCP_ERROR 0x320
-
-/* HDCP 100 ms timer */
-#define HDCP_TIMER_100MS 0x324
-/* HDCP 5s timer */
-#define HDCP_TIMER_5S 0x328
-
-/* HDCP Key ram address */
-#define HDCP_RAM_KEY_KSV1 0x400
-#define HDCP_RAM_KEY_KSV2 0x407
-#define HDCP_RAM_KEY_PRIVATE 0x40e
-#define HDCP_KEY_LENGTH 0x13C
-
-
-#define HDCP_ENABLE_HW_AUTH // Enable hardware authentication mode
-#define HDMI_INTERANL_CLK_DIV 0x19
-
-#define HDMIRdReg(addr) __raw_readl(hdmi->regbase + addr)
-#define HDMIWrReg(addr, val) __raw_writel((val), hdmi->regbase + addr);
-#define HDMIMskReg(temp, addr, msk, val) \
- temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \
- __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr);
-
-/* RK30 HDMI Video Configure Parameters */
-struct rk30_hdmi_video_para {
- int vic;
- int input_mode; //input video data interface
- int input_color; //input video color mode
- int output_mode; //output hdmi or dvi
- int output_color; //output video color mode
-};
-
-/* Color Space Convertion Mode */
-enum {
- CSC_RGB_0_255_TO_ITU601_16_235 = 0, //RGB 0-255 input to YCbCr 16-235 output according BT601
- CSC_RGB_0_255_TO_ITU709_16_235, //RGB 0-255 input to YCbCr 16-235 output accroding BT709
- CSC_ITU601_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT601
- CSC_ITU709_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT709
- CSC_ITU601_16_235_TO_RGB_0_255, //YCbCr 16-235 input to RGB 0-255 output according BT601
- CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709
-};
-
-extern int rk30_hdmi_initial(void);
-extern int rk30_hdmi_detect_hotplug(void);
-extern int rk30_hdmi_read_edid(int block, unsigned char *buff);
-extern int rk30_hdmi_removed(void);
-extern int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara);
-extern int rk30_hdmi_config_audio(struct hdmi_audio *audio);
-extern void rk30_hdmi_control_output(int enable);
-
-#endif
\ No newline at end of file
+++ /dev/null
-#include <linux/console.h>
-#include "rk30_hdmi.h"
-#include "rk30_hdmi_hw.h"
-#include<linux/rk_fb.h>
-
-#define OUT_TYPE SCREEN_HDMI
-#define OUT_FACE OUT_P888
-#define DCLK_POL 1
-#define SWAP_RB 0
-#define LCD_ACLK 800000000
-
-const struct fb_videomode hdmi_mode [] = {
- //name refresh xres yres pixclock h_bp h_fp v_bp v_fp h_pw v_pw polariry PorI flag(used for vic)
-//{ "640x480p@60Hz", 60, 640, 480, 25175000, 48, 16, 33, 10, 96, 2, 0, 0, 1 },
-//{ "720x480i@60Hz", 60, 720, 480, 27000000, 114, 38, 15, 4, 124, 3, 0, 1, 6 },
-//{ "720x576i@50Hz", 50, 720, 576, 27000000, 138, 24, 19, 2, 126, 3, 0, 1, 21 },
-{ "720x480p@60Hz", 60, 720, 480, 27000000, 60, 16, 30, 9, 62, 6, 0, 0, 2 },
-{ "720x576p@50Hz", 50, 720, 576, 27000000, 68, 12, 39, 5, 64, 5, 0, 0, 17 },
-//{ "1280x720p@24Hz", 24, 1280, 720, 59400000, 220, 1760, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 60 },
-//{ "1280x720p@25Hz", 25, 1280, 720, 74250000, 220, 2420, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 61 },
-//{ "1280x720p@30Hz", 30, 1280, 720, 74250000, 220, 1760, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 62 },
-{ "1280x720p@50Hz", 50, 1280, 720, 74250000, 220, 440, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 19 },
-{ "1280x720p@60Hz", 60, 1280, 720, 74250000, 220, 110, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 4 },
-//{ "1920x1080p@24Hz", 24, 1920, 1080, 74250000, 148, 638, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 32 },
-//{ "1920x1080p@25Hz", 25, 1920, 1080, 74250000, 148, 528, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 33 },
-//{ "1920x1080p@30Hz", 30, 1920, 1080, 74250000, 148, 88, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 34 },
-//{ "1920x1080i@50Hz_2",50, 1920, 1080, 72000000, 184, 32, 57, 23, 168, 5, FB_SYNC_HOR_HIGH_ACT, 1, 39 },
-//{ "1920x1080i@50Hz", 50, 1920, 1080, 74250000, 148, 528, 15, 2, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 1, 20 },
-//{ "1920x1080i@60Hz", 60, 1920, 1080, 74250000, 148, 88, 15, 2, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 1, 5 },
-{ "1920x1080p@50Hz", 50, 1920, 1080, 148500000, 148, 528, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 31 },
-{ "1920x1080p@60Hz", 60, 1920, 1080, 148500000, 148, 88, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 16 },
-/*
-{ "1440x288p@50Hz", 50, 720, 480, 27000000, 138, 24, 19, 2, 126, 3, 0, 0, 23 },
-{ "2880x576i@50Hz", 50, 1440, 240, 54000000, 276, 48, 19, 2, 252, 3, 0, 1, 25 },
-{ "2880x288p@50Hz", 50, 2880, 480, 54000000, 276, 48, 19, 3, 252, 3, 0, 0, 27 },
-{ "1440x576p@50Hz", 50, 2880, 480, 54000000, 136, 24, 39, 5, 128, 5, 0, 0, 29 },
-{ "2880x576p@50Hz", 50, 1920, 1080, 108000000, 272, 48, 39, 5, 256, 5, 0, 0, 37 },
-{ "1440x240p@60Hz", 60, 1440, 240, 27000000, 114, 38, 15, 4, 124, 3, 0, 0, 8 },
-{ "2880x480i@60Hz", 60, 2880, 480, 54000000, 228, 76, 15, 4, 248, 3, 0, 1, 10 },
-{ "2880x480p@60Hz", 60, 2880, 480, 54000000, 228, 76, 15, 4, 248, 3, 0, 0, 12 },
-{ "1440x480p@60Hz", 60, 1440, 480, 54000000, 120, 32, 30, 9, 124, 6, 0, 0, 14 },
-{ "2880x480p@60Hz", 60, 2880, 480, 54000000, 240, 64, 30, 9, 248, 6, 0, 0, 35 },
-
-{ "1920x1080i@100Hz", 100, 1920, 1080, 148500000, 148, 528, 15, 2, 44, 5, 1, 1, 40 },
-{ "1280x720p@100Hz", 100, 1280, 720, 148500000, 220, 440, 20, 5, 40, 5, 1, 0, 41 },
-{ "720x576p@100Hz", 100, 720, 576, 54000000, 68, 12, 39, 5, 64, 5, 0, 0, 42 },
-{ "1440x576i@100Hz", 100, 1440, 576, 54000000, 138, 24, 19, 2, 12, 3, 0, 1, 44 },
-{ "1920x1080p@100Hz", 100, 1920, 1080, 297000000, 148, 528, 36, 4, 44, 5, 1, 0, 64 },
-
-{ "1920x1080i@120Hz", 120, 1920, 1080, 148500000, 148, 88, 15, 2, 44, 5, 1, 1, 46 },
-{ "1280x720p@120Hz", 120, 1280, 720, 148500000, 220, 110, 20, 5, 40, 5, 1, 0, 47 },
-{ "720x480p@120Hz", 120, 720, 480, 54000000, 60, 16, 30, 9, 62, 6, 0, 0, 48 },
-{ "1440x480i@120Hz", 120, 1440, 480, 54000000, 114, 38, 15, 4, 12, 3, 0, 1, 50 },
-{ "1920x1080p@120Hz", 120, 1920, 1080, 297000000, 148, 88, 36, 4, 44, 5, 1, 0, 63 },
-
-{ "720x576p@200Hz", 200, 720, 576, 108000000, 68, 12, 39, 5, 64, 5, 0, 0, 52 },
-{ "1440x576i@200Hz", 200, 1920, 1080, 108000000, 138, 24, 19, 2, 12, 3, 0, 1, 54 },
-
-{ "720x480p@240Hz", 240, 720, 480, 108000000, 60, 16, 30, 9, 62, 6, 0, 0, 56 },
-{ "1440x480i@240Hz", 240, 1440, 480, 108000000, 114, 38, 15, 4, 12, 3, 0, 1, 58 },
-*/
-
-};
-
-void hdmi_init_lcdc(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info)
-{
- hdmi_set_info(screen, HDMI_VIDEO_DEFAULT_MODE);
-}
-
-int hdmi_set_info(struct rk29fb_screen *screen, unsigned int vic)
-{
- int i;
-
- if(screen == NULL)
- return -1;
-
- if(vic == 0)
- vic = HDMI_VIDEO_DEFAULT_MODE;
-
- for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
- {
- if(hdmi_mode[i].flag == vic)
- break;
- }
- if(i == ARRAY_SIZE(hdmi_mode))
- return -1;
-
- memset(screen, 0, sizeof(struct rk29fb_screen));
-
- /* screen type & face */
- screen->type = OUT_TYPE;
- screen->face = OUT_FACE;
-
- /* Screen size */
- screen->x_res = hdmi_mode[i].xres;
- screen->y_res = hdmi_mode[i].yres;
-
- /* Timing */
- screen->pixclock = hdmi_mode[i].pixclock;
- screen->lcdc_aclk = LCD_ACLK;
- screen->left_margin = hdmi_mode[i].left_margin;
- screen->right_margin = hdmi_mode[i].right_margin;
- screen->hsync_len = hdmi_mode[i].hsync_len;
- screen->upper_margin = hdmi_mode[i].upper_margin;
- screen->lower_margin = hdmi_mode[i].lower_margin;
- screen->vsync_len = hdmi_mode[i].vsync_len;
-
- /* Pin polarity */
- if(FB_SYNC_HOR_HIGH_ACT & hdmi_mode[i].sync)
- screen->pin_hsync = 1;
- else
- screen->pin_hsync = 0;
- if(FB_SYNC_VERT_HIGH_ACT & hdmi_mode[i].sync)
- screen->pin_vsync = 1;
- else
- screen->pin_vsync = 0;
- screen->pin_den = 0;
- screen->pin_dclk = DCLK_POL;
-
- /* Swap rule */
- screen->swap_rb = SWAP_RB;
- screen->swap_rg = 0;
- screen->swap_gb = 0;
- screen->swap_delta = 0;
- screen->swap_dumy = 0;
-
- /* Operation function*/
- screen->init = NULL;
- screen->standby = NULL;
-
- return 0;
-}
-
-static void hdmi_show_sink_info(struct hdmi *hdmi)
-{
- struct list_head *pos, *head = &hdmi->edid.modelist;
- struct fb_modelist *modelist;
- struct fb_videomode *m;
- int i;
- struct hdmi_audio *audio;
-
- hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
- hdmi_dbg(hdmi->dev, "Support video mode: \n");
- list_for_each(pos, head) {
- modelist = list_entry(pos, struct fb_modelist, list);
- m = &modelist->mode;
- hdmi_dbg(hdmi->dev, " %s.\n", m->name);
- }
-
- for(i = 0; i < hdmi->edid.audio_num; i++)
- {
- audio = &(hdmi->edid.audio[i]);
- switch(audio->type)
- {
- case HDMI_AUDIO_LPCM:
- hdmi_dbg(hdmi->dev, "Support audio type: LPCM\n");
- break;
- case HDMI_AUDIO_AC3:
- hdmi_dbg(hdmi->dev, "Support audio type: AC3\n");
- break;
- case HDMI_AUDIO_MPEG1:
- hdmi_dbg(hdmi->dev, "Support audio type: MPEG1\n");
- break;
- case HDMI_AUDIO_MP3:
- hdmi_dbg(hdmi->dev, "Support audio type: MP3\n");
- break;
- case HDMI_AUDIO_MPEG2:
- hdmi_dbg(hdmi->dev, "Support audio type: MPEG2\n");
- break;
- case HDMI_AUDIO_AAC_LC:
- hdmi_dbg(hdmi->dev, "Support audio type: AAC\n");
- break;
- case HDMI_AUDIO_DTS:
- hdmi_dbg(hdmi->dev, "Support audio type: DTS\n");
- break;
- case HDMI_AUDIO_ATARC:
- hdmi_dbg(hdmi->dev, "Support audio type: ATARC\n");
- break;
- case HDMI_AUDIO_DSD:
- hdmi_dbg(hdmi->dev, "Support audio type: DSD\n");
- break;
- case HDMI_AUDIO_E_AC3:
- hdmi_dbg(hdmi->dev, "Support audio type: E-AC3\n");
- break;
- case HDMI_AUDIO_DTS_HD:
- hdmi_dbg(hdmi->dev, "Support audio type: DTS-HD\n");
- break;
- case HDMI_AUDIO_MLP:
- hdmi_dbg(hdmi->dev, "Support audio type: MLP\n");
- break;
- case HDMI_AUDIO_DST:
- hdmi_dbg(hdmi->dev, "Support audio type: DST\n");
- break;
- case HDMI_AUDIO_WMA_PRO:
- hdmi_dbg(hdmi->dev, "Support audio type: WMP-PRO\n");
- break;
- default:
- hdmi_dbg(hdmi->dev, "Support audio type: Unkown\n");
- break;
- }
-
- hdmi_dbg(hdmi->dev, "Support audio sample rate: \n");
- if(audio->rate & HDMI_AUDIO_FS_32000)
- hdmi_dbg(hdmi->dev, " 32000\n");
- if(audio->rate & HDMI_AUDIO_FS_44100)
- hdmi_dbg(hdmi->dev, " 44100\n");
- if(audio->rate & HDMI_AUDIO_FS_48000)
- hdmi_dbg(hdmi->dev, " 48000\n");
- if(audio->rate & HDMI_AUDIO_FS_88200)
- hdmi_dbg(hdmi->dev, " 88200\n");
- if(audio->rate & HDMI_AUDIO_FS_96000)
- hdmi_dbg(hdmi->dev, " 96000\n");
- if(audio->rate & HDMI_AUDIO_FS_176400)
- hdmi_dbg(hdmi->dev, " 176400\n");
- if(audio->rate & HDMI_AUDIO_FS_192000)
- hdmi_dbg(hdmi->dev, " 192000\n");
-
- hdmi_dbg(hdmi->dev, "Support audio word lenght: \n");
- if(audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
- hdmi_dbg(hdmi->dev, " 16bit\n");
- if(audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
- hdmi_dbg(hdmi->dev, " 20bit\n");
- if(audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
- hdmi_dbg(hdmi->dev, " 24bit\n");
- }
- hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
-}
-
-/**
- * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
- * @hdmi: handle of hdmi
- * @edid_ok: get EDID data success or not, HDMI_ERROR_SUCESS means success.
- */
-int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
-{
- struct list_head *head = &hdmi->edid.modelist;
- struct fb_monspecs *specs = hdmi->edid.specs;
- struct fb_videomode *modedb = NULL;
- int i, pixclock;
-
- if(edid_ok != HDMI_ERROR_SUCESS) {
- dev_err(hdmi->dev, "warning: EDID error, assume sink as HDMI !!!!");
- hdmi->edid.sink_hdmi = 1;
- }
-
- if(edid_ok != HDMI_ERROR_SUCESS) {
- hdmi->edid.ycbcr444 = 0;
- hdmi->edid.ycbcr422 = 0;
- hdmi->autoconfig = HDMI_DISABLE;
- }
- if(head->next == head) {
- dev_info(hdmi->dev, "warning: no CEA video mode parsed from EDID !!!!");
- // If EDID get error, list all system supported mode.
- // If output mode is set to DVI and EDID is ok, check
- // the output timing.
-
- if(hdmi->edid.sink_hdmi == 0 && specs && specs->modedb_len) {
- /* Get max resolution timing */
- modedb = &specs->modedb[0];
- for (i = 0; i < specs->modedb_len; i++) {
- if(specs->modedb[i].xres > modedb->xres)
- modedb = &specs->modedb[i];
- else if(specs->modedb[i].yres > modedb->yres)
- modedb = &specs->modedb[i];
- }
- // For some monitor, the max pixclock read from EDID is smaller
- // than the clock of max resolution mode supported. We fix it.
- pixclock = PICOS2KHZ(modedb->pixclock);
- pixclock /= 250;
- pixclock *= 250;
- pixclock *= 1000;
- if(pixclock == 148250000)
- pixclock = 148500000;
- if(pixclock > specs->dclkmax)
- specs->dclkmax = pixclock;
- }
-
- for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
- if(modedb) {
- if( (hdmi_mode[i].pixclock < specs->dclkmin) ||
- (hdmi_mode[i].pixclock > specs->dclkmax) ||
- (hdmi_mode[i].refresh < specs->vfmin) ||
- (hdmi_mode[i].refresh > specs->vfmax) ||
- (hdmi_mode[i].xres > modedb->xres) ||
- (hdmi_mode[i].yres > modedb->yres) )
- continue;
- }
- hdmi_add_videomode(&hdmi_mode[i], head);
- }
- }
-
- #ifdef HDMI_DEBUG
- hdmi_show_sink_info(hdmi);
- #endif
- return HDMI_ERROR_SUCESS;
-}
-/**
- * hdmi_videomode_compare - compare 2 videomodes
- * @mode1: first videomode
- * @mode2: second videomode
- *
- * RETURNS:
- * 1 if mode1 > mode2, 0 if mode1 = mode2, -1 mode1 < mode2
- */
-static int hdmi_videomode_compare(const struct fb_videomode *mode1,
- const struct fb_videomode *mode2)
-{
- if(mode1->xres > mode2->xres)
- return 1;
- else if(mode1->xres == mode2->xres)
- {
- if(mode1->yres > mode2->yres)
- return 1;
- else if(mode1->yres == mode2->yres)
- {
- if(mode1->pixclock > mode2->pixclock)
- return 1;
- else if(mode1->pixclock == mode2->pixclock)
- {
- if(mode1->refresh > mode2->refresh)
- return 1;
- else if(mode1->refresh == mode2->refresh)
- return 0;
- }
- }
- }
- return -1;
-}
-/**
- * hdmi_add_videomode: adds videomode entry to modelist
- * @mode: videomode to add
- * @head: struct list_head of modelist
- *
- * NOTES:
- * Will only add unmatched mode entries
- */
-int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head)
-{
- struct list_head *pos;
- struct fb_modelist *modelist, *modelist_new;
- struct fb_videomode *m;
- int i, found = 0;
-
- for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
- {
- m =(struct fb_videomode*) &hdmi_mode[i];
- if (fb_mode_is_equal(m, mode)) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_for_each(pos, head) {
- modelist = list_entry(pos, struct fb_modelist, list);
- m = &modelist->mode;
- if (fb_mode_is_equal(m, mode)) {
- // m == mode
- return 0;
- }
- else
- {
- if(hdmi_videomode_compare(m, mode) == -1) {
- break;
- }
- }
- }
-
- modelist_new = kmalloc(sizeof(struct fb_modelist),
- GFP_KERNEL);
- if (!modelist_new)
- return -ENOMEM;
- modelist_new->mode = hdmi_mode[i];
- list_add_tail(&modelist_new->list, pos);
- }
-
- return 0;
-}
-
-/**
- * hdmi_videomode_to_vic: transverse video mode to vic
- * @vmode: videomode to transverse
- *
- */
-int hdmi_videomode_to_vic(struct fb_videomode *vmode)
-{
- unsigned char vic = 0;
- int i = 0;
-
- for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
- {
- if( vmode->vmode == hdmi_mode[i].vmode &&
- vmode->refresh == hdmi_mode[i].refresh &&
- vmode->xres == hdmi_mode[i].xres &&
- vmode->left_margin == hdmi_mode[i].left_margin &&
- vmode->right_margin == hdmi_mode[i].right_margin &&
- vmode->upper_margin == hdmi_mode[i].upper_margin &&
- vmode->lower_margin == hdmi_mode[i].lower_margin &&
- vmode->hsync_len == hdmi_mode[i].hsync_len &&
- vmode->vsync_len == hdmi_mode[i].vsync_len)
- {
- if( (vmode->vmode == FB_VMODE_NONINTERLACED && vmode->yres == hdmi_mode[i].yres) ||
- (vmode->vmode == FB_VMODE_INTERLACED && vmode->yres == hdmi_mode[i].yres/2))
- {
- vic = hdmi_mode[i].flag;
- break;
- }
- }
- }
- return vic;
-}
-
-/**
- * hdmi_vic_to_videomode: transverse vic mode to video mode
- * @vmode: vic to transverse
- *
- */
-const struct fb_videomode* hdmi_vic_to_videomode(int vic)
-{
- int i;
-
- if(vic == 0)
- return NULL;
-
- for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
- {
- if(hdmi_mode[i].flag == vic)
- return &hdmi_mode[i];
- }
- return NULL;
-}
-
-/**
- * hdmi_find_best_mode: find the video mode nearest to input vic
- * @hdmi:
- * @vic: input vic
- *
- * NOTES:
- * If vic is zero, return the high resolution video mode vic.
- */
-int hdmi_find_best_mode(struct hdmi* hdmi, int vic)
-{
- struct list_head *pos, *head = &hdmi->edid.modelist;
- struct fb_modelist *modelist;
- struct fb_videomode *m = NULL;
- int found = 0;
-
- if(vic)
- {
- list_for_each(pos, head) {
- modelist = list_entry(pos, struct fb_modelist, list);
- m = &modelist->mode;
- if(m->flag == vic)
- {
- found = 1;
- break;
- }
- }
- }
- if( (vic == 0 || found == 0) && head->next != head)
- {
- modelist = list_entry(head->next, struct fb_modelist, list);
- m = &modelist->mode;
- }
- if(m != NULL)
- return m->flag;
- else
- return 0;
-}
-
-const char *hdmi_get_video_mode_name(unsigned char vic)
-{
- int i;
-
- for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
- {
- if(vic == hdmi_mode[i].flag)
- break;
- }
- if(i == ARRAY_SIZE(hdmi_mode))
- return NULL;
- else
- return hdmi_mode[i].name;
-}
-
-/**
- * hdmi_switch_fb: switch lcdc mode to required video mode
- * @hdmi:
- * @type:
- *
- * NOTES:
- *
- */
-int hdmi_switch_fb(struct hdmi *hdmi, int vic)
-{
- int rc = 0;
-
- if(hdmi->vic == 0)
- hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
-
- if(hdmi->lcdc == NULL || hdmi->lcdc->screen == NULL) {
- dev_err(hdmi->dev, "lcdc %d not exist\n", HDMI_SOURCE_DEFAULT);
- return -1;
- }
-
- rc = hdmi_set_info(hdmi->lcdc->screen, hdmi->vic);
-
- if(rc == 0) {
- rk_fb_switch_screen(hdmi->lcdc->screen, 1, HDMI_SOURCE_DEFAULT);
- rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, HDMI_SOURCE_DEFAULT);
- }
- return rc;
-}
-
-/**
- * hdmi_get_status: get hdmi hotplug status
- *
- * NOTES:
- *
- */
-int hdmi_get_hotplug(void)
-{
- if(hdmi)
- return hdmi->hotplug;
- else
- return HDMI_HPD_REMOVED;
-}
\ No newline at end of file
+++ /dev/null
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/display-sys.h>
-#include <linux/interrupt.h>
-#include "rk30_hdmi.h"
-
-static int hdmi_get_enable(struct rk_display_device *device)
-{
- struct hdmi *hdmi = device->priv_data;
- int enable;
-
- mutex_lock(&hdmi->enable_mutex);
- enable = hdmi->enable;
- mutex_unlock(&hdmi->enable_mutex);
-
- return enable;
-}
-
-static int hdmi_set_enable(struct rk_display_device *device, int enable)
-{
- struct hdmi *hdmi = device->priv_data;
-
- mutex_lock(&hdmi->enable_mutex);
- if(hdmi->enable == enable) {
- mutex_unlock(&hdmi->enable_mutex);
- return 0;
- }
- hdmi->enable = enable;
-
- if(hdmi->suspend ) {
- mutex_unlock(&hdmi->enable_mutex);
- return 0;
- }
-
- if(enable == 0) {
- disable_irq(hdmi->irq);
- mutex_unlock(&hdmi->enable_mutex);
- hdmi->command = HDMI_CONFIG_ENABLE;
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
- }
- else {
- enable_irq(hdmi->irq);
- mutex_unlock(&hdmi->enable_mutex);
- }
- return 0;
-}
-
-static int hdmi_get_status(struct rk_display_device *device)
-{
- struct hdmi *hdmi = device->priv_data;
- if(hdmi->hotplug == HDMI_HPD_ACTIVED)
- return 1;
- else
- return 0;
-}
-
-static int hdmi_get_modelist(struct rk_display_device *device, struct list_head **modelist)
-{
- struct hdmi *hdmi = device->priv_data;
- if(!hdmi->hotplug)
- return -1;
- *modelist = &hdmi->edid.modelist;
- return 0;
-}
-
-static int hdmi_set_mode(struct rk_display_device *device, struct fb_videomode *mode)
-{
- struct hdmi *hdmi = device->priv_data;
- int vic = hdmi_videomode_to_vic(mode);
-
- if(!hdmi->hotplug)
- return -1;
- hdmi->autoconfig = HDMI_DISABLE;
- if(vic && hdmi->vic != vic)
- {
- hdmi->vic = vic;
- hdmi->command = HDMI_CONFIG_VIDEO;
- init_completion(&hdmi->complete);
- hdmi->wait = 1;
- queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
- wait_for_completion_interruptible_timeout(&hdmi->complete,
- msecs_to_jiffies(10000));
- }
- return 0;
-}
-
-static int hdmi_get_mode(struct rk_display_device *device, struct fb_videomode *mode)
-{
- struct hdmi *hdmi = device->priv_data;
- struct fb_videomode *vmode;
-
- if(!hdmi->hotplug)
- return -1;
-
- vmode = (struct fb_videomode*) hdmi_vic_to_videomode(hdmi->vic);
- if(unlikely(vmode == NULL))
- return -1;
- *mode = *vmode;
- return 0;
-}
-
-static int hdmi_set_scale(struct rk_display_device *device, int direction, int value)
-{
- struct hdmi *hdmi = device->priv_data;
-
- if(!hdmi || value < 0 || value > 100)
- return -1;
-
- if(direction == DISPLAY_SCALE_X)
- hdmi->xscale = value;
- else if(direction == DISPLAY_SCALE_Y)
- hdmi->yscale = value;
- else
- return -1;
- rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, HDMI_SOURCE_DEFAULT);
- return 0;
-}
-
-static int hdmi_get_scale(struct rk_display_device *device, int direction)
-{
- struct hdmi *hdmi = device->priv_data;
-
- if(!hdmi)
- return -1;
-
- if(direction == DISPLAY_SCALE_X)
- return hdmi->xscale;
- else if(direction == DISPLAY_SCALE_Y)
- return hdmi->yscale;
- else
- return -1;
-}
-
-struct rk_display_ops hdmi_display_ops = {
- .setenable = hdmi_set_enable,
- .getenable = hdmi_get_enable,
- .getstatus = hdmi_get_status,
- .getmodelist = hdmi_get_modelist,
- .setmode = hdmi_set_mode,
- .getmode = hdmi_get_mode,
- .setscale = hdmi_set_scale,
- .getscale = hdmi_get_scale,
-};
-
-#if 1
-static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
-{
- device->owner = THIS_MODULE;
- strcpy(device->type, "HDMI");
- device->priority = DISPLAY_PRIORITY_HDMI;
-// device->name = kmalloc(strlen(name), GFP_KERNEL);
-// if(device->name)
-// {
-// strcpy(device->name, name);
-// }
- device->priv_data = devdata;
- device->ops = &hdmi_display_ops;
- return 1;
-}
-
-static struct rk_display_driver display_hdmi = {
- .probe = hdmi_display_probe,
-};
-
-static struct rk_display_device *display_device_hdmi = NULL;
-
-void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent)
-{
- display_device_hdmi = rk_display_device_register(&display_hdmi, parent, hdmi);
-}
-
-void hdmi_unregister_display_sysfs(struct hdmi *hdmi)
-{
- if(display_device_hdmi)
- rk_display_device_unregister(display_device_hdmi);
-}
-#endif
\ No newline at end of file
+++ /dev/null
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include "rk30_hdmi.h"
-#include "rk30_hdmi_hw.h"
-
-#ifdef CONFIG_HDMI_RK30_CTL_CODEC
-extern void codec_set_spk(bool on);
-#endif
-
-#define HDMI_MAX_TRY_TIMES 1
-
-static char *envp[] = {"INTERFACE=HDMI", NULL};
-
-static void hdmi_sys_show_state(int state)
-{
- switch(state)
- {
- case HDMI_SLEEP:
- dev_printk(KERN_INFO, hdmi->dev, "HDMI_SLEEP\n");
- break;
- case HDMI_INITIAL:
- dev_printk(KERN_INFO, hdmi->dev, "HDMI_INITIAL\n");
- break;
- case WAIT_HOTPLUG:
- dev_printk(KERN_INFO, hdmi->dev, "WAIT_HOTPLUG\n");
- break;
- case READ_PARSE_EDID:
- dev_printk(KERN_INFO, hdmi->dev, "READ_PARSE_EDID\n");
- break;
- case WAIT_HDMI_ENABLE:
- dev_printk(KERN_INFO, hdmi->dev, "WAIT_HDMI_ENABLE\n");
- break;
- case SYSTEM_CONFIG:
- dev_printk(KERN_INFO, hdmi->dev, "SYSTEM_CONFIG\n");
- break;
- case CONFIG_VIDEO:
- dev_printk(KERN_INFO, hdmi->dev, "CONFIG_VIDEO\n");
- break;
- case CONFIG_AUDIO:
- dev_printk(KERN_INFO, hdmi->dev, "CONFIG_AUDIO\n");
- break;
- case PLAY_BACK:
- dev_printk(KERN_INFO, hdmi->dev, "PLAY_BACK\n");
- break;
- default:
- dev_printk(KERN_INFO, hdmi->dev, "Unkown State %d\n", state);
- break;
- }
-}
-
-int hdmi_sys_init(void)
-{
- hdmi->pwr_mode = PWR_SAVE_MODE_A;
- hdmi->hotplug = HDMI_HPD_REMOVED;
- hdmi->state = HDMI_SLEEP;
- hdmi->enable = HDMI_ENABLE;
- hdmi->autoconfig = HDMI_AUTO_CONFIGURE;
- hdmi->display = HDMI_DISABLE;
-
- hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
- hdmi->audio.channel = HDMI_AUDIO_DEFAULT_CHANNEL;
- hdmi->audio.rate = HDMI_AUDIO_DEFAULT_RATE;
- hdmi->audio.word_length = HDMI_AUDIO_DEFAULT_WORD_LENGTH;
-
- memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
- INIT_LIST_HEAD(&hdmi->edid.modelist);
- return 0;
-}
-
-void hdmi_sys_remove(void)
-{
- fb_destroy_modelist(&hdmi->edid.modelist);
- if(hdmi->edid.audio)
- kfree(hdmi->edid.audio);
- if(hdmi->edid.specs)
- {
- if(hdmi->edid.specs->modedb)
- kfree(hdmi->edid.specs->modedb);
- kfree(hdmi->edid.specs);
- }
- memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
- INIT_LIST_HEAD(&hdmi->edid.modelist);
- hdmi->display = HDMI_DISABLE;
- rk_fb_switch_screen(hdmi->lcdc->screen, 0, HDMI_SOURCE_DEFAULT);
- kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
- #ifdef CONFIG_SWITCH
- switch_set_state(&(hdmi->switch_hdmi), 0);
- #endif
- #ifdef CONFIG_HDMI_RK30_CTL_CODEC
- codec_set_spk(1);
- #endif
-}
-
-static void hdmi_sys_sleep(void)
-{
- mutex_lock(&hdmi->enable_mutex);
- if(hdmi->enable)
- disable_irq(hdmi->irq);
- hdmi->state = HDMI_SLEEP;
- rk30_hdmi_removed();
- if(hdmi->enable)
- enable_irq(hdmi->irq);
- mutex_unlock(&hdmi->enable_mutex);
-}
-
-static int hdmi_process_command(void)
-{
- int change, state = hdmi->state;
-
- change = hdmi->command;
- if(change != HDMI_CONFIG_NONE)
- {
- hdmi->command = HDMI_CONFIG_NONE;
- switch(change)
- {
- case HDMI_CONFIG_ENABLE:
- /* disable HDMI */
- mutex_lock(&hdmi->enable_mutex);
- if(!hdmi->enable || hdmi->suspend)
- {
- if(hdmi->hotplug == HDMI_HPD_ACTIVED)
- hdmi_sys_remove();
- hdmi->state = HDMI_SLEEP;
- hdmi->hotplug = HDMI_HPD_REMOVED;
- rk30_hdmi_removed();
- state = HDMI_SLEEP;
- }
- mutex_unlock(&hdmi->enable_mutex);
- if(hdmi->wait == 1) {
- complete(&hdmi->complete);
- hdmi->wait = 0;
- }
- break;
- case HDMI_CONFIG_COLOR:
- if(state > CONFIG_VIDEO)
- state = CONFIG_VIDEO;
- break;
- case HDMI_CONFIG_HDCP:
- break;
- case HDMI_CONFIG_DISPLAY:
- break;
- case HDMI_CONFIG_AUDIO:
- if(state > CONFIG_AUDIO)
- state = CONFIG_AUDIO;
- break;
- case HDMI_CONFIG_VIDEO:
- default:
- if(state > SYSTEM_CONFIG)
- state = SYSTEM_CONFIG;
- else
- {
- if(hdmi->wait == 1) {
- complete(&hdmi->complete);
- hdmi->wait = 0;
- }
- }
- break;
- }
- }
- else if(state == HDMI_SLEEP)
- state = WAIT_HOTPLUG;
- return state;
-}
-
-static DEFINE_MUTEX(work_mutex);
-
-void hdmi_work(struct work_struct *work)
-{
- int hotplug, state_last;
- int rc = HDMI_ERROR_SUCESS, trytimes = 0;
- struct rk30_hdmi_video_para video;
-
- mutex_lock(&work_mutex);
- /* Process hdmi command */
- hdmi->state = hdmi_process_command();
-
- if(!hdmi->enable || hdmi->suspend) {
- mutex_unlock(&work_mutex);
- return;
- }
- hotplug = rk30_hdmi_detect_hotplug();
- hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
-
- if(hotplug != hdmi->hotplug)
- {
- if(hotplug == HDMI_HPD_ACTIVED){
- hdmi->state = READ_PARSE_EDID;
- }
- else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
- hdmi_sys_remove();
- hdmi->hotplug = hotplug;
- if(hotplug == HDMI_HPD_REMOVED)
- hdmi_sys_sleep();
- else {
- hdmi->state = WAIT_HOTPLUG;
- rk30_hdmi_removed();
- }
- if(hdmi->wait == 1) {
- complete(&hdmi->complete);
- hdmi->wait = 0;
- }
- mutex_unlock(&work_mutex);
- return;
- }
- else if(hotplug == HDMI_HPD_REMOVED) {
- hdmi->state = HDMI_SLEEP;
- rk30_hdmi_removed();
- }
- hdmi->hotplug = hotplug;
- }
- else if(hotplug == HDMI_HPD_REMOVED)
- hdmi_sys_sleep();
-
- do {
- hdmi_sys_show_state(hdmi->state);
- state_last = hdmi->state;
- switch(hdmi->state)
- {
- case READ_PARSE_EDID:
- rc = hdmi_sys_parse_edid(hdmi);
- if(rc == HDMI_ERROR_SUCESS)
- {
- hdmi->state = SYSTEM_CONFIG;
- kobject_uevent_env(&hdmi->dev->kobj, KOBJ_ADD, envp);
- #ifdef CONFIG_SWITCH
- switch_set_state(&(hdmi->switch_hdmi), 1);
- #endif
- #ifdef CONFIG_HDMI_RK30_CTL_CODEC
- codec_set_spk(0);
- #endif
- }
- break;
- case SYSTEM_CONFIG:
- if(hdmi->autoconfig)
- hdmi->vic = hdmi_find_best_mode(hdmi, 0);
- else
- hdmi->vic = hdmi_find_best_mode(hdmi, hdmi->vic);
- rc = hdmi_switch_fb(hdmi, hdmi->vic);
- if(rc == HDMI_ERROR_SUCESS)
- hdmi->state = CONFIG_VIDEO;
- break;
- case CONFIG_VIDEO:
- hdmi->display = HDMI_DISABLE;
- video.vic = hdmi->vic;
- video.input_mode = VIDEO_INPUT_RGB_YCBCR_444;
- video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
- video.output_mode = hdmi->edid.sink_hdmi;
-
- if(hdmi->edid.ycbcr444)
- video.output_color = VIDEO_OUTPUT_YCBCR444;
- else if(hdmi->edid.ycbcr422)
- video.output_color = VIDEO_OUTPUT_YCBCR422;
- else
- video.output_color = VIDEO_OUTPUT_RGB444;
- // For DVI, output RGB
- if(hdmi->edid.sink_hdmi == 0)
- video.output_color = VIDEO_OUTPUT_RGB444;
-
- rc = rk30_hdmi_config_video(&video);
- if(rc == HDMI_ERROR_SUCESS)
- {
- if(hdmi->edid.sink_hdmi)
- hdmi->state = CONFIG_AUDIO;
- else
- hdmi->state = PLAY_BACK;
- }
- break;
- case CONFIG_AUDIO:
- rc = rk30_hdmi_config_audio(&(hdmi->audio));
-
- if(rc == HDMI_ERROR_SUCESS)
- hdmi->state = PLAY_BACK;
- break;
- case PLAY_BACK:
- if(hdmi->display != HDMI_ENABLE) {
- rk30_hdmi_control_output(HDMI_ENABLE);
- hdmi->display = HDMI_ENABLE;
- if(hdmi->hdcp_cb) {
- hdmi->hdcp_cb();
- }
- }
-
- if(hdmi->wait == 1) {
- complete(&hdmi->complete);
- hdmi->wait = 0;
- }
- break;
- default:
- break;
- }
- if(rc != HDMI_ERROR_SUCESS)
- {
- trytimes++;
- msleep(10);
- }
- if(hdmi->state != state_last)
- trytimes = 0;
-
- }while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
-
-// if(trytimes == HDMI_MAX_TRY_TIMES)
-// {
-// if(hdmi->hotplug) {
-// hdmi_sys_remove();
-// hdmi->hotplug = HDMI_HPD_REMOVED;
-// hdmi_sys_sleep();
-//
-// }
-// }
- hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
- mutex_unlock(&work_mutex);
-}
\ No newline at end of file
#ifndef __RK_HDMI_H__
#define __RK_HDMI_H__
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/display-sys.h>
+#ifdef CONFIG_SWITCH
+#include <linux/switch.h>
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <asm/atomic.h>
+#include<linux/rk_screen.h>
+#include <linux/rk_fb.h>
+
+/* default HDMI output video mode */
+#define HDMI_VIDEO_DEFAULT_MODE HDMI_1280x720p_60Hz//HDMI_1920x1080p_60Hz
+
+// HDMI video source
+enum {
+ HDMI_SOURCE_LCDC0 = 0,
+ HDMI_SOURCE_LCDC1 = 1
+};
+
+/* default HDMI video source */
+#define HDMI_SOURCE_DEFAULT HDMI_SOURCE_LCDC1
+/* If HDMI_ENABLE, system will auto configure output mode according to EDID
+ * If HDMI_DISABLE, system will output mode according to macro HDMI_VIDEO_DEFAULT_MODE
+ */
+#define HDMI_AUTO_CONFIGURE HDMI_ENABLE
+
+/* default HDMI output audio mode */
+#define HDMI_AUDIO_DEFAULT_CHANNEL 2
+#define HDMI_AUDIO_DEFAULT_RATE HDMI_AUDIO_FS_44100
+#define HDMI_AUDIO_DEFAULT_WORD_LENGTH HDMI_AUDIO_WORD_LENGTH_16bit
+enum {
+ VIDEO_INPUT_RGB_YCBCR_444 = 0,
+ VIDEO_INPUT_YCBCR422,
+ VIDEO_INPUT_YCBCR422_EMBEDDED_SYNC,
+ VIDEO_INPUT_2X_CLOCK,
+ VIDEO_INPUT_2X_CLOCK_EMBEDDED_SYNC,
+ VIDEO_INPUT_RGB444_DDR,
+ VIDEO_INPUT_YCBCR422_DDR
+};
+enum {
+ VIDEO_OUTPUT_RGB444 = 0,
+ VIDEO_OUTPUT_YCBCR444,
+ VIDEO_OUTPUT_YCBCR422
+};
+enum {
+ VIDEO_INPUT_COLOR_RGB = 0,
+ VIDEO_INPUT_COLOR_YCBCR
+};
/********************************************************************
** ½á¹¹¶¨Òå *
********************************************************************/
};
extern const struct fb_videomode hdmi_mode[];
+/* RK HDMI Video Configure Parameters */
+struct hdmi_video_para {
+ int vic;
+ int input_mode; //input video data interface
+ int input_color; //input video color mode
+ int output_mode; //output hdmi or dvi
+ int output_color; //output video color mode
+};
+struct hdmi {
+ struct device *dev;
+ struct clk *hclk; //HDMI AHP clk
+ int id;
+ int regbase;
+ int irq;
+ int regbase_phy;
+ int regsize_phy;
+ struct rk_lcdc_device_driver *lcdc;
+
+ #ifdef CONFIG_SWITCH
+ struct switch_dev switch_hdmi;
+ #endif
+
+ struct workqueue_struct *workqueue;
+ struct delayed_work delay_work;
+
+ spinlock_t irq_lock;
+ struct mutex enable_mutex;
+
+ int wait;
+ struct completion complete;
+
+ int suspend;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+
+ struct hdmi_edid edid;
+ int enable; // Enable HDMI output or not
+ int vic; // HDMI output video mode code
+ struct hdmi_audio audio; // HDMI output audio type.
+
+ int pwr_mode; // power mode
+ int hotplug; // hot plug status
+ int state; // hdmi state machine status
+ int autoconfig; // if true, auto config hdmi output mode according to EDID.
+ int command; // HDMI configuration command
+ int display; // HDMI display status
+ int xscale; // x direction scale value
+ int yscale; // y directoon scale value
+ int tmdsclk; // TDMS Clock frequency
+
+
+ int (*hdmi_removed)(void);
+ void (*control_output)(int enable);
+ int (*config_video)(struct hdmi_video_para *vpara);
+ int (*config_audio)(struct hdmi_audio *audio);
+ int (*detect_hotplug)(void);
+ // call back for edid
+ int (*read_edid)(int block, unsigned char *buff);
+
+ // call back for hdcp operatoion
+ void (*hdcp_cb)(void);
+ void (*hdcp_irq_cb)(int);
+ int (*hdcp_power_on_cb)(void);
+ void (*hdcp_power_off_cb)(void);
+};
#define hdmi_err(dev, format, arg...) \
dev_printk(KERN_ERR , dev , format , ## arg)
#define hdmi_dbg(dev, format, arg...)
#endif
+extern struct hdmi *hdmi;
+extern struct hdmi *hdmi_register(int extra);
+extern void hdmi_unregister(struct hdmi *hdmi);
extern int hdmi_get_hotplug(void);
extern int hdmi_set_info(struct rk29fb_screen *screen, unsigned int vic);
extern void hdmi_init_lcdc(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info);
+extern int hdmi_sys_init(void);
+extern int hdmi_sys_parse_edid(struct hdmi* hdmi);
+extern const char *hdmi_get_video_mode_name(unsigned char vic);
+extern int hdmi_videomode_to_vic(struct fb_videomode *vmode);
+extern const struct fb_videomode* hdmi_vic_to_videomode(int vic);
+extern int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head);
+extern struct hdmi_video_timing * hdmi_find_mode(int vic);
+extern int hdmi_find_best_mode(struct hdmi* hdmi, int vic);
+extern int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok);
+extern int hdmi_switch_fb(struct hdmi *hdmi, int vic);
+extern void hdmi_sys_remove(void);
+
#endif
--- /dev/null
+#include <linux/kernel.h>\r
+#include <linux/delay.h>\r
+#include <linux/module.h>\r
+#include <linux/err.h>\r
+#include <linux/slab.h>\r
+#include <linux/hdmi.h>\r
+#include <linux/input.h>\r
+\r
+\r
+struct class *hdmi_class;\r
+struct hdmi_id_ref_info {\r
+ struct hdmi *hdmi;\r
+ int id;\r
+ int ref;\r
+}ref_info[HDMI_MAX_ID];\r
+#ifdef CONFIG_SYSFS\r
+\r
+extern int hdmi_create_attrs(struct hdmi *hdmi);\r
+extern void hdmi_remove_attrs(struct hdmi *hdmi);\r
+\r
+#else\r
+\r
+static inline int hdmi_create_attrs(struct hdmi *hdmi)\r
+{ return 0; }\r
+static inline void hdmi_remove_attrs(struct hdmi *hdmi) {}\r
+\r
+#endif /* CONFIG_SYSFS */\r
+static void __hdmi_changed(struct hdmi *hdmi)\r
+{\r
+ int precent;\r
+ \r
+ mutex_lock(&hdmi->lock);\r
+ precent = hdmi->ops->hdmi_precent(hdmi);\r
+ if(precent && (hdmi->mode == DISP_ON_LCD) && hdmi->display_on){\r
+ if(hdmi->ops->insert(hdmi) == 0){\r
+ hdmi->mode = hdmi->display_on;\r
+ kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE);\r
+ }\r
+ else\r
+ hdmi_dbg(hdmi->dev, "insert error\n");\r
+ hdmi_set_backlight(hdmi->display_on==DISP_ON_HDMI?HDMI_DISABLE: HDMI_ENABLE);\r
+\r
+ }\r
+ else if(precent &&(hdmi->mode != hdmi->display_on)&& hdmi->display_on){\r
+ hdmi->mode = hdmi->display_on;\r
+ hdmi_set_backlight(hdmi->display_on==DISP_ON_HDMI?HDMI_DISABLE: HDMI_ENABLE); \r
+ }\r
+ else if((!precent || !hdmi->display_on) && hdmi->mode != DISP_ON_LCD){\r
+ if(hdmi->ops->remove(hdmi) == 0){\r
+ hdmi->mode = DISP_ON_LCD;\r
+ hdmi_set_backlight(HDMI_ENABLE);\r
+ kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE);\r
+ }\r
+ else\r
+ hdmi_dbg(hdmi->dev, "remove error\n");\r
+ }\r
+ mutex_unlock(&hdmi->lock);\r
+ return;\r
+}\r
+\r
+void hdmi_changed(struct hdmi *hdmi, int msec)\r
+{ \r
+ schedule_delayed_work(&hdmi->work, msecs_to_jiffies(msec));\r
+ return;\r
+}\r
+void hdmi_suspend(struct hdmi *hdmi)\r
+{\r
+ del_timer(&hdmi->timer);\r
+ flush_delayed_work(&hdmi->work);\r
+ if(hdmi->mode != DISP_ON_LCD){\r
+ hdmi->ops->remove(hdmi);\r
+ hdmi->mode = DISP_ON_LCD;\r
+ }\r
+ return;\r
+}\r
+void hdmi_resume(struct hdmi *hdmi)\r
+{\r
+ mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(10));\r
+ return;\r
+}\r
+\r
+static void hdmi_changed_work(struct work_struct *work)\r
+{\r
+ struct hdmi *hdmi = container_of(work, struct hdmi,\r
+ work.work);\r
+ \r
+ __hdmi_changed(hdmi);\r
+ return;\r
+}\r
+\r
+void *hdmi_priv(struct hdmi *hdmi)\r
+{\r
+ return (void *)hdmi->priv;\r
+}\r
+static void hdmi_detect_timer(unsigned long data)\r
+{\r
+ struct hdmi *hdmi = (struct hdmi*)data;\r
+ \r
+ int precent = hdmi->ops->hdmi_precent(hdmi);\r
+\r
+ if((precent && hdmi->mode == DISP_ON_LCD) ||\r
+ (!precent && hdmi->mode != DISP_ON_LCD))\r
+ hdmi_changed(hdmi, 100);\r
+ mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200));\r
+}\r
+struct hdmi *hdmi_register(int extra, struct device *parent)\r
+{\r
+ int rc = 0, i;\r
+ char name[8];\r
+ struct hdmi *hdmi = kzalloc(sizeof(struct hdmi)+ extra, GFP_KERNEL);\r
+\r
+ if(!hdmi)\r
+ return NULL;\r
+ for(i = 0; i < HDMI_MAX_ID; i++) \r
+ {\r
+ if(ref_info[i].ref == 0)\r
+ {\r
+ ref_info[i].ref = 1;\r
+ hdmi->id = i;\r
+ break;\r
+ }\r
+ }\r
+ if(i == HDMI_MAX_ID)\r
+ {\r
+ kfree(hdmi);\r
+ return NULL;\r
+ }\r
+ sprintf(name, "hdmi-%d", hdmi->id);\r
+ \r
+ hdmi->dev = device_create(hdmi_class, parent, 0,\r
+ "%s", name);\r
+ if (IS_ERR(hdmi->dev)) {\r
+ rc = PTR_ERR(hdmi->dev);\r
+ goto dev_create_failed;\r
+ }\r
+\r
+ dev_set_drvdata(hdmi->dev, hdmi);\r
+ ref_info[i].hdmi = hdmi;\r
+\r
+ INIT_DELAYED_WORK(&hdmi->work, hdmi_changed_work);\r
+\r
+ rc = hdmi_create_attrs(hdmi);\r
+ if (rc)\r
+ goto create_attrs_failed;\r
+\r
+ goto success;\r
+\r
+create_attrs_failed:\r
+ device_unregister(hdmi->dev);\r
+dev_create_failed:\r
+ hdmi_remove_attrs(hdmi);\r
+ kfree(hdmi);\r
+ return NULL;\r
+success:\r
+ mutex_init(&hdmi->lock);\r
+ setup_timer(&hdmi->timer, hdmi_detect_timer,(unsigned long)hdmi);\r
+ mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200));\r
+ return hdmi;\r
+}\r
+void hdmi_unregister(struct hdmi *hdmi)\r
+{\r
+ int id;\r
+\r
+ if(!hdmi)\r
+ return;\r
+ id = hdmi->id;\r
+ del_timer(&hdmi->timer);\r
+ flush_scheduled_work();\r
+ hdmi_remove_attrs(hdmi);\r
+ device_unregister(hdmi->dev);\r
+\r
+ kfree(hdmi);\r
+ hdmi = NULL;\r
+ ref_info[id].ref = 0;\r
+ ref_info[id].hdmi = NULL;\r
+}\r
+struct hdmi *get_hdmi_struct(int nr)\r
+{\r
+ if(ref_info[nr].ref == 0)\r
+ return NULL;\r
+ else\r
+ return ref_info[nr].hdmi;\r
+}\r
+int hdmi_is_insert(void)\r
+{\r
+ struct hdmi *hdmi = get_hdmi_struct(0);\r
+\r
+ if(hdmi && hdmi->ops && hdmi->ops->hdmi_precent)\r
+ return hdmi->ops->hdmi_precent(hdmi);\r
+ else\r
+ return 0;\r
+}\r
+int hdmi_get_scale(void)\r
+{\r
+ struct hdmi* hdmi = get_hdmi_struct(0);\r
+ if(!hdmi)\r
+ return 100;\r
+ else if(hdmi->mode != DISP_ON_LCD)\r
+ return hdmi->scale;\r
+ else\r
+ return 100;\r
+}\r
+\r
+int hdmi_set_scale(int event, char *data, int len)\r
+{\r
+ int result;\r
+ struct hdmi* hdmi = get_hdmi_struct(0);\r
+\r
+ if(!hdmi)\r
+ return -1;\r
+ if(len != 4)\r
+ return -1;\r
+ if(fb_get_video_mode() || hdmi->mode == DISP_ON_LCD)\r
+ return -1;\r
+\r
+ result = data[0] | data[1]<<1 | data[2]<<2;\r
+ if(event != MOUSE_NONE && (result & event) != event)\r
+ return -1;\r
+\r
+ hdmi->scale += data[3];\r
+ \r
+ hdmi->scale = (hdmi->scale>100)?100:hdmi->scale;\r
+ hdmi->scale = (hdmi->scale<MIN_SCALE)?MIN_SCALE:hdmi->scale;\r
+ return 0; \r
+}\r
+\r
+static int __init hdmi_class_init(void)\r
+{\r
+ int i;\r
+ \r
+ hdmi_class = class_create(THIS_MODULE, "hdmi");\r
+\r
+ if (IS_ERR(hdmi_class))\r
+ return PTR_ERR(hdmi_class);\r
+ for(i = 0; i < HDMI_MAX_ID; i++) {\r
+ ref_info[i].id = i;\r
+ ref_info[i].ref = 0;\r
+ ref_info[i].hdmi = NULL;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static void __exit hdmi_class_exit(void)\r
+{\r
+ class_destroy(hdmi_class);\r
+}\r
+EXPORT_SYMBOL(hdmi_changed);\r
+EXPORT_SYMBOL(hdmi_register);\r
+EXPORT_SYMBOL(hdmi_unregister);\r
+EXPORT_SYMBOL(get_hdmi_struct);\r
+\r
+subsys_initcall(hdmi_class_init);\r
+module_exit(hdmi_class_exit);\r
+\r
--- /dev/null
+#include "rk_hdmi.h"\r
+#include "../../edid.h"\r
+\r
+#define hdmi_edid_error(fmt, ...) \\r
+ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)\r
+\r
+#if 0\r
+#define hdmi_edid_debug(fmt, ...) \\r
+ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)\r
+#else\r
+#define hdmi_edid_debug(fmt, ...) \r
+#endif\r
+\r
+typedef enum HDMI_EDID_ERRORCODE\r
+{\r
+ E_HDMI_EDID_SUCCESS = 0,\r
+ E_HDMI_EDID_PARAM,\r
+ E_HDMI_EDID_HEAD,\r
+ E_HDMI_EDID_CHECKSUM,\r
+ E_HDMI_EDID_VERSION,\r
+ E_HDMI_EDID_UNKOWNDATA,\r
+ E_HDMI_EDID_NOMEMORY\r
+}HDMI_EDID_ErrorCode;\r
+\r
+static const unsigned int double_aspect_vic[] = {3, 7, 9, 11, 13, 15, 18, 22, 24, 26, 28, 30, 36, 38, 43, 45, 49, 51, 53, 55, 57, 59};\r
+static int hdmi_edid_checksum(unsigned char *buf)\r
+{\r
+ int i;\r
+ int checksum = 0;\r
+ \r
+ for(i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)\r
+ checksum += buf[i]; \r
+ \r
+ checksum &= 0xff;\r
+ \r
+ if(checksum == 0)\r
+ return E_HDMI_EDID_SUCCESS;\r
+ else\r
+ return E_HDMI_EDID_CHECKSUM;\r
+}\r
+\r
+/*\r
+ @Des Parse Detail Timing Descriptor.\r
+ @Param buf : pointer to DTD data.\r
+ @Param pvic: VIC of DTD descripted.\r
+ */\r
+static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)\r
+{\r
+ mode->xres = H_ACTIVE;\r
+ mode->yres = V_ACTIVE;\r
+ mode->pixclock = PIXEL_CLOCK;\r
+// mode->pixclock /= 1000;\r
+// mode->pixclock = KHZ2PICOS(mode->pixclock);\r
+ mode->right_margin = H_SYNC_OFFSET;\r
+ mode->left_margin = (H_ACTIVE + H_BLANKING) -\r
+ (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);\r
+ mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -\r
+ V_SYNC_WIDTH;\r
+ mode->lower_margin = V_SYNC_OFFSET;\r
+ mode->hsync_len = H_SYNC_WIDTH;\r
+ mode->vsync_len = V_SYNC_WIDTH;\r
+ if (HSYNC_POSITIVE)\r
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;\r
+ if (VSYNC_POSITIVE)\r
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;\r
+ mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *\r
+ (V_ACTIVE + V_BLANKING));\r
+ if (INTERLACED) {\r
+ mode->yres *= 2;\r
+ mode->upper_margin *= 2;\r
+ mode->lower_margin *= 2;\r
+ mode->vsync_len *= 2;\r
+ mode->vmode |= FB_VMODE_INTERLACED;\r
+ }\r
+ mode->flag = FB_MODE_IS_DETAILED;\r
+\r
+ hdmi_edid_debug("<<<<<<<<Detailed Time>>>>>>>>>\n");\r
+ hdmi_edid_debug("%d KHz Refresh %d Hz", PIXEL_CLOCK/1000, mode->refresh);\r
+ hdmi_edid_debug("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,\r
+ H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);\r
+ hdmi_edid_debug("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,\r
+ V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);\r
+ hdmi_edid_debug("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",\r
+ (VSYNC_POSITIVE) ? "+" : "-");\r
+ return E_HDMI_EDID_SUCCESS;\r
+}\r
+\r
+static int hdmi_edid_parse_base(unsigned char *buf, int *extend_num, struct hdmi_edid *pedid)\r
+{\r
+ int rc, i;\r
+ \r
+ if(buf == NULL || extend_num == NULL)\r
+ return E_HDMI_EDID_PARAM;\r
+ \r
+ #ifdef DEBUG \r
+ for(i = 0; i < HDMI_EDID_BLOCK_SIZE; i++)\r
+ {\r
+ hdmi_edid_debug("%02x ", buf[i]&0xff);\r
+ if((i+1) % 16 == 0)\r
+ hdmi_edid_debug("\n");\r
+ }\r
+ #endif\r
+ \r
+ // Check first 8 byte to ensure it is an edid base block.\r
+ if( buf[0] != 0x00 ||\r
+ buf[1] != 0xFF ||\r
+ buf[2] != 0xFF ||\r
+ buf[3] != 0xFF ||\r
+ buf[4] != 0xFF ||\r
+ buf[5] != 0xFF ||\r
+ buf[6] != 0xFF ||\r
+ buf[7] != 0x00)\r
+ {\r
+ hdmi_edid_error("[EDID] check header error\n");\r
+ return E_HDMI_EDID_HEAD;\r
+ }\r
+ \r
+ *extend_num = buf[0x7e];\r
+ #ifdef DEBUG\r
+ hdmi_edid_debug("[EDID] extend block num is %d\n", buf[0x7e]);\r
+ #endif\r
+ \r
+ // Checksum\r
+ rc = hdmi_edid_checksum(buf);\r
+ if( rc != E_HDMI_EDID_SUCCESS)\r
+ {\r
+ hdmi_edid_error("[EDID] base block checksum error\n");\r
+ return E_HDMI_EDID_CHECKSUM;\r
+ }\r
+\r
+ pedid->specs = kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);\r
+ if(pedid->specs == NULL)\r
+ return E_HDMI_EDID_NOMEMORY;\r
+ \r
+ fb_edid_to_monspecs(buf, pedid->specs);\r
+ \r
+ return E_HDMI_EDID_SUCCESS;\r
+}\r
+\r
+// Parse CEA Short Video Descriptor\r
+static int hdmi_edid_get_cea_svd(unsigned char *buf, struct hdmi_edid *pedid)\r
+{\r
+ const struct fb_videomode *mode;\r
+ int count, i, j, vic;\r
+\r
+ count = buf[0] & 0x1F;\r
+ for(i = 0; i < count; i++)\r
+ {\r
+ hdmi_edid_debug("[EDID-CEA] %02x VID %d native %d\n", buf[1 + i], buf[1 + i] & 0x7f, buf[1 + i] >> 7);\r
+ vic = buf[1 + i] & 0x7f;\r
+ for(j = 0; j < ARRAY_SIZE(double_aspect_vic); j++)\r
+ {\r
+ if(vic == double_aspect_vic[j])\r
+ { \r
+ vic--;\r
+ break;\r
+ }\r
+ }\r
+ if(vic)\r
+ {\r
+ mode = hdmi_vic_to_videomode(vic);\r
+ if(mode)\r
+ { \r
+ hdmi_add_videomode(mode, &pedid->modelist);\r
+ }\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+// Parse CEA Short Audio Descriptor\r
+static int hdmi_edid_parse_cea_sad(unsigned char *buf, struct hdmi_edid *pedid)\r
+{\r
+ int i, count;\r
+ \r
+ count = buf[0] & 0x1F;\r
+ pedid->audio = kmalloc((count/3)*sizeof(struct hdmi_audio), GFP_KERNEL);\r
+ if(pedid->audio == NULL)\r
+ return E_HDMI_EDID_NOMEMORY;\r
+ pedid->audio_num = count/3;\r
+ for(i = 0; i < pedid->audio_num; i++)\r
+ {\r
+ pedid->audio[i].type = (buf[1 + i*3] >> 3) & 0x0F;\r
+ pedid->audio[i].channel = (buf[1 + i*3] & 0x07) + 1;\r
+ pedid->audio[i].rate = buf[1 + i*3 + 1];\r
+ if(pedid->audio[i].type == HDMI_AUDIO_LPCM)//LPCM \r
+ {\r
+ pedid->audio[i].word_length = buf[1 + i*3 + 2];\r
+ }\r
+// printk("[EDID-CEA] type %d channel %d rate %d word length %d\n", \r
+// pedid->audio[i].type, pedid->audio[i].channel, pedid->audio[i].rate, pedid->audio[i].word_length);\r
+ }\r
+ return E_HDMI_EDID_SUCCESS;\r
+}\r
+// Parse CEA 861 Serial Extension.\r
+static int hdmi_edid_parse_extensions_cea(unsigned char *buf, struct hdmi_edid *pedid)\r
+{\r
+ unsigned int ddc_offset, native_dtd_num, cur_offset = 4;\r
+ unsigned int underscan_support, baseaudio_support;\r
+ unsigned int tag, IEEEOUI = 0;\r
+// unsigned int supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444;\r
+// unsigned char vic;\r
+ \r
+ if(buf == NULL)\r
+ return E_HDMI_EDID_PARAM;\r
+ \r
+ // Check ces extension version\r
+ if(buf[1] != 3)\r
+ {\r
+ hdmi_edid_error("[EDID-CEA] error version.\n");\r
+ return E_HDMI_EDID_VERSION;\r
+ }\r
+ \r
+ ddc_offset = buf[2];\r
+ underscan_support = (buf[3] >> 7) & 0x01;\r
+ baseaudio_support = (buf[3] >> 6) & 0x01;\r
+ pedid->ycbcr444 = (buf[3] >> 5) & 0x01;\r
+ pedid->ycbcr422 = (buf[3] >> 4) & 0x01;\r
+ native_dtd_num = buf[3] & 0x0F;\r
+// hdmi_edid_debug("[EDID-CEA] ddc_offset %d underscan_support %d baseaudio_support %d yuv_support %d native_dtd_num %d\n", ddc_offset, underscan_support, baseaudio_support, yuv_support, native_dtd_num);\r
+ // Parse data block\r
+ while(cur_offset < ddc_offset)\r
+ {\r
+ tag = buf[cur_offset] >> 5;\r
+ switch(tag)\r
+ {\r
+ case 0x02: // Video Data Block\r
+ hdmi_edid_debug("[EDID-CEA] It is a Video Data Block.\n");\r
+ hdmi_edid_get_cea_svd(buf + cur_offset, pedid);\r
+ break;\r
+ case 0x01: // Audio Data Block\r
+ hdmi_edid_debug("[EDID-CEA] It is a Audio Data Block.\n");\r
+ hdmi_edid_parse_cea_sad(buf + cur_offset, pedid);\r
+ break;\r
+ case 0x04: // Speaker Allocation Data Block\r
+ hdmi_edid_debug("[EDID-CEA] It is a Speaker Allocatio Data Block.\n");\r
+ break;\r
+ case 0x03: // Vendor Specific Data Block\r
+ hdmi_edid_debug("[EDID-CEA] It is a Vendor Specific Data Block.\n");\r
+\r
+ IEEEOUI = buf[cur_offset + 2 + 1];\r
+ IEEEOUI <<= 8;\r
+ IEEEOUI += buf[cur_offset + 1 + 1];\r
+ IEEEOUI <<= 8;\r
+ IEEEOUI += buf[cur_offset + 1];\r
+ hdmi_edid_debug("[EDID-CEA] IEEEOUI is 0x%08x.\n", IEEEOUI);\r
+ if(IEEEOUI == 0x0c03)\r
+ pedid->sink_hdmi = 1;\r
+// if(count > 5)\r
+// {\r
+// pedid->deepcolor = (buf[cur_offset + 5] >> 3) & 0x0F;\r
+// supports_ai = buf[cur_offset + 5] >> 7;\r
+// dc_48bit = (buf[cur_offset + 5] >> 6) & 0x1;\r
+// dc_36bit = (buf[cur_offset + 5] >> 5) & 0x1;\r
+// dc_30bit = (buf[cur_offset + 5] >> 4) & 0x1;\r
+// dc_y444 = (buf[cur_offset + 5] >> 3) & 0x1;\r
+// hdmi_edid_debug("[EDID-CEA] supports_ai %d dc_48bit %d dc_36bit %d dc_30bit %d dc_y444 %d \n", supports_ai, dc_48bit, dc_36bit, dc_30bit, dc_y444);\r
+// }\r
+// if(count > 6)\r
+// pedid->maxtmdsclock = buf[cur_offset + 6] * 5000000;\r
+// if(count > 7)\r
+// {\r
+// pedid->latency_fields_present = (buf[cur_offset + 7] & 0x80) ? 1:0;\r
+// pedid->i_latency_fields_present = (buf[cur_offset + 7] & 0x40) ? 1:0;\r
+// }\r
+// if(count > 9 && pedid->latency_fields_present)\r
+// {\r
+// pedid->video_latency = buf[cur_offset + 8];\r
+// pedid->audio_latency = buf[cur_offset + 9];\r
+// }\r
+// if(count > 11 && pedid->i_latency_fields_present)\r
+// {\r
+// pedid->interlaced_video_latency = buf[cur_offset + 10];\r
+// pedid->interlaced_audio_latency = buf[cur_offset + 11];\r
+// }\r
+ break; \r
+ case 0x05: // VESA DTC Data Block\r
+ hdmi_edid_debug("[EDID-CEA] It is a VESA DTC Data Block.\n");\r
+ break;\r
+ case 0x07: // Use Extended Tag\r
+ hdmi_edid_debug("[EDID-CEA] It is a Use Extended Tag Data Block.\n");\r
+ break;\r
+ default:\r
+ hdmi_edid_error("[EDID-CEA] unkowned data block tag.\n");\r
+ break;\r
+ }\r
+ cur_offset += (buf[cur_offset] & 0x1F) + 1;\r
+ }\r
+#if 1 \r
+{\r
+ // Parse DTD\r
+ struct fb_videomode *vmode = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);\r
+ if(vmode == NULL)\r
+ return E_HDMI_EDID_SUCCESS; \r
+ while(ddc_offset < HDMI_EDID_BLOCK_SIZE - 2) //buf[126] = 0 and buf[127] = checksum\r
+ {\r
+ if(!buf[ddc_offset] && !buf[ddc_offset + 1])\r
+ break;\r
+ memset(vmode, 0, sizeof(struct fb_videomode));\r
+ hdmi_edid_parse_dtd(buf + ddc_offset, vmode);\r
+ hdmi_add_videomode(vmode, &pedid->modelist);\r
+ ddc_offset += 18;\r
+ }\r
+ kfree(vmode);\r
+}\r
+#endif\r
+ return E_HDMI_EDID_SUCCESS;\r
+}\r
+\r
+static int hdmi_edid_parse_extensions(unsigned char *buf, struct hdmi_edid *pedid)\r
+{\r
+ int rc;\r
+ \r
+ if(buf == NULL || pedid == NULL)\r
+ return E_HDMI_EDID_PARAM;\r
+ \r
+ // Checksum\r
+ rc = hdmi_edid_checksum(buf);\r
+ if( rc != E_HDMI_EDID_SUCCESS)\r
+ {\r
+ hdmi_edid_error("[EDID] extensions block checksum error\n");\r
+ return E_HDMI_EDID_CHECKSUM;\r
+ }\r
+ \r
+ switch(buf[0])\r
+ {\r
+ case 0xF0:\r
+ hdmi_edid_debug("[EDID-EXTEND] It is a extensions block map.\n");\r
+ break;\r
+ case 0x02:\r
+ hdmi_edid_debug("[EDID-EXTEND] It is a CEA 861 Series Extension.\n");\r
+ hdmi_edid_parse_extensions_cea(buf, pedid);\r
+ break;\r
+ case 0x10:\r
+ hdmi_edid_debug("[EDID-EXTEND] It is a Video Timing Block Extension.\n");\r
+ break;\r
+ case 0x40:\r
+ hdmi_edid_debug("[EDID-EXTEND] It is a Display Information Extension.\n");\r
+ break;\r
+ case 0x50:\r
+ hdmi_edid_debug("[EDID-EXTEND] It is a Localized String Extension.\n");\r
+ break;\r
+ case 0x60:\r
+ hdmi_edid_debug("[EDID-EXTEND] It is a Digital Packet Video Link Extension.\n");\r
+ break;\r
+ default:\r
+ hdmi_edid_debug("[EDID-EXTEND] Unkowned extension.\n");\r
+ break;\r
+ }\r
+ \r
+ return E_HDMI_EDID_SUCCESS;\r
+}\r
+\r
+\r
+int hdmi_sys_parse_edid(struct hdmi* hdmi)\r
+{\r
+ struct hdmi_edid *pedid;\r
+ unsigned char *buff = NULL;\r
+ int rc = HDMI_ERROR_SUCESS, extendblock = 0, i;\r
+ \r
+ if(hdmi == NULL)\r
+ return HDMI_ERROR_FALSE;\r
+\r
+ pedid = &(hdmi->edid);\r
+ memset(pedid, 0, sizeof(struct hdmi_edid));\r
+ INIT_LIST_HEAD(&pedid->modelist);\r
+ \r
+ buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);\r
+ if(buff == NULL)\r
+ { \r
+ hdmi_dbg(hdmi->dev, "[%s] can not allocate memory for edid buff.\n", __FUNCTION__);\r
+ return -1;\r
+ }\r
+ // Read base block edid.\r
+ memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);\r
+ rc = hdmi->read_edid(0, buff);\r
+ if(rc)\r
+ {\r
+ dev_err(hdmi->dev, "[HDMI] read edid base block error\n");\r
+ goto out;\r
+ }\r
+ rc = hdmi_edid_parse_base(buff, &extendblock, pedid);\r
+ if(rc)\r
+ {\r
+ dev_err(hdmi->dev, "[HDMI] parse edid base block error\n");\r
+ goto out;\r
+ }\r
+ for(i = 1; i < extendblock + 1; i++)\r
+ {\r
+ memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);\r
+ rc = hdmi->read_edid(i, buff);\r
+ if(rc)\r
+ {\r
+ printk("[HDMI] read edid block %d error\n", i); \r
+ goto out;\r
+ }\r
+ rc = hdmi_edid_parse_extensions(buff, pedid);\r
+ if(rc)\r
+ {\r
+ dev_err(hdmi->dev, "[HDMI] parse edid block %d error\n", i);\r
+ continue;\r
+ }\r
+ }\r
+out:\r
+ if(buff)\r
+ kfree(buff);\r
+ rc = hdmi_ouputmode_select(hdmi, rc);\r
+ return rc;\r
+}\r
--- /dev/null
+#include <linux/console.h>
+#include<linux/rk_fb.h>
+#include "rk_hdmi.h"
+
+#define OUT_TYPE SCREEN_HDMI
+#define OUT_FACE OUT_P888
+#define DCLK_POL 1
+#define SWAP_RB 0
+#define LCD_ACLK 800000000
+
+const struct fb_videomode hdmi_mode [] = {
+ //name refresh xres yres pixclock h_bp h_fp v_bp v_fp h_pw v_pw polariry PorI flag(used for vic)
+//{ "640x480p@60Hz", 60, 640, 480, 25175000, 48, 16, 33, 10, 96, 2, 0, 0, 1 },
+//{ "720x480i@60Hz", 60, 720, 480, 27000000, 114, 38, 15, 4, 124, 3, 0, 1, 6 },
+//{ "720x576i@50Hz", 50, 720, 576, 27000000, 138, 24, 19, 2, 126, 3, 0, 1, 21 },
+{ "720x480p@60Hz", 60, 720, 480, 27000000, 60, 16, 30, 9, 62, 6, 0, 0, 2 },
+{ "720x576p@50Hz", 50, 720, 576, 27000000, 68, 12, 39, 5, 64, 5, 0, 0, 17 },
+//{ "1280x720p@24Hz", 24, 1280, 720, 59400000, 220, 1760, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 60 },
+//{ "1280x720p@25Hz", 25, 1280, 720, 74250000, 220, 2420, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 61 },
+//{ "1280x720p@30Hz", 30, 1280, 720, 74250000, 220, 1760, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 62 },
+{ "1280x720p@50Hz", 50, 1280, 720, 74250000, 220, 440, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 19 },
+{ "1280x720p@60Hz", 60, 1280, 720, 74250000, 220, 110, 20, 5, 40, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 4 },
+//{ "1920x1080p@24Hz", 24, 1920, 1080, 74250000, 148, 638, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 32 },
+//{ "1920x1080p@25Hz", 25, 1920, 1080, 74250000, 148, 528, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 33 },
+//{ "1920x1080p@30Hz", 30, 1920, 1080, 74250000, 148, 88, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 34 },
+//{ "1920x1080i@50Hz_2",50, 1920, 1080, 72000000, 184, 32, 57, 23, 168, 5, FB_SYNC_HOR_HIGH_ACT, 1, 39 },
+//{ "1920x1080i@50Hz", 50, 1920, 1080, 74250000, 148, 528, 15, 2, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 1, 20 },
+//{ "1920x1080i@60Hz", 60, 1920, 1080, 74250000, 148, 88, 15, 2, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 1, 5 },
+{ "1920x1080p@50Hz", 50, 1920, 1080, 148500000, 148, 528, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 31 },
+{ "1920x1080p@60Hz", 60, 1920, 1080, 148500000, 148, 88, 36, 4, 44, 5, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 0, 16 },
+/*
+{ "1440x288p@50Hz", 50, 720, 480, 27000000, 138, 24, 19, 2, 126, 3, 0, 0, 23 },
+{ "2880x576i@50Hz", 50, 1440, 240, 54000000, 276, 48, 19, 2, 252, 3, 0, 1, 25 },
+{ "2880x288p@50Hz", 50, 2880, 480, 54000000, 276, 48, 19, 3, 252, 3, 0, 0, 27 },
+{ "1440x576p@50Hz", 50, 2880, 480, 54000000, 136, 24, 39, 5, 128, 5, 0, 0, 29 },
+{ "2880x576p@50Hz", 50, 1920, 1080, 108000000, 272, 48, 39, 5, 256, 5, 0, 0, 37 },
+{ "1440x240p@60Hz", 60, 1440, 240, 27000000, 114, 38, 15, 4, 124, 3, 0, 0, 8 },
+{ "2880x480i@60Hz", 60, 2880, 480, 54000000, 228, 76, 15, 4, 248, 3, 0, 1, 10 },
+{ "2880x480p@60Hz", 60, 2880, 480, 54000000, 228, 76, 15, 4, 248, 3, 0, 0, 12 },
+{ "1440x480p@60Hz", 60, 1440, 480, 54000000, 120, 32, 30, 9, 124, 6, 0, 0, 14 },
+{ "2880x480p@60Hz", 60, 2880, 480, 54000000, 240, 64, 30, 9, 248, 6, 0, 0, 35 },
+
+{ "1920x1080i@100Hz", 100, 1920, 1080, 148500000, 148, 528, 15, 2, 44, 5, 1, 1, 40 },
+{ "1280x720p@100Hz", 100, 1280, 720, 148500000, 220, 440, 20, 5, 40, 5, 1, 0, 41 },
+{ "720x576p@100Hz", 100, 720, 576, 54000000, 68, 12, 39, 5, 64, 5, 0, 0, 42 },
+{ "1440x576i@100Hz", 100, 1440, 576, 54000000, 138, 24, 19, 2, 12, 3, 0, 1, 44 },
+{ "1920x1080p@100Hz", 100, 1920, 1080, 297000000, 148, 528, 36, 4, 44, 5, 1, 0, 64 },
+
+{ "1920x1080i@120Hz", 120, 1920, 1080, 148500000, 148, 88, 15, 2, 44, 5, 1, 1, 46 },
+{ "1280x720p@120Hz", 120, 1280, 720, 148500000, 220, 110, 20, 5, 40, 5, 1, 0, 47 },
+{ "720x480p@120Hz", 120, 720, 480, 54000000, 60, 16, 30, 9, 62, 6, 0, 0, 48 },
+{ "1440x480i@120Hz", 120, 1440, 480, 54000000, 114, 38, 15, 4, 12, 3, 0, 1, 50 },
+{ "1920x1080p@120Hz", 120, 1920, 1080, 297000000, 148, 88, 36, 4, 44, 5, 1, 0, 63 },
+
+{ "720x576p@200Hz", 200, 720, 576, 108000000, 68, 12, 39, 5, 64, 5, 0, 0, 52 },
+{ "1440x576i@200Hz", 200, 1920, 1080, 108000000, 138, 24, 19, 2, 12, 3, 0, 1, 54 },
+
+{ "720x480p@240Hz", 240, 720, 480, 108000000, 60, 16, 30, 9, 62, 6, 0, 0, 56 },
+{ "1440x480i@240Hz", 240, 1440, 480, 108000000, 114, 38, 15, 4, 12, 3, 0, 1, 58 },
+*/
+
+};
+
+void hdmi_init_lcdc(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info)
+{
+ hdmi_set_info(screen, HDMI_VIDEO_DEFAULT_MODE);
+}
+
+int hdmi_set_info(struct rk29fb_screen *screen, unsigned int vic)
+{
+ int i;
+
+ if(screen == NULL)
+ return -1;
+
+ if(vic == 0)
+ vic = HDMI_VIDEO_DEFAULT_MODE;
+
+ for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
+ {
+ if(hdmi_mode[i].flag == vic)
+ break;
+ }
+ if(i == ARRAY_SIZE(hdmi_mode))
+ return -1;
+
+ memset(screen, 0, sizeof(struct rk29fb_screen));
+
+ /* screen type & face */
+ screen->type = OUT_TYPE;
+ screen->face = OUT_FACE;
+
+ /* Screen size */
+ screen->x_res = hdmi_mode[i].xres;
+ screen->y_res = hdmi_mode[i].yres;
+
+ /* Timing */
+ screen->pixclock = hdmi_mode[i].pixclock;
+ screen->lcdc_aclk = LCD_ACLK;
+ screen->left_margin = hdmi_mode[i].left_margin;
+ screen->right_margin = hdmi_mode[i].right_margin;
+ screen->hsync_len = hdmi_mode[i].hsync_len;
+ screen->upper_margin = hdmi_mode[i].upper_margin;
+ screen->lower_margin = hdmi_mode[i].lower_margin;
+ screen->vsync_len = hdmi_mode[i].vsync_len;
+
+ /* Pin polarity */
+ if(FB_SYNC_HOR_HIGH_ACT & hdmi_mode[i].sync)
+ screen->pin_hsync = 1;
+ else
+ screen->pin_hsync = 0;
+ if(FB_SYNC_VERT_HIGH_ACT & hdmi_mode[i].sync)
+ screen->pin_vsync = 1;
+ else
+ screen->pin_vsync = 0;
+ screen->pin_den = 0;
+ screen->pin_dclk = DCLK_POL;
+
+ /* Swap rule */
+ screen->swap_rb = SWAP_RB;
+ screen->swap_rg = 0;
+ screen->swap_gb = 0;
+ screen->swap_delta = 0;
+ screen->swap_dumy = 0;
+
+ /* Operation function*/
+ screen->init = NULL;
+ screen->standby = NULL;
+
+ return 0;
+}
+
+static void hdmi_show_sink_info(struct hdmi *hdmi)
+{
+ struct list_head *pos, *head = &hdmi->edid.modelist;
+ struct fb_modelist *modelist;
+ struct fb_videomode *m;
+ int i;
+ struct hdmi_audio *audio;
+
+ hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
+ hdmi_dbg(hdmi->dev, "Support video mode: \n");
+ list_for_each(pos, head) {
+ modelist = list_entry(pos, struct fb_modelist, list);
+ m = &modelist->mode;
+ hdmi_dbg(hdmi->dev, " %s.\n", m->name);
+ }
+
+ for(i = 0; i < hdmi->edid.audio_num; i++)
+ {
+ audio = &(hdmi->edid.audio[i]);
+ switch(audio->type)
+ {
+ case HDMI_AUDIO_LPCM:
+ hdmi_dbg(hdmi->dev, "Support audio type: LPCM\n");
+ break;
+ case HDMI_AUDIO_AC3:
+ hdmi_dbg(hdmi->dev, "Support audio type: AC3\n");
+ break;
+ case HDMI_AUDIO_MPEG1:
+ hdmi_dbg(hdmi->dev, "Support audio type: MPEG1\n");
+ break;
+ case HDMI_AUDIO_MP3:
+ hdmi_dbg(hdmi->dev, "Support audio type: MP3\n");
+ break;
+ case HDMI_AUDIO_MPEG2:
+ hdmi_dbg(hdmi->dev, "Support audio type: MPEG2\n");
+ break;
+ case HDMI_AUDIO_AAC_LC:
+ hdmi_dbg(hdmi->dev, "Support audio type: AAC\n");
+ break;
+ case HDMI_AUDIO_DTS:
+ hdmi_dbg(hdmi->dev, "Support audio type: DTS\n");
+ break;
+ case HDMI_AUDIO_ATARC:
+ hdmi_dbg(hdmi->dev, "Support audio type: ATARC\n");
+ break;
+ case HDMI_AUDIO_DSD:
+ hdmi_dbg(hdmi->dev, "Support audio type: DSD\n");
+ break;
+ case HDMI_AUDIO_E_AC3:
+ hdmi_dbg(hdmi->dev, "Support audio type: E-AC3\n");
+ break;
+ case HDMI_AUDIO_DTS_HD:
+ hdmi_dbg(hdmi->dev, "Support audio type: DTS-HD\n");
+ break;
+ case HDMI_AUDIO_MLP:
+ hdmi_dbg(hdmi->dev, "Support audio type: MLP\n");
+ break;
+ case HDMI_AUDIO_DST:
+ hdmi_dbg(hdmi->dev, "Support audio type: DST\n");
+ break;
+ case HDMI_AUDIO_WMA_PRO:
+ hdmi_dbg(hdmi->dev, "Support audio type: WMP-PRO\n");
+ break;
+ default:
+ hdmi_dbg(hdmi->dev, "Support audio type: Unkown\n");
+ break;
+ }
+
+ hdmi_dbg(hdmi->dev, "Support audio sample rate: \n");
+ if(audio->rate & HDMI_AUDIO_FS_32000)
+ hdmi_dbg(hdmi->dev, " 32000\n");
+ if(audio->rate & HDMI_AUDIO_FS_44100)
+ hdmi_dbg(hdmi->dev, " 44100\n");
+ if(audio->rate & HDMI_AUDIO_FS_48000)
+ hdmi_dbg(hdmi->dev, " 48000\n");
+ if(audio->rate & HDMI_AUDIO_FS_88200)
+ hdmi_dbg(hdmi->dev, " 88200\n");
+ if(audio->rate & HDMI_AUDIO_FS_96000)
+ hdmi_dbg(hdmi->dev, " 96000\n");
+ if(audio->rate & HDMI_AUDIO_FS_176400)
+ hdmi_dbg(hdmi->dev, " 176400\n");
+ if(audio->rate & HDMI_AUDIO_FS_192000)
+ hdmi_dbg(hdmi->dev, " 192000\n");
+
+ hdmi_dbg(hdmi->dev, "Support audio word lenght: \n");
+ if(audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
+ hdmi_dbg(hdmi->dev, " 16bit\n");
+ if(audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
+ hdmi_dbg(hdmi->dev, " 20bit\n");
+ if(audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
+ hdmi_dbg(hdmi->dev, " 24bit\n");
+ }
+ hdmi_dbg(hdmi->dev, "******** Show Sink Info ********\n");
+}
+
+/**
+ * hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
+ * @hdmi: handle of hdmi
+ * @edid_ok: get EDID data success or not, HDMI_ERROR_SUCESS means success.
+ */
+int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
+{
+ struct list_head *head = &hdmi->edid.modelist;
+ struct fb_monspecs *specs = hdmi->edid.specs;
+ struct fb_videomode *modedb = NULL;
+ int i, pixclock;
+
+ if(edid_ok != HDMI_ERROR_SUCESS) {
+ dev_err(hdmi->dev, "warning: EDID error, assume sink as HDMI !!!!");
+ hdmi->edid.sink_hdmi = 1;
+ }
+
+ if(edid_ok != HDMI_ERROR_SUCESS) {
+ hdmi->edid.ycbcr444 = 0;
+ hdmi->edid.ycbcr422 = 0;
+ hdmi->autoconfig = HDMI_DISABLE;
+ }
+ if(head->next == head) {
+ dev_info(hdmi->dev, "warning: no CEA video mode parsed from EDID !!!!");
+ // If EDID get error, list all system supported mode.
+ // If output mode is set to DVI and EDID is ok, check
+ // the output timing.
+
+ if(hdmi->edid.sink_hdmi == 0 && specs && specs->modedb_len) {
+ /* Get max resolution timing */
+ modedb = &specs->modedb[0];
+ for (i = 0; i < specs->modedb_len; i++) {
+ if(specs->modedb[i].xres > modedb->xres)
+ modedb = &specs->modedb[i];
+ else if(specs->modedb[i].yres > modedb->yres)
+ modedb = &specs->modedb[i];
+ }
+ // For some monitor, the max pixclock read from EDID is smaller
+ // than the clock of max resolution mode supported. We fix it.
+ pixclock = PICOS2KHZ(modedb->pixclock);
+ pixclock /= 250;
+ pixclock *= 250;
+ pixclock *= 1000;
+ if(pixclock == 148250000)
+ pixclock = 148500000;
+ if(pixclock > specs->dclkmax)
+ specs->dclkmax = pixclock;
+ }
+
+ for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
+ if(modedb) {
+ if( (hdmi_mode[i].pixclock < specs->dclkmin) ||
+ (hdmi_mode[i].pixclock > specs->dclkmax) ||
+ (hdmi_mode[i].refresh < specs->vfmin) ||
+ (hdmi_mode[i].refresh > specs->vfmax) ||
+ (hdmi_mode[i].xres > modedb->xres) ||
+ (hdmi_mode[i].yres > modedb->yres) )
+ continue;
+ }
+ hdmi_add_videomode(&hdmi_mode[i], head);
+ }
+ }
+
+ #ifdef HDMI_DEBUG
+ hdmi_show_sink_info(hdmi);
+ #endif
+ return HDMI_ERROR_SUCESS;
+}
+/**
+ * hdmi_videomode_compare - compare 2 videomodes
+ * @mode1: first videomode
+ * @mode2: second videomode
+ *
+ * RETURNS:
+ * 1 if mode1 > mode2, 0 if mode1 = mode2, -1 mode1 < mode2
+ */
+static int hdmi_videomode_compare(const struct fb_videomode *mode1,
+ const struct fb_videomode *mode2)
+{
+ if(mode1->xres > mode2->xres)
+ return 1;
+ else if(mode1->xres == mode2->xres)
+ {
+ if(mode1->yres > mode2->yres)
+ return 1;
+ else if(mode1->yres == mode2->yres)
+ {
+ if(mode1->pixclock > mode2->pixclock)
+ return 1;
+ else if(mode1->pixclock == mode2->pixclock)
+ {
+ if(mode1->refresh > mode2->refresh)
+ return 1;
+ else if(mode1->refresh == mode2->refresh)
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+/**
+ * hdmi_add_videomode: adds videomode entry to modelist
+ * @mode: videomode to add
+ * @head: struct list_head of modelist
+ *
+ * NOTES:
+ * Will only add unmatched mode entries
+ */
+int hdmi_add_videomode(const struct fb_videomode *mode, struct list_head *head)
+{
+ struct list_head *pos;
+ struct fb_modelist *modelist, *modelist_new;
+ struct fb_videomode *m;
+ int i, found = 0;
+
+ for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
+ {
+ m =(struct fb_videomode*) &hdmi_mode[i];
+ if (fb_mode_is_equal(m, mode)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_for_each(pos, head) {
+ modelist = list_entry(pos, struct fb_modelist, list);
+ m = &modelist->mode;
+ if (fb_mode_is_equal(m, mode)) {
+ // m == mode
+ return 0;
+ }
+ else
+ {
+ if(hdmi_videomode_compare(m, mode) == -1) {
+ break;
+ }
+ }
+ }
+
+ modelist_new = kmalloc(sizeof(struct fb_modelist),
+ GFP_KERNEL);
+ if (!modelist_new)
+ return -ENOMEM;
+ modelist_new->mode = hdmi_mode[i];
+ list_add_tail(&modelist_new->list, pos);
+ }
+
+ return 0;
+}
+
+/**
+ * hdmi_videomode_to_vic: transverse video mode to vic
+ * @vmode: videomode to transverse
+ *
+ */
+int hdmi_videomode_to_vic(struct fb_videomode *vmode)
+{
+ unsigned char vic = 0;
+ int i = 0;
+
+ for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
+ {
+ if( vmode->vmode == hdmi_mode[i].vmode &&
+ vmode->refresh == hdmi_mode[i].refresh &&
+ vmode->xres == hdmi_mode[i].xres &&
+ vmode->left_margin == hdmi_mode[i].left_margin &&
+ vmode->right_margin == hdmi_mode[i].right_margin &&
+ vmode->upper_margin == hdmi_mode[i].upper_margin &&
+ vmode->lower_margin == hdmi_mode[i].lower_margin &&
+ vmode->hsync_len == hdmi_mode[i].hsync_len &&
+ vmode->vsync_len == hdmi_mode[i].vsync_len)
+ {
+ if( (vmode->vmode == FB_VMODE_NONINTERLACED && vmode->yres == hdmi_mode[i].yres) ||
+ (vmode->vmode == FB_VMODE_INTERLACED && vmode->yres == hdmi_mode[i].yres/2))
+ {
+ vic = hdmi_mode[i].flag;
+ break;
+ }
+ }
+ }
+ return vic;
+}
+
+/**
+ * hdmi_vic_to_videomode: transverse vic mode to video mode
+ * @vmode: vic to transverse
+ *
+ */
+const struct fb_videomode* hdmi_vic_to_videomode(int vic)
+{
+ int i;
+
+ if(vic == 0)
+ return NULL;
+
+ for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
+ {
+ if(hdmi_mode[i].flag == vic)
+ return &hdmi_mode[i];
+ }
+ return NULL;
+}
+
+/**
+ * hdmi_find_best_mode: find the video mode nearest to input vic
+ * @hdmi:
+ * @vic: input vic
+ *
+ * NOTES:
+ * If vic is zero, return the high resolution video mode vic.
+ */
+int hdmi_find_best_mode(struct hdmi* hdmi, int vic)
+{
+ struct list_head *pos, *head = &hdmi->edid.modelist;
+ struct fb_modelist *modelist;
+ struct fb_videomode *m = NULL;
+ int found = 0;
+
+ if(vic)
+ {
+ list_for_each(pos, head) {
+ modelist = list_entry(pos, struct fb_modelist, list);
+ m = &modelist->mode;
+ if(m->flag == vic)
+ {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if( (vic == 0 || found == 0) && head->next != head)
+ {
+ modelist = list_entry(head->next, struct fb_modelist, list);
+ m = &modelist->mode;
+ }
+ if(m != NULL)
+ return m->flag;
+ else
+ return 0;
+}
+
+const char *hdmi_get_video_mode_name(unsigned char vic)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(hdmi_mode); i++)
+ {
+ if(vic == hdmi_mode[i].flag)
+ break;
+ }
+ if(i == ARRAY_SIZE(hdmi_mode))
+ return NULL;
+ else
+ return hdmi_mode[i].name;
+}
+
+/**
+ * hdmi_switch_fb: switch lcdc mode to required video mode
+ * @hdmi:
+ * @type:
+ *
+ * NOTES:
+ *
+ */
+int hdmi_switch_fb(struct hdmi *hdmi, int vic)
+{
+ int rc = 0;
+
+ if(hdmi->vic == 0)
+ hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
+
+ if(hdmi->lcdc == NULL || hdmi->lcdc->screen == NULL) {
+ dev_err(hdmi->dev, "lcdc %d not exist\n", HDMI_SOURCE_DEFAULT);
+ return -1;
+ }
+
+ rc = hdmi_set_info(hdmi->lcdc->screen, hdmi->vic);
+
+ if(rc == 0) {
+ rk_fb_switch_screen(hdmi->lcdc->screen, 1, HDMI_SOURCE_DEFAULT);
+ rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, HDMI_SOURCE_DEFAULT);
+ }
+ return rc;
+}
+
+/**
+ * hdmi_get_status: get hdmi hotplug status
+ *
+ * NOTES:
+ *
+ */
+int hdmi_get_hotplug(void)
+{
+ if(hdmi)
+ return hdmi->hotplug;
+ else
+ return HDMI_HPD_REMOVED;
+}
--- /dev/null
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/display-sys.h>
+#include <linux/interrupt.h>
+#include "rk_hdmi.h"
+
+static int hdmi_get_enable(struct rk_display_device *device)
+{
+ struct hdmi *hdmi = device->priv_data;
+ int enable;
+
+ mutex_lock(&hdmi->enable_mutex);
+ enable = hdmi->enable;
+ mutex_unlock(&hdmi->enable_mutex);
+
+ return enable;
+}
+
+static int hdmi_set_enable(struct rk_display_device *device, int enable)
+{
+ struct hdmi *hdmi = device->priv_data;
+
+ mutex_lock(&hdmi->enable_mutex);
+ if(hdmi->enable == enable) {
+ mutex_unlock(&hdmi->enable_mutex);
+ return 0;
+ }
+ hdmi->enable = enable;
+
+ if(hdmi->suspend ) {
+ mutex_unlock(&hdmi->enable_mutex);
+ return 0;
+ }
+
+ if(enable == 0) {
+ disable_irq(hdmi->irq);
+ mutex_unlock(&hdmi->enable_mutex);
+ hdmi->command = HDMI_CONFIG_ENABLE;
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
+ }
+ else {
+ enable_irq(hdmi->irq);
+ mutex_unlock(&hdmi->enable_mutex);
+ }
+ return 0;
+}
+
+static int hdmi_get_status(struct rk_display_device *device)
+{
+ struct hdmi *hdmi = device->priv_data;
+ if(hdmi->hotplug == HDMI_HPD_ACTIVED)
+ return 1;
+ else
+ return 0;
+}
+
+static int hdmi_get_modelist(struct rk_display_device *device, struct list_head **modelist)
+{
+ struct hdmi *hdmi = device->priv_data;
+ if(!hdmi->hotplug)
+ return -1;
+ *modelist = &hdmi->edid.modelist;
+ return 0;
+}
+
+static int hdmi_set_mode(struct rk_display_device *device, struct fb_videomode *mode)
+{
+ struct hdmi *hdmi = device->priv_data;
+ int vic = hdmi_videomode_to_vic(mode);
+
+ if(!hdmi->hotplug)
+ return -1;
+ hdmi->autoconfig = HDMI_DISABLE;
+ if(vic && hdmi->vic != vic)
+ {
+ hdmi->vic = vic;
+ hdmi->command = HDMI_CONFIG_VIDEO;
+ init_completion(&hdmi->complete);
+ hdmi->wait = 1;
+ queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
+ wait_for_completion_interruptible_timeout(&hdmi->complete,
+ msecs_to_jiffies(10000));
+ }
+ return 0;
+}
+
+static int hdmi_get_mode(struct rk_display_device *device, struct fb_videomode *mode)
+{
+ struct hdmi *hdmi = device->priv_data;
+ struct fb_videomode *vmode;
+
+ if(!hdmi->hotplug)
+ return -1;
+
+ vmode = (struct fb_videomode*) hdmi_vic_to_videomode(hdmi->vic);
+ if(unlikely(vmode == NULL))
+ return -1;
+ *mode = *vmode;
+ return 0;
+}
+
+static int hdmi_set_scale(struct rk_display_device *device, int direction, int value)
+{
+ struct hdmi *hdmi = device->priv_data;
+
+ if(!hdmi || value < 0 || value > 100)
+ return -1;
+
+ if(direction == DISPLAY_SCALE_X)
+ hdmi->xscale = value;
+ else if(direction == DISPLAY_SCALE_Y)
+ hdmi->yscale = value;
+ else
+ return -1;
+ rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, HDMI_SOURCE_DEFAULT);
+ return 0;
+}
+
+static int hdmi_get_scale(struct rk_display_device *device, int direction)
+{
+ struct hdmi *hdmi = device->priv_data;
+
+ if(!hdmi)
+ return -1;
+
+ if(direction == DISPLAY_SCALE_X)
+ return hdmi->xscale;
+ else if(direction == DISPLAY_SCALE_Y)
+ return hdmi->yscale;
+ else
+ return -1;
+}
+
+struct rk_display_ops hdmi_display_ops = {
+ .setenable = hdmi_set_enable,
+ .getenable = hdmi_get_enable,
+ .getstatus = hdmi_get_status,
+ .getmodelist = hdmi_get_modelist,
+ .setmode = hdmi_set_mode,
+ .getmode = hdmi_get_mode,
+ .setscale = hdmi_set_scale,
+ .getscale = hdmi_get_scale,
+};
+
+#if 1
+static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
+{
+ device->owner = THIS_MODULE;
+ strcpy(device->type, "HDMI");
+ device->priority = DISPLAY_PRIORITY_HDMI;
+// device->name = kmalloc(strlen(name), GFP_KERNEL);
+// if(device->name)
+// {
+// strcpy(device->name, name);
+// }
+ device->priv_data = devdata;
+ device->ops = &hdmi_display_ops;
+ return 1;
+}
+
+static struct rk_display_driver display_hdmi = {
+ .probe = hdmi_display_probe,
+};
+
+static struct rk_display_device *display_device_hdmi = NULL;
+
+void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent)
+{
+ display_device_hdmi = rk_display_device_register(&display_hdmi, parent, hdmi);
+}
+
+void hdmi_unregister_display_sysfs(struct hdmi *hdmi)
+{
+ if(display_device_hdmi)
+ rk_display_device_unregister(display_device_hdmi);
+}
+#endif
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "rk_hdmi.h"
+
+#ifdef CONFIG_HDMI_RK30_CTL_CODEC
+extern void codec_set_spk(bool on);
+#endif
+
+#define HDMI_MAX_TRY_TIMES 1
+#define HDMI_MAX_ID 1
+
+static char *envp[] = {"INTERFACE=HDMI", NULL};
+
+static void hdmi_sys_show_state(int state)
+{
+ switch(state)
+ {
+ case HDMI_SLEEP:
+ dev_printk(KERN_INFO, hdmi->dev, "HDMI_SLEEP\n");
+ break;
+ case HDMI_INITIAL:
+ dev_printk(KERN_INFO, hdmi->dev, "HDMI_INITIAL\n");
+ break;
+ case WAIT_HOTPLUG:
+ dev_printk(KERN_INFO, hdmi->dev, "WAIT_HOTPLUG\n");
+ break;
+ case READ_PARSE_EDID:
+ dev_printk(KERN_INFO, hdmi->dev, "READ_PARSE_EDID\n");
+ break;
+ case WAIT_HDMI_ENABLE:
+ dev_printk(KERN_INFO, hdmi->dev, "WAIT_HDMI_ENABLE\n");
+ break;
+ case SYSTEM_CONFIG:
+ dev_printk(KERN_INFO, hdmi->dev, "SYSTEM_CONFIG\n");
+ break;
+ case CONFIG_VIDEO:
+ dev_printk(KERN_INFO, hdmi->dev, "CONFIG_VIDEO\n");
+ break;
+ case CONFIG_AUDIO:
+ dev_printk(KERN_INFO, hdmi->dev, "CONFIG_AUDIO\n");
+ break;
+ case PLAY_BACK:
+ dev_printk(KERN_INFO, hdmi->dev, "PLAY_BACK\n");
+ break;
+ default:
+ dev_printk(KERN_INFO, hdmi->dev, "Unkown State %d\n", state);
+ break;
+ }
+}
+
+int hdmi_sys_init(void)
+{
+ hdmi->hotplug = HDMI_HPD_REMOVED;
+ hdmi->state = HDMI_SLEEP;
+ hdmi->enable = HDMI_ENABLE;
+ hdmi->autoconfig = HDMI_AUTO_CONFIGURE;
+ hdmi->display = HDMI_DISABLE;
+
+ hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
+ hdmi->audio.channel = HDMI_AUDIO_DEFAULT_CHANNEL;
+ hdmi->audio.rate = HDMI_AUDIO_DEFAULT_RATE;
+ hdmi->audio.word_length = HDMI_AUDIO_DEFAULT_WORD_LENGTH;
+
+ memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
+ INIT_LIST_HEAD(&hdmi->edid.modelist);
+ return 0;
+}
+
+void hdmi_sys_remove(void)
+{
+ fb_destroy_modelist(&hdmi->edid.modelist);
+ if(hdmi->edid.audio)
+ kfree(hdmi->edid.audio);
+ if(hdmi->edid.specs)
+ {
+ if(hdmi->edid.specs->modedb)
+ kfree(hdmi->edid.specs->modedb);
+ kfree(hdmi->edid.specs);
+ }
+ memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
+ INIT_LIST_HEAD(&hdmi->edid.modelist);
+ hdmi->display = HDMI_DISABLE;
+ rk_fb_switch_screen(hdmi->lcdc->screen, 0, HDMI_SOURCE_DEFAULT);
+ kobject_uevent_env(&hdmi->dev->kobj, KOBJ_REMOVE, envp);
+ #ifdef CONFIG_SWITCH
+ switch_set_state(&(hdmi->switch_hdmi), 0);
+ #endif
+ #ifdef CONFIG_HDMI_RK30_CTL_CODEC
+ codec_set_spk(1);
+ #endif
+}
+
+static void hdmi_sys_sleep(void)
+{
+ mutex_lock(&hdmi->enable_mutex);
+ if(hdmi->enable)
+ disable_irq(hdmi->irq);
+ hdmi->state = HDMI_SLEEP;
+ hdmi->hdmi_removed();
+ if(hdmi->enable)
+ enable_irq(hdmi->irq);
+ mutex_unlock(&hdmi->enable_mutex);
+}
+
+static int hdmi_process_command(void)
+{
+ int change, state = hdmi->state;
+
+ change = hdmi->command;
+ if(change != HDMI_CONFIG_NONE)
+ {
+ hdmi->command = HDMI_CONFIG_NONE;
+ switch(change)
+ {
+ case HDMI_CONFIG_ENABLE:
+ /* disable HDMI */
+ mutex_lock(&hdmi->enable_mutex);
+ if(!hdmi->enable || hdmi->suspend)
+ {
+ if(hdmi->hotplug == HDMI_HPD_ACTIVED)
+ hdmi_sys_remove();
+ hdmi->state = HDMI_SLEEP;
+ hdmi->hotplug = HDMI_HPD_REMOVED;
+ hdmi->hdmi_removed();
+ state = HDMI_SLEEP;
+ }
+ mutex_unlock(&hdmi->enable_mutex);
+ if(hdmi->wait == 1) {
+ complete(&hdmi->complete);
+ hdmi->wait = 0;
+ }
+ break;
+ case HDMI_CONFIG_COLOR:
+ if(state > CONFIG_VIDEO)
+ state = CONFIG_VIDEO;
+ break;
+ case HDMI_CONFIG_HDCP:
+ break;
+ case HDMI_CONFIG_DISPLAY:
+ break;
+ case HDMI_CONFIG_AUDIO:
+ if(state > CONFIG_AUDIO)
+ state = CONFIG_AUDIO;
+ break;
+ case HDMI_CONFIG_VIDEO:
+ default:
+ if(state > SYSTEM_CONFIG)
+ state = SYSTEM_CONFIG;
+ else
+ {
+ if(hdmi->wait == 1) {
+ complete(&hdmi->complete);
+ hdmi->wait = 0;
+ }
+ }
+ break;
+ }
+ }
+ else if(state == HDMI_SLEEP)
+ state = WAIT_HOTPLUG;
+ return state;
+}
+
+static DEFINE_MUTEX(work_mutex);
+
+void hdmi_work(struct work_struct *work)
+{
+ int hotplug, state_last;
+ int rc = HDMI_ERROR_SUCESS, trytimes = 0;
+ struct hdmi_video_para video;
+
+ mutex_lock(&work_mutex);
+ /* Process hdmi command */
+ hdmi->state = hdmi_process_command();
+
+ if(!hdmi->enable || hdmi->suspend) {
+ mutex_unlock(&work_mutex);
+ return;
+ }
+ hotplug = hdmi->detect_hotplug();
+ hdmi_dbg(hdmi->dev, "[%s] hotplug %02x curvalue %d\n", __FUNCTION__, hotplug, hdmi->hotplug);
+
+ if(hotplug != hdmi->hotplug)
+ {
+ if(hotplug == HDMI_HPD_ACTIVED){
+ hdmi->state = READ_PARSE_EDID;
+ }
+ else if(hdmi->hotplug == HDMI_HPD_ACTIVED) {
+ hdmi_sys_remove();
+ hdmi->hotplug = hotplug;
+ if(hotplug == HDMI_HPD_REMOVED)
+ hdmi_sys_sleep();
+ else {
+ hdmi->state = WAIT_HOTPLUG;
+ hdmi->hdmi_removed();
+ }
+ if(hdmi->wait == 1) {
+ complete(&hdmi->complete);
+ hdmi->wait = 0;
+ }
+ mutex_unlock(&work_mutex);
+ return;
+ }
+ else if(hotplug == HDMI_HPD_REMOVED) {
+ hdmi->state = HDMI_SLEEP;
+ hdmi->hdmi_removed();
+ }
+ hdmi->hotplug = hotplug;
+ }
+ else if(hotplug == HDMI_HPD_REMOVED)
+ hdmi_sys_sleep();
+
+ do {
+ hdmi_sys_show_state(hdmi->state);
+ state_last = hdmi->state;
+ switch(hdmi->state)
+ {
+ case READ_PARSE_EDID:
+ rc = hdmi_sys_parse_edid(hdmi);
+ if(rc == HDMI_ERROR_SUCESS)
+ {
+ hdmi->state = SYSTEM_CONFIG;
+ kobject_uevent_env(&hdmi->dev->kobj, KOBJ_ADD, envp);
+ #ifdef CONFIG_SWITCH
+ switch_set_state(&(hdmi->switch_hdmi), 1);
+ #endif
+ #ifdef CONFIG_HDMI_RK30_CTL_CODEC
+ codec_set_spk(0);
+ #endif
+ }
+ break;
+ case SYSTEM_CONFIG:
+ if(hdmi->autoconfig)
+ hdmi->vic = hdmi_find_best_mode(hdmi, 0);
+ else
+ hdmi->vic = hdmi_find_best_mode(hdmi, hdmi->vic);
+ rc = hdmi_switch_fb(hdmi, hdmi->vic);
+ if(rc == HDMI_ERROR_SUCESS)
+ hdmi->state = CONFIG_VIDEO;
+ break;
+ case CONFIG_VIDEO:
+ hdmi->display = HDMI_DISABLE;
+ video.vic = hdmi->vic;
+ video.input_mode = VIDEO_INPUT_RGB_YCBCR_444;
+ video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR
+ video.output_mode = hdmi->edid.sink_hdmi;
+
+ if(hdmi->edid.ycbcr444)
+ video.output_color = VIDEO_OUTPUT_YCBCR444;
+ else if(hdmi->edid.ycbcr422)
+ video.output_color = VIDEO_OUTPUT_YCBCR422;
+ else
+ video.output_color = VIDEO_OUTPUT_RGB444;
+ // For DVI, output RGB
+ if(hdmi->edid.sink_hdmi == 0)
+ video.output_color = VIDEO_OUTPUT_RGB444;
+
+ rc = hdmi->config_video(&video);
+ if(rc == HDMI_ERROR_SUCESS)
+ {
+ if(hdmi->edid.sink_hdmi)
+ hdmi->state = CONFIG_AUDIO;
+ else
+ hdmi->state = PLAY_BACK;
+ }
+ break;
+ case CONFIG_AUDIO:
+ rc = hdmi->config_audio(&(hdmi->audio));
+
+ if(rc == HDMI_ERROR_SUCESS)
+ hdmi->state = PLAY_BACK;
+ break;
+ case PLAY_BACK:
+ if(hdmi->display != HDMI_ENABLE) {
+ hdmi->control_output(HDMI_ENABLE);
+ hdmi->display = HDMI_ENABLE;
+ if(hdmi->hdcp_cb) {
+ hdmi->hdcp_cb();
+ }
+ }
+
+ if(hdmi->wait == 1) {
+ complete(&hdmi->complete);
+ hdmi->wait = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ if(rc != HDMI_ERROR_SUCESS)
+ {
+ trytimes++;
+ msleep(10);
+ }
+ if(hdmi->state != state_last)
+ trytimes = 0;
+
+ }while((hdmi->state != state_last || (rc != HDMI_ERROR_SUCESS) ) && trytimes < HDMI_MAX_TRY_TIMES);
+
+// if(trytimes == HDMI_MAX_TRY_TIMES)
+// {
+// if(hdmi->hotplug) {
+// hdmi_sys_remove();
+// hdmi->hotplug = HDMI_HPD_REMOVED;
+// hdmi_sys_sleep();
+//
+// }
+// }
+ hdmi_dbg(hdmi->dev, "[%s] done\n", __FUNCTION__);
+ mutex_unlock(&work_mutex);
+}
+