diff --git a/packages/devel/libcec/patches/libcec-03-amlogic-support.patch b/packages/devel/libcec/patches/libcec-03-amlogic-support.patch index b3b93d7b1d..934aea1a79 100644 --- a/packages/devel/libcec/patches/libcec-03-amlogic-support.patch +++ b/packages/devel/libcec/patches/libcec-03-amlogic-support.patch @@ -101,8 +101,8 @@ diff -Nur a/src/libcec/adapter/AdapterFactory.cpp b/src/libcec/adapter/AdapterFa } diff -Nur a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp b/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp --- a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ b/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp 2016-02-10 13:54:51.298457229 +0100 -@@ -0,0 +1,259 @@ ++++ b/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp 2016-02-20 12:46:02.458728701 +0100 +@@ -0,0 +1,269 @@ +/* + * This file is part of the libCEC(R) library. + * @@ -339,6 +339,16 @@ diff -Nur a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp b/src/ + + if (size > 0) + { ++ if (buffer[0] == 0xff) // driver wants us to reread the physical address ++ { ++ if (!IsStopped()) ++ { ++ uint16_t iNewAddress = GetPhysicalAddress(); ++ m_callback->HandlePhysicalAddressChanged(iNewAddress); ++ } ++ continue; ++ } ++ + initiator = cec_logical_address(buffer[0] >> 4); + destination = cec_logical_address(buffer[0] & 0x0f); + @@ -364,8 +374,8 @@ diff -Nur a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.cpp b/src/ +#endif // HAVE_AMLOGIC_API diff -Nur a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h b/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h --- a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h 1970-01-01 01:00:00.000000000 +0100 -+++ b/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h 2016-02-10 13:49:16.546310466 +0100 -@@ -0,0 +1,105 @@ ++++ b/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h 2016-02-20 12:46:02.438728945 +0100 +@@ -0,0 +1,104 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. @@ -465,8 +475,7 @@ diff -Nur a/src/libcec/adapter/Amlogic/AmlogicCECAdapterCommunication.h b/src/li + + bool m_bLogicalAddressChanged; + cec_logical_addresses m_logicalAddresses; -+ -+ PLATFORM::CMutex m_mutex; ++ PLATFORM::CMutex m_mutex; + int m_fd; + }; +}; diff --git a/projects/WeTek_Core/patches/linux/080-amlogic-cec-driver.patch b/projects/WeTek_Core/patches/linux/080-amlogic-cec-driver.patch index 54f63fef7c..2dafb595e7 100644 --- a/projects/WeTek_Core/patches/linux/080-amlogic-cec-driver.patch +++ b/projects/WeTek_Core/patches/linux/080-amlogic-cec-driver.patch @@ -1,749 +1,618 @@ -From 3bde21926d476a3fc0f4d37275f8fde11f09dade Mon Sep 17 00:00:00 2001 -From: Gerald Dachs -Date: Wed, 3 Feb 2016 19:19:49 +0100 -Subject: [PATCH] New amlogic cec driver - ---- - .../mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c | 3 +- - drivers/amlogic/hdmi/Kconfig | 8 + - drivers/amlogic/hdmi/hdmi_tx/Makefile | 8 +- - drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c | 534 +++++++++++++++++++++ - drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c | 11 +- - drivers/amlogic/input/new_remote/remote_func.c | 6 + - drivers/amlogic/input/remote/am_remote.c | 2 + - 7 files changed, 569 insertions(+), 3 deletions(-) - create mode 100644 drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c - -diff --git a/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c b/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c -index a2a78bd..762feba 100644 ---- a/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c -+++ b/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c -@@ -996,6 +996,7 @@ void cec_tx_irq_handle(void) - #endif - } - -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - void cec_polling_online_dev(int log_addr, int *bool) - { - #ifdef AO_CEC -@@ -1005,7 +1006,7 @@ void cec_polling_online_dev(int log_addr, int *bool) - #endif - hdmi_print(INF, CEC "CEC: poll online logic device: 0x%x BOOL: %d\n", log_addr, *bool); - } -- -+#endif - - // DELETE LATER, TEST ONLY - void cec_test_(unsigned int cmd) -diff --git a/drivers/amlogic/hdmi/Kconfig b/drivers/amlogic/hdmi/Kconfig -index 71f6bf8..1bfc289 100755 ---- a/drivers/amlogic/hdmi/Kconfig -+++ b/drivers/amlogic/hdmi/Kconfig -@@ -24,4 +24,12 @@ config AML_HDMI_TX_HDCP - hdmitx hdcp enable, it should be enalbe if board burned hdmitx hdcp keys - endif - -+if AML_HDMI_TX -+config AML_HDMI_TX_NEW_CEC_DRIVER -+ bool "HDMI new CEC driver" -+ default n -+ help -+ hdmitx uses new CEC driver -+endif -+ - endmenu -diff --git a/drivers/amlogic/hdmi/hdmi_tx/Makefile b/drivers/amlogic/hdmi/hdmi_tx/Makefile -index 7a944cd..f74ec1f 100755 ---- a/drivers/amlogic/hdmi/hdmi_tx/Makefile -+++ b/drivers/amlogic/hdmi/hdmi_tx/Makefile -@@ -1,5 +1,11 @@ - obj-$(CONFIG_AML_HDMI_TX) += hdmitx.o - --hdmitx-objs := hdmi_tx.o hdmi_tx_cec.o hdmi_cec_key.o hdmi_tx_video.o hdmi_tx_audio.o hdmi_tx_edid.o hdmi_tx_audio.o hdmi_tx_hdcp.o hdmi_tx_compliance.o -+hdmitx-objs := hdmi_tx.o hdmi_tx_video.o hdmi_tx_audio.o hdmi_tx_edid.o hdmi_tx_audio.o hdmi_tx_hdcp.o hdmi_tx_compliance.o -+ -+ifdef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER -+ hdmitx-objs += amlogic_cec.o -+else -+ hdmitx-objs += hdmi_tx_cec.o hdmi_cec_key.o -+endif - - #EXTRA_CFLAGS += -O2 diff --git a/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c -new file mode 100644 -index 0000000..61fb500 ---- /dev/null +index 61fb500..d1d3511 100644 +--- a/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c +++ b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c -@@ -0,0 +1,534 @@ -+/* linux/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c -+ * -+ * Copyright (c) 2016 Gerald Dachs -+ * -+ * CEC interface file for Amlogic -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ +@@ -36,7 +36,9 @@ + #include + #include + +-#define CONFIG_TV_DEBUG ++#define CONFIG_TV_DEBUG // for verbose output ++//#undef CONFIG_TV_DEBUG ++bool cec_msg_dbg_en = 1; + + MODULE_AUTHOR("Gerald Dachs"); + MODULE_DESCRIPTION("Amlogic CEC driver"); +@@ -55,24 +57,16 @@ MODULE_LICENSE("GPL"); + #define CEC_TX_BUFF_SIZE 16 + + #define DRV_NAME "amlogic_cec" +-#ifndef tvout_dbg ++#ifndef amlogic_cec_log_dbg + #ifdef CONFIG_TV_DEBUG +-#define tvout_dbg(fmt, ...) \ ++#define amlogic_cec_log_dbg(fmt, ...) \ + printk(KERN_INFO "[%s] %s(): " fmt, \ + DRV_NAME, __func__, ##__VA_ARGS__) + #else +-#define tvout_dbg(fmt, ...) ++#define amlogic_cec_log_dbg(fmt, ...) + #endif + #endif + +-static atomic_t hdmi_on = ATOMIC_INIT(0); +- +-bool cec_msg_dbg_en = 1; +-cec_global_info_t cec_global_info; +- +-static hdmitx_dev_t* hdmitx_device = NULL; +-static struct workqueue_struct *cec_workqueue = NULL; +- + struct cec_rx_list { + u8 buffer[CEC_RX_BUFF_SIZE]; + unsigned char size; +@@ -86,6 +80,12 @@ struct cec_rx_struct { + struct list_head list; + }; + ++struct cec_tx_struct { ++ spinlock_t lock; ++ wait_queue_head_t waitq; ++ atomic_t state; ++}; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define CONFIG_TV_DEBUG -+ -+MODULE_AUTHOR("Gerald Dachs"); -+MODULE_DESCRIPTION("Amlogic CEC driver"); -+MODULE_LICENSE("GPL"); -+ -+#define CEC_IOC_MAGIC 'c' -+#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int) -+#define CEC_IOC_GETPADDR _IO(CEC_IOC_MAGIC, 1) -+ -+#define VERSION "1.0" /* Driver version number */ -+#define CEC_MINOR 243 /* Major 10, Minor 242, /dev/cec */ -+ -+/* CEC Rx buffer size */ -+#define CEC_RX_BUFF_SIZE 16 -+/* CEC Tx buffer size */ -+#define CEC_TX_BUFF_SIZE 16 -+ -+#define DRV_NAME "amlogic_cec" -+#ifndef tvout_dbg -+#ifdef CONFIG_TV_DEBUG -+#define tvout_dbg(fmt, ...) \ -+ printk(KERN_INFO "[%s] %s(): " fmt, \ -+ DRV_NAME, __func__, ##__VA_ARGS__) -+#else -+#define tvout_dbg(fmt, ...) -+#endif -+#endif + enum cec_state { + STATE_RX, + STATE_TX, +@@ -98,58 +98,133 @@ static char banner[] __initdata = + + static struct cec_rx_struct cec_rx_struct; + +-unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) ++static struct cec_tx_struct cec_tx_struct; + +static atomic_t hdmi_on = ATOMIC_INIT(0); + -+bool cec_msg_dbg_en = 1; +cec_global_info_t cec_global_info; + +static hdmitx_dev_t* hdmitx_device = NULL; +static struct workqueue_struct *cec_workqueue = NULL; + -+struct cec_rx_list { -+ u8 buffer[CEC_RX_BUFF_SIZE]; -+ unsigned char size; -+ struct list_head list; -+}; -+ -+struct cec_rx_struct { -+ spinlock_t lock; -+ wait_queue_head_t waitq; -+ atomic_t state; -+ struct list_head list; -+}; -+ -+enum cec_state { -+ STATE_RX, -+ STATE_TX, -+ STATE_DONE, -+ STATE_ERROR -+}; -+ -+static char banner[] __initdata = -+ "Amlogic CEC Driver, (c) 2016 Gerald Dachs\n"; -+ -+static struct cec_rx_struct cec_rx_struct; -+ -+unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) -+{ -+ unsigned short us = CEC_UNREGISTERED_DEVICE_TYPE; -+ if ((1 << log_addr) & CEC_DISPLAY_DEVICE) -+ { -+ us = CEC_DISPLAY_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_RECORDING_DEVICE) -+ { -+ us = CEC_RECORDING_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_PLAYBACK_DEVICE) -+ { -+ us = CEC_PLAYBACK_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_TUNER_DEVICE) -+ { -+ us = CEC_TUNER_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_AUDIO_SYSTEM_DEVICE) -+ { -+ us = CEC_AUDIO_SYSTEM_DEVICE_TYPE; -+ } -+ -+ return us; -+} -+ -+void cec_report_physical_address_smp(void) -+{ -+ unsigned char msg[5]; -+ unsigned char index = cec_global_info.my_node_index; -+ unsigned char phy_addr_ab = (aml_read_reg32(P_AO_DEBUG_REG1) >> 8) & 0xff; -+ unsigned char phy_addr_cd = aml_read_reg32(P_AO_DEBUG_REG1) & 0xff; -+ -+ tvout_dbg("cec_report_physical_address_smp: enter\n"); -+ -+ msg[0] = ((index & 0xf) << 4) | CEC_BROADCAST_ADDR; -+ msg[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS; -+ msg[2] = phy_addr_ab; -+ msg[3] = phy_addr_cd; -+ msg[4] = cec_log_addr_to_dev_type(index); -+ -+ cec_ll_tx(msg, 5); -+ -+ tvout_dbg("cec_report_physical_address_smp: leave\n"); -+} -+ -+void cec_node_init(hdmitx_dev_t* hdmitx_device) -+{ -+ unsigned long cec_phy_addr; -+ -+ tvout_dbg("cec node init: enter\n"); -+ -+ cec_phy_addr = (((hdmitx_device->hdmi_info.vsdb_phy_addr.a) & 0xf) << 12) -+ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.b) & 0xf) << 8) -+ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.c) & 0xf) << 4) -+ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.d) & 0xf) << 0); -+ -+ // If VSDB is not valid,use last or default physical address. -+ if (hdmitx_device->hdmi_info.vsdb_phy_addr.valid == 0) -+ { -+ tvout_dbg("no valid cec physical address\n"); -+ if (aml_read_reg32 (P_AO_DEBUG_REG1)) -+ { -+ tvout_dbg("use last physical address\n"); -+ } -+ else -+ { -+ aml_write_reg32 (P_AO_DEBUG_REG1, 0x1000); -+ tvout_dbg("use default physical address\n"); -+ } -+ } -+ else -+ { -+ aml_write_reg32 (P_AO_DEBUG_REG1, cec_phy_addr); -+ } -+ tvout_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); -+ -+ if (hdmitx_device->cec_init_ready != 0) -+ { -+ tvout_dbg("report physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); -+ cec_report_physical_address_smp(); -+ } -+ tvout_dbg("cec node init: cec features ok !\n"); -+} ++static int cec_init_flag = 0; + +static void amlogic_cec_set_rx_state(enum cec_state state) -+{ + { +- unsigned short us = CEC_UNREGISTERED_DEVICE_TYPE; +- if ((1 << log_addr) & CEC_DISPLAY_DEVICE) +- { +- us = CEC_DISPLAY_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_RECORDING_DEVICE) +- { +- us = CEC_RECORDING_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_PLAYBACK_DEVICE) +- { +- us = CEC_PLAYBACK_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_TUNER_DEVICE) +- { +- us = CEC_TUNER_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_AUDIO_SYSTEM_DEVICE) + atomic_set(&cec_rx_struct.state, state); +} + -+static int amlogic_cec_open(struct inode *inode, struct file *file) ++static void amlogic_cec_set_tx_state(enum cec_state state) +{ -+ int ret = 0; ++ atomic_set(&cec_tx_struct.state, state); ++} ++ ++static void amlogic_cec_msg_dump(char * msg_tag, const unsigned char *data, unsigned char count) ++{ ++ int i; ++ int pos; ++ unsigned char msg_log_buf[128] = { 0 }; ++ ++ if (cec_msg_dbg_en == 1) ++ { ++ pos = 0; ++ pos += sprintf(msg_log_buf + pos, "msg %s len: %d dat: ", msg_tag, count); ++ for (i = 0; i < count; ++i) ++ { ++ pos += sprintf(msg_log_buf + pos, "%02x ", data[i]); ++ } ++ pos += sprintf(msg_log_buf + pos, "\n"); ++ msg_log_buf[pos] = '\0'; ++ hdmi_print(INF, "[amlogic_cec] dump: %s", msg_log_buf); ++ } ++} ++ ++static unsigned int amlogic_cec_read_reg(unsigned int reg) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ return hdmi_rd_reg(CEC0_BASE_ADDR + reg); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ return aocec_rd_reg(reg); ++#endif ++} ++ ++static void amlogic_cec_write_reg(unsigned int reg, unsigned int value) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ hdmi_wr_reg(CEC0_BASE_ADDR + reg, value); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ aocec_wr_reg(reg, value); ++#endif ++} ++ ++static int amlogic_cec_read_hw(unsigned char *data, unsigned char *count) ++{ ++ int ret = -1; ++ int valid_msg; ++ int rx_msg_status; ++ int rx_num_msg; ++ ++ rx_msg_status = amlogic_cec_read_reg(CEC_RX_MSG_STATUS); ++ rx_num_msg = amlogic_cec_read_reg(CEC_RX_NUM_MSG); ++ ++ amlogic_cec_log_dbg("amlogic_cec_read_hw: enter: CEC_RX_MSG_STATUS %d, CEC_RX_NUM_MSG %d\n", rx_msg_status, rx_num_msg); ++ ++ valid_msg = (RX_DONE == rx_msg_status) && (1 == rx_num_msg); ++ ++ if (valid_msg) + { +- us = CEC_AUDIO_SYSTEM_DEVICE_TYPE; ++ int i; ++ ++ *count = amlogic_cec_read_reg(CEC_RX_MSG_LENGTH) + 1; ++ for (i = 0; i < (*count) && i < CEC_RX_BUFF_SIZE; ++i) ++ { ++ data[i]= amlogic_cec_read_reg(CEC_RX_MSG_0_HEADER + i); ++ } ++ ++ amlogic_cec_msg_dump("RX", data, *count); ++ ++ ret = RX_DONE; + } + +- return us; ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ aml_write_reg32(P_AO_CEC_INTR_CLR, aml_read_reg32(P_AO_CEC_INTR_CLR) | (1 << 2)); ++#endif ++ amlogic_cec_write_reg(CEC_RX_MSG_CMD, valid_msg ? RX_ACK_NEXT : RX_ACK_CURRENT); ++ amlogic_cec_write_reg(CEC_RX_MSG_CMD, RX_NO_OP); + -+ if (atomic_read(&hdmi_on)) -+ { -+ tvout_dbg("do not allow multiple open for tvout cec\n"); -+ ret = -EBUSY; -+ } -+ else -+ { -+ atomic_inc(&hdmi_on); -+ } + return ret; -+} -+ -+static int amlogic_cec_release(struct inode *inode, struct file *file) + } + +-void cec_report_physical_address_smp(void) +-{ +- unsigned char msg[5]; +- unsigned char index = cec_global_info.my_node_index; +- unsigned char phy_addr_ab = (aml_read_reg32(P_AO_DEBUG_REG1) >> 8) & 0xff; +- unsigned char phy_addr_cd = aml_read_reg32(P_AO_DEBUG_REG1) & 0xff; + +- tvout_dbg("cec_report_physical_address_smp: enter\n"); ++static void amlogic_cec_write_hw(const char *data, size_t count) +{ -+ atomic_dec(&hdmi_on); -+ -+ return 0; ++ int i; + +- msg[0] = ((index & 0xf) << 4) | CEC_BROADCAST_ADDR; +- msg[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS; +- msg[2] = phy_addr_ab; +- msg[3] = phy_addr_cd; +- msg[4] = cec_log_addr_to_dev_type(index); ++ for (i = 0; i < count; ++i) ++ { ++ amlogic_cec_write_reg(CEC_TX_MSG_0_HEADER + i, data[i]); ++ } ++ amlogic_cec_write_reg(CEC_TX_MSG_LENGTH, count - 1); ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); + +- cec_ll_tx(msg, 5); ++ amlogic_cec_msg_dump("TX", data, count); +} -+ -+static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, -+ size_t count, loff_t *ppos) + +- tvout_dbg("cec_report_physical_address_smp: leave\n"); ++unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) +{ -+ ssize_t retval; ++// unused, just to satisfy the linker ++ return log_addr; + } + + void cec_node_init(hdmitx_dev_t* hdmitx_device) + { + unsigned long cec_phy_addr; + unsigned long spin_flags; -+ struct cec_rx_list* entry = NULL; ++ struct cec_rx_list *entry; + +- tvout_dbg("cec node init: enter\n"); ++ amlogic_cec_log_dbg("cec node init: enter\n"); + + cec_phy_addr = (((hdmitx_device->hdmi_info.vsdb_phy_addr.a) & 0xf) << 12) + | (((hdmitx_device->hdmi_info.vsdb_phy_addr.b) & 0xf) << 8) +@@ -159,34 +234,46 @@ void cec_node_init(hdmitx_dev_t* hdmitx_device) + // If VSDB is not valid,use last or default physical address. + if (hdmitx_device->hdmi_info.vsdb_phy_addr.valid == 0) + { +- tvout_dbg("no valid cec physical address\n"); +- if (aml_read_reg32 (P_AO_DEBUG_REG1)) ++ amlogic_cec_log_dbg("no valid cec physical address\n"); ++ if (aml_read_reg32(P_AO_DEBUG_REG1)) + { +- tvout_dbg("use last physical address\n"); ++ amlogic_cec_log_dbg("use last physical address\n"); + } + else + { +- aml_write_reg32 (P_AO_DEBUG_REG1, 0x1000); +- tvout_dbg("use default physical address\n"); ++ aml_write_reg32(P_AO_DEBUG_REG1, 0x1000); ++ amlogic_cec_log_dbg("use default physical address\n"); + } + } + else + { +- aml_write_reg32 (P_AO_DEBUG_REG1, cec_phy_addr); +- } +- tvout_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); ++ aml_write_reg32(P_AO_DEBUG_REG1, cec_phy_addr); ++ amlogic_cec_log_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); + +- if (hdmitx_device->cec_init_ready != 0) +- { +- tvout_dbg("report physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); +- cec_report_physical_address_smp(); ++ if ((hdmitx_device->cec_init_ready != 0) && (hdmitx_device->hpd_state != 0)) ++ { ++ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ { ++ amlogic_cec_log_dbg("can't alloc cec_rx_list\n"); ++ } ++ else ++ { ++ // let the libCEC ask for new physical Address ++ entry->buffer[0] = 0xff; ++ entry->size = 1; ++ INIT_LIST_HEAD(&entry->list); + -+ tvout_dbg("amlogic_cec_read: enter\n"); ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ list_add_tail(&entry->list, &cec_rx_struct.list); ++ amlogic_cec_set_rx_state(STATE_DONE); ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); + -+ if (wait_event_interruptible(cec_rx_struct.waitq, -+ atomic_read(&cec_rx_struct.state) == STATE_DONE)) ++ amlogic_cec_log_dbg("trigger libCEC\n"); ++ wake_up_interruptible(&cec_rx_struct.waitq); ++ } ++ } + } +- tvout_dbg("cec node init: cec features ok !\n"); +-} +- +-static void amlogic_cec_set_rx_state(enum cec_state state) +-{ +- atomic_set(&cec_rx_struct.state, state); ++ amlogic_cec_log_dbg("cec node init: cec features ok !\n"); + } + + static int amlogic_cec_open(struct inode *inode, struct file *file) +@@ -195,7 +282,7 @@ static int amlogic_cec_open(struct inode *inode, struct file *file) + + if (atomic_read(&hdmi_on)) + { +- tvout_dbg("do not allow multiple open for tvout cec\n"); ++ amlogic_cec_log_dbg("do not allow multiple open for tvout cec\n"); + ret = -EBUSY; + } + else +@@ -219,12 +306,12 @@ static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, + unsigned long spin_flags; + struct cec_rx_list* entry = NULL; + +- tvout_dbg("amlogic_cec_read: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_read: enter\n"); + + if (wait_event_interruptible(cec_rx_struct.waitq, + atomic_read(&cec_rx_struct.state) == STATE_DONE)) + { +- tvout_dbg("error during wait on state change\n"); ++ amlogic_cec_log_dbg("error during wait on state change\n"); + return -ERESTARTSYS; + } + +@@ -234,7 +321,7 @@ static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, + + if (entry == NULL || entry->size > count) + { +- tvout_dbg("entry is NULL, or empty\n"); ++ amlogic_cec_log_dbg("entry is NULL, or empty\n"); + retval = -1; + goto error_exit; + } +@@ -260,7 +347,7 @@ error_exit: + + spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); + +- tvout_dbg("amlogic_cec_read: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_read: leave\n"); + + return retval; + } +@@ -268,11 +355,8 @@ error_exit: + static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) + { +- int ret = 0; +- + char data[CEC_TX_BUFF_SIZE]; +- +- tvout_dbg("amlogic_cec_write: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_write: enter\n"); + + /* check data size */ + if (count > CEC_TX_BUFF_SIZE || count == 0) +@@ -284,14 +368,34 @@ static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, + return -EFAULT; + } + +- ret = cec_ll_tx(data, count); +- if (ret != 1) ++ amlogic_cec_set_tx_state(STATE_TX); ++ ++ // just for the case that the first write starts ++ // before the end of amlogic_cec_delayed_init() ++ if (wait_event_interruptible(cec_tx_struct.waitq, hdmitx_device->cec_init_ready == 1)) + { -+ tvout_dbg("error during wait on state change\n"); ++ amlogic_cec_log_dbg("error during wait on state change\n"); ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); + return -ERESTARTSYS; + } + -+ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ amlogic_cec_write_hw(data, count); + -+ entry = list_first_entry_or_null(&cec_rx_struct.list, struct cec_rx_list, list); -+ -+ if (entry == NULL || entry->size > count) ++ if (wait_event_interruptible_timeout(cec_tx_struct.waitq, ++ atomic_read(&cec_tx_struct.state) != STATE_TX, 1 * HZ) <= 0) + { -+ tvout_dbg("entry is NULL, or empty\n"); -+ retval = -1; -+ goto error_exit; ++ amlogic_cec_log_dbg("error during wait on state change\n"); ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); ++ return -ERESTARTSYS; + } + -+ if (copy_to_user(buffer, entry->buffer, entry->size)) -+ { -+ printk(KERN_ERR " copy_to_user() failed!\n"); -+ -+ retval = -EFAULT; -+ goto error_exit; -+ } -+ -+ retval = entry->size; -+ -+ amlogic_cec_set_rx_state(STATE_RX); -+ -+error_exit: -+ if (entry != NULL) -+ { -+ list_del(&entry->list); -+ kfree(entry); -+ } -+ -+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); -+ -+ tvout_dbg("amlogic_cec_read: leave\n"); -+ -+ return retval; -+} -+ -+static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ int ret = 0; -+ -+ char data[CEC_TX_BUFF_SIZE]; -+ -+ tvout_dbg("amlogic_cec_write: enter\n"); -+ -+ /* check data size */ -+ if (count > CEC_TX_BUFF_SIZE || count == 0) ++ if (atomic_read(&cec_tx_struct.state) != STATE_DONE) + { +- tvout_dbg("Message transmit failed, ret=%d\n", ret); +- return -1; ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); + return -1; -+ -+ if (copy_from_user(data, buffer, count)) -+ { -+ printk(KERN_ERR " copy_from_user() failed!\n"); -+ return -EFAULT; -+ } -+ -+ ret = cec_ll_tx(data, count); -+ if (ret != 1) -+ { -+ tvout_dbg("Message transmit failed, ret=%d\n", ret); -+ return -1; -+ } -+ -+ tvout_dbg("amlogic_cec_write: leave\n"); -+ -+ return count; -+} -+ -+static long amlogic_cec_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ unsigned char logical_addr; -+ -+ switch(cmd) { -+ case CEC_IOC_SETLADDR: -+ if (get_user(logical_addr, (unsigned char __user *)arg)) -+ { -+ tvout_dbg("Failed to get logical addr from user\n"); -+ return -EFAULT; -+ } -+ -+ cec_global_info.my_node_index = logical_addr; -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ aocec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); -+#endif -+ tvout_dbg("Set logical address: %d\n", logical_addr); -+ return 0; -+ -+ case CEC_IOC_GETPADDR: -+ return aml_read_reg32(P_AO_DEBUG_REG1); -+ } -+ -+ return -EINVAL; -+} -+ -+static u32 amlogic_cec_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &cec_rx_struct.waitq, wait); -+ -+ if (atomic_read(&cec_rx_struct.state) == STATE_DONE) -+ { -+ return POLLIN | POLLRDNORM; -+ } -+ return 0; -+} -+ -+static const struct file_operations cec_fops = { -+ .owner = THIS_MODULE, -+ .open = amlogic_cec_open, -+ .release = amlogic_cec_release, -+ .read = amlogic_cec_read, -+ .write = amlogic_cec_write, -+ .unlocked_ioctl = amlogic_cec_ioctl, -+ .poll = amlogic_cec_poll, -+}; -+ -+static struct miscdevice cec_misc_device = { -+ .minor = CEC_MINOR, -+ .name = "AmlogicCEC", -+ .fops = &cec_fops, -+}; -+ -+static irqreturn_t amlogic_cec_irq_handler(int irq, void *dummy) -+{ -+ unsigned long spin_flags; -+ struct cec_rx_list *entry; -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ unsigned int intr_stat = 0; -+#endif -+ -+ tvout_dbg("amlogic_cec_irq_handler: enter\n"); -+ -+ udelay(100); //Delay execution a little. This fixes an issue when HDMI CEC stops working after a while. -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ tvout_dbg("cec TX status: rx: 0x%x; tx: 0x%x\n", hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS), hdmi_rd_reg(CEC0_BASE_ADDR+CEC_TX_MSG_STATUS)); -+ if (hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS) != RX_DONE) -+ { -+ return IRQ_HANDLED; -+ } -+#endif -+ -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ intr_stat = aml_read_reg32(P_AO_CEC_INTR_STAT); -+ tvout_dbg("aocec irq %x\n", intr_stat); -+ if (intr_stat & (1<<1)) -+ { // aocec tx intr -+ tx_irq_handle(); -+ return IRQ_HANDLED; -+ } -+#endif -+ -+ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) -+ { -+ tvout_dbg("can't alloc cec_rx_list\n"); -+ return IRQ_HANDLED; -+ } -+ -+ if ((-1) == cec_ll_rx(entry->buffer, &entry->size)) -+ { -+ kfree(entry); -+ tvout_dbg("amlogic_cec_irq_handler: nothing to read\n"); -+ return IRQ_HANDLED; -+ } -+ -+ INIT_LIST_HEAD(&entry->list); -+ -+ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); -+ list_add_tail(&entry->list, &cec_rx_struct.list); -+ amlogic_cec_set_rx_state(STATE_DONE); -+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); -+ -+ wake_up_interruptible(&cec_rx_struct.waitq); -+ -+ tvout_dbg("amlogic_cec_irq_handler: leave\n"); -+ -+ return IRQ_HANDLED; -+} -+ -+static void amlogic_cec_delayed_init(struct work_struct *work) -+{ -+ hdmitx_dev_t* hdmitx_device = (hdmitx_dev_t*)container_of(work, hdmitx_dev_t, cec_work); -+ -+ tvout_dbg("amlogic_cec_delayed_init: enter\n"); -+ -+ msleep_interruptible(15000); -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ cec_gpi_init(); -+#endif -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ aml_set_reg32_bits(P_PERIPHS_PIN_MUX_1, 1, 25, 1); -+ // Clear CEC Int. state and set CEC Int. mask -+ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_STAT_CLR, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_STAT_CLR) | (1 << 23)); // Clear the interrupt -+ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK) | (1 << 23)); // Enable the hdmi cec interrupt -+ -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+#if 1 // Please match with H/W cec config -+// GPIOAO_12 -+ aml_set_reg32_bits(P_AO_RTI_PIN_MUX_REG, 0, 14, 1); // bit[14]: AO_PWM_C pinmux //0xc8100014 -+ aml_set_reg32_bits(P_AO_RTI_PULL_UP_REG, 1, 12, 1); // bit[12]: enable AO_12 internal pull-up //0xc810002c -+ aml_set_reg32_bits(P_AO_RTI_PIN_MUX_REG, 1, 17, 1); // bit[17]: AO_CEC pinmux //0xc8100014 -+ ao_cec_init(); -+#else -+// GPIOH_3 -+ aml_set_reg32_bits(P_PAD_PULL_UP_EN_REG1, 0, 19, 1); // disable gpioh_3 internal pull-up -+ aml_set_reg32_bits(P_PERIPHS_PIN_MUX_1, 1, 23, 1); // gpioh_3 cec pinmux -+#endif -+ cec_arbit_bit_time_set(3, 0x118, 0); -+ cec_arbit_bit_time_set(5, 0x000, 0); -+ cec_arbit_bit_time_set(7, 0x2aa, 0); -+#endif -+ -+ hdmitx_device->cec_init_ready = 1; -+ cec_global_info.cec_flag.cec_init_flag = 0; -+ -+ tvout_dbg("amlogic_cec_delayed_init: leave\n"); -+} -+ -+static int amlogic_cec_init(void) -+{ -+ extern hdmitx_dev_t * get_hdmitx_device(void); -+ INIT_LIST_HEAD(&cec_rx_struct.list); -+ -+ printk(banner); -+ -+ hdmitx_device = get_hdmitx_device(); -+ tvout_dbg("CEC init\n"); -+ memset(&cec_global_info, 0, sizeof(cec_global_info_t)); -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_H, 0x00 ); -+ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_L, 0xf0 ); -+#endif -+ -+ cec_global_info.cec_rx_msg_buf.rx_buf_size = sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message)/sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message[0]); -+ cec_global_info.hdmitx_device = hdmitx_device; -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ if (request_irq(INT_HDMI_CEC, &amlogic_cec_irq_handler, -+ IRQF_SHARED, "amhdmitx-cec",(void *)hdmitx_device)) -+ { -+ tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); -+ return -EFAULT; -+ } -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ if (request_irq(INT_AO_CEC, &amlogic_cec_irq_handler, -+ IRQF_SHARED, "amhdmitx-aocec",(void *)hdmitx_device)) -+ { -+ tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); -+ return -EFAULT; -+ } -+#endif -+ -+ init_waitqueue_head(&cec_rx_struct.waitq); -+ spin_lock_init(&cec_rx_struct.lock); -+ -+ if (misc_register(&cec_misc_device)) -+ { -+ printk(KERN_WARNING " Couldn't register device 10, %d.\n", CEC_MINOR); -+ return -EBUSY; -+ } -+ -+ cec_workqueue = create_workqueue("cec_work"); -+ if (cec_workqueue == NULL) -+ { -+ printk("create work queue failed\n"); -+ return -EFAULT; -+ } -+ INIT_WORK(&hdmitx_device->cec_work, amlogic_cec_delayed_init); -+ queue_work(cec_workqueue, &hdmitx_device->cec_work); // for init -+ -+ tvout_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); -+ -+ return 0; -+} -+ -+static void amlogic_cec_exit(void) -+{ -+ if (cec_global_info.cec_flag.cec_init_flag == 1) -+ { -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK) & ~(1 << 23)); // Disable the hdmi cec interrupt -+ free_irq(INT_HDMI_CEC, (void *)hdmitx_device); -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ free_irq(INT_AO_CEC, (void *)hdmitx_device); -+#endif -+ cec_global_info.cec_flag.cec_init_flag = 0; -+ } -+ -+ misc_deregister(&cec_misc_device); -+} -+ -+module_init(amlogic_cec_init); -+module_exit(amlogic_cec_exit); -+ -diff --git a/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c b/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c -index 3e043bc..69b3ffc 100755 ---- a/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c -+++ b/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c -@@ -542,6 +542,7 @@ static ssize_t store_disp_mode(struct device * dev, struct device_attribute *att - return 16; - } + } -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - /*cec attr*/ - static ssize_t show_cec(struct device * dev, struct device_attribute *attr, char * buf) +- tvout_dbg("amlogic_cec_write: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_write: leave\n"); + + return count; + } +@@ -300,26 +404,22 @@ static long amlogic_cec_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { -@@ -589,6 +590,7 @@ static ssize_t show_cec_lang_config(struct device * dev, struct device_attribute - pos+=snprintf(buf+pos, PAGE_SIZE, "%x\n",cec_global_info.cec_node_info[cec_global_info.my_node_index].menu_lang); - return pos; + unsigned char logical_addr; ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: enter\n"); + + switch(cmd) { + case CEC_IOC_SETLADDR: + if (get_user(logical_addr, (unsigned char __user *)arg)) + { +- tvout_dbg("Failed to get logical addr from user\n"); ++ amlogic_cec_log_dbg("Failed to get logical addr from user\n"); + return -EFAULT; + } + +- cec_global_info.my_node_index = logical_addr; +-#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 +- hdmi_wr_reg(CEC0_BASE_ADDR+CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); +-#endif +-#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 +- aocec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); +-#endif +- tvout_dbg("Set logical address: %d\n", logical_addr); ++ amlogic_cec_write_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: Set logical address: %d\n", logical_addr); + return 0; + + case CEC_IOC_GETPADDR: ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: return physical address 0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); + return aml_read_reg32(P_AO_DEBUG_REG1); + } + +@@ -357,55 +457,63 @@ static irqreturn_t amlogic_cec_irq_handler(int irq, void *dummy) + { + unsigned long spin_flags; + struct cec_rx_list *entry; +-#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 +- unsigned int intr_stat = 0; +-#endif ++ unsigned int tx_msg_state; ++ unsigned int rx_msg_state; + +- tvout_dbg("amlogic_cec_irq_handler: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: enter\n"); + + udelay(100); //Delay execution a little. This fixes an issue when HDMI CEC stops working after a while. + +-#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 +- tvout_dbg("cec TX status: rx: 0x%x; tx: 0x%x\n", hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS), hdmi_rd_reg(CEC0_BASE_ADDR+CEC_TX_MSG_STATUS)); +- if (hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS) != RX_DONE) +- { +- return IRQ_HANDLED; +- } +-#endif ++ tx_msg_state = amlogic_cec_read_reg(CEC_TX_MSG_STATUS); ++ rx_msg_state = amlogic_cec_read_reg(CEC_RX_MSG_STATUS); + +-#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 +- intr_stat = aml_read_reg32(P_AO_CEC_INTR_STAT); +- tvout_dbg("aocec irq %x\n", intr_stat); +- if (intr_stat & (1<<1)) +- { // aocec tx intr +- tx_irq_handle(); +- return IRQ_HANDLED; +- } +-#endif ++ amlogic_cec_log_dbg("cec msg status: rx: 0x%x; tx: 0x%x\n", rx_msg_state, tx_msg_state); + +- if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ if ((tx_msg_state == TX_DONE) || (tx_msg_state == TX_ERROR)) + { +- tvout_dbg("can't alloc cec_rx_list\n"); +- return IRQ_HANDLED; ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ ++ switch (tx_msg_state) { ++ case TX_ERROR : ++ amlogic_cec_set_tx_state(STATE_ERROR); ++ break; ++ case TX_DONE : ++ amlogic_cec_set_tx_state(STATE_DONE); ++ break; ++ default : ++ amlogic_cec_log_dbg("unexpected ts message state: 0x%x", tx_msg_state); ++ break; ++ } ++ wake_up_interruptible(&cec_tx_struct.waitq); + } + +- if ((-1) == cec_ll_rx(entry->buffer, &entry->size)) ++ if (rx_msg_state == RX_DONE) + { +- kfree(entry); +- tvout_dbg("amlogic_cec_irq_handler: nothing to read\n"); +- return IRQ_HANDLED; +- } + +- INIT_LIST_HEAD(&entry->list); ++ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ { ++ amlogic_cec_log_dbg("can't alloc cec_rx_list\n"); ++ return IRQ_HANDLED; ++ } + +- spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); +- list_add_tail(&entry->list, &cec_rx_struct.list); +- amlogic_cec_set_rx_state(STATE_DONE); +- spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); ++ if ((-1) == amlogic_cec_read_hw(entry->buffer, &entry->size)) ++ { ++ kfree(entry); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: nothing to read\n"); ++ return IRQ_HANDLED; ++ } ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ list_add_tail(&entry->list, &cec_rx_struct.list); ++ amlogic_cec_set_rx_state(STATE_DONE); ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); + +- wake_up_interruptible(&cec_rx_struct.waitq); ++ wake_up_interruptible(&cec_rx_struct.waitq); ++ } + +- tvout_dbg("amlogic_cec_irq_handler: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: leave\n"); + + return IRQ_HANDLED; } -+#endif +@@ -414,10 +522,12 @@ static void amlogic_cec_delayed_init(struct work_struct *work) + { + hdmitx_dev_t* hdmitx_device = (hdmitx_dev_t*)container_of(work, hdmitx_dev_t, cec_work); - /*aud_mode attr*/ - static ssize_t show_aud_mode(struct device * dev, struct device_attribute *attr, char * buf) -@@ -963,10 +965,12 @@ static DEVICE_ATTR(disp_cap_3d, S_IWUSR | S_IRUGO, show_disp_cap_3d, NULL); - static DEVICE_ATTR(hdcp_ksv_info, S_IWUSR | S_IRUGO, show_hdcp_ksv_info, NULL); - static DEVICE_ATTR(hpd_state, S_IWUSR | S_IRUGO, show_hpd_state, NULL); - static DEVICE_ATTR(support_3d, S_IWUSR | S_IRUGO, show_support_3d, NULL); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - static DEVICE_ATTR(cec, S_IWUSR | S_IRUGO, show_cec, store_cec); - static DEVICE_ATTR(cec_config, S_IWUSR | S_IRUGO | S_IWGRP, show_cec_config, store_cec_config); - //static DEVICE_ATTR(cec_config, S_IWUGO | S_IRUGO , NULL, store_cec_config); - static DEVICE_ATTR(cec_lang_config, S_IWUSR | S_IRUGO | S_IWGRP, show_cec_lang_config, store_cec_lang_config); -+#endif +- tvout_dbg("amlogic_cec_delayed_init: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_delayed_init: enter\n"); - /***************************** - * hdmitx display client interface -@@ -1643,9 +1647,11 @@ static int amhdmitx_probe(struct platform_device *pdev) - ret=device_create_file(hdmitx_dev, &dev_attr_hdcp_ksv_info); - ret=device_create_file(hdmitx_dev, &dev_attr_hpd_state); - ret=device_create_file(hdmitx_dev, &dev_attr_support_3d); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - ret=device_create_file(hdmitx_dev, &dev_attr_cec); - ret=device_create_file(hdmitx_dev, &dev_attr_cec_config); - ret=device_create_file(hdmitx_dev, &dev_attr_cec_lang_config); -+#endif + msleep_interruptible(15000); - if (hdmitx_dev == NULL) { - hdmi_print(ERR, SYS "device_create create error\n"); -@@ -1732,7 +1738,9 @@ static int amhdmitx_probe(struct platform_device *pdev) ++ cec_init_flag = 1; ++ + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 + cec_gpi_init(); + #endif +@@ -446,10 +556,12 @@ static void amlogic_cec_delayed_init(struct work_struct *work) + cec_arbit_bit_time_set(7, 0x2aa, 0); + #endif + ++ cec_init_flag = 0; ++ + hdmitx_device->cec_init_ready = 1; +- cec_global_info.cec_flag.cec_init_flag = 0; ++ wake_up_interruptible(&cec_tx_struct.waitq); + +- tvout_dbg("amlogic_cec_delayed_init: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_delayed_init: leave\n"); + } + + static int amlogic_cec_init(void) +@@ -460,22 +572,17 @@ static int amlogic_cec_init(void) + printk(banner); + + hdmitx_device = get_hdmitx_device(); +- tvout_dbg("CEC init\n"); +- memset(&cec_global_info, 0, sizeof(cec_global_info_t)); +- ++ amlogic_cec_log_dbg("CEC init\n"); + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 + hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_H, 0x00 ); + hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_L, 0xf0 ); + #endif + +- cec_global_info.cec_rx_msg_buf.rx_buf_size = sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message)/sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message[0]); +- cec_global_info.hdmitx_device = hdmitx_device; +- + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 + if (request_irq(INT_HDMI_CEC, &amlogic_cec_irq_handler, + IRQF_SHARED, "amhdmitx-cec",(void *)hdmitx_device)) + { +- tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); ++ amlogic_cec_log_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); + return -EFAULT; } #endif - switch_dev_register(&sdev); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - switch_dev_register(&lang_dev); -+#endif - - hdmitx_init_parameters(&hdmitx_device.hdmi_info); - HDMITX_Meson_Init(&hdmitx_device); -@@ -1771,8 +1779,9 @@ static int amhdmitx_remove(struct platform_device *pdev) - device_remove_file(hdmitx_dev, &dev_attr_disp_cap_3d); - device_remove_file(hdmitx_dev, &dev_attr_hpd_state); - device_remove_file(hdmitx_dev, &dev_attr_support_3d); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - device_remove_file(hdmitx_dev, &dev_attr_cec); -- -+#endif - cdev_del(&hdmitx_device.cdev); - - device_destroy(hdmitx_class, hdmitx_id); -diff --git a/drivers/amlogic/input/new_remote/remote_func.c b/drivers/amlogic/input/new_remote/remote_func.c -index e36e272..807c255 100755 ---- a/drivers/amlogic/input/new_remote/remote_func.c -+++ b/drivers/amlogic/input/new_remote/remote_func.c -@@ -525,6 +525,7 @@ int remote_hw_reprot_key(struct remote *remote_data) - mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); - } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key - #ifdef CONFIG_AML_HDMI_TX -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - extern int rc_long_press_pwr_key; - if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { - rc_long_press_pwr_key = 1; -@@ -534,6 +535,7 @@ int remote_hw_reprot_key(struct remote *remote_data) - cec_repeat--; - +@@ -483,14 +590,19 @@ static int amlogic_cec_init(void) + if (request_irq(INT_AO_CEC, &amlogic_cec_irq_handler, + IRQF_SHARED, "amhdmitx-aocec",(void *)hdmitx_device)) + { +- tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); ++ amlogic_cec_log_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); + return -EFAULT; + } #endif -+#endif - if (remote_data->repeat_enable) { - repeat_count++; - if (remote_data->repeat_tick < jiffies) { -@@ -618,6 +620,7 @@ int remote_hw_nec_rca_2in1_reprot_key(struct remote *remote_data) - mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); - } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key - #ifdef CONFIG_AML_HDMI_TX -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - extern int rc_long_press_pwr_key; - if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { - rc_long_press_pwr_key = 1; -@@ -627,6 +630,7 @@ int remote_hw_nec_rca_2in1_reprot_key(struct remote *remote_data) - cec_repeat--; - #endif -+#endif - if (remote_data->repeat_enable) { - repeat_count++; - if (remote_data->repeat_tick < jiffies) { -@@ -700,6 +704,7 @@ int remote_hw_nec_toshiba_2in1_reprot_key(struct remote *remote_data) - mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); - } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key - #ifdef CONFIG_AML_HDMI_TX -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - extern int rc_long_press_pwr_key; - if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { - rc_long_press_pwr_key = 1; -@@ -709,6 +714,7 @@ int remote_hw_nec_toshiba_2in1_reprot_key(struct remote *remote_data) - cec_repeat--; + init_waitqueue_head(&cec_rx_struct.waitq); ++ + spin_lock_init(&cec_rx_struct.lock); ++ init_waitqueue_head(&cec_tx_struct.waitq); ++ ++ spin_lock_init(&cec_tx_struct.lock); ++ + if (misc_register(&cec_misc_device)) + { + printk(KERN_WARNING " Couldn't register device 10, %d.\n", CEC_MINOR); +@@ -506,14 +618,14 @@ static int amlogic_cec_init(void) + INIT_WORK(&hdmitx_device->cec_work, amlogic_cec_delayed_init); + queue_work(cec_workqueue, &hdmitx_device->cec_work); // for init + +- tvout_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); ++ amlogic_cec_log_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); + + return 0; + } + + static void amlogic_cec_exit(void) + { +- if (cec_global_info.cec_flag.cec_init_flag == 1) ++ if (cec_init_flag == 1) + { + + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 +@@ -523,7 +635,7 @@ static void amlogic_cec_exit(void) + #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 + free_irq(INT_AO_CEC, (void *)hdmitx_device); #endif -+#endif - if (remote_data->repeat_enable) { - repeat_count++; - if (remote_data->repeat_tick < jiffies) { -diff --git a/drivers/amlogic/input/remote/am_remote.c b/drivers/amlogic/input/remote/am_remote.c -index c824efb..01f0bfba 100755 ---- a/drivers/amlogic/input/remote/am_remote.c -+++ b/drivers/amlogic/input/remote/am_remote.c -@@ -390,6 +390,7 @@ static inline int remote_hw_reprot_key(struct remote *remote_data) - } - #ifdef CONFIG_AML_HDMI_TX - #ifdef CONFIG_ARCH_MESON6 -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - //printk("last_scan_code:%x\n", last_scan_code); - if((((scan_code >> 16) & 0xff) == 0x1a) && (!cec_repeat)) { - extern int rc_long_press_pwr_key; -@@ -401,6 +402,7 @@ static inline int remote_hw_reprot_key(struct remote *remote_data) - cec_repeat--; - #endif - #endif -+#endif - if (remote_data->repeat_enable) { - if ((remote_data->repeat_tick < jiffies)&&(repeat_flag == 1)) { - remote_send_key(remote_data->input, (scan_code >> 16) & 0xff, 2); +- cec_global_info.cec_flag.cec_init_flag = 0; ++ cec_init_flag = 0; + } + + misc_deregister(&cec_misc_device); diff --git a/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch b/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch index 54f63fef7c..2dafb595e7 100644 --- a/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch +++ b/projects/WeTek_Play/patches/linux/080-amlogic-cec-driver.patch @@ -1,749 +1,618 @@ -From 3bde21926d476a3fc0f4d37275f8fde11f09dade Mon Sep 17 00:00:00 2001 -From: Gerald Dachs -Date: Wed, 3 Feb 2016 19:19:49 +0100 -Subject: [PATCH] New amlogic cec driver - ---- - .../mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c | 3 +- - drivers/amlogic/hdmi/Kconfig | 8 + - drivers/amlogic/hdmi/hdmi_tx/Makefile | 8 +- - drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c | 534 +++++++++++++++++++++ - drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c | 11 +- - drivers/amlogic/input/new_remote/remote_func.c | 6 + - drivers/amlogic/input/remote/am_remote.c | 2 + - 7 files changed, 569 insertions(+), 3 deletions(-) - create mode 100644 drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c - -diff --git a/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c b/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c -index a2a78bd..762feba 100644 ---- a/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c -+++ b/arch/arm/mach-mesong9bb/hdmi_tx_hw_20/hdmi_tx_cec_hw.c -@@ -996,6 +996,7 @@ void cec_tx_irq_handle(void) - #endif - } - -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - void cec_polling_online_dev(int log_addr, int *bool) - { - #ifdef AO_CEC -@@ -1005,7 +1006,7 @@ void cec_polling_online_dev(int log_addr, int *bool) - #endif - hdmi_print(INF, CEC "CEC: poll online logic device: 0x%x BOOL: %d\n", log_addr, *bool); - } -- -+#endif - - // DELETE LATER, TEST ONLY - void cec_test_(unsigned int cmd) -diff --git a/drivers/amlogic/hdmi/Kconfig b/drivers/amlogic/hdmi/Kconfig -index 71f6bf8..1bfc289 100755 ---- a/drivers/amlogic/hdmi/Kconfig -+++ b/drivers/amlogic/hdmi/Kconfig -@@ -24,4 +24,12 @@ config AML_HDMI_TX_HDCP - hdmitx hdcp enable, it should be enalbe if board burned hdmitx hdcp keys - endif - -+if AML_HDMI_TX -+config AML_HDMI_TX_NEW_CEC_DRIVER -+ bool "HDMI new CEC driver" -+ default n -+ help -+ hdmitx uses new CEC driver -+endif -+ - endmenu -diff --git a/drivers/amlogic/hdmi/hdmi_tx/Makefile b/drivers/amlogic/hdmi/hdmi_tx/Makefile -index 7a944cd..f74ec1f 100755 ---- a/drivers/amlogic/hdmi/hdmi_tx/Makefile -+++ b/drivers/amlogic/hdmi/hdmi_tx/Makefile -@@ -1,5 +1,11 @@ - obj-$(CONFIG_AML_HDMI_TX) += hdmitx.o - --hdmitx-objs := hdmi_tx.o hdmi_tx_cec.o hdmi_cec_key.o hdmi_tx_video.o hdmi_tx_audio.o hdmi_tx_edid.o hdmi_tx_audio.o hdmi_tx_hdcp.o hdmi_tx_compliance.o -+hdmitx-objs := hdmi_tx.o hdmi_tx_video.o hdmi_tx_audio.o hdmi_tx_edid.o hdmi_tx_audio.o hdmi_tx_hdcp.o hdmi_tx_compliance.o -+ -+ifdef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER -+ hdmitx-objs += amlogic_cec.o -+else -+ hdmitx-objs += hdmi_tx_cec.o hdmi_cec_key.o -+endif - - #EXTRA_CFLAGS += -O2 diff --git a/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c -new file mode 100644 -index 0000000..61fb500 ---- /dev/null +index 61fb500..d1d3511 100644 +--- a/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c +++ b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c -@@ -0,0 +1,534 @@ -+/* linux/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c -+ * -+ * Copyright (c) 2016 Gerald Dachs -+ * -+ * CEC interface file for Amlogic -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+*/ +@@ -36,7 +36,9 @@ + #include + #include + +-#define CONFIG_TV_DEBUG ++#define CONFIG_TV_DEBUG // for verbose output ++//#undef CONFIG_TV_DEBUG ++bool cec_msg_dbg_en = 1; + + MODULE_AUTHOR("Gerald Dachs"); + MODULE_DESCRIPTION("Amlogic CEC driver"); +@@ -55,24 +57,16 @@ MODULE_LICENSE("GPL"); + #define CEC_TX_BUFF_SIZE 16 + + #define DRV_NAME "amlogic_cec" +-#ifndef tvout_dbg ++#ifndef amlogic_cec_log_dbg + #ifdef CONFIG_TV_DEBUG +-#define tvout_dbg(fmt, ...) \ ++#define amlogic_cec_log_dbg(fmt, ...) \ + printk(KERN_INFO "[%s] %s(): " fmt, \ + DRV_NAME, __func__, ##__VA_ARGS__) + #else +-#define tvout_dbg(fmt, ...) ++#define amlogic_cec_log_dbg(fmt, ...) + #endif + #endif + +-static atomic_t hdmi_on = ATOMIC_INIT(0); +- +-bool cec_msg_dbg_en = 1; +-cec_global_info_t cec_global_info; +- +-static hdmitx_dev_t* hdmitx_device = NULL; +-static struct workqueue_struct *cec_workqueue = NULL; +- + struct cec_rx_list { + u8 buffer[CEC_RX_BUFF_SIZE]; + unsigned char size; +@@ -86,6 +80,12 @@ struct cec_rx_struct { + struct list_head list; + }; + ++struct cec_tx_struct { ++ spinlock_t lock; ++ wait_queue_head_t waitq; ++ atomic_t state; ++}; + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define CONFIG_TV_DEBUG -+ -+MODULE_AUTHOR("Gerald Dachs"); -+MODULE_DESCRIPTION("Amlogic CEC driver"); -+MODULE_LICENSE("GPL"); -+ -+#define CEC_IOC_MAGIC 'c' -+#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int) -+#define CEC_IOC_GETPADDR _IO(CEC_IOC_MAGIC, 1) -+ -+#define VERSION "1.0" /* Driver version number */ -+#define CEC_MINOR 243 /* Major 10, Minor 242, /dev/cec */ -+ -+/* CEC Rx buffer size */ -+#define CEC_RX_BUFF_SIZE 16 -+/* CEC Tx buffer size */ -+#define CEC_TX_BUFF_SIZE 16 -+ -+#define DRV_NAME "amlogic_cec" -+#ifndef tvout_dbg -+#ifdef CONFIG_TV_DEBUG -+#define tvout_dbg(fmt, ...) \ -+ printk(KERN_INFO "[%s] %s(): " fmt, \ -+ DRV_NAME, __func__, ##__VA_ARGS__) -+#else -+#define tvout_dbg(fmt, ...) -+#endif -+#endif + enum cec_state { + STATE_RX, + STATE_TX, +@@ -98,58 +98,133 @@ static char banner[] __initdata = + + static struct cec_rx_struct cec_rx_struct; + +-unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) ++static struct cec_tx_struct cec_tx_struct; + +static atomic_t hdmi_on = ATOMIC_INIT(0); + -+bool cec_msg_dbg_en = 1; +cec_global_info_t cec_global_info; + +static hdmitx_dev_t* hdmitx_device = NULL; +static struct workqueue_struct *cec_workqueue = NULL; + -+struct cec_rx_list { -+ u8 buffer[CEC_RX_BUFF_SIZE]; -+ unsigned char size; -+ struct list_head list; -+}; -+ -+struct cec_rx_struct { -+ spinlock_t lock; -+ wait_queue_head_t waitq; -+ atomic_t state; -+ struct list_head list; -+}; -+ -+enum cec_state { -+ STATE_RX, -+ STATE_TX, -+ STATE_DONE, -+ STATE_ERROR -+}; -+ -+static char banner[] __initdata = -+ "Amlogic CEC Driver, (c) 2016 Gerald Dachs\n"; -+ -+static struct cec_rx_struct cec_rx_struct; -+ -+unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) -+{ -+ unsigned short us = CEC_UNREGISTERED_DEVICE_TYPE; -+ if ((1 << log_addr) & CEC_DISPLAY_DEVICE) -+ { -+ us = CEC_DISPLAY_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_RECORDING_DEVICE) -+ { -+ us = CEC_RECORDING_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_PLAYBACK_DEVICE) -+ { -+ us = CEC_PLAYBACK_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_TUNER_DEVICE) -+ { -+ us = CEC_TUNER_DEVICE_TYPE; -+ } -+ else if ((1 << log_addr) & CEC_AUDIO_SYSTEM_DEVICE) -+ { -+ us = CEC_AUDIO_SYSTEM_DEVICE_TYPE; -+ } -+ -+ return us; -+} -+ -+void cec_report_physical_address_smp(void) -+{ -+ unsigned char msg[5]; -+ unsigned char index = cec_global_info.my_node_index; -+ unsigned char phy_addr_ab = (aml_read_reg32(P_AO_DEBUG_REG1) >> 8) & 0xff; -+ unsigned char phy_addr_cd = aml_read_reg32(P_AO_DEBUG_REG1) & 0xff; -+ -+ tvout_dbg("cec_report_physical_address_smp: enter\n"); -+ -+ msg[0] = ((index & 0xf) << 4) | CEC_BROADCAST_ADDR; -+ msg[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS; -+ msg[2] = phy_addr_ab; -+ msg[3] = phy_addr_cd; -+ msg[4] = cec_log_addr_to_dev_type(index); -+ -+ cec_ll_tx(msg, 5); -+ -+ tvout_dbg("cec_report_physical_address_smp: leave\n"); -+} -+ -+void cec_node_init(hdmitx_dev_t* hdmitx_device) -+{ -+ unsigned long cec_phy_addr; -+ -+ tvout_dbg("cec node init: enter\n"); -+ -+ cec_phy_addr = (((hdmitx_device->hdmi_info.vsdb_phy_addr.a) & 0xf) << 12) -+ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.b) & 0xf) << 8) -+ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.c) & 0xf) << 4) -+ | (((hdmitx_device->hdmi_info.vsdb_phy_addr.d) & 0xf) << 0); -+ -+ // If VSDB is not valid,use last or default physical address. -+ if (hdmitx_device->hdmi_info.vsdb_phy_addr.valid == 0) -+ { -+ tvout_dbg("no valid cec physical address\n"); -+ if (aml_read_reg32 (P_AO_DEBUG_REG1)) -+ { -+ tvout_dbg("use last physical address\n"); -+ } -+ else -+ { -+ aml_write_reg32 (P_AO_DEBUG_REG1, 0x1000); -+ tvout_dbg("use default physical address\n"); -+ } -+ } -+ else -+ { -+ aml_write_reg32 (P_AO_DEBUG_REG1, cec_phy_addr); -+ } -+ tvout_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); -+ -+ if (hdmitx_device->cec_init_ready != 0) -+ { -+ tvout_dbg("report physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); -+ cec_report_physical_address_smp(); -+ } -+ tvout_dbg("cec node init: cec features ok !\n"); -+} ++static int cec_init_flag = 0; + +static void amlogic_cec_set_rx_state(enum cec_state state) -+{ + { +- unsigned short us = CEC_UNREGISTERED_DEVICE_TYPE; +- if ((1 << log_addr) & CEC_DISPLAY_DEVICE) +- { +- us = CEC_DISPLAY_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_RECORDING_DEVICE) +- { +- us = CEC_RECORDING_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_PLAYBACK_DEVICE) +- { +- us = CEC_PLAYBACK_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_TUNER_DEVICE) +- { +- us = CEC_TUNER_DEVICE_TYPE; +- } +- else if ((1 << log_addr) & CEC_AUDIO_SYSTEM_DEVICE) + atomic_set(&cec_rx_struct.state, state); +} + -+static int amlogic_cec_open(struct inode *inode, struct file *file) ++static void amlogic_cec_set_tx_state(enum cec_state state) +{ -+ int ret = 0; ++ atomic_set(&cec_tx_struct.state, state); ++} ++ ++static void amlogic_cec_msg_dump(char * msg_tag, const unsigned char *data, unsigned char count) ++{ ++ int i; ++ int pos; ++ unsigned char msg_log_buf[128] = { 0 }; ++ ++ if (cec_msg_dbg_en == 1) ++ { ++ pos = 0; ++ pos += sprintf(msg_log_buf + pos, "msg %s len: %d dat: ", msg_tag, count); ++ for (i = 0; i < count; ++i) ++ { ++ pos += sprintf(msg_log_buf + pos, "%02x ", data[i]); ++ } ++ pos += sprintf(msg_log_buf + pos, "\n"); ++ msg_log_buf[pos] = '\0'; ++ hdmi_print(INF, "[amlogic_cec] dump: %s", msg_log_buf); ++ } ++} ++ ++static unsigned int amlogic_cec_read_reg(unsigned int reg) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ return hdmi_rd_reg(CEC0_BASE_ADDR + reg); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ return aocec_rd_reg(reg); ++#endif ++} ++ ++static void amlogic_cec_write_reg(unsigned int reg, unsigned int value) ++{ ++#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 ++ hdmi_wr_reg(CEC0_BASE_ADDR + reg, value); ++#endif ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ aocec_wr_reg(reg, value); ++#endif ++} ++ ++static int amlogic_cec_read_hw(unsigned char *data, unsigned char *count) ++{ ++ int ret = -1; ++ int valid_msg; ++ int rx_msg_status; ++ int rx_num_msg; ++ ++ rx_msg_status = amlogic_cec_read_reg(CEC_RX_MSG_STATUS); ++ rx_num_msg = amlogic_cec_read_reg(CEC_RX_NUM_MSG); ++ ++ amlogic_cec_log_dbg("amlogic_cec_read_hw: enter: CEC_RX_MSG_STATUS %d, CEC_RX_NUM_MSG %d\n", rx_msg_status, rx_num_msg); ++ ++ valid_msg = (RX_DONE == rx_msg_status) && (1 == rx_num_msg); ++ ++ if (valid_msg) + { +- us = CEC_AUDIO_SYSTEM_DEVICE_TYPE; ++ int i; ++ ++ *count = amlogic_cec_read_reg(CEC_RX_MSG_LENGTH) + 1; ++ for (i = 0; i < (*count) && i < CEC_RX_BUFF_SIZE; ++i) ++ { ++ data[i]= amlogic_cec_read_reg(CEC_RX_MSG_0_HEADER + i); ++ } ++ ++ amlogic_cec_msg_dump("RX", data, *count); ++ ++ ret = RX_DONE; + } + +- return us; ++#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 ++ aml_write_reg32(P_AO_CEC_INTR_CLR, aml_read_reg32(P_AO_CEC_INTR_CLR) | (1 << 2)); ++#endif ++ amlogic_cec_write_reg(CEC_RX_MSG_CMD, valid_msg ? RX_ACK_NEXT : RX_ACK_CURRENT); ++ amlogic_cec_write_reg(CEC_RX_MSG_CMD, RX_NO_OP); + -+ if (atomic_read(&hdmi_on)) -+ { -+ tvout_dbg("do not allow multiple open for tvout cec\n"); -+ ret = -EBUSY; -+ } -+ else -+ { -+ atomic_inc(&hdmi_on); -+ } + return ret; -+} -+ -+static int amlogic_cec_release(struct inode *inode, struct file *file) + } + +-void cec_report_physical_address_smp(void) +-{ +- unsigned char msg[5]; +- unsigned char index = cec_global_info.my_node_index; +- unsigned char phy_addr_ab = (aml_read_reg32(P_AO_DEBUG_REG1) >> 8) & 0xff; +- unsigned char phy_addr_cd = aml_read_reg32(P_AO_DEBUG_REG1) & 0xff; + +- tvout_dbg("cec_report_physical_address_smp: enter\n"); ++static void amlogic_cec_write_hw(const char *data, size_t count) +{ -+ atomic_dec(&hdmi_on); -+ -+ return 0; ++ int i; + +- msg[0] = ((index & 0xf) << 4) | CEC_BROADCAST_ADDR; +- msg[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS; +- msg[2] = phy_addr_ab; +- msg[3] = phy_addr_cd; +- msg[4] = cec_log_addr_to_dev_type(index); ++ for (i = 0; i < count; ++i) ++ { ++ amlogic_cec_write_reg(CEC_TX_MSG_0_HEADER + i, data[i]); ++ } ++ amlogic_cec_write_reg(CEC_TX_MSG_LENGTH, count - 1); ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); + +- cec_ll_tx(msg, 5); ++ amlogic_cec_msg_dump("TX", data, count); +} -+ -+static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, -+ size_t count, loff_t *ppos) + +- tvout_dbg("cec_report_physical_address_smp: leave\n"); ++unsigned short cec_log_addr_to_dev_type(unsigned char log_addr) +{ -+ ssize_t retval; ++// unused, just to satisfy the linker ++ return log_addr; + } + + void cec_node_init(hdmitx_dev_t* hdmitx_device) + { + unsigned long cec_phy_addr; + unsigned long spin_flags; -+ struct cec_rx_list* entry = NULL; ++ struct cec_rx_list *entry; + +- tvout_dbg("cec node init: enter\n"); ++ amlogic_cec_log_dbg("cec node init: enter\n"); + + cec_phy_addr = (((hdmitx_device->hdmi_info.vsdb_phy_addr.a) & 0xf) << 12) + | (((hdmitx_device->hdmi_info.vsdb_phy_addr.b) & 0xf) << 8) +@@ -159,34 +234,46 @@ void cec_node_init(hdmitx_dev_t* hdmitx_device) + // If VSDB is not valid,use last or default physical address. + if (hdmitx_device->hdmi_info.vsdb_phy_addr.valid == 0) + { +- tvout_dbg("no valid cec physical address\n"); +- if (aml_read_reg32 (P_AO_DEBUG_REG1)) ++ amlogic_cec_log_dbg("no valid cec physical address\n"); ++ if (aml_read_reg32(P_AO_DEBUG_REG1)) + { +- tvout_dbg("use last physical address\n"); ++ amlogic_cec_log_dbg("use last physical address\n"); + } + else + { +- aml_write_reg32 (P_AO_DEBUG_REG1, 0x1000); +- tvout_dbg("use default physical address\n"); ++ aml_write_reg32(P_AO_DEBUG_REG1, 0x1000); ++ amlogic_cec_log_dbg("use default physical address\n"); + } + } + else + { +- aml_write_reg32 (P_AO_DEBUG_REG1, cec_phy_addr); +- } +- tvout_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); ++ aml_write_reg32(P_AO_DEBUG_REG1, cec_phy_addr); ++ amlogic_cec_log_dbg("physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); + +- if (hdmitx_device->cec_init_ready != 0) +- { +- tvout_dbg("report physical address:0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); +- cec_report_physical_address_smp(); ++ if ((hdmitx_device->cec_init_ready != 0) && (hdmitx_device->hpd_state != 0)) ++ { ++ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ { ++ amlogic_cec_log_dbg("can't alloc cec_rx_list\n"); ++ } ++ else ++ { ++ // let the libCEC ask for new physical Address ++ entry->buffer[0] = 0xff; ++ entry->size = 1; ++ INIT_LIST_HEAD(&entry->list); + -+ tvout_dbg("amlogic_cec_read: enter\n"); ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ list_add_tail(&entry->list, &cec_rx_struct.list); ++ amlogic_cec_set_rx_state(STATE_DONE); ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); + -+ if (wait_event_interruptible(cec_rx_struct.waitq, -+ atomic_read(&cec_rx_struct.state) == STATE_DONE)) ++ amlogic_cec_log_dbg("trigger libCEC\n"); ++ wake_up_interruptible(&cec_rx_struct.waitq); ++ } ++ } + } +- tvout_dbg("cec node init: cec features ok !\n"); +-} +- +-static void amlogic_cec_set_rx_state(enum cec_state state) +-{ +- atomic_set(&cec_rx_struct.state, state); ++ amlogic_cec_log_dbg("cec node init: cec features ok !\n"); + } + + static int amlogic_cec_open(struct inode *inode, struct file *file) +@@ -195,7 +282,7 @@ static int amlogic_cec_open(struct inode *inode, struct file *file) + + if (atomic_read(&hdmi_on)) + { +- tvout_dbg("do not allow multiple open for tvout cec\n"); ++ amlogic_cec_log_dbg("do not allow multiple open for tvout cec\n"); + ret = -EBUSY; + } + else +@@ -219,12 +306,12 @@ static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, + unsigned long spin_flags; + struct cec_rx_list* entry = NULL; + +- tvout_dbg("amlogic_cec_read: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_read: enter\n"); + + if (wait_event_interruptible(cec_rx_struct.waitq, + atomic_read(&cec_rx_struct.state) == STATE_DONE)) + { +- tvout_dbg("error during wait on state change\n"); ++ amlogic_cec_log_dbg("error during wait on state change\n"); + return -ERESTARTSYS; + } + +@@ -234,7 +321,7 @@ static ssize_t amlogic_cec_read(struct file *file, char __user *buffer, + + if (entry == NULL || entry->size > count) + { +- tvout_dbg("entry is NULL, or empty\n"); ++ amlogic_cec_log_dbg("entry is NULL, or empty\n"); + retval = -1; + goto error_exit; + } +@@ -260,7 +347,7 @@ error_exit: + + spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); + +- tvout_dbg("amlogic_cec_read: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_read: leave\n"); + + return retval; + } +@@ -268,11 +355,8 @@ error_exit: + static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) + { +- int ret = 0; +- + char data[CEC_TX_BUFF_SIZE]; +- +- tvout_dbg("amlogic_cec_write: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_write: enter\n"); + + /* check data size */ + if (count > CEC_TX_BUFF_SIZE || count == 0) +@@ -284,14 +368,34 @@ static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, + return -EFAULT; + } + +- ret = cec_ll_tx(data, count); +- if (ret != 1) ++ amlogic_cec_set_tx_state(STATE_TX); ++ ++ // just for the case that the first write starts ++ // before the end of amlogic_cec_delayed_init() ++ if (wait_event_interruptible(cec_tx_struct.waitq, hdmitx_device->cec_init_ready == 1)) + { -+ tvout_dbg("error during wait on state change\n"); ++ amlogic_cec_log_dbg("error during wait on state change\n"); ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); + return -ERESTARTSYS; + } + -+ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ amlogic_cec_write_hw(data, count); + -+ entry = list_first_entry_or_null(&cec_rx_struct.list, struct cec_rx_list, list); -+ -+ if (entry == NULL || entry->size > count) ++ if (wait_event_interruptible_timeout(cec_tx_struct.waitq, ++ atomic_read(&cec_tx_struct.state) != STATE_TX, 1 * HZ) <= 0) + { -+ tvout_dbg("entry is NULL, or empty\n"); -+ retval = -1; -+ goto error_exit; ++ amlogic_cec_log_dbg("error during wait on state change\n"); ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); ++ return -ERESTARTSYS; + } + -+ if (copy_to_user(buffer, entry->buffer, entry->size)) -+ { -+ printk(KERN_ERR " copy_to_user() failed!\n"); -+ -+ retval = -EFAULT; -+ goto error_exit; -+ } -+ -+ retval = entry->size; -+ -+ amlogic_cec_set_rx_state(STATE_RX); -+ -+error_exit: -+ if (entry != NULL) -+ { -+ list_del(&entry->list); -+ kfree(entry); -+ } -+ -+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); -+ -+ tvout_dbg("amlogic_cec_read: leave\n"); -+ -+ return retval; -+} -+ -+static ssize_t amlogic_cec_write(struct file *file, const char __user *buffer, -+ size_t count, loff_t *ppos) -+{ -+ int ret = 0; -+ -+ char data[CEC_TX_BUFF_SIZE]; -+ -+ tvout_dbg("amlogic_cec_write: enter\n"); -+ -+ /* check data size */ -+ if (count > CEC_TX_BUFF_SIZE || count == 0) ++ if (atomic_read(&cec_tx_struct.state) != STATE_DONE) + { +- tvout_dbg("Message transmit failed, ret=%d\n", ret); +- return -1; ++ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n"); + return -1; -+ -+ if (copy_from_user(data, buffer, count)) -+ { -+ printk(KERN_ERR " copy_from_user() failed!\n"); -+ return -EFAULT; -+ } -+ -+ ret = cec_ll_tx(data, count); -+ if (ret != 1) -+ { -+ tvout_dbg("Message transmit failed, ret=%d\n", ret); -+ return -1; -+ } -+ -+ tvout_dbg("amlogic_cec_write: leave\n"); -+ -+ return count; -+} -+ -+static long amlogic_cec_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ unsigned char logical_addr; -+ -+ switch(cmd) { -+ case CEC_IOC_SETLADDR: -+ if (get_user(logical_addr, (unsigned char __user *)arg)) -+ { -+ tvout_dbg("Failed to get logical addr from user\n"); -+ return -EFAULT; -+ } -+ -+ cec_global_info.my_node_index = logical_addr; -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ aocec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); -+#endif -+ tvout_dbg("Set logical address: %d\n", logical_addr); -+ return 0; -+ -+ case CEC_IOC_GETPADDR: -+ return aml_read_reg32(P_AO_DEBUG_REG1); -+ } -+ -+ return -EINVAL; -+} -+ -+static u32 amlogic_cec_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &cec_rx_struct.waitq, wait); -+ -+ if (atomic_read(&cec_rx_struct.state) == STATE_DONE) -+ { -+ return POLLIN | POLLRDNORM; -+ } -+ return 0; -+} -+ -+static const struct file_operations cec_fops = { -+ .owner = THIS_MODULE, -+ .open = amlogic_cec_open, -+ .release = amlogic_cec_release, -+ .read = amlogic_cec_read, -+ .write = amlogic_cec_write, -+ .unlocked_ioctl = amlogic_cec_ioctl, -+ .poll = amlogic_cec_poll, -+}; -+ -+static struct miscdevice cec_misc_device = { -+ .minor = CEC_MINOR, -+ .name = "AmlogicCEC", -+ .fops = &cec_fops, -+}; -+ -+static irqreturn_t amlogic_cec_irq_handler(int irq, void *dummy) -+{ -+ unsigned long spin_flags; -+ struct cec_rx_list *entry; -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ unsigned int intr_stat = 0; -+#endif -+ -+ tvout_dbg("amlogic_cec_irq_handler: enter\n"); -+ -+ udelay(100); //Delay execution a little. This fixes an issue when HDMI CEC stops working after a while. -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ tvout_dbg("cec TX status: rx: 0x%x; tx: 0x%x\n", hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS), hdmi_rd_reg(CEC0_BASE_ADDR+CEC_TX_MSG_STATUS)); -+ if (hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS) != RX_DONE) -+ { -+ return IRQ_HANDLED; -+ } -+#endif -+ -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ intr_stat = aml_read_reg32(P_AO_CEC_INTR_STAT); -+ tvout_dbg("aocec irq %x\n", intr_stat); -+ if (intr_stat & (1<<1)) -+ { // aocec tx intr -+ tx_irq_handle(); -+ return IRQ_HANDLED; -+ } -+#endif -+ -+ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) -+ { -+ tvout_dbg("can't alloc cec_rx_list\n"); -+ return IRQ_HANDLED; -+ } -+ -+ if ((-1) == cec_ll_rx(entry->buffer, &entry->size)) -+ { -+ kfree(entry); -+ tvout_dbg("amlogic_cec_irq_handler: nothing to read\n"); -+ return IRQ_HANDLED; -+ } -+ -+ INIT_LIST_HEAD(&entry->list); -+ -+ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); -+ list_add_tail(&entry->list, &cec_rx_struct.list); -+ amlogic_cec_set_rx_state(STATE_DONE); -+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); -+ -+ wake_up_interruptible(&cec_rx_struct.waitq); -+ -+ tvout_dbg("amlogic_cec_irq_handler: leave\n"); -+ -+ return IRQ_HANDLED; -+} -+ -+static void amlogic_cec_delayed_init(struct work_struct *work) -+{ -+ hdmitx_dev_t* hdmitx_device = (hdmitx_dev_t*)container_of(work, hdmitx_dev_t, cec_work); -+ -+ tvout_dbg("amlogic_cec_delayed_init: enter\n"); -+ -+ msleep_interruptible(15000); -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ cec_gpi_init(); -+#endif -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ aml_set_reg32_bits(P_PERIPHS_PIN_MUX_1, 1, 25, 1); -+ // Clear CEC Int. state and set CEC Int. mask -+ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_STAT_CLR, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_STAT_CLR) | (1 << 23)); // Clear the interrupt -+ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK) | (1 << 23)); // Enable the hdmi cec interrupt -+ -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+#if 1 // Please match with H/W cec config -+// GPIOAO_12 -+ aml_set_reg32_bits(P_AO_RTI_PIN_MUX_REG, 0, 14, 1); // bit[14]: AO_PWM_C pinmux //0xc8100014 -+ aml_set_reg32_bits(P_AO_RTI_PULL_UP_REG, 1, 12, 1); // bit[12]: enable AO_12 internal pull-up //0xc810002c -+ aml_set_reg32_bits(P_AO_RTI_PIN_MUX_REG, 1, 17, 1); // bit[17]: AO_CEC pinmux //0xc8100014 -+ ao_cec_init(); -+#else -+// GPIOH_3 -+ aml_set_reg32_bits(P_PAD_PULL_UP_EN_REG1, 0, 19, 1); // disable gpioh_3 internal pull-up -+ aml_set_reg32_bits(P_PERIPHS_PIN_MUX_1, 1, 23, 1); // gpioh_3 cec pinmux -+#endif -+ cec_arbit_bit_time_set(3, 0x118, 0); -+ cec_arbit_bit_time_set(5, 0x000, 0); -+ cec_arbit_bit_time_set(7, 0x2aa, 0); -+#endif -+ -+ hdmitx_device->cec_init_ready = 1; -+ cec_global_info.cec_flag.cec_init_flag = 0; -+ -+ tvout_dbg("amlogic_cec_delayed_init: leave\n"); -+} -+ -+static int amlogic_cec_init(void) -+{ -+ extern hdmitx_dev_t * get_hdmitx_device(void); -+ INIT_LIST_HEAD(&cec_rx_struct.list); -+ -+ printk(banner); -+ -+ hdmitx_device = get_hdmitx_device(); -+ tvout_dbg("CEC init\n"); -+ memset(&cec_global_info, 0, sizeof(cec_global_info_t)); -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_H, 0x00 ); -+ hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_L, 0xf0 ); -+#endif -+ -+ cec_global_info.cec_rx_msg_buf.rx_buf_size = sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message)/sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message[0]); -+ cec_global_info.hdmitx_device = hdmitx_device; -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ if (request_irq(INT_HDMI_CEC, &amlogic_cec_irq_handler, -+ IRQF_SHARED, "amhdmitx-cec",(void *)hdmitx_device)) -+ { -+ tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); -+ return -EFAULT; -+ } -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ if (request_irq(INT_AO_CEC, &amlogic_cec_irq_handler, -+ IRQF_SHARED, "amhdmitx-aocec",(void *)hdmitx_device)) -+ { -+ tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); -+ return -EFAULT; -+ } -+#endif -+ -+ init_waitqueue_head(&cec_rx_struct.waitq); -+ spin_lock_init(&cec_rx_struct.lock); -+ -+ if (misc_register(&cec_misc_device)) -+ { -+ printk(KERN_WARNING " Couldn't register device 10, %d.\n", CEC_MINOR); -+ return -EBUSY; -+ } -+ -+ cec_workqueue = create_workqueue("cec_work"); -+ if (cec_workqueue == NULL) -+ { -+ printk("create work queue failed\n"); -+ return -EFAULT; -+ } -+ INIT_WORK(&hdmitx_device->cec_work, amlogic_cec_delayed_init); -+ queue_work(cec_workqueue, &hdmitx_device->cec_work); // for init -+ -+ tvout_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); -+ -+ return 0; -+} -+ -+static void amlogic_cec_exit(void) -+{ -+ if (cec_global_info.cec_flag.cec_init_flag == 1) -+ { -+ -+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 -+ aml_write_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK, aml_read_reg32(P_SYS_CPU_0_IRQ_IN1_INTR_MASK) & ~(1 << 23)); // Disable the hdmi cec interrupt -+ free_irq(INT_HDMI_CEC, (void *)hdmitx_device); -+#endif -+#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 -+ free_irq(INT_AO_CEC, (void *)hdmitx_device); -+#endif -+ cec_global_info.cec_flag.cec_init_flag = 0; -+ } -+ -+ misc_deregister(&cec_misc_device); -+} -+ -+module_init(amlogic_cec_init); -+module_exit(amlogic_cec_exit); -+ -diff --git a/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c b/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c -index 3e043bc..69b3ffc 100755 ---- a/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c -+++ b/drivers/amlogic/hdmi/hdmi_tx/hdmi_tx.c -@@ -542,6 +542,7 @@ static ssize_t store_disp_mode(struct device * dev, struct device_attribute *att - return 16; - } + } -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - /*cec attr*/ - static ssize_t show_cec(struct device * dev, struct device_attribute *attr, char * buf) +- tvout_dbg("amlogic_cec_write: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_write: leave\n"); + + return count; + } +@@ -300,26 +404,22 @@ static long amlogic_cec_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { -@@ -589,6 +590,7 @@ static ssize_t show_cec_lang_config(struct device * dev, struct device_attribute - pos+=snprintf(buf+pos, PAGE_SIZE, "%x\n",cec_global_info.cec_node_info[cec_global_info.my_node_index].menu_lang); - return pos; + unsigned char logical_addr; ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: enter\n"); + + switch(cmd) { + case CEC_IOC_SETLADDR: + if (get_user(logical_addr, (unsigned char __user *)arg)) + { +- tvout_dbg("Failed to get logical addr from user\n"); ++ amlogic_cec_log_dbg("Failed to get logical addr from user\n"); + return -EFAULT; + } + +- cec_global_info.my_node_index = logical_addr; +-#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 +- hdmi_wr_reg(CEC0_BASE_ADDR+CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); +-#endif +-#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 +- aocec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); +-#endif +- tvout_dbg("Set logical address: %d\n", logical_addr); ++ amlogic_cec_write_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | logical_addr); ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: Set logical address: %d\n", logical_addr); + return 0; + + case CEC_IOC_GETPADDR: ++ amlogic_cec_log_dbg("amlogic_cec_ioctl: return physical address 0x%x\n", aml_read_reg32(P_AO_DEBUG_REG1)); + return aml_read_reg32(P_AO_DEBUG_REG1); + } + +@@ -357,55 +457,63 @@ static irqreturn_t amlogic_cec_irq_handler(int irq, void *dummy) + { + unsigned long spin_flags; + struct cec_rx_list *entry; +-#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 +- unsigned int intr_stat = 0; +-#endif ++ unsigned int tx_msg_state; ++ unsigned int rx_msg_state; + +- tvout_dbg("amlogic_cec_irq_handler: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: enter\n"); + + udelay(100); //Delay execution a little. This fixes an issue when HDMI CEC stops working after a while. + +-#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 +- tvout_dbg("cec TX status: rx: 0x%x; tx: 0x%x\n", hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS), hdmi_rd_reg(CEC0_BASE_ADDR+CEC_TX_MSG_STATUS)); +- if (hdmi_rd_reg(CEC0_BASE_ADDR+CEC_RX_MSG_STATUS) != RX_DONE) +- { +- return IRQ_HANDLED; +- } +-#endif ++ tx_msg_state = amlogic_cec_read_reg(CEC_TX_MSG_STATUS); ++ rx_msg_state = amlogic_cec_read_reg(CEC_RX_MSG_STATUS); + +-#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 +- intr_stat = aml_read_reg32(P_AO_CEC_INTR_STAT); +- tvout_dbg("aocec irq %x\n", intr_stat); +- if (intr_stat & (1<<1)) +- { // aocec tx intr +- tx_irq_handle(); +- return IRQ_HANDLED; +- } +-#endif ++ amlogic_cec_log_dbg("cec msg status: rx: 0x%x; tx: 0x%x\n", rx_msg_state, tx_msg_state); + +- if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ if ((tx_msg_state == TX_DONE) || (tx_msg_state == TX_ERROR)) + { +- tvout_dbg("can't alloc cec_rx_list\n"); +- return IRQ_HANDLED; ++ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ ++ switch (tx_msg_state) { ++ case TX_ERROR : ++ amlogic_cec_set_tx_state(STATE_ERROR); ++ break; ++ case TX_DONE : ++ amlogic_cec_set_tx_state(STATE_DONE); ++ break; ++ default : ++ amlogic_cec_log_dbg("unexpected ts message state: 0x%x", tx_msg_state); ++ break; ++ } ++ wake_up_interruptible(&cec_tx_struct.waitq); + } + +- if ((-1) == cec_ll_rx(entry->buffer, &entry->size)) ++ if (rx_msg_state == RX_DONE) + { +- kfree(entry); +- tvout_dbg("amlogic_cec_irq_handler: nothing to read\n"); +- return IRQ_HANDLED; +- } + +- INIT_LIST_HEAD(&entry->list); ++ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL) ++ { ++ amlogic_cec_log_dbg("can't alloc cec_rx_list\n"); ++ return IRQ_HANDLED; ++ } + +- spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); +- list_add_tail(&entry->list, &cec_rx_struct.list); +- amlogic_cec_set_rx_state(STATE_DONE); +- spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); ++ if ((-1) == amlogic_cec_read_hw(entry->buffer, &entry->size)) ++ { ++ kfree(entry); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: nothing to read\n"); ++ return IRQ_HANDLED; ++ } ++ ++ INIT_LIST_HEAD(&entry->list); ++ ++ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags); ++ list_add_tail(&entry->list, &cec_rx_struct.list); ++ amlogic_cec_set_rx_state(STATE_DONE); ++ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags); + +- wake_up_interruptible(&cec_rx_struct.waitq); ++ wake_up_interruptible(&cec_rx_struct.waitq); ++ } + +- tvout_dbg("amlogic_cec_irq_handler: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_irq_handler: leave\n"); + + return IRQ_HANDLED; } -+#endif +@@ -414,10 +522,12 @@ static void amlogic_cec_delayed_init(struct work_struct *work) + { + hdmitx_dev_t* hdmitx_device = (hdmitx_dev_t*)container_of(work, hdmitx_dev_t, cec_work); - /*aud_mode attr*/ - static ssize_t show_aud_mode(struct device * dev, struct device_attribute *attr, char * buf) -@@ -963,10 +965,12 @@ static DEVICE_ATTR(disp_cap_3d, S_IWUSR | S_IRUGO, show_disp_cap_3d, NULL); - static DEVICE_ATTR(hdcp_ksv_info, S_IWUSR | S_IRUGO, show_hdcp_ksv_info, NULL); - static DEVICE_ATTR(hpd_state, S_IWUSR | S_IRUGO, show_hpd_state, NULL); - static DEVICE_ATTR(support_3d, S_IWUSR | S_IRUGO, show_support_3d, NULL); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - static DEVICE_ATTR(cec, S_IWUSR | S_IRUGO, show_cec, store_cec); - static DEVICE_ATTR(cec_config, S_IWUSR | S_IRUGO | S_IWGRP, show_cec_config, store_cec_config); - //static DEVICE_ATTR(cec_config, S_IWUGO | S_IRUGO , NULL, store_cec_config); - static DEVICE_ATTR(cec_lang_config, S_IWUSR | S_IRUGO | S_IWGRP, show_cec_lang_config, store_cec_lang_config); -+#endif +- tvout_dbg("amlogic_cec_delayed_init: enter\n"); ++ amlogic_cec_log_dbg("amlogic_cec_delayed_init: enter\n"); - /***************************** - * hdmitx display client interface -@@ -1643,9 +1647,11 @@ static int amhdmitx_probe(struct platform_device *pdev) - ret=device_create_file(hdmitx_dev, &dev_attr_hdcp_ksv_info); - ret=device_create_file(hdmitx_dev, &dev_attr_hpd_state); - ret=device_create_file(hdmitx_dev, &dev_attr_support_3d); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - ret=device_create_file(hdmitx_dev, &dev_attr_cec); - ret=device_create_file(hdmitx_dev, &dev_attr_cec_config); - ret=device_create_file(hdmitx_dev, &dev_attr_cec_lang_config); -+#endif + msleep_interruptible(15000); - if (hdmitx_dev == NULL) { - hdmi_print(ERR, SYS "device_create create error\n"); -@@ -1732,7 +1738,9 @@ static int amhdmitx_probe(struct platform_device *pdev) ++ cec_init_flag = 1; ++ + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 + cec_gpi_init(); + #endif +@@ -446,10 +556,12 @@ static void amlogic_cec_delayed_init(struct work_struct *work) + cec_arbit_bit_time_set(7, 0x2aa, 0); + #endif + ++ cec_init_flag = 0; ++ + hdmitx_device->cec_init_ready = 1; +- cec_global_info.cec_flag.cec_init_flag = 0; ++ wake_up_interruptible(&cec_tx_struct.waitq); + +- tvout_dbg("amlogic_cec_delayed_init: leave\n"); ++ amlogic_cec_log_dbg("amlogic_cec_delayed_init: leave\n"); + } + + static int amlogic_cec_init(void) +@@ -460,22 +572,17 @@ static int amlogic_cec_init(void) + printk(banner); + + hdmitx_device = get_hdmitx_device(); +- tvout_dbg("CEC init\n"); +- memset(&cec_global_info, 0, sizeof(cec_global_info_t)); +- ++ amlogic_cec_log_dbg("CEC init\n"); + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 + hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_H, 0x00 ); + hdmi_wr_reg(CEC0_BASE_ADDR+CEC_CLOCK_DIV_L, 0xf0 ); + #endif + +- cec_global_info.cec_rx_msg_buf.rx_buf_size = sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message)/sizeof(cec_global_info.cec_rx_msg_buf.cec_rx_message[0]); +- cec_global_info.hdmitx_device = hdmitx_device; +- + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 + if (request_irq(INT_HDMI_CEC, &amlogic_cec_irq_handler, + IRQF_SHARED, "amhdmitx-cec",(void *)hdmitx_device)) + { +- tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); ++ amlogic_cec_log_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); + return -EFAULT; } #endif - switch_dev_register(&sdev); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - switch_dev_register(&lang_dev); -+#endif - - hdmitx_init_parameters(&hdmitx_device.hdmi_info); - HDMITX_Meson_Init(&hdmitx_device); -@@ -1771,8 +1779,9 @@ static int amhdmitx_remove(struct platform_device *pdev) - device_remove_file(hdmitx_dev, &dev_attr_disp_cap_3d); - device_remove_file(hdmitx_dev, &dev_attr_hpd_state); - device_remove_file(hdmitx_dev, &dev_attr_support_3d); -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - device_remove_file(hdmitx_dev, &dev_attr_cec); -- -+#endif - cdev_del(&hdmitx_device.cdev); - - device_destroy(hdmitx_class, hdmitx_id); -diff --git a/drivers/amlogic/input/new_remote/remote_func.c b/drivers/amlogic/input/new_remote/remote_func.c -index e36e272..807c255 100755 ---- a/drivers/amlogic/input/new_remote/remote_func.c -+++ b/drivers/amlogic/input/new_remote/remote_func.c -@@ -525,6 +525,7 @@ int remote_hw_reprot_key(struct remote *remote_data) - mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); - } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key - #ifdef CONFIG_AML_HDMI_TX -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - extern int rc_long_press_pwr_key; - if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { - rc_long_press_pwr_key = 1; -@@ -534,6 +535,7 @@ int remote_hw_reprot_key(struct remote *remote_data) - cec_repeat--; - +@@ -483,14 +590,19 @@ static int amlogic_cec_init(void) + if (request_irq(INT_AO_CEC, &amlogic_cec_irq_handler, + IRQF_SHARED, "amhdmitx-aocec",(void *)hdmitx_device)) + { +- tvout_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); ++ amlogic_cec_log_dbg("Can't register IRQ %d\n",INT_HDMI_CEC); + return -EFAULT; + } #endif -+#endif - if (remote_data->repeat_enable) { - repeat_count++; - if (remote_data->repeat_tick < jiffies) { -@@ -618,6 +620,7 @@ int remote_hw_nec_rca_2in1_reprot_key(struct remote *remote_data) - mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); - } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key - #ifdef CONFIG_AML_HDMI_TX -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - extern int rc_long_press_pwr_key; - if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { - rc_long_press_pwr_key = 1; -@@ -627,6 +630,7 @@ int remote_hw_nec_rca_2in1_reprot_key(struct remote *remote_data) - cec_repeat--; - #endif -+#endif - if (remote_data->repeat_enable) { - repeat_count++; - if (remote_data->repeat_tick < jiffies) { -@@ -700,6 +704,7 @@ int remote_hw_nec_toshiba_2in1_reprot_key(struct remote *remote_data) - mod_timer(&remote_data->timer, jiffies + msecs_to_jiffies(remote_data->release_delay[remote_data->map_num]+remote_data->repeat_delay[remote_data->map_num])); - } else if((remote_data->frame_status & REPEARTFLAG) && remote_data->enable_repeat_falg) { //repeate key - #ifdef CONFIG_AML_HDMI_TX -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - extern int rc_long_press_pwr_key; - if((remote_data->repeat_release_code == 0x1a) && (!cec_repeat)) { - rc_long_press_pwr_key = 1; -@@ -709,6 +714,7 @@ int remote_hw_nec_toshiba_2in1_reprot_key(struct remote *remote_data) - cec_repeat--; + init_waitqueue_head(&cec_rx_struct.waitq); ++ + spin_lock_init(&cec_rx_struct.lock); ++ init_waitqueue_head(&cec_tx_struct.waitq); ++ ++ spin_lock_init(&cec_tx_struct.lock); ++ + if (misc_register(&cec_misc_device)) + { + printk(KERN_WARNING " Couldn't register device 10, %d.\n", CEC_MINOR); +@@ -506,14 +618,14 @@ static int amlogic_cec_init(void) + INIT_WORK(&hdmitx_device->cec_work, amlogic_cec_delayed_init); + queue_work(cec_workqueue, &hdmitx_device->cec_work); // for init + +- tvout_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); ++ amlogic_cec_log_dbg("hdmitx_device->cec_init_ready:0x%x\n", hdmitx_device->cec_init_ready); + + return 0; + } + + static void amlogic_cec_exit(void) + { +- if (cec_global_info.cec_flag.cec_init_flag == 1) ++ if (cec_init_flag == 1) + { + + #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 +@@ -523,7 +635,7 @@ static void amlogic_cec_exit(void) + #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 + free_irq(INT_AO_CEC, (void *)hdmitx_device); #endif -+#endif - if (remote_data->repeat_enable) { - repeat_count++; - if (remote_data->repeat_tick < jiffies) { -diff --git a/drivers/amlogic/input/remote/am_remote.c b/drivers/amlogic/input/remote/am_remote.c -index c824efb..01f0bfba 100755 ---- a/drivers/amlogic/input/remote/am_remote.c -+++ b/drivers/amlogic/input/remote/am_remote.c -@@ -390,6 +390,7 @@ static inline int remote_hw_reprot_key(struct remote *remote_data) - } - #ifdef CONFIG_AML_HDMI_TX - #ifdef CONFIG_ARCH_MESON6 -+#ifndef CONFIG_AML_HDMI_TX_NEW_CEC_DRIVER - //printk("last_scan_code:%x\n", last_scan_code); - if((((scan_code >> 16) & 0xff) == 0x1a) && (!cec_repeat)) { - extern int rc_long_press_pwr_key; -@@ -401,6 +402,7 @@ static inline int remote_hw_reprot_key(struct remote *remote_data) - cec_repeat--; - #endif - #endif -+#endif - if (remote_data->repeat_enable) { - if ((remote_data->repeat_tick < jiffies)&&(repeat_flag == 1)) { - remote_send_key(remote_data->input, (scan_code >> 16) & 0xff, 2); +- cec_global_info.cec_flag.cec_init_flag = 0; ++ cec_init_flag = 0; + } + + misc_deregister(&cec_misc_device);