author | Xindong Xu <xindong.xu@amlogic.com> | 2018-03-09 02:51:04 (GMT) |
---|---|---|
committer | Xindong Xu <xindong.xu@amlogic.com> | 2018-03-09 04:51:36 (GMT) |
commit | f147474d83e57cab17e523e2d5b2a3856ef97778 (patch) | |
tree | 33160f25d9b0489cd955af31e44d91cb55fdf051 | |
parent | 48adbd18aaacf17714bb5026e20949a13f6584db (diff) | |
download | common-f147474d83e57cab17e523e2d5b2a3856ef97778.zip common-f147474d83e57cab17e523e2d5b2a3856ef97778.tar.gz common-f147474d83e57cab17e523e2d5b2a3856ef97778.tar.bz2 |
cec: merge cec from trunk [1/1]
PD# NONE
merge cec from trunk
Change-Id: I65944fe77b1d4c3f0d58777fec881648fa7f8abc
-rw-r--r-- | arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts | 4 | ||||
-rw-r--r-- | arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts | 4 | ||||
-rw-r--r-- | arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts | 4 | ||||
-rw-r--r-- | arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts | 4 | ||||
-rw-r--r-- | drivers/amlogic/cec/hdmi_ao_cec.c | 1774 | ||||
-rw-r--r-- | drivers/amlogic/cec/hdmi_ao_cec.h | 360 | ||||
-rw-r--r-- | include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h | 6 |
7 files changed, 1431 insertions, 725 deletions
diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts index ee8111e..7565ddc 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts @@ -606,12 +606,12 @@ status = "okay"; vendor_id = <0x000000>; cec_osd_string = "MBox"; /* Max Chars: 14 */ - cec_version = <6>; /* 5: 1.4, 6: 2.0 */ + cec_version = <5>; /* 5: 1.4, 6: 2.0 */ port_num = <1>; arc_port_mask = <0x0>; interrupts = <0 199 1>; interrupt-names = "hdmi_aocec"; - pinctrl-names = "hdmitx_aocec"; + pinctrl-names = "default"; pinctrl-0=<&hdmitx_aocec>; reg = <0x0 0xc810023c 0x0 0x4 0x0 0xc8100000 0x0 0x200>; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts index 2f0c547..f105eab 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts @@ -703,12 +703,12 @@ status = "okay"; vendor_id = <0x000000>; cec_osd_string = "MBox"; /* Max Chars: 14 */ - cec_version = <6>; /* 5: 1.4, 6: 2.0 */ + cec_version = <5>; /* 5: 1.4, 6: 2.0 */ port_num = <1>; arc_port_mask = <0x0>; interrupts = <0 199 1>; interrupt-names = "hdmi_aocec"; - pinctrl-names = "hdmitx_aocec"; + pinctrl-names = "default"; pinctrl-0=<&hdmitx_aocec>; reg = <0x0 0xc810023c 0x0 0x4 0x0 0xc8100000 0x0 0x200>; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts index 46f128b..18ea849 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts @@ -619,12 +619,12 @@ status = "okay"; vendor_id = <0x000000>; cec_osd_string = "MBox"; /* Max Chars: 14 */ - cec_version = <6>; /* 5: 1.4, 6: 2.0 */ + cec_version = <5>; /* 5: 1.4, 6: 2.0 */ port_num = <1>; arc_port_mask = <0x0>; interrupts = <0 199 1>; interrupt-names = "hdmi_aocec"; - pinctrl-names = "hdmitx_aocec"; + pinctrl-names = "default"; pinctrl-0=<&hdmitx_aocec>; reg = <0x0 0xc810023c 0x0 0x4 0x0 0xc8100000 0x0 0x200>; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts index 46ad8ae..aa2edd7 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts @@ -619,12 +619,12 @@ status = "okay"; vendor_id = <0x000000>; cec_osd_string = "MBox"; /* Max Chars: 14 */ - cec_version = <6>; /* 5: 1.4, 6: 2.0 */ + cec_version = <5>; /* 5: 1.4, 6: 2.0 */ port_num = <1>; arc_port_mask = <0x0>; interrupts = <0 199 1>; interrupt-names = "hdmi_aocec"; - pinctrl-names = "hdmitx_aocec"; + pinctrl-names = "default"; pinctrl-0=<&hdmitx_aocec>; reg = <0x0 0xc810023c 0x0 0x4 0x0 0xc8100000 0x0 0x200>; diff --git a/drivers/amlogic/cec/hdmi_ao_cec.c b/drivers/amlogic/cec/hdmi_ao_cec.c index 39f051f..baad0cf 100644 --- a/drivers/amlogic/cec/hdmi_ao_cec.c +++ b/drivers/amlogic/cec/hdmi_ao_cec.c @@ -8,13 +8,14 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. */ +#include <asm/irq.h> + #include <linux/version.h> #include <linux/module.h> #include <linux/irq.h> @@ -23,6 +24,7 @@ #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/delay.h> +#include <linux/uaccess.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/init.h> @@ -32,119 +34,127 @@ #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/cdev.h> -#include <asm/irq.h> #include <linux/io.h> -#include <linux/module.h> -#include <linux/kernel.h> #include <linux/slab.h> #include <linux/list.h> #include <linux/spinlock.h> #include <linux/spinlock_types.h> #include <linux/workqueue.h> #include <linux/timer.h> - -#include <linux/uaccess.h> -#include <linux/delay.h> - -#include <linux/amlogic/pm.h> +#include <linux/atomic.h> #include <linux/of.h> -#include <linux/pinctrl/consumer.h> +#include <linux/of_device.h> +#include <linux/of_address.h> #include <linux/of_irq.h> -#include "hdmi_ao_cec.h" -#include <linux/notifier.h> #include <linux/reboot.h> -#include <linux/of_address.h> +#include <linux/notifier.h> #include <linux/random.h> -#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND +#include <linux/pinctrl/consumer.h> + +#include <linux/amlogic/media/frame_provider/tvin/tvin.h> +#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h> +#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h> #include <linux/amlogic/pm.h> -#endif #include <linux/amlogic/cpu_version.h> -#include <linux/amlogic/cec_common.h> -#include <linux/notifier.h> +#include <linux/amlogic/jtag.h> -#ifdef CONFIG_AMLOGIC_HDMITX -#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +static struct early_suspend aocec_suspend_handler; #endif -#define DEFAULT_DEBUG_EN 0 +#include "hdmi_ao_cec.h" + + +#define CEC_FRAME_DELAY msecs_to_jiffies(400) +#define CEC_DEV_NAME "cec" + +#define DEV_TYPE_TV 0 +#define DEV_TYPE_RECORDER 1 +#define DEV_TYPE_RESERVED 2 +#define DEV_TYPE_TUNER 3 +#define DEV_TYPE_PLAYBACK 4 +#define DEV_TYPE_AUDIO_SYSTEM 5 +#define DEV_TYPE_PURE_CEC_SWITCH 6 +#define DEV_TYPE_VIDEO_PROCESSOR 7 + +#define CEC_POWER_ON (0 << 0) +#define CEC_EARLY_SUSPEND (1 << 0) +#define CEC_DEEP_SUSPEND (1 << 1) +#define CEC_POWER_RESUME (1 << 2) -#define DBG_BUF_SIZE 80 -#define MAX_INT 0x7ffffff +#define HR_DELAY(n) (ktime_set(0, n * 1000 * 1000)) +#define MAX_INT 0x7ffffff + +struct cec_platform_data_s { + unsigned int line_bit;/*cec gpio position in reg*/ + bool ee_to_ao;/*ee cec hw module mv to ao;ao cec delete*/ +}; /* global struct for tx and rx */ struct ao_cec_dev { - unsigned char rx_msg[MAX_MSG]; - /* bit filed for flags */ - struct { - unsigned char my_log_addr : 4; - unsigned char port_num : 4; /* first bytes */ - unsigned char cec_tx_result : 2; - unsigned char power_status : 2; - unsigned char rx_len : 4; /* second bytes */ - #ifdef CONFIG_PM - unsigned char cec_suspend : 2; - #endif - unsigned char dev_type : 3; - unsigned char cec_version : 3; /* third bytes */ - /* remaining bool flags */ - bool new_msg : 1; - bool phy_addr_test : 1; - bool wake_ok : 1; - bool ee_cec : 1; - bool cec_msg_dbg_en : 1; - bool hal_control : 1; - /* - * pin_status: tv support cec check, for box - * hpd_state: hdmi cable connected status - * - * hpd_state pin_status | TV support cec - * 0 x | N/A - * 1 0 | 0 - * 1 1 | 1 - */ - bool pin_status : 1; - bool hpd_state : 1; - }; - - /* hardware config */ - unsigned short arc_port; - unsigned short phy_addr; - unsigned short irq_cec; - unsigned short cec_line_cnt; - unsigned short hal_flag; - unsigned int port_seq; - - /* miscellaneous */ - unsigned int menu_lang; - unsigned int open_count; - dev_t dev_no; - - /* vendor related */ - unsigned int vendor_id; - char *osd_name; - char *product; - const char *pin_name; - - /* resource of register */ + unsigned long dev_type; + unsigned int port_num; + unsigned int arc_port; + unsigned int hal_flag; + unsigned int phy_addr; + unsigned int port_seq; + unsigned int cpu_type; + unsigned long irq_cec; void __iomem *exit_reg; void __iomem *cec_reg; void __iomem *hdmi_rxreg; void __iomem *hhi_reg; - - /* kernel resource */ - struct input_dev *remote_cec_dev; - struct notifier_block hdmitx_nb; + struct hdmitx_dev *tx_dev; struct workqueue_struct *cec_thread; struct device *dbg_dev; + const char *pin_name; struct delayed_work cec_work; struct completion rx_ok; struct completion tx_ok; spinlock_t cec_reg_lock; struct mutex cec_mutex; - struct hrtimer start_bit_check; + struct mutex cec_ioctl_mutex; +#ifdef CONFIG_PM + int cec_suspend; +#endif + struct vendor_info_data v_data; + struct cec_global_info_t cec_info; + struct cec_platform_data_s *plat_data; +}; + +struct cec_msg_last { + unsigned char msg[MAX_MSG]; + int len; + int last_result; + unsigned long last_jiffies; +}; +static struct cec_msg_last *last_cec_msg; + +static int phy_addr_test; + +/* from android cec hal */ +enum { + HDMI_OPTION_WAKEUP = 1, + HDMI_OPTION_ENABLE_CEC = 2, + HDMI_OPTION_SYSTEM_CEC_CONTROL = 3, + HDMI_OPTION_SET_LANG = 5, + HDMI_OPTION_SERVICE_FLAG = 16, }; static struct ao_cec_dev *cec_dev; +static int cec_tx_result; + +static int cec_line_cnt; +static struct hrtimer start_bit_check; + +static unsigned char rx_msg[MAX_MSG]; +static unsigned char rx_len; +static unsigned int new_msg; +static bool wake_ok = 1; +static bool ee_cec; +static bool pin_status; +static bool cec_msg_dbg_en; #define CEC_ERR(format, args...) \ {if (cec_dev->dbg_dev) \ @@ -152,17 +162,18 @@ static struct ao_cec_dev *cec_dev; } #define CEC_INFO(format, args...) \ - {if (cec_dev->cec_msg_dbg_en && cec_dev->dbg_dev) \ + {if (cec_msg_dbg_en && cec_dev->dbg_dev) \ dev_info(cec_dev->dbg_dev, format, ##args); \ } +static unsigned char msg_log_buf[128] = { 0 }; -#define waiting_aocec_free() \ +#define waiting_aocec_free(r) \ do {\ unsigned long cnt = 0;\ - while (readl(cec_dev->cec_reg + AO_CEC_RW_REG) & (1<<23)) {\ - if (cnt++ >= 3500) { \ - pr_info("waiting aocec free time out.\n");\ + while (readl(cec_dev->cec_reg + r) & (1<<23)) {\ + if (cnt++ == 3500) { \ + pr_info("waiting aocec %x free time out\n", r);\ break;\ } \ } \ @@ -179,12 +190,12 @@ static void cec_set_reg_bits(unsigned int addr, unsigned int value, writel(data32, cec_dev->cec_reg + addr); } -static unsigned int aocec_rd_reg(unsigned long addr) +unsigned int aocec_rd_reg(unsigned long addr) { unsigned int data32; unsigned long flags; - waiting_aocec_free(); + waiting_aocec_free(AO_CEC_RW_REG); spin_lock_irqsave(&cec_dev->cec_reg_lock, flags); data32 = 0; data32 |= 0 << 16; /* [16] cec_reg_wr */ @@ -192,18 +203,18 @@ static unsigned int aocec_rd_reg(unsigned long addr) data32 |= addr << 0; /* [7:0] cec_reg_addr */ writel(data32, cec_dev->cec_reg + AO_CEC_RW_REG); - waiting_aocec_free(); + waiting_aocec_free(AO_CEC_RW_REG); data32 = ((readl(cec_dev->cec_reg + AO_CEC_RW_REG)) >> 24) & 0xff; spin_unlock_irqrestore(&cec_dev->cec_reg_lock, flags); return data32; } /* aocec_rd_reg */ -static void aocec_wr_reg(unsigned long addr, unsigned long data) +void aocec_wr_reg(unsigned long addr, unsigned long data) { unsigned long data32; unsigned long flags; - waiting_aocec_free(); + waiting_aocec_free(AO_CEC_RW_REG); spin_lock_irqsave(&cec_dev->cec_reg_lock, flags); data32 = 0; data32 |= 1 << 16; /* [16] cec_reg_wr */ @@ -213,6 +224,38 @@ static void aocec_wr_reg(unsigned long addr, unsigned long data) spin_unlock_irqrestore(&cec_dev->cec_reg_lock, flags); } /* aocec_wr_only_reg */ +/*------------for AO_CECB------------------*/ +static unsigned int aocecb_rd_reg(unsigned long addr) +{ + unsigned int data32; + unsigned long flags; + + spin_lock_irqsave(&cec_dev->cec_reg_lock, flags); + data32 = 0; + data32 |= 0 << 16; /* [16] cec_reg_wr */ + data32 |= 0 << 8; /* [15:8] cec_reg_wrdata */ + data32 |= addr << 0; /* [7:0] cec_reg_addr */ + writel(data32, cec_dev->cec_reg + AO_CECB_RW_REG); + + data32 = ((readl(cec_dev->cec_reg + AO_CECB_RW_REG)) >> 24) & 0xff; + spin_unlock_irqrestore(&cec_dev->cec_reg_lock, flags); + return data32; +} /* aocecb_rd_reg */ + +static void aocecb_wr_reg(unsigned long addr, unsigned long data) +{ + unsigned long data32; + unsigned long flags; + + spin_lock_irqsave(&cec_dev->cec_reg_lock, flags); + data32 = 0; + data32 |= 1 << 16; /* [16] cec_reg_wr */ + data32 |= data << 8; /* [15:8] cec_reg_wrdata */ + data32 |= addr << 0; /* [7:0] cec_reg_addr */ + writel(data32, cec_dev->cec_reg + AO_CECB_RW_REG); + spin_unlock_irqrestore(&cec_dev->cec_reg_lock, flags); +} /* aocecb_wr_only_reg */ + /*----------------- low level for EE cec rx/tx support ----------------*/ static inline void hdmirx_set_bits_top(uint32_t reg, uint32_t bits, uint32_t start, uint32_t len) @@ -225,21 +268,47 @@ static inline void hdmirx_set_bits_top(uint32_t reg, uint32_t bits, hdmirx_wr_top(reg, tmp); } +static unsigned int hdmirx_cec_read(unsigned int reg) +{ + /* + * TXLX has moved ee cec to ao domain + */ + if (reg >= DWC_CEC_CTRL && cec_dev->plat_data->ee_to_ao) + return aocecb_rd_reg((reg - DWC_CEC_CTRL) / 4); + else + return hdmirx_rd_dwc(reg); +} + +/*only for ee cec*/ +static void hdmirx_cec_write(unsigned int reg, unsigned int value) +{ + /* + * TXLX has moved ee cec to ao domain + */ + if (reg >= DWC_CEC_CTRL && cec_dev->plat_data->ee_to_ao) + aocecb_wr_reg((reg - DWC_CEC_CTRL) / 4, value); + else + hdmirx_wr_dwc(reg, value); +} + static inline void hdmirx_set_bits_dwc(uint32_t reg, uint32_t bits, uint32_t start, uint32_t len) { unsigned int tmp; - tmp = hdmirx_rd_dwc(reg); + tmp = hdmirx_cec_read(reg); tmp &= ~(((1 << len) - 1) << start); tmp |= (bits << start); - hdmirx_wr_dwc(reg, tmp); + hdmirx_cec_write(reg, tmp); } -static void cecrx_hw_reset(void) +void cecrx_hw_reset(void) { /* cec disable */ - hdmirx_set_bits_dwc(DWC_DMI_DISABLE_IF, 0, 5, 1); + if (!cec_dev->plat_data->ee_to_ao) + hdmirx_set_bits_dwc(DWC_DMI_DISABLE_IF, 0, 5, 1); + else + cec_set_reg_bits(AO_CECB_GEN_CNTL, 0, 0, 1); udelay(500); } @@ -247,37 +316,33 @@ static void cecrx_check_irq_enable(void) { unsigned int reg32; - reg32 = hdmirx_rd_dwc(DWC_AUD_CLK_IEN); + /* irq on chip txlx has sperate from EE cec, no need check */ + if (cec_dev->plat_data->ee_to_ao) + return; + + reg32 = hdmirx_cec_read(DWC_AUD_CEC_IEN); if ((reg32 & EE_CEC_IRQ_EN_MASK) != EE_CEC_IRQ_EN_MASK) { CEC_INFO("irq_en is wrong:%x, checker:%pf\n", reg32, (void *)_RET_IP_); - hdmirx_wr_dwc(DWC_AUD_CLK_IEN_SET, EE_CEC_IRQ_EN_MASK); + hdmirx_cec_write(DWC_AUD_CEC_IEN_SET, EE_CEC_IRQ_EN_MASK); } } -static void format_msg_str(const char *msg, char len, char *prefix, char *buf) -{ - int size = 0, i; - - size = sprintf(buf + size, "%s %2d:", prefix, len); - for (i = 0; i < len; i++) - size += sprintf(buf + size, " %02x", msg[i]); - buf[size] = '\0'; - WARN_ON(size >= DBG_BUF_SIZE); -} - static int cecrx_trigle_tx(const unsigned char *msg, unsigned char len) { - int i = 0; + int i = 0, size = 0; int lock; cecrx_check_irq_enable(); while (1) { /* send is in process */ - lock = hdmirx_rd_dwc(DWC_CEC_LOCK); - if (lock) + lock = hdmirx_cec_read(DWC_CEC_LOCK); + if (lock) { CEC_ERR("recevie msg in tx\n"); - if (hdmirx_rd_dwc(DWC_CEC_CTRL) & 0x01) + cecrx_irq_handle(); + return -1; + } + if (hdmirx_cec_read(DWC_CEC_CTRL) & 0x01) i++; else break; @@ -287,73 +352,97 @@ static int cecrx_trigle_tx(const unsigned char *msg, unsigned char len) } msleep(20); } - - for (i = 0; i < len; i++) - hdmirx_wr_dwc(DWC_CEC_TX_DATA0 + i * 4, msg[i]); - - if (cec_dev->cec_msg_dbg_en) { - char buf[DBG_BUF_SIZE] = {}; - - format_msg_str(msg, len, "CEC tx msg", buf); - pr_info("%s\n", buf); + size += sprintf(msg_log_buf + size, "CEC tx msg len %d:", len); + for (i = 0; i < len; i++) { + hdmirx_cec_write(DWC_CEC_TX_DATA0 + i * 4, msg[i]); + size += sprintf(msg_log_buf + size, " %02x", msg[i]); } - + msg_log_buf[size] = '\0'; + CEC_INFO("%s\n", msg_log_buf); /* start send */ - hdmirx_wr_dwc(DWC_CEC_TX_CNT, len); + hdmirx_cec_write(DWC_CEC_TX_CNT, len); hdmirx_set_bits_dwc(DWC_CEC_CTRL, 3, 0, 3); return 0; } -static int cec_pick_msg(unsigned char *msg) +int cec_has_irq(void) { - int i; + unsigned int intr_cec; + + if (!cec_dev->plat_data->ee_to_ao) { + intr_cec = hdmirx_cec_read(DWC_AUD_CEC_ISTS); + intr_cec &= EE_CEC_IRQ_EN_MASK; + } else { + intr_cec = readl(cec_dev->cec_reg + AO_CECB_INTR_STAT); + intr_cec &= CECB_IRQ_EN_MASK; + } + return intr_cec; +} + +static inline void cecrx_clear_irq(unsigned int flags) +{ + if (!cec_dev->plat_data->ee_to_ao) + hdmirx_cec_write(DWC_AUD_CEC_ICLR, flags); + else + writel(flags, cec_dev->cec_reg + AO_CECB_INTR_CLR); +} + +static int cec_pick_msg(unsigned char *msg, unsigned char *out_len) +{ + int i, size; int len; struct delayed_work *dwork; dwork = &cec_dev->cec_work; - len = hdmirx_rd_dwc(DWC_CEC_RX_CNT); - for (i = 0; i < len; i++) - msg[i] = hdmirx_rd_dwc(DWC_CEC_RX_DATA0 + i * 4); + len = hdmirx_cec_read(DWC_CEC_RX_CNT); + size = sprintf(msg_log_buf, "CEC RX len %d:", len); + for (i = 0; i < len; i++) { + msg[i] = hdmirx_cec_read(DWC_CEC_RX_DATA0 + i * 4); + size += sprintf(msg_log_buf + size, " %02x", msg[i]); + } + size += sprintf(msg_log_buf + size, "\n"); + msg_log_buf[size] = '\0'; /* clr CEC lock bit */ - hdmirx_wr_dwc(DWC_CEC_LOCK, 0); + hdmirx_cec_write(DWC_CEC_LOCK, 0); mod_delayed_work(cec_dev->cec_thread, dwork, 0); - if (cec_dev->cec_msg_dbg_en) { - char buf[DBG_BUF_SIZE] = {}; - - format_msg_str(msg, len, "CEC rx msg", buf); - pr_info("%s\n", buf); - } - cec_dev->rx_len = len; - cec_dev->pin_status = 1; + CEC_INFO("%s", msg_log_buf); + if (((msg[0] & 0xf0) >> 4) == cec_dev->cec_info.log_addr) { + *out_len = 0; + CEC_ERR("bad iniator with self:%s", msg_log_buf); + } else + *out_len = len; + pin_status = 1; return 0; } -static void cecrx_irq_handle(void) +void cecrx_irq_handle(void) { uint32_t intr_cec; uint32_t lock; + int shift = 0; - intr_cec = (hdmirx_rd_dwc(DWC_AUD_CLK_ISTS) & EE_CEC_IRQ_EN_MASK); + intr_cec = cec_has_irq(); /* clear irq */ if (intr_cec != 0) - hdmirx_wr_dwc(DWC_AUD_CLK_ICLR, intr_cec); + cecrx_clear_irq(intr_cec); - if (!cec_dev->ee_cec) + if (!ee_cec) return; + if (cec_dev->plat_data->ee_to_ao) + shift = 16; /* TX DONE irq, increase tx buffer pointer */ if (intr_cec & CEC_IRQ_TX_DONE) { - cec_dev->cec_tx_result = CEC_FAIL_NONE; + cec_tx_result = CEC_FAIL_NONE; complete(&cec_dev->tx_ok); } - lock = hdmirx_rd_dwc(DWC_CEC_LOCK); + lock = hdmirx_cec_read(DWC_CEC_LOCK); /* EOM irq, message is coming */ if ((intr_cec & CEC_IRQ_RX_EOM) || lock) { - cec_pick_msg(cec_dev->rx_msg); + cec_pick_msg(rx_msg, &rx_len); complete(&cec_dev->rx_ok); - cec_dev->new_msg = 1; } /* TX error irq flags */ @@ -363,14 +452,14 @@ static void cecrx_irq_handle(void) if (!(intr_cec & CEC_IRQ_TX_NACK)) CEC_ERR("tx msg failed, flag:%08x\n", intr_cec); if (intr_cec & CEC_IRQ_TX_NACK) - cec_dev->cec_tx_result = CEC_FAIL_NACK; + cec_tx_result = CEC_FAIL_NACK; else if (intr_cec & CEC_IRQ_TX_ARB_LOST) { - cec_dev->cec_tx_result = CEC_FAIL_BUSY; + cec_tx_result = CEC_FAIL_BUSY; /* clear start */ - hdmirx_wr_dwc(DWC_CEC_TX_CNT, 0); + hdmirx_cec_write(DWC_CEC_TX_CNT, 0); hdmirx_set_bits_dwc(DWC_CEC_CTRL, 0, 0, 3); } else - cec_dev->cec_tx_result = CEC_FAIL_OTHER; + cec_tx_result = CEC_FAIL_OTHER; complete(&cec_dev->tx_ok); } @@ -382,7 +471,7 @@ static void cecrx_irq_handle(void) if (intr_cec & CEC_IRQ_RX_WAKEUP) { CEC_INFO("rx wake up\n"); - hdmirx_wr_dwc(DWC_CEC_WKUPCTRL, 0); + hdmirx_cec_write(DWC_CEC_WKUPCTRL, 0); /* TODO: wake up system if needed */ } } @@ -393,73 +482,134 @@ static irqreturn_t cecrx_isr(int irq, void *dev_instance) return IRQ_HANDLED; } -static void cec_hw_buf_clear(void) +static void ao_cecb_init(void) { - aocec_wr_reg(CEC_RX_MSG_CMD, RX_DISABLE); - aocec_wr_reg(CEC_TX_MSG_CMD, TX_ABORT); - aocec_wr_reg(CEC_RX_CLEAR_BUF, 1); - aocec_wr_reg(CEC_TX_CLEAR_BUF, 1); - udelay(100); - aocec_wr_reg(CEC_RX_CLEAR_BUF, 0); - aocec_wr_reg(CEC_TX_CLEAR_BUF, 0); - udelay(100); - aocec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); - aocec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); + unsigned long data32; + unsigned int reg; + + if (!cec_dev->plat_data->ee_to_ao) + return; + + reg = (0 << 31) | + (0 << 30) | + (1 << 28) | /* clk_div0/clk_div1 in turn */ + ((732-1) << 12) | /* Div_tcnt1 */ + ((733-1) << 0); /* Div_tcnt0 */ + writel(reg, cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG0); + reg = (0 << 13) | + ((11-1) << 12) | + ((8-1) << 0); + writel(reg, cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG1); + + reg = readl(cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG0); + reg |= (1 << 31); + writel(reg, cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG0); + + udelay(200); + reg |= (1 << 30); + writel(reg, cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG0); + + reg = readl(cec_dev->cec_reg + AO_RTI_PWR_CNTL_REG0); + reg |= (0x01 << 14); /* xtal gate */ + writel(reg, cec_dev->cec_reg + AO_RTI_PWR_CNTL_REG0); + + data32 = 0; + data32 |= (7 << 12); /* filter_del */ + data32 |= (1 << 8); /* filter_tick: 1us */ + data32 |= (1 << 3); /* enable system clock */ + data32 |= 0 << 1; /* [2:1] cntl_clk: */ + /* 0=Disable clk (Power-off mode); */ + /* 1=Enable gated clock (Normal mode); */ + /* 2=Enable free-run clk (Debug mode). */ + data32 |= 1 << 0; /* [0] sw_reset: 1=Reset */ + writel(data32, cec_dev->cec_reg + AO_CECB_GEN_CNTL); + /* Enable gated clock (Normal mode). */ + cec_set_reg_bits(AO_CECB_GEN_CNTL, 1, 1, 1); + /* Release SW reset */ + cec_set_reg_bits(AO_CECB_GEN_CNTL, 0, 0, 1); + + /* Enable all AO_CECB interrupt sources */ + cec_irq_enable(true); + hdmirx_cec_write(DWC_CEC_WKUPCTRL, 0); } -static void cec_logicaddr_set(int l_add) +void eecec_irq_enable(bool enable) { - /* save logical address for suspend/wake up */ - cec_set_reg_bits(AO_DEBUG_REG1, l_add, 16, 4); - if (cec_dev->ee_cec) { - /* set ee_cec logical addr */ - if (l_add < 8) - hdmirx_wr_dwc(DWC_CEC_ADDR_L, 1 << l_add); + if (cec_dev->cpu_type < MESON_CPU_MAJOR_ID_TXLX) { + if (enable) + hdmirx_cec_write(DWC_AUD_CEC_IEN_SET, + EE_CEC_IRQ_EN_MASK); + else { + hdmirx_cec_write(DWC_AUD_CEC_ICLR, + (~(hdmirx_cec_read(DWC_AUD_CEC_IEN)) | + EE_CEC_IRQ_EN_MASK)); + hdmirx_cec_write(DWC_AUD_CEC_IEN_SET, + hdmirx_cec_read(DWC_AUD_CEC_IEN) & + ~EE_CEC_IRQ_EN_MASK); + hdmirx_cec_write(DWC_AUD_CEC_IEN_CLR, + (~(hdmirx_cec_read(DWC_AUD_CEC_IEN)) | + EE_CEC_IRQ_EN_MASK)); + } + CEC_INFO("ee enable:int mask:0x%x\n", + hdmirx_cec_read(DWC_AUD_CEC_IEN)); + } else { + if (enable) + writel(CECB_IRQ_EN_MASK, + cec_dev->cec_reg + AO_CECB_INTR_MASKN); else - hdmirx_wr_dwc(DWC_CEC_ADDR_H, 1 << (l_add - 8) | 0x80); - return; + writel(readl(cec_dev->cec_reg + AO_CECB_INTR_MASKN) + & ~CECB_IRQ_EN_MASK, + cec_dev->cec_reg + AO_CECB_INTR_MASKN); + CEC_INFO("ao move enable:int mask:0x%x\n", + readl(cec_dev->cec_reg + AO_CECB_INTR_MASKN)); } - aocec_wr_reg(CEC_LOGICAL_ADDR0, 0); - cec_hw_buf_clear(); - aocec_wr_reg(CEC_LOGICAL_ADDR0, (l_add & 0xf)); - udelay(100); - aocec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | (l_add & 0xf)); - if (cec_dev->cec_msg_dbg_en) - CEC_INFO("set logical addr:0x%x\n", - aocec_rd_reg(CEC_LOGICAL_ADDR0)); } -static int cecrx_hw_init(void) +void cec_irq_enable(bool enable) +{ + if (ee_cec) + eecec_irq_enable(enable); + else + aocec_irq_enable(enable); +} + +int cecrx_hw_init(void) { unsigned int data32; - if (!cec_dev->ee_cec) + if (!ee_cec) return -1; cecrx_hw_reset(); - /* set cec clk 32768k */ - data32 = readl(cec_dev->hhi_reg + HHI_32K_CLK_CNTL); - data32 = 0; - /* [17:16] clk_sel: 0=oscin; 1=slow_oscin; 2=fclk_div3; 3=fclk_div5. */ - data32 |= 0 << 16; - /* [ 15] clk_en */ - data32 |= 1 << 15; - /* [13: 0] clk_div */ - data32 |= (732-1) << 0; - writel(data32, cec_dev->hhi_reg + HHI_32K_CLK_CNTL); - hdmirx_wr_top(TOP_EDID_ADDR_CEC, EDID_CEC_ID_ADDR); - - /* hdmirx_cecclk_en */ - hdmirx_set_bits_top(TOP_CLK_CNTL, 1, 2, 1); - hdmirx_set_bits_top(TOP_EDID_GEN_CNTL, EDID_AUTO_CEC_EN, 11, 1); - - /* enable all cec irq */ - hdmirx_wr_dwc(DWC_AUD_CLK_IEN_SET, EE_CEC_IRQ_EN_MASK); - /* clear all wake up source */ - hdmirx_wr_dwc(DWC_CEC_WKUPCTRL, 0); - /* cec enable */ - hdmirx_set_bits_dwc(DWC_DMI_DISABLE_IF, 1, 5, 1); - - cec_logicaddr_set(cec_dev->my_log_addr); + if (!cec_dev->plat_data->ee_to_ao) { + /* set cec clk 32768k */ + data32 = readl(cec_dev->hhi_reg + HHI_32K_CLK_CNTL); + data32 = 0; + /* + * [17:16] clk_sel: 0=oscin; 1=slow_oscin; + * 2=fclk_div3; 3=fclk_div5. + */ + data32 |= 0 << 16; + /* [ 15] clk_en */ + data32 |= 1 << 15; + /* [13: 0] clk_div */ + data32 |= (732-1) << 0; + writel(data32, cec_dev->hhi_reg + HHI_32K_CLK_CNTL); + hdmirx_wr_top(TOP_EDID_ADDR_CEC, EDID_CEC_ID_ADDR); + + /* hdmirx_cecclk_en */ + hdmirx_set_bits_top(TOP_CLK_CNTL, 1, 2, 1); + hdmirx_set_bits_top(TOP_EDID_GEN_CNTL, EDID_AUTO_CEC_EN, 11, 1); + + /* enable all cec irq */ + cec_irq_enable(true); + /* clear all wake up source */ + hdmirx_cec_write(DWC_CEC_WKUPCTRL, 0); + /* cec enable */ + hdmirx_set_bits_dwc(DWC_DMI_DISABLE_IF, 1, 5, 1); + } else + ao_cecb_init(); + + cec_logicaddr_set(cec_dev->cec_info.log_addr); return 0; } @@ -469,41 +619,56 @@ static int dump_cecrx_reg(char *b) unsigned char reg; unsigned int reg32; - reg32 = readl(cec_dev->hhi_reg + HHI_32K_CLK_CNTL); - s += sprintf(b + s, "HHI_32K_CLK_CNTL: 0x%08x\n", reg32); - reg32 = hdmirx_rd_top(TOP_EDID_ADDR_CEC); - s += sprintf(b + s, "TOP_EDID_ADDR_CEC: 0x%08x\n", reg32); - reg32 = hdmirx_rd_top(TOP_EDID_GEN_CNTL); - s += sprintf(b + s, "TOP_EDID_GEN_CNTL: 0x%08x\n", reg32); - reg32 = hdmirx_rd_dwc(DWC_AUD_CLK_IEN); - s += sprintf(b + s, "DWC_AUD_CLK_IEN: 0x%08x\n", reg32); - reg32 = hdmirx_rd_dwc(DWC_AUD_CLK_ISTS); - s += sprintf(b + s, "DWC_AUD_CLK_ISTS: 0x%08x\n", reg32); - reg32 = hdmirx_rd_dwc(DWC_DMI_DISABLE_IF); - s += sprintf(b + s, "DWC_DMI_DISABLE_IF: 0x%08x\n", reg32); - reg32 = hdmirx_rd_top(TOP_CLK_CNTL); - s += sprintf(b + s, "TOP_CLK_CNTL: 0x%08x\n", reg32); + if (!cec_dev->plat_data->ee_to_ao) { + reg32 = readl(cec_dev->hhi_reg + HHI_32K_CLK_CNTL); + s += sprintf(b + s, "HHI_32K_CLK_CNTL: 0x%08x\n", reg32); + reg32 = hdmirx_rd_top(TOP_EDID_ADDR_CEC); + s += sprintf(b + s, "TOP_EDID_ADDR_CEC: 0x%08x\n", reg32); + reg32 = hdmirx_rd_top(TOP_EDID_GEN_CNTL); + s += sprintf(b + s, "TOP_EDID_GEN_CNTL: 0x%08x\n", reg32); + reg32 = hdmirx_cec_read(DWC_AUD_CEC_IEN); + s += sprintf(b + s, "DWC_AUD_CEC_IEN: 0x%08x\n", reg32); + reg32 = hdmirx_cec_read(DWC_AUD_CEC_ISTS); + s += sprintf(b + s, "DWC_AUD_CEC_ISTS: 0x%08x\n", reg32); + reg32 = hdmirx_cec_read(DWC_DMI_DISABLE_IF); + s += sprintf(b + s, "DWC_DMI_DISABLE_IF: 0x%08x\n", reg32); + reg32 = hdmirx_rd_top(TOP_CLK_CNTL); + s += sprintf(b + s, "TOP_CLK_CNTL: 0x%08x\n", reg32); + } else { + reg32 = readl(cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG0); + s += sprintf(b + s, "AO_CECB_CLK_CNTL_REG0: 0x%08x\n", reg32); + reg32 = readl(cec_dev->cec_reg + AO_CECB_CLK_CNTL_REG1); + s += sprintf(b + s, "AO_CECB_CLK_CNTL_REG1: 0x%08x\n", reg32); + reg32 = readl(cec_dev->cec_reg + AO_CECB_GEN_CNTL); + s += sprintf(b + s, "AO_CECB_GEN_CNTL: 0x%08x\n", reg32); + reg32 = readl(cec_dev->cec_reg + AO_CECB_RW_REG); + s += sprintf(b + s, "AO_CECB_RW_REG: 0x%08x\n", reg32); + reg32 = readl(cec_dev->cec_reg + AO_CECB_INTR_MASKN); + s += sprintf(b + s, "AO_CECB_INTR_MASKN: 0x%08x\n", reg32); + reg32 = readl(cec_dev->cec_reg + AO_CECB_INTR_STAT); + s += sprintf(b + s, "AO_CECB_INTR_STAT: 0x%08x\n", reg32); + } s += sprintf(b + s, "CEC MODULE REGS:\n"); - s += sprintf(b + s, "CEC_CTRL = 0x%02x\n", hdmirx_rd_dwc(0x1f00)); - s += sprintf(b + s, "CEC_MASK = 0x%02x\n", hdmirx_rd_dwc(0x1f08)); - s += sprintf(b + s, "CEC_ADDR_L = 0x%02x\n", hdmirx_rd_dwc(0x1f14)); - s += sprintf(b + s, "CEC_ADDR_H = 0x%02x\n", hdmirx_rd_dwc(0x1f18)); - s += sprintf(b + s, "CEC_TX_CNT = 0x%02x\n", hdmirx_rd_dwc(0x1f1c)); - s += sprintf(b + s, "CEC_RX_CNT = 0x%02x\n", hdmirx_rd_dwc(0x1f20)); - s += sprintf(b + s, "CEC_LOCK = 0x%02x\n", hdmirx_rd_dwc(0x1fc0)); - s += sprintf(b + s, "CEC_WKUPCTRL = 0x%02x\n", hdmirx_rd_dwc(0x1fc4)); + s += sprintf(b + s, "CEC_CTRL = 0x%02x\n", hdmirx_cec_read(0x1f00)); + s += sprintf(b + s, "CEC_MASK = 0x%02x\n", hdmirx_cec_read(0x1f08)); + s += sprintf(b + s, "CEC_ADDR_L = 0x%02x\n", hdmirx_cec_read(0x1f14)); + s += sprintf(b + s, "CEC_ADDR_H = 0x%02x\n", hdmirx_cec_read(0x1f18)); + s += sprintf(b + s, "CEC_TX_CNT = 0x%02x\n", hdmirx_cec_read(0x1f1c)); + s += sprintf(b + s, "CEC_RX_CNT = 0x%02x\n", hdmirx_cec_read(0x1f20)); + s += sprintf(b + s, "CEC_LOCK = 0x%02x\n", hdmirx_cec_read(0x1fc0)); + s += sprintf(b + s, "CEC_WKUPCTRL = 0x%02x\n", hdmirx_cec_read(0x1fc4)); s += sprintf(b + s, "%s", "RX buffer:"); for (i = 0; i < 16; i++) { - reg = (hdmirx_rd_dwc(0x1f80 + i * 4) & 0xff); + reg = (hdmirx_cec_read(0x1f80 + i * 4) & 0xff); s += sprintf(b + s, " %02x", reg); } s += sprintf(b + s, "\n"); s += sprintf(b + s, "%s", "TX buffer:"); for (i = 0; i < 16; i++) { - reg = (hdmirx_rd_dwc(0x1f40 + i * 4) & 0xff); + reg = (hdmirx_cec_read(0x1f40 + i * 4) & 0xff); s += sprintf(b + s, " %02x", reg); } s += sprintf(b + s, "\n"); @@ -512,75 +677,55 @@ static int dump_cecrx_reg(char *b) /*--------------------- END of EE CEC --------------------*/ -static void cec_enable_irq(void) +void aocec_irq_enable(bool enable) { - cec_set_reg_bits(AO_CEC_INTR_MASKN, 0x6, 0, 3); - CEC_INFO("enable:int mask:0x%x\n", + if (enable) + cec_set_reg_bits(AO_CEC_INTR_MASKN, 0x6, 0, 3); + else + cec_set_reg_bits(AO_CEC_INTR_MASKN, 0x0, 0, 3); + CEC_INFO("ao enable:int mask:0x%x\n", readl(cec_dev->cec_reg + AO_CEC_INTR_MASKN)); } -static void cec_arbit_bit_time_set(unsigned int bit_set, - unsigned int time_set, unsigned int flag) -{ /* 11bit:bit[10:0] */ - if (flag) { - CEC_INFO("bit_set:0x%x;time_set:0x%x\n", - bit_set, time_set); - } +static void cec_hw_buf_clear(void) +{ + aocec_wr_reg(CEC_RX_MSG_CMD, RX_DISABLE); + aocec_wr_reg(CEC_TX_MSG_CMD, TX_ABORT); + aocec_wr_reg(CEC_RX_CLEAR_BUF, 1); + aocec_wr_reg(CEC_TX_CLEAR_BUF, 1); + udelay(100); + aocec_wr_reg(CEC_RX_CLEAR_BUF, 0); + aocec_wr_reg(CEC_TX_CLEAR_BUF, 0); + udelay(100); + aocec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); + aocec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); +} - switch (bit_set) { - case 3: - /* 3 bit */ - if (flag) { - CEC_INFO("read 3 bit:0x%x%x\n", - aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT10_8), - aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT7_0)); - } - aocec_wr_reg(AO_CEC_TXTIME_4BIT_BIT7_0, time_set & 0xff); - aocec_wr_reg(AO_CEC_TXTIME_4BIT_BIT10_8, (time_set >> 8) & 0x7); - if (flag) { - CEC_INFO("write 3 bit:0x%x%x\n", - aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT10_8), - aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT7_0)); - } - break; - /* 5 bit */ - case 5: - if (flag) { - CEC_INFO("read 5 bit:0x%x%x\n", - aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT10_8), - aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT7_0)); - } - aocec_wr_reg(AO_CEC_TXTIME_2BIT_BIT7_0, time_set & 0xff); - aocec_wr_reg(AO_CEC_TXTIME_2BIT_BIT10_8, (time_set >> 8) & 0x7); - if (flag) { - CEC_INFO("write 5 bit:0x%x%x\n", - aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT10_8), - aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT7_0)); - } - break; - /* 7 bit */ - case 7: - if (flag) { - CEC_INFO("read 7 bit:0x%x%x\n", - aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT10_8), - aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT7_0)); - } - aocec_wr_reg(AO_CEC_TXTIME_17MS_BIT7_0, time_set & 0xff); - aocec_wr_reg(AO_CEC_TXTIME_17MS_BIT10_8, (time_set >> 8) & 0x7); - if (flag) { - CEC_INFO("write 7 bit:0x%x%x\n", - aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT10_8), - aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT7_0)); - } - break; - default: - break; +void cec_logicaddr_set(int l_add) +{ + /* save logical address for suspend/wake up */ + cec_set_reg_bits(AO_DEBUG_REG1, l_add, 16, 4); + if (ee_cec) { + /* set ee_cec logical addr */ + if (l_add < 8) + hdmirx_cec_write(DWC_CEC_ADDR_L, 1 << l_add); + else + hdmirx_cec_write(DWC_CEC_ADDR_H, 1 << (l_add - 8)|0x80); + return; } + aocec_wr_reg(CEC_LOGICAL_ADDR0, 0); + cec_hw_buf_clear(); + aocec_wr_reg(CEC_LOGICAL_ADDR0, (l_add & 0xf)); + udelay(100); + aocec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | (l_add & 0xf)); + if (cec_msg_dbg_en) + CEC_INFO("set logical addr:0x%x\n", + aocec_rd_reg(CEC_LOGICAL_ADDR0)); } static void cec_hw_reset(void) { - if (cec_dev->ee_cec) { + if (ee_cec) { cecrx_hw_init(); return; } @@ -593,9 +738,9 @@ static void cec_hw_reset(void) cec_set_reg_bits(AO_CEC_GEN_CNTL, 0, 0, 1); /* Enable all AO_CEC interrupt sources */ - cec_set_reg_bits(AO_CEC_INTR_MASKN, 0x6, 0, 3); + cec_irq_enable(true); - cec_logicaddr_set(cec_dev->my_log_addr); + cec_logicaddr_set(cec_dev->cec_info.log_addr); /* Cec arbitration 3/5/7 bit time set. */ cec_arbit_bit_time_set(3, 0x118, 0); @@ -606,17 +751,66 @@ static void cec_hw_reset(void) aocec_rd_reg(CEC_LOGICAL_ADDR0)); } -static void cec_rx_buf_clear(void) +void cec_rx_buf_clear(void) { aocec_wr_reg(CEC_RX_CLEAR_BUF, 0x1); aocec_wr_reg(CEC_RX_CLEAR_BUF, 0x0); } -static int cec_rx_buf_check(void) +static inline bool is_poll_message(unsigned char header) +{ + unsigned char initiator, follower; + + initiator = (header >> 4) & 0xf; + follower = (header) & 0xf; + return initiator == follower; +} + +static inline bool is_feature_abort_msg(const unsigned char *msg, int len) +{ + if (!msg || len < 2) + return false; + if (msg[1] == CEC_OC_FEATURE_ABORT) + return true; + return false; +} + +static inline bool is_report_phy_addr_msg(const unsigned char *msg, int len) +{ + if (!msg || len < 4) + return false; + if (msg[1] == CEC_OC_REPORT_PHYSICAL_ADDRESS) + return true; + return false; +} + +static bool need_nack_repeat_msg(const unsigned char *msg, int len, int t) +{ + if (len == last_cec_msg->len && + (is_poll_message(msg[0]) || is_feature_abort_msg(msg, len) || + is_report_phy_addr_msg(msg, len)) && + last_cec_msg->last_result == CEC_FAIL_NACK && + jiffies - last_cec_msg->last_jiffies < t) { + return true; + } + return false; +} + +static void cec_clear_logical_addr(void) +{ + if (ee_cec) { + hdmirx_cec_write(DWC_CEC_ADDR_L, 0); + hdmirx_cec_write(DWC_CEC_ADDR_H, 0x80); + } else + aocec_wr_reg(CEC_LOGICAL_ADDR0, 0); + udelay(100); +} + +int cec_rx_buf_check(void) { unsigned int rx_num_msg; - if (cec_dev->ee_cec) { + if (ee_cec) { cecrx_check_irq_enable(); cecrx_irq_handle(); return 0; @@ -629,12 +823,12 @@ static int cec_rx_buf_check(void) return rx_num_msg; } -int cec_ll_rx(unsigned char *msg) +int cec_ll_rx(unsigned char *msg, unsigned char *len) { int i; int ret = -1; + int pos; int rx_stat; - int len; rx_stat = aocec_rd_reg(CEC_RX_MSG_STATUS); if ((rx_stat != RX_DONE) || (aocec_rd_reg(CEC_RX_NUM_MSG) != 1)) { @@ -646,26 +840,30 @@ int cec_ll_rx(unsigned char *msg) return ret; } - len = aocec_rd_reg(CEC_RX_MSG_LENGTH) + 1; - cec_dev->rx_len = len; + *len = aocec_rd_reg(CEC_RX_MSG_LENGTH) + 1; - for (i = 0; i < len && i < MAX_MSG; i++) + for (i = 0; i < (*len) && i < MAX_MSG; i++) msg[i] = aocec_rd_reg(CEC_RX_MSG_0_HEADER + i); ret = rx_stat; - if (cec_dev->cec_msg_dbg_en) { - char buf[DBG_BUF_SIZE] = {}; - - format_msg_str(msg, len, "CEC rx msg", buf); - pr_info("%s\n", buf); - } - + /* ignore ping message */ + if (cec_msg_dbg_en == 1 && *len > 1) { + pos = 0; + pos += sprintf(msg_log_buf + pos, + "CEC: rx msg len: %d dat: ", *len); + for (i = 0; i < (*len); i++) + pos += sprintf(msg_log_buf + pos, "%02x ", msg[i]); + pos += sprintf(msg_log_buf + pos, "\n"); + msg_log_buf[pos] = '\0'; + CEC_INFO("%s", msg_log_buf); + } + last_cec_msg->len = 0; /* invalid back up msg when rx */ writel((1 << 2), cec_dev->cec_reg + AO_CEC_INTR_CLR); aocec_wr_reg(CEC_RX_MSG_CMD, RX_ACK_CURRENT); aocec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); cec_rx_buf_clear(); - cec_dev->pin_status = 1; + pin_status = 1; return ret; } @@ -676,10 +874,12 @@ int cec_ll_rx(unsigned char *msg) static int cec_ll_trigle_tx(const unsigned char *msg, int len) { int i; + unsigned int n; + int pos; int reg; unsigned int j = 40; unsigned int tx_stat; - int cec_timeout_cnt = 1; + static int cec_timeout_cnt = 1; while (1) { tx_stat = aocec_rd_reg(CEC_TX_MSG_STATUS); @@ -704,48 +904,56 @@ static int cec_ll_trigle_tx(const unsigned char *msg, int len) aocec_wr_reg(CEC_TX_MSG_LENGTH, len-1); aocec_wr_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); - if (cec_dev->cec_msg_dbg_en) { - char buf[DBG_BUF_SIZE] = {}; - format_msg_str(msg, len, "CEC tx msg", buf); - pr_info("%s\n", buf); + if (cec_msg_dbg_en == 1) { + pos = 0; + pos += sprintf(msg_log_buf + pos, + "CEC: tx msg len: %d dat: ", len); + for (n = 0; n < len; n++) { + pos += sprintf(msg_log_buf + pos, + "%02x ", msg[n]); + } + + pos += sprintf(msg_log_buf + pos, "\n"); + + msg_log_buf[pos] = '\0'; + pr_info("%s", msg_log_buf); } + cec_timeout_cnt = 0; return 0; } return -1; } -static void tx_irq_handle(void) +void tx_irq_handle(void) { unsigned int tx_status = aocec_rd_reg(CEC_TX_MSG_STATUS); + cec_tx_result = -1; switch (tx_status) { case TX_DONE: aocec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); - cec_dev->cec_tx_result = CEC_FAIL_NONE; + cec_tx_result = CEC_FAIL_NONE; break; case TX_BUSY: CEC_ERR("TX_BUSY\n"); - cec_dev->cec_tx_result = CEC_FAIL_BUSY; + cec_tx_result = CEC_FAIL_BUSY; break; case TX_ERROR: - if (cec_dev->cec_msg_dbg_en == 1) + if (cec_msg_dbg_en == 1) CEC_ERR("TX ERROR!!!\n"); - if (aocec_rd_reg(CEC_RX_MSG_STATUS) == RX_ERROR) - cec_hw_reset(); - else - aocec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); - cec_dev->cec_tx_result = CEC_FAIL_NACK; + aocec_wr_reg(CEC_TX_MSG_CMD, TX_ABORT); + cec_hw_reset(); + cec_tx_result = CEC_FAIL_NACK; break; case TX_IDLE: CEC_ERR("TX_IDLE\n"); - cec_dev->cec_tx_result = CEC_FAIL_OTHER; + cec_tx_result = CEC_FAIL_OTHER; break; default: - cec_dev->cec_tx_result = CEC_FAIL_OTHER; break; } writel((1 << 1), cec_dev->cec_reg + AO_CEC_INTR_CLR); @@ -754,35 +962,18 @@ static void tx_irq_handle(void) static int get_line(void) { - int reg, cpu_type, ret = -EINVAL; + int reg, ret = -EINVAL; reg = readl(cec_dev->cec_reg + AO_GPIO_I); - cpu_type = get_cpu_type(); - switch (cpu_type) { - case MESON_CPU_MAJOR_ID_GXBB: - ret = (reg & (1 << 12)); - break; - case MESON_CPU_MAJOR_ID_GXL: - case MESON_CPU_MAJOR_ID_GXM: - ret = (reg & (1 << 8)); - break; - case MESON_CPU_MAJOR_ID_GXTVBB: - ret = (reg & (1 << 9)); - break; - case MESON_CPU_MAJOR_ID_TXL: - ret = (reg & (1 << 7)); - break; - default: - CEC_ERR("unknown cpu type:%d\n", cpu_type); - break; - } + ret = (reg & (1 << cec_dev->plat_data->line_bit)); + return ret; } static enum hrtimer_restart cec_line_check(struct hrtimer *timer) { if (get_line() == 0) - cec_dev->cec_line_cnt++; + cec_line_cnt++; hrtimer_forward_now(timer, HR_DELAY(1)); return HRTIMER_RESTART; } @@ -791,72 +982,33 @@ static int check_confilct(void) { int i; - for (i = 0; i < 50; i++) { + for (i = 0; i < 200; i++) { /* * sleep 20ms and using hrtimer to check cec line every 1ms */ - cec_dev->cec_line_cnt = 0; - hrtimer_start(&cec_dev->start_bit_check, - HR_DELAY(1), HRTIMER_MODE_REL); + cec_line_cnt = 0; + hrtimer_start(&start_bit_check, HR_DELAY(1), HRTIMER_MODE_REL); msleep(20); - hrtimer_cancel(&cec_dev->start_bit_check); - if (cec_dev->cec_line_cnt == 0) + hrtimer_cancel(&start_bit_check); + if (cec_line_cnt == 0) break; - CEC_INFO("line busy:%d\n", cec_dev->cec_line_cnt); + CEC_INFO("line busy:%d\n", cec_line_cnt); } - if (i >= 50) + if (i >= 200) return -EBUSY; else return 0; } -static inline bool physical_addr_valid(void) -{ - if (cec_dev->dev_type == DEV_TYPE_TV) - return 1; - if (cec_dev->phy_addr_test) - return 1; - if (cec_dev->phy_addr == INVALID_PHY_ADDR) - return 0; - return 1; -} - -static int cec_hdmi_tx_notify_handler(struct notifier_block *nb, - unsigned long value, void *p) -{ - int ret = 0; - int phy_addr = 0; - - switch (value) { - case HDMITX_PLUG: - cec_dev->hpd_state = 1; - CEC_INFO("%s, HDMITX_PLUG\n", __func__); - break; - - case HDMITX_UNPLUG: - cec_dev->hpd_state = 0; - CEC_INFO("%s, HDMITX_UNPLUG\n", __func__); - break; - - case HDMITX_PHY_ADDR_VALID: - phy_addr = *((int *)p); - cec_dev->phy_addr = phy_addr & 0xffff; - cec_dev->hpd_state = 1; - CEC_INFO("%s, phy_addr %x ok\n", __func__, cec_dev->phy_addr); - break; - - default: - CEC_INFO("unsupported hdmitx notify:%ld, arg:%p\n", value, p); - ret = -EINVAL; - break; - } - return ret; -} - static bool check_physical_addr_valid(int timeout) { while (timeout > 0) { - if (!physical_addr_valid()) { + if (cec_dev->dev_type == DEV_TYPE_TV) + break; + if (phy_addr_test) + break; + /* physical address for box */ + if (cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.valid == 0) { msleep(100); timeout--; } else @@ -867,21 +1019,37 @@ static bool check_physical_addr_valid(int timeout) return true; } - /* Return value: < 0: fail, > 0: success */ int cec_ll_tx(const unsigned char *msg, unsigned char len) { int ret = -1; - int t = msecs_to_jiffies(2000); + int t = msecs_to_jiffies(ee_cec ? 2000 : 5000); int retry = 2; if (len == 0) return CEC_FAIL_NONE; + if (is_poll_message(msg[0])) + cec_clear_logical_addr(); + + /* + * for CEC CTS 9.3. Android will try 3 poll message if got NACK + * but AOCEC will retry 4 tx for each poll message. Framework + * repeat this poll message so quick makes 12 sequential poll + * waveform seen on CEC bus. And did not pass CTS + * specification of 9.3 + */ + if (!ee_cec && need_nack_repeat_msg(msg, len, t)) { + if (!memcmp(msg, last_cec_msg->msg, len)) { + CEC_INFO("NACK repeat message:%x\n", len); + return CEC_FAIL_NACK; + } + } + mutex_lock(&cec_dev->cec_mutex); - /* make sure physical address is valid before send */ + /* make sure we got valid physical address */ if (len >= 2 && msg[1] == CEC_OC_REPORT_PHYSICAL_ADDRESS) - check_physical_addr_valid(20); + check_physical_addr_valid(3); try_again: reinit_completion(&cec_dev->tx_ok); @@ -897,7 +1065,7 @@ try_again: return CEC_FAIL_BUSY; } - if (cec_dev->ee_cec) + if (ee_cec) ret = cecrx_trigle_tx(msg, len); else ret = cec_ll_trigle_tx(msg, len); @@ -912,7 +1080,7 @@ try_again: mutex_unlock(&cec_dev->cec_mutex); return CEC_FAIL_BUSY; } - cec_dev->cec_tx_result = CEC_FAIL_OTHER; + cec_tx_result = -1; ret = wait_for_completion_timeout(&cec_dev->tx_ok, t); if (ret <= 0) { /* timeout or interrupt */ @@ -922,7 +1090,7 @@ try_again: } ret = CEC_FAIL_OTHER; } else { - ret = cec_dev->cec_tx_result; + ret = cec_tx_result; } if (ret != CEC_FAIL_NONE && ret != CEC_FAIL_NACK) { if (retry > 0) { @@ -933,13 +1101,21 @@ try_again: } mutex_unlock(&cec_dev->cec_mutex); + if (!ee_cec) { + last_cec_msg->last_result = ret; + if (ret == CEC_FAIL_NACK) { + memcpy(last_cec_msg->msg, msg, len); + last_cec_msg->len = len; + last_cec_msg->last_jiffies = jiffies; + } + } return ret; } /* -------------------------------------------------------------------------- */ /* AO CEC0 config */ /* -------------------------------------------------------------------------- */ -static void ao_cec_init(void) +void ao_cec_init(void) { unsigned long data32; unsigned int reg; @@ -988,7 +1164,66 @@ static void ao_cec_init(void) cec_set_reg_bits(AO_CEC_GEN_CNTL, 0, 0, 1); /* Enable all AO_CEC interrupt sources */ - cec_enable_irq(); + cec_irq_enable(true); +} + +void cec_arbit_bit_time_set(unsigned int bit_set, + unsigned int time_set, unsigned int flag) +{ /* 11bit:bit[10:0] */ + if (flag) { + CEC_INFO("bit_set:0x%x;time_set:0x%x\n", + bit_set, time_set); + } + + switch (bit_set) { + case 3: + /* 3 bit */ + if (flag) { + CEC_INFO("read 3 bit:0x%x%x\n", + aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT10_8), + aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT7_0)); + } + aocec_wr_reg(AO_CEC_TXTIME_4BIT_BIT7_0, time_set & 0xff); + aocec_wr_reg(AO_CEC_TXTIME_4BIT_BIT10_8, (time_set >> 8) & 0x7); + if (flag) { + CEC_INFO("write 3 bit:0x%x%x\n", + aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT10_8), + aocec_rd_reg(AO_CEC_TXTIME_4BIT_BIT7_0)); + } + break; + /* 5 bit */ + case 5: + if (flag) { + CEC_INFO("read 5 bit:0x%x%x\n", + aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT10_8), + aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT7_0)); + } + aocec_wr_reg(AO_CEC_TXTIME_2BIT_BIT7_0, time_set & 0xff); + aocec_wr_reg(AO_CEC_TXTIME_2BIT_BIT10_8, (time_set >> 8) & 0x7); + if (flag) { + CEC_INFO("write 5 bit:0x%x%x\n", + aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT10_8), + aocec_rd_reg(AO_CEC_TXTIME_2BIT_BIT7_0)); + } + break; + /* 7 bit */ + case 7: + if (flag) { + CEC_INFO("read 7 bit:0x%x%x\n", + aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT10_8), + aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT7_0)); + } + aocec_wr_reg(AO_CEC_TXTIME_17MS_BIT7_0, time_set & 0xff); + aocec_wr_reg(AO_CEC_TXTIME_17MS_BIT10_8, (time_set >> 8) & 0x7); + if (flag) { + CEC_INFO("write 7 bit:0x%x%x\n", + aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT10_8), + aocec_rd_reg(AO_CEC_TXTIME_17MS_BIT7_0)); + } + break; + default: + break; + } } static unsigned int ao_cec_intr_stat(void) @@ -996,7 +1231,7 @@ static unsigned int ao_cec_intr_stat(void) return readl(cec_dev->cec_reg + AO_CEC_INTR_STAT); } -static unsigned int cec_intr_stat(void) +unsigned int cec_intr_stat(void) { return ao_cec_intr_stat(); } @@ -1005,7 +1240,7 @@ static unsigned int cec_intr_stat(void) *wr_flag: 1 write; value valid * 0 read; value invalid */ -static unsigned int cec_config(unsigned int value, bool wr_flag) +unsigned int cec_config(unsigned int value, bool wr_flag) { if (wr_flag) cec_set_reg_bits(AO_DEBUG_REG0, value, 0, 8); @@ -1017,7 +1252,7 @@ static unsigned int cec_config(unsigned int value, bool wr_flag) *wr_flag:1 write; value valid * 0 read; value invalid */ -static unsigned int cec_phyaddr_config(unsigned int value, bool wr_flag) +unsigned int cec_phyaddr_config(unsigned int value, bool wr_flag) { if (wr_flag) cec_set_reg_bits(AO_DEBUG_REG1, value, 0, 16); @@ -1025,9 +1260,9 @@ static unsigned int cec_phyaddr_config(unsigned int value, bool wr_flag) return readl(cec_dev->cec_reg + AO_DEBUG_REG1); } -static void cec_keep_reset(void) +void cec_keep_reset(void) { - if (cec_dev->ee_cec) + if (ee_cec) cecrx_hw_reset(); else writel(0x1, cec_dev->cec_reg + AO_CEC_GEN_CNTL); @@ -1039,7 +1274,12 @@ static void cec_pre_init(void) { unsigned int reg = readl(cec_dev->cec_reg + AO_RTI_STATUS_REG1); - if (cec_dev->ee_cec) { + reg &= 0xfffff; + if ((reg & 0xffff) == 0xffff) + wake_ok = 0; + pr_info("cec: wake up flag:%x\n", reg); + + if (ee_cec) { cecrx_hw_init(); return; } @@ -1048,10 +1288,6 @@ static void cec_pre_init(void) cec_arbit_bit_time_set(3, 0x118, 0); cec_arbit_bit_time_set(5, 0x000, 0); cec_arbit_bit_time_set(7, 0x2aa, 0); - reg &= 0xfffff; - if ((reg & 0xffff) == 0xffff) - cec_dev->wake_ok = 0; - pr_info("cec: wake up flag:%x\n", reg); } static int cec_late_check_rx_buffer(void) @@ -1065,47 +1301,44 @@ static int cec_late_check_rx_buffer(void) /* * start another check if rx buffer is full */ - if ((-1) == cec_ll_rx(cec_dev->rx_msg)) { + if ((-1) == cec_ll_rx(rx_msg, &rx_len)) { CEC_INFO("buffer got unrecorgnized msg\n"); cec_rx_buf_clear(); - ret = 0; - } else { - mod_delayed_work(cec_dev->cec_thread, dwork, 0); - ret = 1; + return 0; } - return ret; + mod_delayed_work(cec_dev->cec_thread, dwork, 0); + return 1; } -static void cec_key_report(int suspend) +void cec_key_report(int suspend) { - input_event(cec_dev->remote_cec_dev, EV_KEY, KEY_POWER, 1); - input_sync(cec_dev->remote_cec_dev); - input_event(cec_dev->remote_cec_dev, EV_KEY, KEY_POWER, 0); - input_sync(cec_dev->remote_cec_dev); - pm_wakeup_event(cec_dev->dbg_dev, 2000); + input_event(cec_dev->cec_info.remote_cec_dev, EV_KEY, KEY_POWER, 1); + input_sync(cec_dev->cec_info.remote_cec_dev); + input_event(cec_dev->cec_info.remote_cec_dev, EV_KEY, KEY_POWER, 0); + input_sync(cec_dev->cec_info.remote_cec_dev); if (!suspend) CEC_INFO("== WAKE UP BY CEC ==\n") else CEC_INFO("== SLEEP by CEC==\n") } -static void cec_give_version(unsigned int dest) +void cec_give_version(unsigned int dest) { - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char msg[3]; if (dest != 0xf) { msg[0] = ((index & 0xf) << 4) | dest; msg[1] = CEC_OC_CEC_VERSION; - msg[2] = cec_dev->cec_version; + msg[2] = cec_dev->cec_info.cec_version; cec_ll_tx(msg, 3); } } -static void cec_report_physical_address_smp(void) +void cec_report_physical_address_smp(void) { unsigned char msg[5]; - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char phy_addr_ab, phy_addr_cd; phy_addr_ab = (cec_dev->phy_addr >> 8) & 0xff; @@ -1119,13 +1352,13 @@ static void cec_report_physical_address_smp(void) cec_ll_tx(msg, 5); } -static void cec_device_vendor_id(void) +void cec_device_vendor_id(void) { - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char msg[5]; unsigned int vendor_id; - vendor_id = cec_dev->vendor_id; + vendor_id = cec_dev->v_data.vendor_id; msg[0] = ((index & 0xf) << 4) | CEC_BROADCAST_ADDR; msg[1] = CEC_OC_DEVICE_VENDOR_ID; msg[2] = (vendor_id >> 16) & 0xff; @@ -1135,9 +1368,9 @@ static void cec_device_vendor_id(void) cec_ll_tx(msg, 5); } -static void cec_give_deck_status(unsigned int dest) +void cec_give_deck_status(unsigned int dest) { - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char msg[3]; msg[0] = ((index & 0xf) << 4) | dest; @@ -1146,10 +1379,10 @@ static void cec_give_deck_status(unsigned int dest) cec_ll_tx(msg, 3); } -static void cec_menu_status_smp(int dest, int status) +void cec_menu_status_smp(int dest, int status) { unsigned char msg[3]; - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; msg[0] = ((index & 0xf) << 4) | dest; msg[1] = CEC_OC_MENU_STATUS; @@ -1160,9 +1393,9 @@ static void cec_menu_status_smp(int dest, int status) cec_ll_tx(msg, 3); } -static void cec_inactive_source(int dest) +void cec_inactive_source(int dest) { - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char msg[4]; unsigned char phy_addr_ab, phy_addr_cd; @@ -1176,25 +1409,25 @@ static void cec_inactive_source(int dest) cec_ll_tx(msg, 4); } -static void cec_set_osd_name(int dest) +void cec_set_osd_name(int dest) { - unsigned char index = cec_dev->my_log_addr; - unsigned char osd_len = strlen(cec_dev->osd_name); + unsigned char index = cec_dev->cec_info.log_addr; + unsigned char osd_len = strlen(cec_dev->cec_info.osd_name); unsigned char msg[16]; if (dest != 0xf) { msg[0] = ((index & 0xf) << 4) | dest; msg[1] = CEC_OC_SET_OSD_NAME; - memcpy(&msg[2], cec_dev->osd_name, osd_len); + memcpy(&msg[2], cec_dev->cec_info.osd_name, osd_len); cec_ll_tx(msg, 2 + osd_len); } } -static void cec_active_source_smp(void) +void cec_active_source_smp(void) { unsigned char msg[4]; - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char phy_addr_ab; unsigned char phy_addr_cd; @@ -1207,17 +1440,17 @@ static void cec_active_source_smp(void) cec_ll_tx(msg, 4); } -static void cec_request_active_source(void) +void cec_request_active_source(void) { unsigned char msg[2]; - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; msg[0] = ((index & 0xf) << 4) | CEC_BROADCAST_ADDR; msg[1] = CEC_OC_REQUEST_ACTIVE_SOURCE; cec_ll_tx(msg, 2); } -static void cec_set_stream_path(unsigned char *msg) +void cec_set_stream_path(unsigned char *msg) { unsigned int phy_addr_active; @@ -1233,9 +1466,9 @@ static void cec_set_stream_path(unsigned char *msg) } } -static void cec_report_power_status(int dest, int status) +void cec_report_power_status(int dest, int status) { - unsigned char index = cec_dev->my_log_addr; + unsigned char index = cec_dev->cec_info.log_addr; unsigned char msg[3]; msg[0] = ((index & 0xf) << 4) | dest; @@ -1246,31 +1479,31 @@ static void cec_report_power_status(int dest, int status) static void cec_rx_process(void) { - int len = cec_dev->rx_len; + int len = rx_len; int initiator, follower; int opcode; unsigned char msg[MAX_MSG] = {}; int dest_phy_addr; - if (len < 2 || !cec_dev->new_msg) /* ignore ping message */ + if (len < 2 || !new_msg) /* ignore ping message */ return; - memcpy(msg, cec_dev->rx_msg, len); + memcpy(msg, rx_msg, len); initiator = ((msg[0] >> 4) & 0xf); follower = msg[0] & 0xf; - if (follower != 0xf && follower != cec_dev->my_log_addr) { + if (follower != 0xf && follower != cec_dev->cec_info.log_addr) { CEC_ERR("wrong rx message of bad follower:%x", follower); return; } opcode = msg[1]; switch (opcode) { case CEC_OC_ACTIVE_SOURCE: - if (cec_dev->wake_ok == 0) { + if (wake_ok == 0) { int phy_addr = msg[2] << 8 | msg[3]; - if (phy_addr == INVALID_PHY_ADDR) + if (phy_addr == 0xffff) break; - cec_dev->wake_ok = 1; + wake_ok = 1; phy_addr |= (initiator << 16); writel(phy_addr, cec_dev->cec_reg + AO_RTI_STATUS_REG1); CEC_INFO("found wake up source:%x", phy_addr); @@ -1279,7 +1512,8 @@ static void cec_rx_process(void) case CEC_OC_ROUTING_CHANGE: dest_phy_addr = msg[4] << 8 | msg[5]; - if (dest_phy_addr == cec_dev->phy_addr) { + if ((dest_phy_addr == cec_dev->phy_addr) && + (cec_dev->cec_suspend == CEC_EARLY_SUSPEND)) { CEC_INFO("wake up by ROUTING_CHANGE\n"); cec_key_report(0); } @@ -1318,13 +1552,17 @@ static void cec_rx_process(void) break; case CEC_OC_REQUEST_ACTIVE_SOURCE: - if (!cec_dev->cec_suspend) + if (cec_dev->cec_suspend == CEC_POWER_ON) cec_active_source_smp(); break; case CEC_OC_GIVE_DEVICE_POWER_STATUS: - if (cec_dev->cec_suspend) + if (cec_dev->cec_suspend == CEC_DEEP_SUSPEND) cec_report_power_status(initiator, POWER_STANDBY); + else if (cec_dev->cec_suspend == CEC_EARLY_SUSPEND) + cec_report_power_status(initiator, TRANS_ON_TO_STANDBY); + else if (cec_dev->cec_suspend == CEC_POWER_RESUME) + cec_report_power_status(initiator, TRANS_STANDBY_TO_ON); else cec_report_power_status(initiator, POWER_ON); break; @@ -1338,7 +1576,7 @@ static void cec_rx_process(void) break; case CEC_OC_MENU_REQUEST: - if (cec_dev->cec_suspend) + if (cec_dev->cec_suspend != CEC_POWER_ON) cec_menu_status_smp(initiator, DEVICE_MENU_INACTIVE); else cec_menu_status_smp(initiator, DEVICE_MENU_ACTIVE); @@ -1348,7 +1586,7 @@ static void cec_rx_process(void) CEC_ERR("unsupported command:%x\n", opcode); break; } - cec_dev->new_msg = 0; + new_msg = 0; } static bool cec_service_suspended(void) @@ -1366,7 +1604,7 @@ static void cec_task(struct work_struct *work) struct delayed_work *dwork; dwork = &cec_dev->cec_work; - if (cec_dev && (!cec_dev->wake_ok || cec_service_suspended())) + if (cec_dev && (!wake_ok || cec_service_suspended())) cec_rx_process(); if (!cec_late_check_rx_buffer()) @@ -1384,19 +1622,19 @@ static irqreturn_t cec_isr_handler(int irq, void *dev_instance) tx_irq_handle(); return IRQ_HANDLED; } - if ((-1) == cec_ll_rx(cec_dev->rx_msg)) + if ((-1) == cec_ll_rx(rx_msg, &rx_len)) return IRQ_HANDLED; complete(&cec_dev->rx_ok); /* check rx buffer is full */ - cec_dev->new_msg = 1; + new_msg = 1; mod_delayed_work(cec_dev->cec_thread, dwork, 0); return IRQ_HANDLED; } static void check_wake_up(void) { - if (cec_dev->wake_ok == 0) + if (wake_ok == 0) cec_request_active_source(); } @@ -1404,19 +1642,19 @@ static void check_wake_up(void) static ssize_t device_type_show(struct class *cla, struct class_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", cec_dev->dev_type); + return sprintf(buf, "%ld\n", cec_dev->dev_type); } static ssize_t device_type_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count) { - unsigned long type; + unsigned int type; - if (kstrtol(buf, 10, &type)) + if (kstrtouint(buf, 10, &type) != 1) return -EINVAL; cec_dev->dev_type = type; - CEC_ERR("set dev_type to %ld\n", type); + CEC_ERR("set dev_type to %d\n", type); return count; } @@ -1425,9 +1663,9 @@ static ssize_t menu_language_show(struct class *cla, { char a, b, c; - a = ((cec_dev->menu_lang >> 16) & 0xff); - b = ((cec_dev->menu_lang >> 8) & 0xff); - c = ((cec_dev->menu_lang >> 0) & 0xff); + a = ((cec_dev->cec_info.menu_lang >> 16) & 0xff); + b = ((cec_dev->cec_info.menu_lang >> 8) & 0xff); + c = ((cec_dev->cec_info.menu_lang >> 0) & 0xff); return sprintf(buf, "%c%c%c\n", a, b, c); } @@ -1439,7 +1677,7 @@ static ssize_t menu_language_store(struct class *cla, if (sscanf(buf, "%c%c%c", &a, &b, &c) != 3) return -EINVAL; - cec_dev->menu_lang = (a << 16) | (b << 8) | c; + cec_dev->cec_info.menu_lang = (a << 16) | (b << 8) | c; CEC_ERR("set menu_language to %s\n", buf); return count; } @@ -1447,17 +1685,17 @@ static ssize_t menu_language_store(struct class *cla, static ssize_t vendor_id_show(struct class *cla, struct class_attribute *attr, char *buf) { - return sprintf(buf, "%x\n", cec_dev->vendor_id); + return sprintf(buf, "%x\n", cec_dev->cec_info.vendor_id); } static ssize_t vendor_id_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count) { - int id; + unsigned int id; - if (kstrtoint(buf, 16, &id)) + if (kstrtouint(buf, 16, &id) != 1) return -EINVAL; - cec_dev->vendor_id = id; + cec_dev->cec_info.vendor_id = id; return count; } @@ -1496,7 +1734,7 @@ static ssize_t dump_reg_show(struct class *cla, { int i, s = 0; - if (cec_dev->ee_cec) + if (ee_cec) return dump_cecrx_reg(b); s += sprintf(b + s, "TX buffer:\n"); @@ -1528,7 +1766,21 @@ static ssize_t arc_port_show(struct class *cla, static ssize_t osd_name_show(struct class *cla, struct class_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", cec_dev->osd_name); + return sprintf(buf, "%s\n", cec_dev->cec_info.osd_name); +} + +static ssize_t port_seq_store(struct class *cla, + struct class_attribute *attr, + const char *buf, size_t count) +{ + unsigned int seq; + + if (kstrtouint(buf, 16, &seq) != 1) + return -EINVAL; + + CEC_ERR("port_seq:%x\n", seq); + cec_dev->port_seq = seq; + return count; } static ssize_t port_seq_show(struct class *cla, @@ -1543,7 +1795,7 @@ static ssize_t port_status_show(struct class *cla, unsigned int tmp; unsigned int tx_hpd; - tx_hpd = cec_dev->hpd_state; + tx_hpd = cec_dev->tx_dev->hpd_state; if (cec_dev->dev_type == DEV_TYPE_PLAYBACK) { tmp = tx_hpd; return sprintf(buf, "%x\n", tmp); @@ -1560,17 +1812,17 @@ static ssize_t port_status_show(struct class *cla, static ssize_t pin_status_show(struct class *cla, struct class_attribute *attr, char *buf) { - unsigned int tx_hpd = 0; + unsigned int tx_hpd; char p; - tx_hpd = cec_dev->hpd_state; + tx_hpd = cec_dev->tx_dev->hpd_state; if (cec_dev->dev_type == DEV_TYPE_PLAYBACK) { if (!tx_hpd) { - cec_dev->pin_status = 0; + pin_status = 0; return sprintf(buf, "%s\n", "disconnected"); } - if (cec_dev->pin_status == 0) { - p = (cec_dev->my_log_addr << 4) | CEC_TV_ADDR; + if (pin_status == 0) { + p = (cec_dev->cec_info.log_addr << 4) | CEC_TV_ADDR; if (cec_ll_tx(&p, 1) == CEC_FAIL_NONE) return sprintf(buf, "%s\n", "ok"); else @@ -1578,8 +1830,7 @@ static ssize_t pin_status_show(struct class *cla, } else return sprintf(buf, "%s\n", "ok"); } else { - return sprintf(buf, "%s\n", - cec_dev->pin_status ? "ok" : "fail"); + return sprintf(buf, "%s\n", pin_status ? "ok" : "fail"); } } @@ -1597,23 +1848,22 @@ static ssize_t physical_addr_store(struct class *cla, { int addr; - if (kstrtoint(buf, 16, &addr)) + if (kstrtouint(buf, 16, &addr) != 1) return -EINVAL; - - if (addr > INVALID_PHY_ADDR || addr < 0) { + if (addr > 0xffff || addr < 0) { CEC_ERR("invalid input:%s\n", buf); - cec_dev->phy_addr_test = 0; + phy_addr_test = 0; return -EINVAL; } cec_dev->phy_addr = addr; - cec_dev->phy_addr_test = 1; + phy_addr_test = 1; return count; } static ssize_t dbg_en_show(struct class *cla, struct class_attribute *attr, char *buf) { - return sprintf(buf, "%x\n", cec_dev->cec_msg_dbg_en); + return sprintf(buf, "%x\n", cec_msg_dbg_en); } static ssize_t dbg_en_store(struct class *cla, struct class_attribute *attr, @@ -1621,26 +1871,22 @@ static ssize_t dbg_en_store(struct class *cla, struct class_attribute *attr, { int en; - if (kstrtoint(buf, 10, &en)) + if (kstrtouint(buf, 16, &en) != 1) return -EINVAL; - cec_dev->cec_msg_dbg_en = en ? 1 : 0; + cec_msg_dbg_en = en ? 1 : 0; return count; } static ssize_t cmd_store(struct class *cla, struct class_attribute *attr, const char *bu, size_t count) { - char buf[16] = {}; + char buf[6] = {}; int cnt; - cnt = sscanf(bu, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + cnt = sscanf(bu, "%x %x %x %x %x %x", (int *)&buf[0], (int *)&buf[1], (int *)&buf[2], - (int *)&buf[3], (int *)&buf[4], (int *)&buf[5], - (int *)&buf[6], (int *)&buf[7], (int *)&buf[8], - (int *)&buf[9], (int *)&buf[10], (int *)&buf[11], - (int *)&buf[12], (int *)&buf[13], (int *)&buf[14], - (int *)&buf[15]); + (int *)&buf[3], (int *)&buf[4], (int *)&buf[5]); if (cnt < 0) return -EINVAL; cec_ll_tx(buf, cnt); @@ -1660,7 +1906,7 @@ static ssize_t fun_cfg_store(struct class *cla, struct class_attribute *attr, { int cnt, val; - cnt = kstrtoint(bu, 16, &val); + cnt = kstrtouint(bu, 16, &val); if (cnt < 0 || val > 0xff) return -EINVAL; cec_config(val, 1); @@ -1679,6 +1925,12 @@ static ssize_t fun_cfg_show(struct class *cla, return sprintf(buf, "0x%x\n", reg & 0xff); } +static ssize_t cec_version_show(struct class *cla, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", cec_dev->cec_info.cec_version); +} + static ssize_t log_addr_store(struct class *cla, struct class_attribute *attr, const char *bu, size_t count) { @@ -1689,8 +1941,8 @@ static ssize_t log_addr_store(struct class *cla, struct class_attribute *attr, return -EINVAL; cec_logicaddr_set(val); /* add by hal, to init some data structure */ - cec_dev->my_log_addr = val; - cec_dev->power_status = POWER_ON; + cec_dev->cec_info.log_addr = val; + cec_dev->cec_info.power_status = POWER_ON; return count; } @@ -1698,35 +1950,35 @@ static ssize_t log_addr_store(struct class *cla, struct class_attribute *attr, static ssize_t log_addr_show(struct class *cla, struct class_attribute *attr, char *buf) { - return sprintf(buf, "0x%x\n", cec_dev->my_log_addr); + return sprintf(buf, "0x%x\n", cec_dev->cec_info.log_addr); } static struct class_attribute aocec_class_attr[] = { __ATTR_WO(cmd), __ATTR_RO(port_num), - __ATTR_RO(port_seq), __ATTR_RO(osd_name), __ATTR_RO(dump_reg), __ATTR_RO(port_status), __ATTR_RO(pin_status), + __ATTR_RO(cec_version), __ATTR_RO(arc_port), __ATTR_RO(wake_up), + __ATTR(port_seq, 0664, port_seq_show, port_seq_store), __ATTR(physical_addr, 0664, physical_addr_show, physical_addr_store), __ATTR(vendor_id, 0664, vendor_id_show, vendor_id_store), __ATTR(menu_language, 0664, menu_language_show, menu_language_store), __ATTR(device_type, 0664, device_type_show, device_type_store), __ATTR(dbg_en, 0664, dbg_en_show, dbg_en_store), - __ATTR(fun_cfg, 0664, fun_cfg_show, fun_cfg_store), __ATTR(log_addr, 0664, log_addr_show, log_addr_store), + __ATTR(fun_cfg, 0664, fun_cfg_show, fun_cfg_store), __ATTR_NULL }; /******************** cec hal interface ***************************/ static int hdmitx_cec_open(struct inode *inode, struct file *file) { - cec_dev->open_count++; - if (cec_dev->open_count) { - cec_dev->hal_control = 1; + if (atomic_add_return(1, &cec_dev->cec_info.open_count)) { + cec_dev->cec_info.hal_ctl = 1; /* set default logical addr flag for uboot */ cec_set_reg_bits(AO_DEBUG_REG1, 0xf, 16, 4); } @@ -1735,9 +1987,8 @@ static int hdmitx_cec_open(struct inode *inode, struct file *file) static int hdmitx_cec_release(struct inode *inode, struct file *file) { - cec_dev->open_count--; - if (!cec_dev->open_count) - cec_dev->hal_control = 0; + if (!atomic_sub_return(1, &cec_dev->cec_info.open_count)) + cec_dev->cec_info.hal_ctl = 0; return 0; } @@ -1747,16 +1998,16 @@ static ssize_t hdmitx_cec_read(struct file *f, char __user *buf, int ret; if ((cec_dev->hal_flag & (1 << HDMI_OPTION_SYSTEM_CEC_CONTROL))) - cec_dev->rx_len = 0; + rx_len = 0; ret = wait_for_completion_timeout(&cec_dev->rx_ok, CEC_FRAME_DELAY); if (ret <= 0) return ret; - if (cec_dev->rx_len == 0) + if (rx_len == 0) return 0; - if (copy_to_user(buf, cec_dev->rx_msg, cec_dev->rx_len)) + if (copy_to_user(buf, rx_msg, rx_len)) return -EINVAL; - return cec_dev->rx_len; + return rx_len; } static ssize_t hdmitx_cec_write(struct file *f, const char __user *buf, @@ -1780,15 +2031,21 @@ static ssize_t hdmitx_cec_write(struct file *f, const char __user *buf, static void init_cec_port_info(struct hdmi_port_info *port, struct ao_cec_dev *cec_dev) { - unsigned int a, b, c; + unsigned int a, b, c, d, e = 0; unsigned int phy_head = 0xf000, phy_app = 0x1000, phy_addr; + struct hdmitx_dev *tx_dev; /* physical address for TV or repeator */ - if (cec_dev->dev_type == DEV_TYPE_TV) + tx_dev = cec_dev->tx_dev; + if (tx_dev == NULL || cec_dev->dev_type == DEV_TYPE_TV) { phy_addr = 0; - else if (cec_dev->phy_addr != INVALID_PHY_ADDR) - phy_addr = cec_dev->phy_addr; - else + } else if (tx_dev->hdmi_info.vsdb_phy_addr.valid == 1) { + a = tx_dev->hdmi_info.vsdb_phy_addr.a; + b = tx_dev->hdmi_info.vsdb_phy_addr.b; + c = tx_dev->hdmi_info.vsdb_phy_addr.c; + d = tx_dev->hdmi_info.vsdb_phy_addr.d; + phy_addr = ((a << 12) | (b << 8) | (c << 4) | (d)); + } else phy_addr = 0; /* found physical address append for repeator */ @@ -1805,33 +2062,40 @@ static void init_cec_port_info(struct hdmi_port_info *port, b = cec_dev->port_num; /* init for port info */ - for (a = 0; a < b; a++) { - port[a].type = HDMI_INPUT; - port[a].port_id = a + 1; - port[a].cec_supported = 1; - /* set ARC feature according mask */ - if (cec_dev->arc_port & (1 << a)) - port[a].arc_supported = 1; - else - port[a].arc_supported = 0; - + for (a = 0; a < sizeof(cec_dev->port_seq) * 2; a++) { /* set port physical address according port sequence */ if (cec_dev->port_seq) { c = (cec_dev->port_seq >> (4 * a)) & 0xf; - port[a].physical_address = (c + 1) * phy_app + phy_addr; + if (c == 0xf) { /* not used */ + CEC_INFO("port %d is not used\n", a); + continue; + } else if (!c) + break; + port[e].physical_address = (c) * phy_app + phy_addr; } else { /* asending order if port_seq is not set */ - port[a].physical_address = (a + 1) * phy_app + phy_addr; + port[e].physical_address = (e + 1) * phy_app + phy_addr; } + port[e].type = HDMI_INPUT; + port[e].port_id = a + 1; + port[e].cec_supported = 1; + /* set ARC feature according mask */ + if (cec_dev->arc_port & (1 << a)) + port[e].arc_supported = 1; + else + port[e].arc_supported = 0; + e++; + if (e >= b) + break; } if (cec_dev->dev_type == DEV_TYPE_TUNER) { /* last port is for tx in mixed tx/rx */ - port[a].type = HDMI_OUTPUT; - port[a].port_id = a + 1; - port[a].cec_supported = 1; - port[a].arc_supported = 0; - port[a].physical_address = phy_addr; + port[e].type = HDMI_OUTPUT; + port[e].port_id = 0; /* 0 for tx port id */ + port[e].cec_supported = 1; + port[e].arc_supported = 0; + port[e].physical_address = phy_addr; } } @@ -1839,80 +2103,112 @@ static long hdmitx_cec_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; - unsigned long tmp = 0, i; + unsigned long tmp; struct hdmi_port_info *port; - int tx_hpd = 0; + int a, b, c, d; + struct hdmitx_dev *tx_dev; + int tx_hpd; + mutex_lock(&cec_dev->cec_ioctl_mutex); switch (cmd) { case CEC_IOC_GET_PHYSICAL_ADDR: check_physical_addr_valid(20); - if (cec_dev->dev_type == DEV_TYPE_PLAYBACK && - !cec_dev->phy_addr_test) { + if (cec_dev->dev_type == DEV_TYPE_PLAYBACK && !phy_addr_test) { /* physical address for mbox */ - if (cec_dev->phy_addr == INVALID_PHY_ADDR) + if (cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.valid + == 0) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; - tmp = cec_dev->phy_addr; + } + a = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.a; + b = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.b; + c = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.c; + d = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.d; + tmp = ((a << 12) | (b << 8) | (c << 4) | (d << 0)); } else { - if (cec_dev->dev_type == DEV_TYPE_TV) + /* physical address for TV or repeator */ + tx_dev = cec_dev->tx_dev; + if (!tx_dev || cec_dev->dev_type == DEV_TYPE_TV) { tmp = 0; - /* for repeator */ - else if (cec_dev->phy_addr != INVALID_PHY_ADDR) - tmp = cec_dev->phy_addr; - else + } else if (tx_dev->hdmi_info.vsdb_phy_addr.valid == 1) { + a = tx_dev->hdmi_info.vsdb_phy_addr.a; + b = tx_dev->hdmi_info.vsdb_phy_addr.b; + c = tx_dev->hdmi_info.vsdb_phy_addr.c; + d = tx_dev->hdmi_info.vsdb_phy_addr.d; + tmp = ((a << 12) | (b << 8) | (c << 4) | (d)); + } else tmp = 0; } - if (!cec_dev->phy_addr_test) { + if (!phy_addr_test) { cec_dev->phy_addr = tmp; cec_phyaddr_config(tmp, 1); } else tmp = cec_dev->phy_addr; - if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) + if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; + } break; case CEC_IOC_GET_VERSION: - tmp = cec_dev->cec_version; - if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) + tmp = cec_dev->cec_info.cec_version; + if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; + } break; case CEC_IOC_GET_VENDOR_ID: - tmp = cec_dev->vendor_id; - if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) + tmp = cec_dev->v_data.vendor_id; + if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; + } break; case CEC_IOC_GET_PORT_NUM: tmp = cec_dev->port_num; - if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) + if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; + } break; case CEC_IOC_GET_PORT_INFO: port = kcalloc(cec_dev->port_num, sizeof(*port), GFP_KERNEL); if (!port) { CEC_ERR("no memory\n"); + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; } + check_physical_addr_valid(20); if (cec_dev->dev_type == DEV_TYPE_PLAYBACK) { /* for tx only 1 port */ - tmp = cec_dev->phy_addr; + a = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.a; + b = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.b; + c = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.c; + d = cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.d; + tmp = ((a << 12) | (b << 8) | (c << 4) | (d << 0)); + if (cec_dev->tx_dev->hdmi_info.vsdb_phy_addr.valid == 0) + tmp = 0xffff; port->type = HDMI_OUTPUT; - port->port_id = 1; + port->port_id = 0; port->cec_supported = 1; /* not support arc for tx */ port->arc_supported = 0; - port->physical_address = tmp & INVALID_PHY_ADDR; + port->physical_address = tmp & 0xffff; if (copy_to_user(argp, port, sizeof(*port))) { kfree(port); + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; } } else { - tmp = cec_dev->port_num; + b = cec_dev->port_num; init_cec_port_info(port, cec_dev); - if (copy_to_user(argp, port, sizeof(*port) * tmp)) { + if (copy_to_user(argp, port, sizeof(*port) * b)) { kfree(port); + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; } } @@ -1958,54 +2254,67 @@ static long hdmitx_cec_ioctl(struct file *f, break; case CEC_IOC_SET_OPTION_SET_LANG: - cec_dev->menu_lang = arg; + cec_dev->cec_info.menu_lang = arg; break; case CEC_IOC_GET_CONNECT_STATUS: - tx_hpd = cec_dev->hpd_state; + tx_hpd = cec_dev->tx_dev->hpd_state; if (cec_dev->dev_type == DEV_TYPE_PLAYBACK) tmp = tx_hpd; else { - if (copy_from_user(&i, argp, _IOC_SIZE(cmd))) + if (copy_from_user(&a, argp, _IOC_SIZE(cmd))) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; - if (cec_dev->port_num == i && - cec_dev->dev_type == DEV_TYPE_TUNER) + } + if (!a && cec_dev->dev_type == DEV_TYPE_TUNER) tmp = tx_hpd; else { /* mixed for rx */ tmp = (hdmirx_rd_top(TOP_HPD_PWR5V) >> 20); - if (tmp & (1 << (i - 1))) + if (tmp & (1 << (a - 1))) tmp = 1; else tmp = 0; } } - if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) + if (copy_to_user(argp, &tmp, _IOC_SIZE(cmd))) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; + } break; case CEC_IOC_ADD_LOGICAL_ADDR: tmp = arg & 0xf; cec_logicaddr_set(tmp); /* add by hal, to init some data structure */ - cec_dev->my_log_addr = tmp; - if (cec_dev->dev_type != DEV_TYPE_PLAYBACK) + cec_dev->cec_info.log_addr = tmp; + cec_dev->cec_info.power_status = POWER_ON; + + cec_dev->cec_info.vendor_id = cec_dev->v_data.vendor_id; + strcpy(cec_dev->cec_info.osd_name, + cec_dev->v_data.cec_osd_string); + + if (cec_dev->dev_type == DEV_TYPE_PLAYBACK) + cec_dev->cec_info.menu_status = DEVICE_MENU_ACTIVE; + else check_wake_up(); break; case CEC_IOC_CLR_LOGICAL_ADDR: - /* TODO: clear global info */ + cec_clear_logical_addr(); break; case CEC_IOC_SET_DEV_TYPE: - if (arg < DEV_TYPE_TV && arg > DEV_TYPE_VIDEO_PROCESSOR) + if (arg > DEV_TYPE_VIDEO_PROCESSOR) { + mutex_unlock(&cec_dev->cec_ioctl_mutex); return -EINVAL; + } cec_dev->dev_type = arg; break; case CEC_IOC_SET_ARC_ENABLE: /* select arc according arg */ if (arg) - hdmirx_wr_top(TOP_ARCTX_CNTL, 0x03); + hdmirx_wr_top(TOP_ARCTX_CNTL, 0x01); else hdmirx_wr_top(TOP_ARCTX_CNTL, 0x00); CEC_INFO("set arc en:%ld, reg:%lx\n", @@ -2015,6 +2324,7 @@ static long hdmitx_cec_ioctl(struct file *f, default: break; } + mutex_unlock(&cec_dev->cec_ioctl_mutex); return 0; } @@ -2030,9 +2340,11 @@ static long hdmitx_cec_compat_ioctl(struct file *f, /* for improve rw permission */ static char *aml_cec_class_devnode(struct device *dev, umode_t *mode) { - if (mode) + if (mode) { *mode = 0666; - CEC_INFO("mode is %x\n", *mode); + CEC_INFO("mode is %x\n", *mode); + } else + CEC_INFO("mode is null\n"); return NULL; } @@ -2056,8 +2368,7 @@ static const struct file_operations hdmitx_cec_fops = { }; /************************ cec high level code *****************************/ -#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND -struct early_suspend aocec_suspend_handler; +#ifdef CONFIG_HAS_EARLYSUSPEND static void aocec_early_suspend(struct early_suspend *h) { cec_dev->cec_suspend = CEC_EARLY_SUSPEND; @@ -2066,120 +2377,162 @@ static void aocec_early_suspend(struct early_suspend *h) static void aocec_late_resume(struct early_suspend *h) { - cec_dev->cec_suspend = 0; + cec_dev->cec_suspend = CEC_POWER_ON; CEC_INFO("%s, suspend:%d\n", __func__, cec_dev->cec_suspend); + } +#endif + +#ifdef CONFIG_OF +static const struct cec_platform_data_s cec_gxl_data = { + .line_bit = 8, + .ee_to_ao = 0, +}; -#endif //CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND +static const struct cec_platform_data_s cec_txlx_data = { + .line_bit = 7, + .ee_to_ao = 1, +}; + +static const struct cec_platform_data_s cec_g12a_data = { + .line_bit = 7, + .ee_to_ao = 1, +}; + +static const struct of_device_id aml_cec_dt_match[] = { + { + .compatible = "amlogic, amlogic-aocec", + .data = &cec_gxl_data, + }, + { + .compatible = "amlogic, aocec-txlx", + .data = &cec_txlx_data, + }, + { + .compatible = "amlogic, aocec-g12a", + .data = &cec_g12a_data, + }, +}; +#endif static int aml_cec_probe(struct platform_device *pdev) { struct device *cdev; + int ret = 0; + const struct of_device_id *of_id; #ifdef CONFIG_OF struct device_node *node = pdev->dev.of_node; - unsigned int tmp; - int irq_idx = 0, r, num; + int irq_idx = 0, r; const char *irq_name = NULL; struct pinctrl *p; + struct vendor_info_data *vend; struct resource *res; resource_size_t *base; #endif - cec_dev = kzalloc(sizeof(struct ao_cec_dev), GFP_KERNEL); - if (!cec_dev) - return -ENOMEM; + cec_dev = devm_kzalloc(&pdev->dev, sizeof(struct ao_cec_dev), + GFP_KERNEL); + if (!cec_dev) { + CEC_ERR("device malloc err!\n"); + ret = -ENOMEM; + goto tag_cec_devm_err; + } + CEC_ERR("cec driver date:%s\n", CEC_DRIVER_VERSION); cec_dev->dev_type = DEV_TYPE_PLAYBACK; cec_dev->dbg_dev = &pdev->dev; - cec_dev->wake_ok = 1; - cec_dev->phy_addr = INVALID_PHY_ADDR; + cec_dev->tx_dev = get_hdmitx_device(); + cec_dev->cpu_type = get_cpu_type(); + phy_addr_test = 0; /* cdev registe */ r = class_register(&aocec_class); if (r) { CEC_ERR("regist class failed\n"); - return -EINVAL; + ret = -EINVAL; + goto tag_cec_class_reg; } pdev->dev.class = &aocec_class; - cec_dev->dev_no = register_chrdev(0, CEC_DEV_NAME, + r = register_chrdev(0, CEC_DEV_NAME, &hdmitx_cec_fops); - if (cec_dev->dev_no < 0) { + if (r < 0) { CEC_ERR("alloc chrdev failed\n"); - return -EINVAL; + ret = -EINVAL; + goto tag_cec_chr_reg_err; } - CEC_INFO("alloc chrdev %x\n", cec_dev->dev_no); + cec_dev->cec_info.dev_no = r; + CEC_INFO("alloc chrdev %x\n", cec_dev->cec_info.dev_no); cdev = device_create(&aocec_class, &pdev->dev, - MKDEV(cec_dev->dev_no, 0), + MKDEV(cec_dev->cec_info.dev_no, 0), NULL, CEC_DEV_NAME); if (IS_ERR(cdev)) { CEC_ERR("create chrdev failed, dev:%p\n", cdev); - unregister_chrdev(cec_dev->dev_no, - CEC_DEV_NAME); - return -EINVAL; + ret = -EINVAL; + goto tag_cec_device_create_err; } + /*get compatible matched device, to get chip related data*/ + of_id = of_match_device(aml_cec_dt_match, &pdev->dev); + if (!of_id) + CEC_ERR("unable to get matched device\n"); + cec_dev->plat_data = (struct cec_platform_data_s *)of_id->data; + + cec_dev->cec_info.open_count.counter = 0; init_completion(&cec_dev->rx_ok); init_completion(&cec_dev->tx_ok); mutex_init(&cec_dev->cec_mutex); + mutex_init(&cec_dev->cec_ioctl_mutex); spin_lock_init(&cec_dev->cec_reg_lock); cec_dev->cec_thread = create_workqueue("cec_work"); if (cec_dev->cec_thread == NULL) { CEC_INFO("create work queue failed\n"); - return -EFAULT; + ret = -EFAULT; + goto tag_cec_threat_err; } INIT_DELAYED_WORK(&cec_dev->cec_work, cec_task); - cec_dev->remote_cec_dev = input_allocate_device(); - if (!cec_dev->remote_cec_dev) + cec_dev->cec_info.remote_cec_dev = input_allocate_device(); + if (!cec_dev->cec_info.remote_cec_dev) { CEC_INFO("No enough memory\n"); + ret = -ENOMEM; + goto tag_cec_alloc_input_err; + } - cec_dev->remote_cec_dev->name = "cec_input"; + cec_dev->cec_info.remote_cec_dev->name = "cec_input"; - cec_dev->remote_cec_dev->evbit[0] = BIT_MASK(EV_KEY); - cec_dev->remote_cec_dev->keybit[BIT_WORD(BTN_0)] = + cec_dev->cec_info.remote_cec_dev->evbit[0] = BIT_MASK(EV_KEY); + cec_dev->cec_info.remote_cec_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); - cec_dev->remote_cec_dev->id.bustype = BUS_ISA; - cec_dev->remote_cec_dev->id.vendor = 0x1b8e; - cec_dev->remote_cec_dev->id.product = 0x0cec; - cec_dev->remote_cec_dev->id.version = 0x0001; + cec_dev->cec_info.remote_cec_dev->id.bustype = BUS_ISA; + cec_dev->cec_info.remote_cec_dev->id.vendor = 0x1b8e; + cec_dev->cec_info.remote_cec_dev->id.product = 0x0cec; + cec_dev->cec_info.remote_cec_dev->id.version = 0x0001; - set_bit(KEY_POWER, cec_dev->remote_cec_dev->keybit); + set_bit(KEY_POWER, cec_dev->cec_info.remote_cec_dev->keybit); - if (input_register_device(cec_dev->remote_cec_dev)) { + if (input_register_device(cec_dev->cec_info.remote_cec_dev)) { CEC_INFO("Failed to register device\n"); - input_free_device(cec_dev->remote_cec_dev); + input_free_device(cec_dev->cec_info.remote_cec_dev); } #ifdef CONFIG_OF /* if using EE CEC */ if (of_property_read_bool(node, "ee_cec")) - cec_dev->ee_cec = 1; + ee_cec = 1; else - cec_dev->ee_cec = 0; - CEC_INFO("using EE cec:%d\n", cec_dev->ee_cec); - + ee_cec = 0; + CEC_INFO("using EE cec:%d\n", ee_cec); /* pinmux set */ if (of_get_property(node, "pinctrl-names", NULL)) { r = of_property_read_string(node, "pinctrl-names", &cec_dev->pin_name); - if (!r) + if ((!r) && strcmp(cec_dev->pin_name, "default")) { + CEC_INFO("%s pin name:%s\n", __func__, + cec_dev->pin_name); p = devm_pinctrl_get_select(&pdev->dev, cec_dev->pin_name); - } - - /* irq set */ - irq_idx = of_irq_get(node, 0); - cec_dev->irq_cec = irq_idx; - if (of_get_property(node, "interrupt-names", NULL)) { - r = of_property_read_string(node, "interrupt-names", &irq_name); - if (!r && !cec_dev->ee_cec) { - r = request_irq(irq_idx, &cec_isr_handler, IRQF_SHARED, - irq_name, (void *)cec_dev); - } - if (!r && cec_dev->ee_cec) { - r = request_irq(irq_idx, &cecrx_isr, IRQF_SHARED, - irq_name, (void *)cec_dev); } } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) { base = ioremap(res->start, res->end - res->start); @@ -2212,86 +2565,118 @@ static int aml_cec_probe(struct platform_device *pdev) CEC_ERR("no hhi reg resource\n"); cec_dev->hhi_reg = NULL; } - - r = of_property_read_u32(node, "port_num", &num); + r = of_property_read_u32(node, "port_num", &(cec_dev->port_num)); if (r) { CEC_ERR("not find 'port_num'\n"); cec_dev->port_num = 1; - } else - cec_dev->port_num = num; - r = of_property_read_u32(node, "arc_port_mask", &num); + } + r = of_property_read_u32(node, "arc_port_mask", &(cec_dev->arc_port)); if (r) { CEC_ERR("not find 'arc_port_mask'\n"); cec_dev->arc_port = 0; - } else - cec_dev->arc_port = num; + } + + vend = &cec_dev->v_data; + r = of_property_read_string(node, "vendor_name", + (const char **)&(vend->vendor_name)); + if (r) + CEC_INFO("not find vendor name\n"); - r = of_property_read_u32(node, "vendor_id", &(cec_dev->vendor_id)); + r = of_property_read_u32(node, "vendor_id", &(vend->vendor_id)); if (r) CEC_INFO("not find vendor id\n"); + r = of_property_read_string(node, "product_desc", + (const char **)&(vend->product_desc)); + if (r) + CEC_INFO("not find product desc\n"); + r = of_property_read_string(node, "cec_osd_string", - (const char **)&(cec_dev->osd_name)); + (const char **)&(vend->cec_osd_string)); if (r) { CEC_INFO("not find cec osd string\n"); - cec_dev->osd_name = "Amlogic"; + strcpy(vend->cec_osd_string, "AML TV/BOX"); } - r = of_property_read_u32(node, "cec_version", - &(tmp)); + &(cec_dev->cec_info.cec_version)); if (r) { /* default set to 2.0 */ CEC_INFO("not find cec_version\n"); - cec_dev->cec_version = CEC_VERSION_20; - } else - cec_dev->cec_version = tmp; + cec_dev->cec_info.cec_version = CEC_VERSION_20; + } - /* get port sequence */ - node = of_find_node_by_path("/hdmirx"); - if (node == NULL) { - CEC_ERR("can't find hdmirx\n"); - cec_dev->port_seq = 0; - } else { - r = of_property_read_u32(node, "rx_port_maps", - &(cec_dev->port_seq)); - if (r) - CEC_INFO("not find rx_port_maps\n"); + /* irq set */ + cec_irq_enable(false); + irq_idx = of_irq_get(node, 0); + cec_dev->irq_cec = irq_idx; + if (of_get_property(node, "interrupt-names", NULL)) { + r = of_property_read_string(node, "interrupt-names", &irq_name); + if (!r && !ee_cec) { + r = request_irq(irq_idx, &cec_isr_handler, IRQF_SHARED, + irq_name, (void *)cec_dev); + } + if (!r && ee_cec) { + r = request_irq(irq_idx, &cecrx_isr, IRQF_SHARED, + irq_name, (void *)cec_dev); + } } #endif -#ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND + if (!ee_cec) { + last_cec_msg = devm_kzalloc(&pdev->dev, + sizeof(*last_cec_msg), GFP_KERNEL); + if (!last_cec_msg) { + CEC_ERR("allocate last_cec_msg failed\n"); + ret = -ENOMEM; + goto tag_cec_msg_alloc_err; + } + } + +#ifdef CONFIG_HAS_EARLYSUSPEND aocec_suspend_handler.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20; aocec_suspend_handler.suspend = aocec_early_suspend; aocec_suspend_handler.resume = aocec_late_resume; aocec_suspend_handler.param = cec_dev; register_early_suspend(&aocec_suspend_handler); #endif - device_init_wakeup(cec_dev->dbg_dev, 1); - - hrtimer_init(&cec_dev->start_bit_check, - CLOCK_MONOTONIC, HRTIMER_MODE_REL); - cec_dev->start_bit_check.function = cec_line_check; - cec_dev->cec_msg_dbg_en = DEFAULT_DEBUG_EN; - cec_dev->hdmitx_nb.notifier_call = cec_hdmi_tx_notify_handler; - hdmitx_event_notifier_regist(&cec_dev->hdmitx_nb); + hrtimer_init(&start_bit_check, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + start_bit_check.function = cec_line_check; /* for init */ cec_pre_init(); queue_delayed_work(cec_dev->cec_thread, &cec_dev->cec_work, 0); + + CEC_ERR("%s success end\n", __func__); + return 0; +tag_cec_msg_alloc_err: + input_free_device(cec_dev->cec_info.remote_cec_dev); +tag_cec_alloc_input_err: + destroy_workqueue(cec_dev->cec_thread); +tag_cec_threat_err: + device_destroy(&aocec_class, + MKDEV(cec_dev->cec_info.dev_no, 0)); +tag_cec_device_create_err: + unregister_chrdev(cec_dev->cec_info.dev_no, CEC_DEV_NAME); +tag_cec_chr_reg_err: + class_unregister(&aocec_class); +tag_cec_class_reg: + devm_kfree(&pdev->dev, cec_dev); +tag_cec_devm_err: + return ret; } -static __exit int aml_cec_remove(struct platform_device *pdev) +static int aml_cec_remove(struct platform_device *pdev) { CEC_INFO("cec uninit!\n"); free_irq(cec_dev->irq_cec, (void *)cec_dev); + kfree(last_cec_msg); - hdmitx_event_notifier_unregist(&cec_dev->hdmitx_nb); if (cec_dev->cec_thread) { cancel_delayed_work_sync(&cec_dev->cec_work); destroy_workqueue(cec_dev->cec_thread); } - input_unregister_device(cec_dev->remote_cec_dev); - unregister_chrdev(cec_dev->dev_no, CEC_DEV_NAME); + input_unregister_device(cec_dev->cec_info.remote_cec_dev); + unregister_chrdev(cec_dev->cec_info.dev_no, CEC_DEV_NAME); class_unregister(&aocec_class); kfree(cec_dev); return 0; @@ -2317,57 +2702,25 @@ static void aml_cec_pm_complete(struct device *dev) cec_key_report(0); } -static int aml_cec_suspend_late(struct device *dev) +static int aml_cec_suspend_noirq(struct device *dev) { - struct pinctrl *p; - struct pinctrl_state *s; - int ret; - - CEC_INFO("%s!\n", __func__); - if (cec_dev->ee_cec) { - p = devm_pinctrl_get(cec_dev->dbg_dev); - if (IS_ERR(p)) - return -EINVAL; - s = pinctrl_lookup_state(p, "dummy"); - ret = pinctrl_select_state(p, s); - if (ret < 0) - devm_pinctrl_put(p); - CEC_INFO("%s, unselect pin mux\n", __func__); - return ret; - } return 0; } -static int aml_cec_resume_early(struct device *dev) +static int aml_cec_resume_noirq(struct device *dev) { - struct pinctrl *p; + CEC_INFO("cec resume noirq!\n"); + cec_dev->cec_info.power_status = TRANS_STANDBY_TO_ON; + cec_dev->cec_suspend = CEC_POWER_RESUME; - CEC_INFO("%s!\n", __func__); - cec_dev->power_status = TRANS_STANDBY_TO_ON; - - /* reselect pin mux if resume */ - if (cec_dev->ee_cec) { - p = devm_pinctrl_get_select(cec_dev->dbg_dev, - cec_dev->pin_name); - CEC_INFO("%s, reselect pin:%p\n", __func__, p); - } return 0; } static const struct dev_pm_ops aml_cec_pm = { .prepare = aml_cec_pm_prepare, .complete = aml_cec_pm_complete, - .suspend_late = aml_cec_suspend_late, - .resume_early = aml_cec_resume_early, -}; -#endif - -#ifdef CONFIG_OF -static const struct of_device_id aml_cec_dt_match[] = { - { - .compatible = "amlogic, amlogic-aocec", - }, - {}, + .suspend_noirq = aml_cec_suspend_noirq, + .resume_noirq = aml_cec_resume_noirq, }; #endif @@ -2399,7 +2752,6 @@ static void __exit cec_uninit(void) platform_driver_unregister(&aml_cec_driver); } - module_init(cec_init); module_exit(cec_uninit); MODULE_DESCRIPTION("AMLOGIC HDMI TX CEC driver"); diff --git a/drivers/amlogic/cec/hdmi_ao_cec.h b/drivers/amlogic/cec/hdmi_ao_cec.h index 4b185e9..551b089 100644 --- a/drivers/amlogic/cec/hdmi_ao_cec.h +++ b/drivers/amlogic/cec/hdmi_ao_cec.h @@ -18,8 +18,7 @@ #ifndef __AO_CEC_H__ #define __AO_CEC_H__ -#include "ao_cec_reg.h" -#include "ee_cec_reg.h" +#define CEC_DRIVER_VERSION "2018/02/22\n" #define CEC_FRAME_DELAY msecs_to_jiffies(400) #define CEC_DEV_NAME "cec" @@ -29,7 +28,361 @@ #define HR_DELAY(n) (ktime_set(0, n * 1000 * 1000)) -#ifdef CONFIG_TVIN_HDMI +#define CEC_FUNC_MASK 0 +#define ONE_TOUCH_PLAY_MASK 1 +#define ONE_TOUCH_STANDBY_MASK 2 +#define AUTO_POWER_ON_MASK 3 + + +#define AO_BASE 0xc8100000 + +#define AO_GPIO_I ((0x0A << 2)) + +#define AO_CEC_GEN_CNTL ((0x40 << 2)) +#define AO_CEC_RW_REG ((0x41 << 2)) +#define AO_CEC_INTR_MASKN ((0x42 << 2)) +#define AO_CEC_INTR_CLR ((0x43 << 2)) +#define AO_CEC_INTR_STAT ((0x44 << 2)) + +#define AO_RTI_PWR_CNTL_REG0 ((0x04 << 2)) +#define AO_CRT_CLK_CNTL1 ((0x1a << 2)) +#define AO_RTC_ALT_CLK_CNTL0 ((0x25 << 2)) +#define AO_RTC_ALT_CLK_CNTL1 ((0x26 << 2)) + +/* for TXLX, same as AO_RTC_ALT_CLK_CNTLx */ +#define AO_CEC_CLK_CNTL_REG0 ((0x1d << 2)) +#define AO_CEC_CLK_CNTL_REG1 ((0x1e << 2)) + +#define AO_RTI_STATUS_REG1 ((0x01 << 2)) +#define AO_DEBUG_REG0 ((0x28 << 2)) +#define AO_DEBUG_REG1 ((0x29 << 2)) +#define AO_DEBUG_REG2 ((0x2a << 2)) +#define AO_DEBUG_REG3 ((0x2b << 2)) +#define AO_CEC_STICKY_DATA0 ((0xca << 2)) +#define AO_CEC_STICKY_DATA1 ((0xcb << 2)) +#define AO_CEC_STICKY_DATA2 ((0xcc << 2)) +#define AO_CEC_STICKY_DATA3 ((0xcd << 2)) +#define AO_CEC_STICKY_DATA4 ((0xce << 2)) +#define AO_CEC_STICKY_DATA5 ((0xcf << 2)) +#define AO_CEC_STICKY_DATA6 ((0xd0 << 2)) +#define AO_CEC_STICKY_DATA7 ((0xd1 << 2)) + +/* + * AOCEC_B + */ +#define AO_CECB_CLK_CNTL_REG0 ((0xa0 << 2)) +#define AO_CECB_CLK_CNTL_REG1 ((0xa1 << 2)) +#define AO_CECB_GEN_CNTL ((0xa2 << 2)) +#define AO_CECB_RW_REG ((0xa3 << 2)) +#define AO_CECB_INTR_MASKN ((0xa4 << 2)) +#define AO_CECB_INTR_CLR ((0xa5 << 2)) +#define AO_CECB_INTR_STAT ((0xa6 << 2)) + +/* read/write */ +#define CEC_TX_MSG_0_HEADER 0x00 +#define CEC_TX_MSG_1_OPCODE 0x01 +#define CEC_TX_MSG_2_OP1 0x02 +#define CEC_TX_MSG_3_OP2 0x03 +#define CEC_TX_MSG_4_OP3 0x04 +#define CEC_TX_MSG_5_OP4 0x05 +#define CEC_TX_MSG_6_OP5 0x06 +#define CEC_TX_MSG_7_OP6 0x07 +#define CEC_TX_MSG_8_OP7 0x08 +#define CEC_TX_MSG_9_OP8 0x09 +#define CEC_TX_MSG_A_OP9 0x0A +#define CEC_TX_MSG_B_OP10 0x0B +#define CEC_TX_MSG_C_OP11 0x0C +#define CEC_TX_MSG_D_OP12 0x0D +#define CEC_TX_MSG_E_OP13 0x0E +#define CEC_TX_MSG_F_OP14 0x0F + +/* read/write */ +#define CEC_TX_MSG_LENGTH 0x10 +#define CEC_TX_MSG_CMD 0x11 +#define CEC_TX_WRITE_BUF 0x12 +#define CEC_TX_CLEAR_BUF 0x13 +#define CEC_RX_MSG_CMD 0x14 +#define CEC_RX_CLEAR_BUF 0x15 +#define CEC_LOGICAL_ADDR0 0x16 +#define CEC_LOGICAL_ADDR1 0x17 +#define CEC_LOGICAL_ADDR2 0x18 +#define CEC_LOGICAL_ADDR3 0x19 +#define CEC_LOGICAL_ADDR4 0x1A +#define CEC_CLOCK_DIV_H 0x1B +#define CEC_CLOCK_DIV_L 0x1C + +/* The following registers are for fine tuning CEC bit timing parameters. + * They are only valid in AO CEC, NOT valid in HDMITX CEC. + * The AO CEC's timing parameters are already set default to work with + * 32768Hz clock, so hopefully SW never need to program these registers. + * The timing registers are made programmable just in case. + */ +#define AO_CEC_QUIESCENT_25MS_BIT7_0 0x20 +#define AO_CEC_QUIESCENT_25MS_BIT11_8 0x21 +#define AO_CEC_STARTBITMINL2H_3MS5_BIT7_0 0x22 +#define AO_CEC_STARTBITMINL2H_3MS5_BIT8 0x23 +#define AO_CEC_STARTBITMAXL2H_3MS9_BIT7_0 0x24 +#define AO_CEC_STARTBITMAXL2H_3MS9_BIT8 0x25 +#define AO_CEC_STARTBITMINH_0MS6_BIT7_0 0x26 +#define AO_CEC_STARTBITMINH_0MS6_BIT8 0x27 +#define AO_CEC_STARTBITMAXH_1MS0_BIT7_0 0x28 +#define AO_CEC_STARTBITMAXH_1MS0_BIT8 0x29 +#define AO_CEC_STARTBITMINTOTAL_4MS3_BIT7_0 0x2A +#define AO_CEC_STARTBITMINTOTAL_4MS3_BIT9_8 0x2B +#define AO_CEC_STARTBITMAXTOTAL_4MS7_BIT7_0 0x2C +#define AO_CEC_STARTBITMAXTOTAL_4MS7_BIT9_8 0x2D +#define AO_CEC_LOGIC1MINL2H_0MS4_BIT7_0 0x2E +#define AO_CEC_LOGIC1MINL2H_0MS4_BIT8 0x2F +#define AO_CEC_LOGIC1MAXL2H_0MS8_BIT7_0 0x30 +#define AO_CEC_LOGIC1MAXL2H_0MS8_BIT8 0x31 +#define AO_CEC_LOGIC0MINL2H_1MS3_BIT7_0 0x32 +#define AO_CEC_LOGIC0MINL2H_1MS3_BIT8 0x33 +#define AO_CEC_LOGIC0MAXL2H_1MS7_BIT7_0 0x34 +#define AO_CEC_LOGIC0MAXL2H_1MS7_BIT8 0x35 +#define AO_CEC_LOGICMINTOTAL_2MS05_BIT7_0 0x36 +#define AO_CEC_LOGICMINTOTAL_2MS05_BIT9_8 0x37 +#define AO_CEC_LOGICMAXHIGH_2MS8_BIT7_0 0x38 +#define AO_CEC_LOGICMAXHIGH_2MS8_BIT8 0x39 +#define AO_CEC_LOGICERRLOW_3MS4_BIT7_0 0x3A +#define AO_CEC_LOGICERRLOW_3MS4_BIT8 0x3B +#define AO_CEC_NOMSMPPOINT_1MS05 0x3C +#define AO_CEC_DELCNTR_LOGICERR 0x3E +#define AO_CEC_TXTIME_17MS_BIT7_0 0x40 +#define AO_CEC_TXTIME_17MS_BIT10_8 0x41 +#define AO_CEC_TXTIME_2BIT_BIT7_0 0x42 +#define AO_CEC_TXTIME_2BIT_BIT10_8 0x43 +#define AO_CEC_TXTIME_4BIT_BIT7_0 0x44 +#define AO_CEC_TXTIME_4BIT_BIT10_8 0x45 +#define AO_CEC_STARTBITNOML2H_3MS7_BIT7_0 0x46 +#define AO_CEC_STARTBITNOML2H_3MS7_BIT8 0x47 +#define AO_CEC_STARTBITNOMH_0MS8_BIT7_0 0x48 +#define AO_CEC_STARTBITNOMH_0MS8_BIT8 0x49 +#define AO_CEC_LOGIC1NOML2H_0MS6_BIT7_0 0x4A +#define AO_CEC_LOGIC1NOML2H_0MS6_BIT8 0x4B +#define AO_CEC_LOGIC0NOML2H_1MS5_BIT7_0 0x4C +#define AO_CEC_LOGIC0NOML2H_1MS5_BIT8 0x4D +#define AO_CEC_LOGIC1NOMH_1MS8_BIT7_0 0x4E +#define AO_CEC_LOGIC1NOMH_1MS8_BIT8 0x4F +#define AO_CEC_LOGIC0NOMH_0MS9_BIT7_0 0x50 +#define AO_CEC_LOGIC0NOMH_0MS9_BIT8 0x51 +#define AO_CEC_LOGICERRLOW_3MS6_BIT7_0 0x52 +#define AO_CEC_LOGICERRLOW_3MS6_BIT8 0x53 +#define AO_CEC_CHKCONTENTION_0MS1 0x54 +#define AO_CEC_PREPARENXTBIT_0MS05_BIT7_0 0x56 +#define AO_CEC_PREPARENXTBIT_0MS05_BIT8 0x57 +#define AO_CEC_NOMSMPACKPOINT_0MS45 0x58 +#define AO_CEC_ACK0NOML2H_1MS5_BIT7_0 0x5A +#define AO_CEC_ACK0NOML2H_1MS5_BIT8 0x5B + +#define AO_CEC_BUGFIX_DISABLE_0 0x60 +#define AO_CEC_BUGFIX_DISABLE_1 0x61 + +/* read only */ +#define CEC_RX_MSG_0_HEADER 0x80 +#define CEC_RX_MSG_1_OPCODE 0x81 +#define CEC_RX_MSG_2_OP1 0x82 +#define CEC_RX_MSG_3_OP2 0x83 +#define CEC_RX_MSG_4_OP3 0x84 +#define CEC_RX_MSG_5_OP4 0x85 +#define CEC_RX_MSG_6_OP5 0x86 +#define CEC_RX_MSG_7_OP6 0x87 +#define CEC_RX_MSG_8_OP7 0x88 +#define CEC_RX_MSG_9_OP8 0x89 +#define CEC_RX_MSG_A_OP9 0x8A +#define CEC_RX_MSG_B_OP10 0x8B +#define CEC_RX_MSG_C_OP11 0x8C +#define CEC_RX_MSG_D_OP12 0x8D +#define CEC_RX_MSG_E_OP13 0x8E +#define CEC_RX_MSG_F_OP14 0x8F + +/* read only */ +#define CEC_RX_MSG_LENGTH 0x90 +#define CEC_RX_MSG_STATUS 0x91 +#define CEC_RX_NUM_MSG 0x92 +#define CEC_TX_MSG_STATUS 0x93 +#define CEC_TX_NUM_MSG 0x94 + +/* tx_msg_cmd definition */ +#define TX_NO_OP 0 /* No transaction */ +#define TX_REQ_CURRENT 1 /* Transmit earliest message in buffer */ +#define TX_ABORT 2 /* Abort transmitting earliest message */ +/* Overwrite earliest message in buffer and transmit next message */ +#define TX_REQ_NEXT 3 + +/* tx_msg_status definition */ +#define TX_IDLE 0 /* No transaction */ +#define TX_BUSY 1 /* Transmitter is busy */ +/* Message has been successfully transmitted */ +#define TX_DONE 2 +#define TX_ERROR 3 /* Message has been transmitted with error */ + +/* rx_msg_cmd */ +#define RX_NO_OP 0 /* No transaction */ +#define RX_ACK_CURRENT 1 /* Read earliest message in buffer */ +#define RX_DISABLE 2 /* Disable receiving latest message */ +/* Clear earliest message from buffer and read next message */ +#define RX_ACK_NEXT 3 + +/* rx_msg_status */ +#define RX_IDLE 0 /* No transaction */ +#define RX_BUSY 1 /* Receiver is busy */ +#define RX_DONE 2 /* Message has been received successfully */ +#define RX_ERROR 3 /* Message has been received with error */ + +#define TOP_HPD_PWR5V 0x002 +#define TOP_ARCTX_CNTL 0x010 +#define TOP_CLK_CNTL 0x001 +#define TOP_EDID_GEN_CNTL 0x004 +#define TOP_EDID_ADDR_CEC 0x005 + +/** Register address: audio clock interrupt clear enable */ +#define DWC_AUD_CEC_IEN_CLR (0xF90UL) +/** Register address: audio clock interrupt set enable */ +#define DWC_AUD_CEC_IEN_SET (0xF94UL) +/** Register address: audio clock interrupt status */ +#define DWC_AUD_CEC_ISTS (0xF98UL) +/** Register address: audio clock interrupt enable */ +#define DWC_AUD_CEC_IEN (0xF9CUL) +/** Register address: audio clock interrupt clear status */ +#define DWC_AUD_CEC_ICLR (0xFA0UL) +/** Register address: audio clock interrupt set status */ +#define DWC_AUD_CEC_ISET (0xFA4UL) +/** Register address: DMI disable interface */ +#define DWC_DMI_DISABLE_IF (0xFF4UL) + +/*---- registers for EE CEC ----*/ +#define DWC_CEC_CTRL 0x1F00 +#define DWC_CEC_STAT 0x1F04 +#define DWC_CEC_MASK 0x1F08 +#define DWC_CEC_POLARITY 0x1F0C +#define DWC_CEC_INT 0x1F10 +#define DWC_CEC_ADDR_L 0x1F14 +#define DWC_CEC_ADDR_H 0x1F18 +#define DWC_CEC_TX_CNT 0x1F1C +#define DWC_CEC_RX_CNT 0x1F20 +#define DWC_CEC_TX_DATA0 0x1F40 +#define DWC_CEC_TX_DATA1 0x1F44 +#define DWC_CEC_TX_DATA2 0x1F48 +#define DWC_CEC_TX_DATA3 0x1F4C +#define DWC_CEC_TX_DATA4 0x1F50 +#define DWC_CEC_TX_DATA5 0x1F54 +#define DWC_CEC_TX_DATA6 0x1F58 +#define DWC_CEC_TX_DATA7 0x1F5C +#define DWC_CEC_TX_DATA8 0x1F60 +#define DWC_CEC_TX_DATA9 0x1F64 +#define DWC_CEC_TX_DATA10 0x1F68 +#define DWC_CEC_TX_DATA11 0x1F6C +#define DWC_CEC_TX_DATA12 0x1F70 +#define DWC_CEC_TX_DATA13 0x1F74 +#define DWC_CEC_TX_DATA14 0x1F78 +#define DWC_CEC_TX_DATA15 0x1F7C +#define DWC_CEC_RX_DATA0 0x1F80 +#define DWC_CEC_RX_DATA1 0x1F84 +#define DWC_CEC_RX_DATA2 0x1F88 +#define DWC_CEC_RX_DATA3 0x1F8C +#define DWC_CEC_RX_DATA4 0x1F90 +#define DWC_CEC_RX_DATA5 0x1F94 +#define DWC_CEC_RX_DATA6 0x1F98 +#define DWC_CEC_RX_DATA7 0x1F9C +#define DWC_CEC_RX_DATA8 0x1FA0 +#define DWC_CEC_RX_DATA9 0x1FA4 +#define DWC_CEC_RX_DATA10 0x1FA8 +#define DWC_CEC_RX_DATA11 0x1FAC +#define DWC_CEC_RX_DATA12 0x1FB0 +#define DWC_CEC_RX_DATA13 0x1FB4 +#define DWC_CEC_RX_DATA14 0x1FB8 +#define DWC_CEC_RX_DATA15 0x1FBC +#define DWC_CEC_LOCK 0x1FC0 +#define DWC_CEC_WKUPCTRL 0x1FC4 + +/* FOR AO_CECB */ +#define AO_CECB_CTRL_ADDR 0x00 +#define AO_CECB_INTR_MASK_ADDR 0x02 +#define AO_CECB_LADD_LOW_ADDR 0x05 +#define AO_CECB_LADD_HIGH_ADDR 0x06 +#define AO_CECB_TX_CNT_ADDR 0x07 +#define AO_CECB_RX_CNT_ADDR 0x08 +#define AO_CECB_TX_DATA00_ADDR 0x10 +#define AO_CECB_TX_DATA01_ADDR 0x11 +#define AO_CECB_TX_DATA02_ADDR 0x12 +#define AO_CECB_TX_DATA03_ADDR 0x13 +#define AO_CECB_TX_DATA04_ADDR 0x14 +#define AO_CECB_TX_DATA05_ADDR 0x15 +#define AO_CECB_TX_DATA06_ADDR 0x16 +#define AO_CECB_TX_DATA07_ADDR 0x17 +#define AO_CECB_TX_DATA08_ADDR 0x18 +#define AO_CECB_TX_DATA09_ADDR 0x19 +#define AO_CECB_TX_DATA10_ADDR 0x1A +#define AO_CECB_TX_DATA11_ADDR 0x1B +#define AO_CECB_TX_DATA12_ADDR 0x1C +#define AO_CECB_TX_DATA13_ADDR 0x1D +#define AO_CECB_TX_DATA14_ADDR 0x1E +#define AO_CECB_TX_DATA15_ADDR 0x1F +#define AO_CECB_RX_DATA00_ADDR 0x20 +#define AO_CECB_RX_DATA01_ADDR 0x21 +#define AO_CECB_RX_DATA02_ADDR 0x22 +#define AO_CECB_RX_DATA03_ADDR 0x23 +#define AO_CECB_RX_DATA04_ADDR 0x24 +#define AO_CECB_RX_DATA05_ADDR 0x25 +#define AO_CECB_RX_DATA06_ADDR 0x26 +#define AO_CECB_RX_DATA07_ADDR 0x27 +#define AO_CECB_RX_DATA08_ADDR 0x28 +#define AO_CECB_RX_DATA09_ADDR 0x29 +#define AO_CECB_RX_DATA10_ADDR 0x2A +#define AO_CECB_RX_DATA11_ADDR 0x2B +#define AO_CECB_RX_DATA12_ADDR 0x2C +#define AO_CECB_RX_DATA13_ADDR 0x2D +#define AO_CECB_RX_DATA14_ADDR 0x2E +#define AO_CECB_RX_DATA15_ADDR 0x2F +#define AO_CECB_LOCK_BUF_ADDR 0x30 +#define AO_CECB_WAKEUPCTRL_ADDR 0x31 + +/* cec ip irq flags bit discription */ +#define EECEC_IRQ_TX_DONE (1 << 16) +#define EECEC_IRQ_RX_EOM (1 << 17) +#define EECEC_IRQ_TX_NACK (1 << 18) +#define EECEC_IRQ_TX_ARB_LOST (1 << 19) +#define EECEC_IRQ_TX_ERR_INITIATOR (1 << 20) +#define EECEC_IRQ_RX_ERR_FOLLOWER (1 << 21) +#define EECEC_IRQ_RX_WAKEUP (1 << 22) +#define EE_CEC_IRQ_EN_MASK (0xf << 16) + +/* cec irq bit flags for AO_CEC_B */ +#define CECB_IRQ_TX_DONE (1 << 0) +#define CECB_IRQ_RX_EOM (1 << 1) +#define CECB_IRQ_TX_NACK (1 << 2) +#define CECB_IRQ_TX_ARB_LOST (1 << 3) +#define CECB_IRQ_TX_ERR_INITIATOR (1 << 4) +#define CECB_IRQ_RX_ERR_FOLLOWER (1 << 5) +#define CECB_IRQ_RX_WAKEUP (1 << 6) +#define CECB_IRQ_EN_MASK (0xf << 0) + +/* common mask */ +#define CEC_IRQ_TX_DONE (1 << (16 - shift)) +#define CEC_IRQ_RX_EOM (1 << (17 - shift)) +#define CEC_IRQ_TX_NACK (1 << (18 - shift)) +#define CEC_IRQ_TX_ARB_LOST (1 << (19 - shift)) +#define CEC_IRQ_TX_ERR_INITIATOR (1 << (20 - shift)) +#define CEC_IRQ_RX_ERR_FOLLOWER (1 << (21 - shift)) +#define CEC_IRQ_RX_WAKEUP (1 << (22 - shift)) + +#define EDID_CEC_ID_ADDR 0x00a100a0 +#define EDID_AUTO_CEC_EN 0 + +#define HHI_32K_CLK_CNTL (0x89 << 2) + +#ifdef CONFIG_AMLOGIC_AO_CEC +unsigned int aocec_rd_reg(unsigned long addr); +void aocec_wr_reg(unsigned long addr, unsigned long data); +void cecrx_irq_handle(void); +void cec_logicaddr_set(int l_add); +void cec_arbit_bit_time_set(unsigned int bit_set, + unsigned int time_set, unsigned int flag); +void cec_irq_enable(bool enable); +void aocec_irq_enable(bool enable); +#endif + +#ifdef CONFIG_AMLOGIC_MEDIA_TVIN_HDMI extern unsigned long hdmirx_rd_top(unsigned long addr); extern void hdmirx_wr_top(unsigned long addr, unsigned long data); extern uint32_t hdmirx_rd_dwc(uint16_t addr); @@ -50,7 +403,6 @@ static inline uint32_t hdmirx_rd_dwc(uint16_t addr) } static inline void hdmirx_wr_dwc(uint16_t addr, uint32_t data) { - } #endif diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h index 5e5abb1..78e69ca 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h @@ -276,8 +276,10 @@ enum cec_version_e { CEC_VERSION_13, CEC_VERSION_13A, CEC_VERSION_14A, + CEC_VERSION_20, }; + #define INFO_MASK_CEC_VERSION (1<<0) #define INFO_MASK_VENDOR_ID (1<<1) #define INFO_MASK_DEVICE_TYPE (1<<2) @@ -305,11 +307,11 @@ struct cec_node_info_t { */ struct cec_global_info_t { dev_t dev_no; - unsigned int open_count; + atomic_t open_count; unsigned int hal_ctl; /* message controlled by hal */ unsigned int vendor_id:24; unsigned int menu_lang; - unsigned char cec_version; + unsigned int cec_version; unsigned char power_status; unsigned char log_addr; unsigned char menu_status; |