mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-24 11:16:51 +00:00
Merge pull request #4743 from gdachs/cec-major-rework
amlogic cec: major rework
This commit is contained in:
commit
e70a58f998
@ -1,5 +1,5 @@
|
||||
diff -Nur a/include/cectypes.h b/include/cectypes.h
|
||||
--- a/include/cectypes.h 2016-02-10 11:50:03.658878388 +0100
|
||||
--- a/include/cectypes.h 2016-02-21 01:11:20.791177759 +0100
|
||||
+++ b/include/cectypes.h 2016-02-10 13:45:19.057046951 +0100
|
||||
@@ -320,6 +320,16 @@
|
||||
|
||||
@ -45,7 +45,7 @@ diff -Nur a/README.md b/README.md
|
||||
To compile in support for TDA995x devices, you have to pass the argument -DHAVE_TDA995X_API=1 to cmake:
|
||||
```
|
||||
diff -Nur a/src/libcec/adapter/AdapterFactory.cpp b/src/libcec/adapter/AdapterFactory.cpp
|
||||
--- a/src/libcec/adapter/AdapterFactory.cpp 2016-02-10 11:49:46.887067255 +0100
|
||||
--- a/src/libcec/adapter/AdapterFactory.cpp 2016-02-21 01:11:12.579266950 +0100
|
||||
+++ b/src/libcec/adapter/AdapterFactory.cpp 2016-02-10 12:41:44.252060917 +0100
|
||||
@@ -63,6 +63,11 @@
|
||||
#include "IMX/IMXCECAdapterCommunication.h"
|
||||
@ -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;
|
||||
+ };
|
||||
+};
|
||||
@ -621,7 +630,7 @@ diff -Nur a/src/libcec/adapter/Amlogic/AmlogicCEC.h b/src/libcec/adapter/Amlogic
|
||||
+#define CEC_IOC_GETPADDR _IO('c', 1)
|
||||
+#define CEC_MAX_FRAME_SIZE 16
|
||||
diff -Nur a/src/libcec/cmake/CheckPlatformSupport.cmake b/src/libcec/cmake/CheckPlatformSupport.cmake
|
||||
--- a/src/libcec/cmake/CheckPlatformSupport.cmake 2016-02-10 11:49:46.891067210 +0100
|
||||
--- a/src/libcec/cmake/CheckPlatformSupport.cmake 2016-02-21 01:11:12.579266950 +0100
|
||||
+++ b/src/libcec/cmake/CheckPlatformSupport.cmake 2016-02-10 13:18:20.847385373 +0100
|
||||
@@ -11,6 +11,7 @@
|
||||
# HAVE_IMX_API 1 if i.MX is supported
|
||||
@ -651,7 +660,7 @@ diff -Nur a/src/libcec/cmake/CheckPlatformSupport.cmake b/src/libcec/cmake/Check
|
||||
|
||||
# rt
|
||||
diff -Nur a/src/libcec/cmake/DisplayPlatformSupport.cmake b/src/libcec/cmake/DisplayPlatformSupport.cmake
|
||||
--- a/src/libcec/cmake/DisplayPlatformSupport.cmake 2016-02-10 11:49:46.891067210 +0100
|
||||
--- a/src/libcec/cmake/DisplayPlatformSupport.cmake 2016-02-21 01:11:12.579266950 +0100
|
||||
+++ b/src/libcec/cmake/DisplayPlatformSupport.cmake 2016-02-10 12:47:10.380408360 +0100
|
||||
@@ -50,6 +50,12 @@
|
||||
message(STATUS "Exynos support: no")
|
||||
@ -680,7 +689,7 @@ diff -Nur a/src/libcec/CMakeLists.txt b/src/libcec/CMakeLists.txt
|
||||
adapter/Pulse-Eight/USBCECAdapterCommunication.h
|
||||
adapter/Pulse-Eight/USBCECAdapterCommands.h
|
||||
diff -Nur a/src/libcec/env.h.in b/src/libcec/env.h.in
|
||||
--- a/src/libcec/env.h.in 2016-02-10 11:49:46.891067210 +0100
|
||||
--- a/src/libcec/env.h.in 2016-02-21 01:11:12.579266950 +0100
|
||||
+++ b/src/libcec/env.h.in 2016-02-10 11:57:58.449532413 +0100
|
||||
@@ -69,6 +69,9 @@
|
||||
/* Define to 1 for Exynos support */
|
||||
|
@ -1,19 +1,3 @@
|
||||
From 3bde21926d476a3fc0f4d37275f8fde11f09dade Mon Sep 17 00:00:00 2001
|
||||
From: Gerald Dachs <gda@dachsweb.de>
|
||||
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
|
||||
@ -71,10 +55,10 @@ index 7a944cd..f74ec1f 100755
|
||||
#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
|
||||
index 0000000..e5397c9
|
||||
--- /dev/null
|
||||
+++ b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c
|
||||
@@ -0,0 +1,534 @@
|
||||
@@ -0,0 +1,648 @@
|
||||
+/* linux/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c
|
||||
+ *
|
||||
+ * Copyright (c) 2016 Gerald Dachs
|
||||
@ -113,7 +97,9 @@ index 0000000..61fb500
|
||||
+#include <mach/hdmi_tx_reg.h>
|
||||
+#include <linux/amlogic/hdmi_tx/hdmi_tx_cec.h>
|
||||
+
|
||||
+#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");
|
||||
@ -132,24 +118,16 @@ index 0000000..61fb500
|
||||
+#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;
|
||||
@ -163,6 +141,12 @@ index 0000000..61fb500
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+struct cec_tx_struct {
|
||||
+ spinlock_t lock;
|
||||
+ wait_queue_head_t waitq;
|
||||
+ atomic_t state;
|
||||
+};
|
||||
+
|
||||
+enum cec_state {
|
||||
+ STATE_RX,
|
||||
+ STATE_TX,
|
||||
@ -175,58 +159,133 @@ index 0000000..61fb500
|
||||
+
|
||||
+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;
|
||||
+ }
|
||||
+static struct cec_tx_struct cec_tx_struct;
|
||||
+
|
||||
+ return us;
|
||||
+static atomic_t hdmi_on = ATOMIC_INIT(0);
|
||||
+
|
||||
+cec_global_info_t cec_global_info;
|
||||
+
|
||||
+static hdmitx_dev_t* hdmitx_device = NULL;
|
||||
+static struct workqueue_struct *cec_workqueue = NULL;
|
||||
+
|
||||
+static int cec_init_flag = 0;
|
||||
+
|
||||
+static void amlogic_cec_set_rx_state(enum cec_state state)
|
||||
+{
|
||||
+ atomic_set(&cec_rx_struct.state, state);
|
||||
+}
|
||||
+
|
||||
+void cec_report_physical_address_smp(void)
|
||||
+static void amlogic_cec_set_tx_state(enum cec_state state)
|
||||
+{
|
||||
+ 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;
|
||||
+ atomic_set(&cec_tx_struct.state, state);
|
||||
+}
|
||||
+
|
||||
+ tvout_dbg("cec_report_physical_address_smp: enter\n");
|
||||
+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 };
|
||||
+
|
||||
+ 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);
|
||||
+ 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);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+ cec_ll_tx(msg, 5);
|
||||
+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
|
||||
+}
|
||||
+
|
||||
+ tvout_dbg("cec_report_physical_address_smp: leave\n");
|
||||
+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)
|
||||
+ {
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+#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);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void amlogic_cec_write_hw(const char *data, size_t count)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ amlogic_cec_msg_dump("TX", data, count);
|
||||
+}
|
||||
+
|
||||
+unsigned short cec_log_addr_to_dev_type(unsigned char log_addr)
|
||||
+{
|
||||
+// 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;
|
||||
+
|
||||
+ 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)
|
||||
@ -236,34 +295,46 @@ index 0000000..61fb500
|
||||
+ // 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();
|
||||
+ }
|
||||
+ tvout_dbg("cec node init: cec features ok !\n");
|
||||
+}
|
||||
+ 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);
|
||||
+
|
||||
+static void amlogic_cec_set_rx_state(enum cec_state state)
|
||||
+{
|
||||
+ atomic_set(&cec_rx_struct.state, state);
|
||||
+ 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);
|
||||
+
|
||||
+ amlogic_cec_log_dbg("trigger libCEC\n");
|
||||
+ wake_up_interruptible(&cec_rx_struct.waitq);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ amlogic_cec_log_dbg("cec node init: cec features ok !\n");
|
||||
+}
|
||||
+
|
||||
+static int amlogic_cec_open(struct inode *inode, struct file *file)
|
||||
@ -272,7 +343,7 @@ index 0000000..61fb500
|
||||
+
|
||||
+ 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
|
||||
@ -296,12 +367,12 @@ index 0000000..61fb500
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
@ -311,7 +382,7 @@ index 0000000..61fb500
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
@ -337,7 +408,7 @@ index 0000000..61fb500
|
||||
+
|
||||
+ 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;
|
||||
+}
|
||||
@ -345,11 +416,8 @@ index 0000000..61fb500
|
||||
+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)
|
||||
@ -361,14 +429,36 @@ index 0000000..61fb500
|
||||
+ 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("Message transmit failed, ret=%d\n", ret);
|
||||
+ return -1;
|
||||
+ amlogic_cec_log_dbg("error during wait on state change\n");
|
||||
+ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n");
|
||||
+ return -ERESTARTSYS;
|
||||
+ }
|
||||
+
|
||||
+ tvout_dbg("amlogic_cec_write: leave\n");
|
||||
+ amlogic_cec_write_hw(data, count);
|
||||
+
|
||||
+ if (wait_event_interruptible_timeout(cec_tx_struct.waitq,
|
||||
+ atomic_read(&cec_tx_struct.state) != STATE_TX, 2 * HZ) <= 0)
|
||||
+ {
|
||||
+ amlogic_cec_log_dbg("error during wait on state change, resetting\n");
|
||||
+ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n");
|
||||
+ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_ABORT); // stop cec tx for hw retry.
|
||||
+ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP);
|
||||
+ return -ERESTARTSYS;
|
||||
+ }
|
||||
+
|
||||
+ if (atomic_read(&cec_tx_struct.state) != STATE_DONE)
|
||||
+ {
|
||||
+ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_write: leave\n");
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
@ -377,26 +467,22 @@ index 0000000..61fb500
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
@ -434,55 +520,63 @@ index 0000000..61fb500
|
||||
+{
|
||||
+ 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)
|
||||
+ tx_msg_state = amlogic_cec_read_reg(CEC_TX_MSG_STATUS);
|
||||
+ rx_msg_state = amlogic_cec_read_reg(CEC_RX_MSG_STATUS);
|
||||
+
|
||||
+ amlogic_cec_log_dbg("cec msg status: rx: 0x%x; tx: 0x%x\n", rx_msg_state, tx_msg_state);
|
||||
+
|
||||
+ if ((tx_msg_state == TX_DONE) || (tx_msg_state == TX_ERROR))
|
||||
+ {
|
||||
+ return IRQ_HANDLED;
|
||||
+ }
|
||||
+#endif
|
||||
+ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP);
|
||||
+
|
||||
+#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;
|
||||
+ 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);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL)
|
||||
+ if (rx_msg_state == RX_DONE)
|
||||
+ {
|
||||
+ tvout_dbg("can't alloc cec_rx_list\n");
|
||||
+ return IRQ_HANDLED;
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
+ 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");
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_irq_handler: leave\n");
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
@ -491,10 +585,12 @@ index 0000000..61fb500
|
||||
+{
|
||||
+ hdmitx_dev_t* hdmitx_device = (hdmitx_dev_t*)container_of(work, hdmitx_dev_t, cec_work);
|
||||
+
|
||||
+ tvout_dbg("amlogic_cec_delayed_init: enter\n");
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_delayed_init: enter\n");
|
||||
+
|
||||
+ msleep_interruptible(15000);
|
||||
+
|
||||
+ cec_init_flag = 1;
|
||||
+
|
||||
+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6
|
||||
+ cec_gpi_init();
|
||||
+#endif
|
||||
@ -523,10 +619,12 @@ index 0000000..61fb500
|
||||
+ cec_arbit_bit_time_set(7, 0x2aa, 0);
|
||||
+#endif
|
||||
+
|
||||
+ hdmitx_device->cec_init_ready = 1;
|
||||
+ cec_global_info.cec_flag.cec_init_flag = 0;
|
||||
+ cec_init_flag = 0;
|
||||
+
|
||||
+ tvout_dbg("amlogic_cec_delayed_init: leave\n");
|
||||
+ hdmitx_device->cec_init_ready = 1;
|
||||
+ wake_up_interruptible(&cec_tx_struct.waitq);
|
||||
+
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_delayed_init: leave\n");
|
||||
+}
|
||||
+
|
||||
+static int amlogic_cec_init(void)
|
||||
@ -537,22 +635,17 @@ index 0000000..61fb500
|
||||
+ 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
|
||||
@ -560,14 +653,19 @@ index 0000000..61fb500
|
||||
+ 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
|
||||
+
|
||||
+ 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);
|
||||
@ -583,14 +681,14 @@ index 0000000..61fb500
|
||||
+ 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
|
||||
@ -600,7 +698,7 @@ index 0000000..61fb500
|
||||
+#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;
|
||||
+ cec_init_flag = 0;
|
||||
+ }
|
||||
+
|
||||
+ misc_deregister(&cec_misc_device);
|
||||
@ -728,7 +826,7 @@ index e36e272..807c255 100755
|
||||
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
|
||||
index c824efb..01f0bfb 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)
|
||||
|
@ -1,19 +1,3 @@
|
||||
From 3bde21926d476a3fc0f4d37275f8fde11f09dade Mon Sep 17 00:00:00 2001
|
||||
From: Gerald Dachs <gda@dachsweb.de>
|
||||
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
|
||||
@ -71,10 +55,10 @@ index 7a944cd..f74ec1f 100755
|
||||
#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
|
||||
index 0000000..e5397c9
|
||||
--- /dev/null
|
||||
+++ b/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c
|
||||
@@ -0,0 +1,534 @@
|
||||
@@ -0,0 +1,648 @@
|
||||
+/* linux/drivers/amlogic/hdmi/hdmi_tx/amlogic_cec.c
|
||||
+ *
|
||||
+ * Copyright (c) 2016 Gerald Dachs
|
||||
@ -113,7 +97,9 @@ index 0000000..61fb500
|
||||
+#include <mach/hdmi_tx_reg.h>
|
||||
+#include <linux/amlogic/hdmi_tx/hdmi_tx_cec.h>
|
||||
+
|
||||
+#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");
|
||||
@ -132,24 +118,16 @@ index 0000000..61fb500
|
||||
+#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;
|
||||
@ -163,6 +141,12 @@ index 0000000..61fb500
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+struct cec_tx_struct {
|
||||
+ spinlock_t lock;
|
||||
+ wait_queue_head_t waitq;
|
||||
+ atomic_t state;
|
||||
+};
|
||||
+
|
||||
+enum cec_state {
|
||||
+ STATE_RX,
|
||||
+ STATE_TX,
|
||||
@ -175,58 +159,133 @@ index 0000000..61fb500
|
||||
+
|
||||
+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;
|
||||
+ }
|
||||
+static struct cec_tx_struct cec_tx_struct;
|
||||
+
|
||||
+ return us;
|
||||
+static atomic_t hdmi_on = ATOMIC_INIT(0);
|
||||
+
|
||||
+cec_global_info_t cec_global_info;
|
||||
+
|
||||
+static hdmitx_dev_t* hdmitx_device = NULL;
|
||||
+static struct workqueue_struct *cec_workqueue = NULL;
|
||||
+
|
||||
+static int cec_init_flag = 0;
|
||||
+
|
||||
+static void amlogic_cec_set_rx_state(enum cec_state state)
|
||||
+{
|
||||
+ atomic_set(&cec_rx_struct.state, state);
|
||||
+}
|
||||
+
|
||||
+void cec_report_physical_address_smp(void)
|
||||
+static void amlogic_cec_set_tx_state(enum cec_state state)
|
||||
+{
|
||||
+ 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;
|
||||
+ atomic_set(&cec_tx_struct.state, state);
|
||||
+}
|
||||
+
|
||||
+ tvout_dbg("cec_report_physical_address_smp: enter\n");
|
||||
+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 };
|
||||
+
|
||||
+ 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);
|
||||
+ 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);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+ cec_ll_tx(msg, 5);
|
||||
+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
|
||||
+}
|
||||
+
|
||||
+ tvout_dbg("cec_report_physical_address_smp: leave\n");
|
||||
+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)
|
||||
+ {
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+#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);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void amlogic_cec_write_hw(const char *data, size_t count)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ amlogic_cec_msg_dump("TX", data, count);
|
||||
+}
|
||||
+
|
||||
+unsigned short cec_log_addr_to_dev_type(unsigned char log_addr)
|
||||
+{
|
||||
+// 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;
|
||||
+
|
||||
+ 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)
|
||||
@ -236,34 +295,46 @@ index 0000000..61fb500
|
||||
+ // 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();
|
||||
+ }
|
||||
+ tvout_dbg("cec node init: cec features ok !\n");
|
||||
+}
|
||||
+ 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);
|
||||
+
|
||||
+static void amlogic_cec_set_rx_state(enum cec_state state)
|
||||
+{
|
||||
+ atomic_set(&cec_rx_struct.state, state);
|
||||
+ 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);
|
||||
+
|
||||
+ amlogic_cec_log_dbg("trigger libCEC\n");
|
||||
+ wake_up_interruptible(&cec_rx_struct.waitq);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ amlogic_cec_log_dbg("cec node init: cec features ok !\n");
|
||||
+}
|
||||
+
|
||||
+static int amlogic_cec_open(struct inode *inode, struct file *file)
|
||||
@ -272,7 +343,7 @@ index 0000000..61fb500
|
||||
+
|
||||
+ 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
|
||||
@ -296,12 +367,12 @@ index 0000000..61fb500
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
@ -311,7 +382,7 @@ index 0000000..61fb500
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
@ -337,7 +408,7 @@ index 0000000..61fb500
|
||||
+
|
||||
+ 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;
|
||||
+}
|
||||
@ -345,11 +416,8 @@ index 0000000..61fb500
|
||||
+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)
|
||||
@ -361,14 +429,36 @@ index 0000000..61fb500
|
||||
+ 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("Message transmit failed, ret=%d\n", ret);
|
||||
+ return -1;
|
||||
+ amlogic_cec_log_dbg("error during wait on state change\n");
|
||||
+ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n");
|
||||
+ return -ERESTARTSYS;
|
||||
+ }
|
||||
+
|
||||
+ tvout_dbg("amlogic_cec_write: leave\n");
|
||||
+ amlogic_cec_write_hw(data, count);
|
||||
+
|
||||
+ if (wait_event_interruptible_timeout(cec_tx_struct.waitq,
|
||||
+ atomic_read(&cec_tx_struct.state) != STATE_TX, 2 * HZ) <= 0)
|
||||
+ {
|
||||
+ amlogic_cec_log_dbg("error during wait on state change, resetting\n");
|
||||
+ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n");
|
||||
+ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_ABORT); // stop cec tx for hw retry.
|
||||
+ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP);
|
||||
+ return -ERESTARTSYS;
|
||||
+ }
|
||||
+
|
||||
+ if (atomic_read(&cec_tx_struct.state) != STATE_DONE)
|
||||
+ {
|
||||
+ printk(KERN_ERR "[amlogic] ##### cec write error! #####\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_write: leave\n");
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
@ -377,26 +467,22 @@ index 0000000..61fb500
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
@ -434,55 +520,63 @@ index 0000000..61fb500
|
||||
+{
|
||||
+ 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)
|
||||
+ tx_msg_state = amlogic_cec_read_reg(CEC_TX_MSG_STATUS);
|
||||
+ rx_msg_state = amlogic_cec_read_reg(CEC_RX_MSG_STATUS);
|
||||
+
|
||||
+ amlogic_cec_log_dbg("cec msg status: rx: 0x%x; tx: 0x%x\n", rx_msg_state, tx_msg_state);
|
||||
+
|
||||
+ if ((tx_msg_state == TX_DONE) || (tx_msg_state == TX_ERROR))
|
||||
+ {
|
||||
+ return IRQ_HANDLED;
|
||||
+ }
|
||||
+#endif
|
||||
+ amlogic_cec_write_reg(CEC_TX_MSG_CMD, TX_NO_OP);
|
||||
+
|
||||
+#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;
|
||||
+ 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);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ if ((entry = kmalloc(sizeof(struct cec_rx_list), GFP_ATOMIC)) == NULL)
|
||||
+ if (rx_msg_state == RX_DONE)
|
||||
+ {
|
||||
+ tvout_dbg("can't alloc cec_rx_list\n");
|
||||
+ return IRQ_HANDLED;
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
+ 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");
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_irq_handler: leave\n");
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
@ -491,10 +585,12 @@ index 0000000..61fb500
|
||||
+{
|
||||
+ hdmitx_dev_t* hdmitx_device = (hdmitx_dev_t*)container_of(work, hdmitx_dev_t, cec_work);
|
||||
+
|
||||
+ tvout_dbg("amlogic_cec_delayed_init: enter\n");
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_delayed_init: enter\n");
|
||||
+
|
||||
+ msleep_interruptible(15000);
|
||||
+
|
||||
+ cec_init_flag = 1;
|
||||
+
|
||||
+#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6
|
||||
+ cec_gpi_init();
|
||||
+#endif
|
||||
@ -523,10 +619,12 @@ index 0000000..61fb500
|
||||
+ cec_arbit_bit_time_set(7, 0x2aa, 0);
|
||||
+#endif
|
||||
+
|
||||
+ hdmitx_device->cec_init_ready = 1;
|
||||
+ cec_global_info.cec_flag.cec_init_flag = 0;
|
||||
+ cec_init_flag = 0;
|
||||
+
|
||||
+ tvout_dbg("amlogic_cec_delayed_init: leave\n");
|
||||
+ hdmitx_device->cec_init_ready = 1;
|
||||
+ wake_up_interruptible(&cec_tx_struct.waitq);
|
||||
+
|
||||
+ amlogic_cec_log_dbg("amlogic_cec_delayed_init: leave\n");
|
||||
+}
|
||||
+
|
||||
+static int amlogic_cec_init(void)
|
||||
@ -537,22 +635,17 @@ index 0000000..61fb500
|
||||
+ 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
|
||||
@ -560,14 +653,19 @@ index 0000000..61fb500
|
||||
+ 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
|
||||
+
|
||||
+ 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);
|
||||
@ -583,14 +681,14 @@ index 0000000..61fb500
|
||||
+ 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
|
||||
@ -600,7 +698,7 @@ index 0000000..61fb500
|
||||
+#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;
|
||||
+ cec_init_flag = 0;
|
||||
+ }
|
||||
+
|
||||
+ misc_deregister(&cec_misc_device);
|
||||
@ -728,7 +826,7 @@ index e36e272..807c255 100755
|
||||
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
|
||||
index c824efb..01f0bfb 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user