diff --git a/projects/Odroid_C2/bootloader/boot.ini b/projects/Odroid_C2/bootloader/boot.ini index 75a435f012..e1df57a56a 100644 --- a/projects/Odroid_C2/bootloader/boot.ini +++ b/projects/Odroid_C2/bootloader/boot.ini @@ -163,7 +163,7 @@ setenv bootcmd "${kernel}; ${dtb}; ${timer}; ${bootseq}" #------------------------------------------------------------------------------------------------------ # Prepare to boot -if test "${hdmi_cec}" = "1"; then setenv cec "hdmitx=cecf"; fi +if test "${hdmi_cec}" = "1"; then setenv cec "hdmitx=cec17"; fi if test "${hdmi_hotplug}" = "0"; then setenv hpd "disablehpd=true"; fi if test "${audio_dac}" = "1"; then setenv dac "enabledac"; fi if test "${vpu}" = "0"; then fdt rm /mesonstream; fdt rm /vdec; fdt rm /ppmgr; fi diff --git a/projects/Odroid_C2/patches/kodi/kodi-0002-disable-suspend.patch b/projects/Odroid_C2/patches/kodi/kodi-0002-disable-suspend.patch new file mode 100644 index 0000000000..42009e9ce6 --- /dev/null +++ b/projects/Odroid_C2/patches/kodi/kodi-0002-disable-suspend.patch @@ -0,0 +1,13 @@ +diff --git a/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp b/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp +index 4e5bcc6..ad5847d 100644 +--- a/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp ++++ b/xbmc/powermanagement/linux/LogindUPowerSyscall.cpp +@@ -53,7 +53,7 @@ CLogindUPowerSyscall::CLogindUPowerSyscall() + m_canPowerdown = LogindCheckCapability("CanPowerOff"); + m_canReboot = LogindCheckCapability("CanReboot"); + m_canHibernate = LogindCheckCapability("CanHibernate"); +- m_canSuspend = LogindCheckCapability("CanSuspend"); ++ m_canSuspend = false; + + InhibitDelayLock(); + diff --git a/projects/Odroid_C2/patches/linux/linux-006-save-cec-config.patch b/projects/Odroid_C2/patches/linux/linux-006-save-cec-config.patch new file mode 100644 index 0000000000..a66b70ff40 --- /dev/null +++ b/projects/Odroid_C2/patches/linux/linux-006-save-cec-config.patch @@ -0,0 +1,85 @@ +diff --git a/drivers/amlogic/cec/hdmi_ao_cec.c b/drivers/amlogic/cec/hdmi_ao_cec.c +index 21ca8bb..9f4686f 100644 +--- a/drivers/amlogic/cec/hdmi_ao_cec.c ++++ b/drivers/amlogic/cec/hdmi_ao_cec.c +@@ -225,14 +225,13 @@ unsigned int aocec_rd_reg(unsigned long addr) + { + unsigned int data32; + unsigned long flags; +- waiting_aocec_free(); + spin_lock_irqsave(&cec_dev->cec_reg_lock, flags); ++ waiting_aocec_free(); + 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 */ ++ data32 |= (addr & 0xff) << 0; /* [7:0] cec_reg_addr */ + writel(data32, cec_dev->cec_reg + AO_CEC_RW_REG); +- + waiting_aocec_free(); + data32 = ((readl(cec_dev->cec_reg + AO_CEC_RW_REG)) >> 24) & 0xff; + spin_unlock_irqrestore(&cec_dev->cec_reg_lock, flags); +@@ -241,15 +240,16 @@ unsigned int aocec_rd_reg(unsigned long addr) + + void aocec_wr_reg(unsigned long addr, unsigned long data) + { +- unsigned long data32; ++ unsigned int data32; + unsigned long flags; +- waiting_aocec_free(); + spin_lock_irqsave(&cec_dev->cec_reg_lock, flags); ++ waiting_aocec_free(); + 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 */ ++ data32 |= (data & 0xff) << 8; /* [15:8] cec_reg_wrdata */ ++ data32 |= (addr & 0xff) << 0; /* [7:0] cec_reg_addr */ + writel(data32, cec_dev->cec_reg + AO_CEC_RW_REG); ++ waiting_aocec_free(); + spin_unlock_irqrestore(&cec_dev->cec_reg_lock, flags); + } /* aocec_wr_only_reg */ + +@@ -737,6 +737,8 @@ static void cec_pre_init(void) + { + ao_cec_init(); + ++ cec_config(cec_dev->tx_dev->cec_func_config, 1); ++ + cec_arbit_bit_time_set(3, 0x118, 0); + cec_arbit_bit_time_set(5, 0x000, 0); + cec_arbit_bit_time_set(7, 0x2aa, 0); +@@ -1452,8 +1454,6 @@ static int hdmitx_cec_open(struct inode *inode, struct file *file) + cec_dev->cec_info.open_count++; + if (cec_dev->cec_info.open_count) { + cec_dev->cec_info.hal_ctl = 1; +- /* enable all cec features */ +- cec_config(0x2f, 1); + } + return 0; + } +@@ -1463,8 +1463,6 @@ static int hdmitx_cec_release(struct inode *inode, struct file *file) + cec_dev->cec_info.open_count--; + if (!cec_dev->cec_info.open_count) { + cec_dev->cec_info.hal_ctl = 0; +- /* disable all cec features */ +- cec_config(0x0, 1); + } + return 0; + } +diff --git a/drivers/amlogic/hdmi/hdmi_tx_20/hdmi_tx_main.c b/drivers/amlogic/hdmi/hdmi_tx_20/hdmi_tx_main.c +index 57105b6..0a7f914 100644 +--- a/drivers/amlogic/hdmi/hdmi_tx_20/hdmi_tx_main.c ++++ b/drivers/amlogic/hdmi/hdmi_tx_20/hdmi_tx_main.c +@@ -2467,9 +2467,9 @@ static int __init hdmitx_boot_para_setup(char *s) + init_flag |= INIT_FLAG_NOT_LOAD; + } else if (strncmp(token, "cec", 3) == 0) { + ret = kstrtoul(token+3, 16, &list); +- if ((list >= 0) && (list <= 0x2f)) ++ if ((list >= 0) && (list <= 0xff)) + hdmitx_device.cec_func_config = list; +- hdmi_print(INF, CEC "HDMI hdmi_cec_func_config:0x%x\n", ++ hdmi_print(IMP, CEC "HDMI hdmi_cec_func_config:0x%x\n", + hdmitx_device.cec_func_config); + } else if (strcmp(token, "forcergb") == 0) { + hdmitx_output_rgb(); diff --git a/projects/Odroid_C2/patches/u-boot/u-boot-0002-fix-power-off-wakeup.patch b/projects/Odroid_C2/patches/u-boot/u-boot-0002-fix-power-off-wakeup.patch new file mode 100644 index 0000000000..67ad437a48 --- /dev/null +++ b/projects/Odroid_C2/patches/u-boot/u-boot-0002-fix-power-off-wakeup.patch @@ -0,0 +1,1468 @@ +From 6e05bb98a2f4b4c45ad0e77eeb014f366ecac3b5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 13 Aug 2016 17:23:22 +0200 +Subject: [PATCH 1/6] Fix secure_task loop + +--- + arch/arm/cpu/armv8/gxb/firmware/scp_task/misc.S | 4 ++-- + arch/arm/cpu/armv8/gxb/firmware/scp_task/user_task.c | 7 +------ + 2 files changed, 3 insertions(+), 8 deletions(-) + +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/misc.S b/arch/arm/cpu/armv8/gxb/firmware/scp_task/misc.S +index 4ce73f2..9b97da3 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/misc.S ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/misc.S +@@ -19,6 +19,6 @@ bss_loop: + + .align 2 + _bss_start: +-.long _bss_start ++.long _bssstart + _bss_end: +-.long _bss_end +\ No newline at end of file ++.long _bssend +\ No newline at end of file +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/user_task.c b/arch/arm/cpu/armv8/gxb/firmware/scp_task/user_task.c +index 53a35c4..b2f6394 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/user_task.c ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/user_task.c +@@ -64,13 +64,8 @@ void secure_task(void) + presume = (struct resume_param *)(response+1); + presume->method = resume_data.method; + } +- +- /* FIXME : __switch_back_highmb() ? */ +- while(1) +- ; + } +- +- __switch_back_highmb(); ++ __switch_back_securemb(); + } + } + + +From e18fc08f3e9675dd6e418fd938bcf05e9d8d287d Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 13 Aug 2016 17:23:22 +0200 +Subject: [PATCH 2/6] Use power_off/on_at_24M to turn off/on blue led + +--- + board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +index 65633b4..374481a 100644 +--- a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c ++++ b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +@@ -96,15 +96,16 @@ static void power_on_at_clk81(void) + power_on_3v3(); + } + ++/*odroidc2 GPIOAO_13 powr on :0, power_off :1*/ + static void power_off_at_24M(void) + { + //LED gpioao_13 +- aml_update_bits(AO_GPIO_O_EN_N, 1<<29, 0); ++ aml_update_bits(AO_GPIO_O_EN_N, 1<<29, 1<<29); + } + + static void power_on_at_24M(void) + { +- aml_update_bits(AO_GPIO_O_EN_N, 1<<29, 1<<29); ++ aml_update_bits(AO_GPIO_O_EN_N, 1<<29, 0); + } + + static void power_off_at_32k(void) +@@ -201,7 +202,7 @@ void set_GPIOAO_BIT13(void) + + void set_custom_gpio_status(void) + { +- set_GPIOAO_BIT13(); ++ //set_GPIOAO_BIT13(); + set_GPIOX_BIT11(); + set_GPIOX_BIT19(); + set_GPIOY_BIT14(); + +From 03115f43534f9d29f952c557d3846028c4ecdf7c Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 13 Aug 2016 17:23:22 +0200 +Subject: [PATCH 3/6] Fix power off/on vcck + +GPIOAO.BIT2 is used for VCCK_CON according to odroid-c2_rev0.2_20160226.pdf + +Also disables power off/on 3v3 +--- + board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +index 374481a..c4d15b8 100644 +--- a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c ++++ b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +@@ -62,25 +62,25 @@ void pwm_set_voltage(unsigned int id, unsigned int voltage) + + static void power_off_3v3(void) + { +- aml_update_bits(AO_GPIO_O_EN_N, 1<<2, 0); +- aml_update_bits(AO_GPIO_O_EN_N, 1<<18, 1<<18); ++ //aml_update_bits(AO_GPIO_O_EN_N, 1<<2, 0); ++ //aml_update_bits(AO_GPIO_O_EN_N, 1<<18, 1<<18); + } + static void power_on_3v3(void) + { +- aml_update_bits(AO_GPIO_O_EN_N, 1<<2, 0); +- aml_update_bits(AO_GPIO_O_EN_N, 1<<18, 0); ++ //aml_update_bits(AO_GPIO_O_EN_N, 1<<2, 0); ++ //aml_update_bits(AO_GPIO_O_EN_N, 1<<18, 0); + } + +-/*p200/201 GPIOAO_4 powr on :1, power_off :0*/ ++/*odroidc2 GPIOAO_2 powr on :1, power_off :0*/ + static void power_off_vcck(void) + { +- aml_update_bits(AO_GPIO_O_EN_N, 1<<4, 0); +- aml_update_bits(AO_GPIO_O_EN_N, 1<<20, 0); ++ aml_update_bits(AO_GPIO_O_EN_N, 1<<2, 0); ++ aml_update_bits(AO_GPIO_O_EN_N, 1<<18, 0); + } + static void power_on_vcck(void) + { +- aml_update_bits(AO_GPIO_O_EN_N, 1<<4, 0); +- aml_update_bits(AO_GPIO_O_EN_N, 1<<20, 1<<20); ++ aml_update_bits(AO_GPIO_O_EN_N, 1<<2, 0); ++ aml_update_bits(AO_GPIO_O_EN_N, 1<<18, 1<<18); + } + + static void power_off_at_clk81(void) + +From 96d7386d8270a8684c3a651fdc20dbc1c2b58226 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 13 Aug 2016 17:23:22 +0200 +Subject: [PATCH 4/6] Disable power-key wakeup + +GPIOAO.BIT3 is used for TF_3V3N_1V8_EN according to odroid-c2_rev0.2_20160226.pdf +--- + board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +index c4d15b8..f6f2a7d 100644 +--- a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c ++++ b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +@@ -249,10 +249,12 @@ unsigned int detect_key(unsigned int suspend_from) + cec_node_init(); + } + #endif ++#if 0 + if ((readl(AO_GPIO_I) & (1<<3)) == 0) { + exit_reason = POWER_KEY_WAKEUP; + break; + } ++#endif + if (time_out != 0) { + if ((get_time() - init_time) >= time_out * 1000 * 1000) { + exit_reason = AUTO_WAKEUP; + +From 57c021cfc6504569aa66d26dc3cd17b97155eddb Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sat, 13 Aug 2016 17:23:22 +0200 +Subject: [PATCH 5/6] Backport remote-power-key wakeup code + +--- + .../cpu/armv8/gxb/firmware/scp_task/scp_remote.c | 93 ++++++++++++++++++++-- + 1 file changed, 88 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/scp_remote.c b/arch/arm/cpu/armv8/gxb/firmware/scp_task/scp_remote.c +index e73d172..e3cabb7 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/scp_remote.c ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/scp_remote.c +@@ -18,22 +18,105 @@ enum{ + DECODEMODE_MAX + }; + ++typedef struct reg_remote { ++ int reg; ++ unsigned int val; ++} reg_remote; ++#define CONFIG_END 0xffffffff + #define IR_POWER_KEY_MASK 0xffffffff ++#if 0 ++//32K ++static const reg_remote RDECODEMODE_NEC[] = { ++ {AO_MF_IR_DEC_LDR_ACTIVE, 350 << 16 | 260 << 0}, ++ {AO_MF_IR_DEC_LDR_IDLE, 200 << 16 | 120 << 0}, ++ {AO_MF_IR_DEC_LDR_REPEAT, 100 << 16 | 70 << 0}, ++ {AO_MF_IR_DEC_BIT_0, 50 << 16 | 20 << 0}, ++ {AO_MF_IR_DEC_REG0, 3 << 28 | (0xFA0 << 12)}, ++ {AO_MF_IR_DEC_STATUS, (100 << 20) | (45 << 10)}, ++ {AO_MF_IR_DEC_REG1, 0x600fdf00}, ++ {AO_MF_IR_DEC_REG2, 0x0}, ++ {AO_MF_IR_DEC_DURATN2, 0}, ++ {AO_MF_IR_DEC_DURATN3, 0}, ++ {CONFIG_END, 0} ++}; ++#else ++//24M ++static const reg_remote RDECODEMODE_NEC[] = { ++ {AO_MF_IR_DEC_LDR_ACTIVE, 477 << 16 | 400 << 0}, ++ {AO_MF_IR_DEC_LDR_IDLE, 248 << 16 | 202 << 0}, ++ {AO_MF_IR_DEC_LDR_REPEAT, 130 << 16 | 110 << 0}, ++ {AO_MF_IR_DEC_BIT_0, 60 << 16 | 48 << 0}, ++ {AO_MF_IR_DEC_REG0, 3 << 28 | (0xFA0 << 12) | 0x13}, ++ {AO_MF_IR_DEC_STATUS, (111 << 20) | (100 << 10)}, ++ {AO_MF_IR_DEC_REG1, 0x9f50}, ++ {AO_MF_IR_DEC_REG2, 0x0}, ++ {AO_MF_IR_DEC_DURATN2, 0}, ++ {AO_MF_IR_DEC_DURATN3, 0}, ++ {CONFIG_END, 0} ++}; ++#endif ++ ++static const reg_remote *remoteregsTab[] = { ++ RDECODEMODE_NEC, ++}; ++ ++void setremotereg(const reg_remote * r) ++{ ++ writel(r->val, r->reg); ++} ++ ++int set_remote_mode(int mode) ++{ ++ const reg_remote *reg; ++ reg = remoteregsTab[mode]; ++ while (CONFIG_END != reg->reg) ++ setremotereg(reg++); ++ return 0; ++} ++ ++/***************************************************************** ++** ++** func : ir_remote_init ++** in this function will do pin configuration and and initialize for ++** IR Remote hardware decoder mode at 32kHZ on ARC. ++** ++********************************************************************/ ++static int ir_remote_init_32k_mode(void) ++{ ++ //volatile unsigned int status,data_value; ++ int val = readl(AO_RTI_PIN_MUX_REG); ++ writel((val | (1 << 0)), AO_RTI_PIN_MUX_REG); ++ set_remote_mode(DECODEMODE_NEC); ++ //status = readl(AO_MF_IR_DEC_STATUS); ++ uart_put_hex(readl(AO_MF_IR_DEC_STATUS), 32); ++ //data_value = readl(AO_MF_IR_DEC_FRAME); ++ uart_put_hex(readl(AO_MF_IR_DEC_FRAME), 32); ++ ++ //step 2 : request nec_remote irq & enable it ++ return 0; ++} ++ ++void init_custom_trigger(void) ++{ ++ ir_remote_init_32k_mode(); ++} ++ + static unsigned int kk[] = { +- 0xe51afb04, ++ 0x23dc4db2, + }; + static int init_remote(void) + { +- uart_put_hex(readl(AO_IR_DEC_STATUS), 32); +- uart_put_hex(readl(AO_IR_DEC_FRAME), 32); ++ //uart_put_hex(readl(AO_IR_DEC_STATUS), 32); ++ //uart_put_hex(readl(AO_IR_DEC_FRAME), 32); ++ init_custom_trigger(); + return 0; + } + + static int remote_detect_key(void) + { + unsigned power_key; +- if (((readl(AO_IR_DEC_STATUS))>>3) & 0x1) { +- power_key = readl(AO_IR_DEC_FRAME); ++ if (((readl(AO_MF_IR_DEC_STATUS))>>3) & 0x1) { ++ power_key = readl(AO_MF_IR_DEC_FRAME); + if ((power_key&IR_POWER_KEY_MASK) == kk[DECODEMODE_NEC]) + return 1; + + +From 005dc1f22f3d3097dbabc6d25cc6e3b54741671b Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 24 Aug 2016 20:04:36 +0200 +Subject: [PATCH 6/6] Fix CEC wakeup + +--- + .../cpu/armv8/gxb/firmware/scp_task/cec_tx_reg.h | 33 +- + .../cpu/armv8/gxb/firmware/scp_task/hdmi_cec_arc.c | 840 ++++++++------------- + arch/arm/cpu/armv8/gxb/firmware/scp_task/suspend.c | 8 +- + .../cpu/armv8/gxb/firmware/scp_task/task_apis.h | 4 +- + .../odroidc2/firmware/scp_task/pwr_ctrl.c | 16 +- + 5 files changed, 349 insertions(+), 552 deletions(-) + +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/cec_tx_reg.h b/arch/arm/cpu/armv8/gxb/firmware/scp_task/cec_tx_reg.h +index 8f4496d..e88be16 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/cec_tx_reg.h ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/cec_tx_reg.h +@@ -197,6 +197,7 @@ typedef unsigned int uint32_t; + #define ONE_TOUCH_PLAY_MASK 1 + #define ONE_TOUCH_STANDBY_MASK 2 + #define AUTO_POWER_ON_MASK 3 ++#define STREAMPATH_POWER_ON_MASK 4 + + //#define P_HHI_GCLK_MPEG2 CBUS_REG_ADDR(HHI_GCLK_MPEG2) + //#define P_HHI_HDMI_CLK_CNTL CBUS_REG_ADDR(HHI_HDMI_CLK_CNTL) +@@ -224,6 +225,13 @@ enum _cec_log_dev_addr_e { + CEC_UNREGISTERED_ADDR + }; + ++typedef enum { ++ POWER_ON = 0x00, ++ POWER_STANDBY, ++ TRANS_STANDBY_TO_ON, ++ TRANS_ON_TO_STANDBY, ++} cec_power_status_e; ++ + typedef enum { + CEC_UNRECONIZED_OPCODE = 0x0, + CEC_NOT_CORRECT_MODE_TO_RESPOND, +@@ -240,37 +248,18 @@ typedef enum { + + /* cec message structure */ + typedef struct { +- unsigned char msg[16]; ++ unsigned char msg[MAX_MSG]; + unsigned char msg_len; +-} cec_msg_buf_t; +- +-typedef struct { +- cec_msg_buf_t buf[4]; // message memory +- unsigned char power_status; +- unsigned char log_addr; + unsigned char cec_power; +- unsigned char test; +- unsigned char rx_write_pos; +- unsigned char rx_read_pos; +- unsigned char rx_buf_size; ++ unsigned char log_addr; ++ unsigned int phy_addr; + } cec_msg_t; + + cec_msg_t cec_msg; + unsigned long hdmi_cec_func_config; + void cec_node_init(void); +-void cec_power_on(void); +-void cec_off(void); + unsigned int cec_handler(void); + void remote_cec_hw_reset(void); +-unsigned char remote_cec_ll_rx(void); +-int remote_cec_ll_tx(unsigned char *msg, unsigned char len); +-void cec_wr_reg(unsigned long addr, unsigned long data); +-unsigned long cec_rd_reg(unsigned long addr); +-void cec_arbit_bit_time_set(unsigned bit_set, unsigned time_set); +-//void cec_give_device_power_status(void); +-void cec_inactive_source(void); +-void cec_set_standby(void); +- + extern void udelay(int i); + + // The following registers are for fine tuning CEC bit timing parameters. +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/hdmi_cec_arc.c b/arch/arm/cpu/armv8/gxb/firmware/scp_task/hdmi_cec_arc.c +index 33f3d83..79f8dbc 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/hdmi_cec_arc.c ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/hdmi_cec_arc.c +@@ -11,41 +11,23 @@ + #define CEC_DBG_PRINT + #ifdef CEC_DBG_PRINT + #define cec_dbg_print(s,v) {uart_puts(s);uart_put_hex(v,8);} +- #define cec_dbg_prints(s) {uart_puts(s);} ++ #define cec_dbg_printx(s,v,x) {uart_puts(s);uart_put_hex(v,x);} ++ #define cec_dbg_prints(s) {uart_puts(s);wait_uart_empty();} + #else + #define cec_dbg_print(s,v) ++ #define cec_dbg_printx(s,v,x) + #define cec_dbg_prints(s) + #endif + +-void cec_reset_addr(void); +-struct cec_tx_msg_t { +- unsigned char buf[16]; +- unsigned char retry; +- unsigned char len; +-}; +- +-#define CEX_TX_MSG_BUF_NUM 8 +-#define CEC_TX_MSG_BUF_MASK (CEX_TX_MSG_BUF_NUM - 1) +- +-struct cec_tx_msg { +- struct cec_tx_msg_t msg[CEX_TX_MSG_BUF_NUM]; +- unsigned int send_idx; +- unsigned int queue_idx; +-}; +- +-struct cec_tx_msg cec_tx_msgs = {}; +- +- +-int cec_strlen(char *p) ++static int cec_strlen(char *p) + { + int i=0; +- + while (*p++) + i++; + return i; + } + +-void *cec_memcpy(void *memto, const void *memfrom, unsigned int size) ++static void *cec_memcpy(void *memto, const void *memfrom, unsigned int size) + { + char *tempfrom = (char *)memfrom; + char *tempto = (char *)memto; +@@ -57,61 +39,46 @@ void *cec_memcpy(void *memto, const void *memfrom, unsigned int size) + return memto; + } + +-#define waiting_aocec_free() \ +- do {\ +- unsigned long cnt = 0;\ +- while (readl(P_AO_CEC_RW_REG) & (1<<23))\ +- {\ +- if (5000 == cnt++)\ +- {\ +- break;\ +- }\ +- }\ +- } while(0) +- +-unsigned long cec_rd_reg(unsigned long addr) ++static void waiting_aocec_free(void) { ++ unsigned long cnt = 0; ++ while (readl(P_AO_CEC_RW_REG) & (1<<23)) ++ { ++ if (8192 <= cnt++) ++ { ++ cec_dbg_printx("\nWARNING: waiting_aocec_free cnt:0x", cnt, 16); ++ cec_dbg_prints("\n"); ++ break; ++ } ++ } ++} ++ ++static unsigned long cec_rd_reg(unsigned long addr) + { + unsigned long data32; + waiting_aocec_free(); + 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 ++ data32 |= 0 << 16; // [16] cec_reg_wr ++ data32 |= 0 << 8; // [15:8] cec_reg_wrdata ++ data32 |= (addr & 0xff) << 0; // [7:0] cec_reg_addr + writel(data32, P_AO_CEC_RW_REG); + waiting_aocec_free(); + data32 = ((readl(P_AO_CEC_RW_REG)) >> 24) & 0xff; +- return (data32); +-} /* cec_rd_reg */ ++ return data32; ++} + +-void cec_wr_reg (unsigned long addr, unsigned long data) ++static void cec_wr_reg(unsigned long addr, unsigned long data) + { + unsigned long data32; + waiting_aocec_free(); + 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 ++ data32 |= 1 << 16; // [16] cec_reg_wr ++ data32 |= (data & 0xff) << 8; // [15:8] cec_reg_wrdata ++ data32 |= (addr & 0xff) << 0; // [7:0] cec_reg_addr + writel(data32, P_AO_CEC_RW_REG); +-} /* aocec_wr_only_reg */ +- +-void cec_off(void) +-{ +- /* +- * [2:1] cntl_clk: 0=Disable clk (Power-off mode); +- * 1=Enable gated clock (Normal mode); +- * 2=Enable free-run clk (Debug mode). +- */ +- writel(0x0, P_AO_CEC_GEN_CNTL); +-} +- +-void cec_rx_read_pos_plus(void) +-{ +- (cec_msg.rx_read_pos == cec_msg.rx_buf_size - 1) ? +- (cec_msg.rx_read_pos = 0) : +- (cec_msg.rx_read_pos++); ++ waiting_aocec_free(); + } + +-void cec_arbit_bit_time_set(unsigned bit_set, unsigned time_set) ++static void cec_arbit_bit_time_set(unsigned bit_set, unsigned time_set) + { + //11bit:bit[10:0] + switch (bit_set) { +@@ -134,7 +101,7 @@ void cec_arbit_bit_time_set(unsigned bit_set, unsigned time_set) + } + } + +-void cec_hw_buf_clear(void) ++static void cec_hw_buf_clear(void) + { + cec_wr_reg(CEC_RX_MSG_CMD, RX_DISABLE); + cec_wr_reg(CEC_TX_MSG_CMD, TX_ABORT); +@@ -150,7 +117,8 @@ void cec_hw_buf_clear(void) + + void remote_cec_hw_reset(void) + { +- cec_dbg_prints("hw reset\n"); ++ cec_dbg_prints("\nremote_cec_hw_reset\n"); ++ + /* + * clock switch to 32k + */ +@@ -174,561 +142,399 @@ void remote_cec_hw_reset(void) + cec_arbit_bit_time_set(7, 0x2aa); + } + +-unsigned char remote_cec_ll_rx(void) +-{ +- int i; +- int print = 1; +- unsigned char rx_msg_length = cec_rd_reg(CEC_RX_MSG_LENGTH) + 1; +- +- cec_dbg_prints("cec R:"); +- for (i = 0; i < rx_msg_length; i++) { +- cec_msg.buf[cec_msg.rx_write_pos].msg[i] = cec_rd_reg(CEC_RX_MSG_0_HEADER + i); +- if (print) { +- cec_dbg_print(" ", cec_msg.buf[cec_msg.rx_write_pos].msg[i]); +- } +- if (i == 1 && cec_msg.buf[cec_msg.rx_write_pos].msg[i] == CEC_OC_VENDOR_COMMAND_WITH_ID) { +- /* do not print command with ID */ +- print = 0; +- } +- } +- cec_msg.buf[cec_msg.rx_write_pos].msg_len = rx_msg_length; +- cec_dbg_prints("\n"); +- +- return 0; +-} +-void cec_buf_clear(void) +-{ +- int i; +- +- for (i = 0; i < 16; i++) +- cec_msg.buf[cec_msg.rx_read_pos].msg[i] = 0; +-} +- +-void cec_tx_buf_init(void) +-{ +- int i, j; +- for (j = 0; j < CEX_TX_MSG_BUF_NUM; j++) { +- for (i = 0; i < 16; i++) { +- cec_tx_msgs.msg[j].buf[i] = 0; +- } +- cec_tx_msgs.msg[j].retry = 0; +- cec_tx_msgs.msg[j].len = 0; +- } +-} +- +-int cec_queue_tx_msg(unsigned char *msg, unsigned char len) +-{ +- int s_idx, q_idx; +- +- s_idx = cec_tx_msgs.send_idx; +- q_idx = cec_tx_msgs.queue_idx; +- if (((q_idx + 1) & CEC_TX_MSG_BUF_MASK) == s_idx) { +- cec_dbg_prints("tx buffer full, abort msg\n"); +- cec_reset_addr(); +- return -1; +- } +- if (len && msg) { +- cec_memcpy(cec_tx_msgs.msg[q_idx].buf, msg, len); +- cec_tx_msgs.msg[q_idx].len = len; +- cec_tx_msgs.queue_idx = (q_idx + 1) & CEC_TX_MSG_BUF_MASK; +- } +- return 0; +-} +- +-int cec_triggle_tx(unsigned char *msg, unsigned char len) +-{ +- int i; +- +- if ((TX_IDLE == cec_rd_reg(CEC_TX_MSG_STATUS)) || +- (TX_DONE == cec_rd_reg(CEC_TX_MSG_STATUS))) { +- cec_dbg_prints("cec T:"); +- for (i = 0; i < len; i++) { +- cec_wr_reg(CEC_TX_MSG_0_HEADER + i, msg[i]); +- cec_dbg_print(" ", msg[i]); +- } +- cec_dbg_prints("\n"); +- cec_wr_reg(CEC_TX_MSG_LENGTH, len-1); +- cec_wr_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); //TX_REQ_NEXT +- return 0; +- } +- return -1; +-} +- +-int remote_cec_ll_tx(unsigned char *msg, unsigned char len) +-{ +- cec_queue_tx_msg(msg, len); +- cec_triggle_tx(msg, len); +- +- return 0; +-} +- +-int ping_cec_ll_tx(unsigned char *msg, unsigned char len) ++static int cec_triggle_tx(unsigned char *msg, unsigned char len) + { +- int i; +- int ret = 0; +- unsigned int n = 900; +- unsigned int reg; +- +- ret = cec_rd_reg(CEC_RX_MSG_STATUS); +- cec_dbg_print("rx stat:", ret); +- ret = cec_rd_reg(CEC_TX_MSG_STATUS); +- cec_dbg_print(", tx stat:", ret); +- cec_dbg_prints("\n"); +- +- while (cec_rd_reg(CEC_TX_MSG_STATUS) == TX_BUSY) { +- /* +- * waiting tx to idle if it is busy, other device may in tx state +- */ +- } +- if (cec_rd_reg(CEC_TX_MSG_STATUS) == TX_ERROR) +- cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ unsigned int i, cnt = 0; + ++ cec_dbg_prints(" T:"); + for (i = 0; i < len; i++) { + cec_wr_reg(CEC_TX_MSG_0_HEADER + i, msg[i]); ++ cec_dbg_print(" ", msg[i]); + } +- cec_wr_reg(CEC_TX_MSG_LENGTH, len-1); +- cec_wr_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); //TX_REQ_NEXT +- ret = cec_rd_reg(CEC_RX_MSG_STATUS); +- cec_dbg_print("rx stat:", ret); +- ret = cec_rd_reg(CEC_TX_MSG_STATUS); +- cec_dbg_print(", tx stat:", ret); + cec_dbg_prints("\n"); ++ cec_wr_reg(CEC_TX_MSG_LENGTH, len - 1); + +- while (1) { +- reg = cec_rd_reg(CEC_TX_MSG_STATUS); +- if ( reg == TX_DONE ) { +- ret = TX_DONE; +- cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); +- cec_dbg_prints("ping_cec_ll_tx:TX_DONE\n") +- break; +- } ++ do { ++ cec_wr_reg(CEC_TX_MSG_CMD, TX_REQ_CURRENT); ++ cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ cnt++; ++ } while (cec_rd_reg(CEC_TX_NUM_MSG)); + +- if (reg == TX_ERROR) { +- ret = TX_ERROR; +- cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); +- cec_dbg_prints("ping_cec_ll_tx:TX_ERROR\n") +- break; +- } +- if (!(n--)) { +- cec_dbg_prints("ping_cec_ll_tx:TX_BUSY\n") +- ret = TX_BUSY; +- cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); +- break; +- } +- if (reg != TX_BUSY) { +- break; +- } +- _udelay(500); ++ if (cnt > 1) { ++ cec_dbg_printx("WARNING: cec_triggle_tx cnt:0x", cnt, 16); ++ cec_dbg_prints("\n"); + } + +- return ret; ++ _udelay(150); ++ return 0; + } + +-void cec_imageview_on(void) +-{ +- unsigned char msg[2]; +- +- msg[0] = ((cec_msg.log_addr & 0xf) << 4)| CEC_TV_ADDR; +- msg[1] = CEC_OC_IMAGE_VIEW_ON; +- +- ping_cec_ll_tx(msg, 2); ++#define DEVICE_TV 0 ++#define DEVICE_RECORDER 1 ++#define DEVICE_RESERVED 2 ++#define DEVICE_TUNER 3 ++#define DEVICE_PLAYBACK 4 ++#define DEVICE_AUDIO_SYSTEM 5 ++#define DEVICE_PURE_CEC_SWITCH 6 ++#define DEVICE_VIDEO_PROCESSOR 7 ++ ++static unsigned char log_addr_to_devtype(unsigned char addr) ++{ ++ static unsigned char addr_map[] = { ++ DEVICE_TV, ++ DEVICE_RECORDER, ++ DEVICE_RECORDER, ++ DEVICE_TUNER, ++ DEVICE_PLAYBACK, ++ DEVICE_AUDIO_SYSTEM, ++ DEVICE_TUNER, ++ DEVICE_TUNER, ++ DEVICE_PLAYBACK, ++ DEVICE_RECORDER, ++ DEVICE_TUNER, ++ DEVICE_PLAYBACK, ++ DEVICE_RESERVED, ++ DEVICE_RESERVED, ++ DEVICE_TV, ++ DEVICE_PLAYBACK ++ }; ++ return addr_map[addr & 0xf]; + } + +-void cec_report_physical_address(void) ++static void cec_report_physical_address(void) + { + unsigned char msg[5]; +- unsigned char phy_addr_ab = (readl(P_AO_DEBUG_REG1) >> 8) & 0xff; +- unsigned char phy_addr_cd = readl(P_AO_DEBUG_REG1) & 0xff; ++ cec_dbg_prints("cec_report_physical_address\n"); + +- msg[0] = ((cec_msg.log_addr & 0xf) << 4)| CEC_BROADCAST_ADDR; ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_BROADCAST_ADDR; + msg[1] = CEC_OC_REPORT_PHYSICAL_ADDRESS; +- msg[2] = phy_addr_ab; +- msg[3] = phy_addr_cd; +- msg[4] = CEC_PLAYBACK_DEVICE_TYPE; ++ msg[2] = (cec_msg.phy_addr >> 8) & 0xff; ++ msg[3] = (cec_msg.phy_addr >> 0) & 0xff; ++ msg[4] = log_addr_to_devtype(cec_msg.log_addr); + +- remote_cec_ll_tx(msg, 5); ++ cec_triggle_tx(msg, 5); + } + +-void cec_report_device_power_status(void) ++static void cec_report_power_status(unsigned char initiator) + { + unsigned char msg[3]; ++ cec_dbg_printx("cec_report_power_status initiator:0x", initiator, 4); ++ cec_dbg_prints("\n"); + +- msg[0] = ((cec_msg.log_addr & 0xf) << 4)| CEC_TV_ADDR; ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | (initiator & 0xf); + msg[1] = CEC_OC_REPORT_POWER_STATUS; +- msg[2] = cec_msg.power_status; ++ msg[2] = POWER_STANDBY; + +- remote_cec_ll_tx(msg, 3); ++ cec_triggle_tx(msg, 3); + } + +-void cec_set_stream_path(void) ++static void cec_feature_abort(unsigned char reason, unsigned char initiator) + { +- unsigned char phy_addr_ab = (readl(P_AO_DEBUG_REG1) >> 8) & 0xff; +- unsigned char phy_addr_cd = readl(P_AO_DEBUG_REG1) & 0xff; +- +- if ((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) { +- if ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) { +- if ((phy_addr_ab == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) && +- (phy_addr_cd == cec_msg.buf[cec_msg.rx_read_pos].msg[3])) { +- cec_msg.cec_power = 0x1; +- } +- } +- } ++ unsigned char msg[4]; ++ cec_dbg_print("cec_feature_abort reason:0x", reason); ++ cec_dbg_printx(", initiator:0x", initiator, 4); ++ cec_dbg_prints("\n"); ++ ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | (initiator & 0xf); ++ msg[1] = CEC_OC_FEATURE_ABORT; ++ msg[2] = cec_msg.msg[1]; ++ msg[3] = reason; ++ ++ cec_triggle_tx(msg, 4); + } + +-void cec_device_vendor_id(void) ++static void cec_menu_status(unsigned char menu_status, unsigned char initiator) + { +- unsigned char msg[5]; ++ unsigned char msg[3]; ++ cec_dbg_print("cec_menu_status menu_status:0x", menu_status); ++ cec_dbg_printx(", initiator:0x", initiator, 4); ++ cec_dbg_prints("\n"); + +- msg[0] = ((cec_msg.log_addr & 0xf) << 4)| CEC_BROADCAST_ADDR; +- msg[1] = CEC_OC_DEVICE_VENDOR_ID; +- msg[2] = 0x00; +- msg[3] = 0x00; +- msg[4] = 0x00; ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | (initiator & 0xf); ++ msg[1] = CEC_OC_MENU_STATUS; ++ msg[2] = menu_status; + +- remote_cec_ll_tx(msg, 5); ++ cec_triggle_tx(msg, 3); + } + +-void cec_feature_abort(void) ++static void cec_set_stream_path(unsigned char initiator) + { +- if (cec_msg.buf[cec_msg.rx_read_pos].msg[1] != 0xf) { +- unsigned char msg[4]; +- +- msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_TV_ADDR; +- msg[1] = CEC_OC_FEATURE_ABORT; +- msg[2] = cec_msg.buf[cec_msg.rx_read_pos].msg[1]; +- msg[3] = CEC_UNRECONIZED_OPCODE; ++ unsigned int phy_addr = (cec_msg.msg[2] << 8) | cec_msg.msg[3]; ++ cec_dbg_printx("cec_set_stream_path initiator:0x", initiator, 4); ++ cec_dbg_printx(", phy_addr:0x", phy_addr, 16); ++ cec_dbg_prints("\n"); + +- remote_cec_ll_tx(msg, 4); ++ if ((hdmi_cec_func_config >> STREAMPATH_POWER_ON_MASK) & 0x1) { ++ if (cec_msg.phy_addr == phy_addr && initiator == CEC_TV_ADDR) { ++ cec_msg.cec_power = 0x1; ++ } + } + } + +-void cec_menu_status_smp(int menu_status) ++static void cec_routing_change(unsigned char initiator) + { +- unsigned char msg[3]; +- +- msg[0] = ((cec_msg.log_addr & 0xf) << 4)| CEC_TV_ADDR; +- msg[1] = CEC_OC_MENU_STATUS; +- msg[2] = menu_status; ++ unsigned int phy_addr = (cec_msg.msg[4] << 8) | cec_msg.msg[5]; ++ cec_dbg_printx("cec_routing_change initiator:0x", initiator, 4); ++ cec_dbg_printx(", phy_addr:0x", phy_addr, 16); ++ cec_dbg_prints("\n"); + +- remote_cec_ll_tx(msg, 3); ++ if ((hdmi_cec_func_config >> STREAMPATH_POWER_ON_MASK) & 0x1) { ++ if (cec_msg.phy_addr == phy_addr && initiator == CEC_TV_ADDR) { ++ cec_msg.cec_power = 0x1; ++ } ++ } + } + +-void cec_inactive_source(void) ++static void cec_user_control_pressed(void) + { +- unsigned char msg[4]; +- unsigned char phy_addr_ab = (readl(P_AO_DEBUG_REG1) >> 8) & 0xff; +- unsigned char phy_addr_cd = readl(P_AO_DEBUG_REG1) & 0xff; +- +- msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_TV_ADDR; +- msg[1] = CEC_OC_INACTIVE_SOURCE; +- msg[2] = phy_addr_ab; +- msg[3] = phy_addr_cd; ++ cec_dbg_print("cec_user_control_pressed operation:0x", cec_msg.msg[2]); ++ cec_dbg_prints("\n"); + +- remote_cec_ll_tx(msg, 4); ++ if ((hdmi_cec_func_config >> ONE_TOUCH_STANDBY_MASK) & 0x1) { ++ if ((0x40 == cec_msg.msg[2]) || // Power ++ (0x6b == cec_msg.msg[2]) || // Power Toggle Function ++ (0x6d == cec_msg.msg[2]) || // Power On Function ++ (0x0a == cec_msg.msg[2]) || // Setup Menu ++ (0x0b == cec_msg.msg[2]) || // Contents Menu ++ (0x10 == cec_msg.msg[2]) || // Media Top Menu ++ (0x11 == cec_msg.msg[2]) || // Media Context-sensitive Menu ++ (0x09 == cec_msg.msg[2])) { // Root Menu ++ cec_msg.cec_power = 0x1; ++ } ++ } + } + +-void cec_set_standby(void) ++static void cec_device_vendor_id(void) + { +- unsigned char msg[2]; ++ unsigned char msg[5]; ++ cec_dbg_prints("cec_device_vendor_id\n"); ++ + msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_BROADCAST_ADDR; +- msg[1] = CEC_OC_STANDBY; ++ msg[1] = CEC_OC_DEVICE_VENDOR_ID; ++ msg[2] = 0x00; ++ msg[3] = 0x00; ++ msg[4] = 0x00; + +- remote_cec_ll_tx(msg, 2); ++ cec_triggle_tx(msg, 5); + } + +-void cec_give_deck_status(void) ++static void cec_deck_status(unsigned char initiator) + { + unsigned char msg[3]; ++ cec_dbg_printx("cec_deck_status initiator:0x", initiator, 4); ++ cec_dbg_prints("\n"); + +- msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_TV_ADDR; ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | (initiator & 0xf); + msg[1] = CEC_OC_DECK_STATUS; +- msg[2] = 0x1a; ++ msg[2] = 0x1a; // DECK_STOP + +- remote_cec_ll_tx(msg, 3); ++ cec_triggle_tx(msg, 3); + } + +-void cec_set_osd_name(void) ++static void cec_set_osd_name(unsigned char initiator) + { + unsigned char msg[16]; + unsigned char osd_len = cec_strlen(CONFIG_CEC_OSD_NAME); ++ cec_dbg_printx("cec_set_osd_name initiator:0x", initiator, 4); ++ cec_dbg_prints("\n"); + +- msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_TV_ADDR; ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | (initiator & 0xf); + msg[1] = CEC_OC_SET_OSD_NAME; + cec_memcpy(&msg[2], CONFIG_CEC_OSD_NAME, osd_len); + +- remote_cec_ll_tx(msg, osd_len + 2); ++ cec_triggle_tx(msg, osd_len + 2); + } + +-void cec_get_version(void) ++static void cec_get_version(unsigned char initiator) + { +- unsigned char dest_log_addr = cec_msg.log_addr & 0xf; + unsigned char msg[3]; ++ cec_dbg_printx("cec_get_version initiator:0x", initiator, 4); ++ cec_dbg_prints("\n"); + +- if (0xf != dest_log_addr) { +- msg[0] = ((cec_msg.log_addr & 0xf) << 4) | CEC_TV_ADDR; +- msg[1] = CEC_OC_CEC_VERSION; +- msg[2] = CEC_VERSION_14A; +- remote_cec_ll_tx(msg, 3); +- } ++ msg[0] = ((cec_msg.log_addr & 0xf) << 4) | (initiator & 0xf); ++ msg[1] = CEC_OC_CEC_VERSION; ++ msg[2] = CEC_VERSION_14A; ++ ++ cec_triggle_tx(msg, 3); + } + +-unsigned int cec_handle_message(void) ++static unsigned int cec_handle_message(void) + { +- unsigned char opcode; +- +- if (((hdmi_cec_func_config>>CEC_FUNC_MASK) & 0x1) && +- (cec_msg.buf[cec_msg.rx_read_pos].msg_len > 1)) { +- opcode = cec_msg.buf[cec_msg.rx_read_pos].msg[1]; +- switch (opcode) { +- case CEC_OC_GET_CEC_VERSION: +- cec_get_version(); +- break; +- case CEC_OC_GIVE_DECK_STATUS: +- cec_give_deck_status(); +- break; +- case CEC_OC_GIVE_PHYSICAL_ADDRESS: +- cec_report_physical_address(); +- break; +- case CEC_OC_GIVE_DEVICE_VENDOR_ID: +- cec_device_vendor_id(); +- break; +- case CEC_OC_GIVE_OSD_NAME: +- cec_set_osd_name(); +- break; +- case CEC_OC_SET_STREAM_PATH: +- cec_set_stream_path(); +- break; +- case CEC_OC_GIVE_DEVICE_POWER_STATUS: +- cec_report_device_power_status(); +- break; +- case CEC_OC_USER_CONTROL_PRESSED: +- if (((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) && +- ((hdmi_cec_func_config >> AUTO_POWER_ON_MASK) & 0x1) && +- (cec_msg.buf[cec_msg.rx_read_pos].msg_len == 3) && +- ((0x40 == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) || +- (0x6d == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) || +- (0x09 == cec_msg.buf[cec_msg.rx_read_pos].msg[2]) )) { +- cec_msg.cec_power = 0x1; +- } +- break; +- case CEC_OC_MENU_REQUEST: +- cec_menu_status_smp(DEVICE_MENU_INACTIVE); +- break; +- default: +- break; ++ unsigned char initiator = (cec_msg.msg[0] >> 4) & 0xf; ++ unsigned char destination = cec_msg.msg[0] & 0xf; ++ unsigned char opcode = (cec_msg.msg_len > 1) ? cec_msg.msg[1] : CEC_OC_POLLING_MESSAGE; ++ unsigned char directly_addressed = (destination != CEC_BROADCAST_ADDR && destination == cec_msg.log_addr); ++ ++ cec_dbg_printx("cec_handle_message initiator:0x", initiator, 4); ++ cec_dbg_printx(", destination:0x", destination, 4); ++ cec_dbg_print(", opcode:0x", opcode); ++ cec_dbg_prints("\n"); ++ ++ switch (opcode) { ++ case CEC_OC_POLLING_MESSAGE: ++ break; ++ case CEC_OC_GET_CEC_VERSION: ++ if (directly_addressed) ++ cec_get_version(initiator); ++ break; ++ case CEC_OC_GIVE_DECK_STATUS: ++ cec_deck_status(initiator); ++ break; ++ case CEC_OC_GIVE_PHYSICAL_ADDRESS: ++ cec_report_physical_address(); ++ break; ++ case CEC_OC_GIVE_DEVICE_VENDOR_ID: ++ cec_device_vendor_id(); ++ break; ++ case CEC_OC_VENDOR_COMMAND: ++ case CEC_OC_VENDOR_COMMAND_WITH_ID: ++ break; ++ case CEC_OC_GIVE_OSD_NAME: ++ if (directly_addressed) ++ cec_set_osd_name(initiator); ++ break; ++ case CEC_OC_SET_STREAM_PATH: ++ cec_set_stream_path(initiator); ++ break; ++ case CEC_OC_ROUTING_CHANGE: ++ cec_routing_change(initiator); ++ break; ++ case CEC_OC_GIVE_DEVICE_POWER_STATUS: ++ if (directly_addressed) ++ cec_report_power_status(initiator); ++ break; ++ case CEC_OC_USER_CONTROL_PRESSED: ++ if (directly_addressed) ++ cec_user_control_pressed(); ++ break; ++ case CEC_OC_USER_CONTROL_RELEASED: ++ break; ++ case CEC_OC_MENU_REQUEST: ++ if (directly_addressed) ++ cec_menu_status(DEVICE_MENU_INACTIVE, initiator); ++ break; ++ case CEC_OC_ABORT_MESSAGE: ++ if (directly_addressed) ++ cec_feature_abort(CEC_UNRECONIZED_OPCODE, initiator); ++ break; ++ default: ++ if (directly_addressed) { ++ cec_dbg_print("WARNING: unhandled directly addressed opcode:0x", opcode); ++ cec_dbg_prints("\n"); ++ cec_feature_abort(CEC_UNABLE_TO_DETERMINE, initiator); + } ++ break; + } +- cec_rx_read_pos_plus(); + return 0; + } + +-void cec_reset_addr(void) ++static unsigned int cec_tx_irq_handler(void) + { +- remote_cec_hw_reset(); +- cec_wr_reg(CEC_LOGICAL_ADDR0, 0); +- cec_hw_buf_clear(); +- cec_wr_reg(CEC_LOGICAL_ADDR0, cec_msg.log_addr); +- _udelay(100); +- cec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | cec_msg.log_addr); ++ unsigned int cnt = 0; ++ unsigned int tx_msg_status = cec_rd_reg(CEC_TX_MSG_STATUS); ++ unsigned int tx_num_msg = cec_rd_reg(CEC_TX_NUM_MSG); ++ cec_dbg_printx("cec_tx_irq_handler tx_msg_status:0x", tx_msg_status, 4); ++ cec_dbg_printx(", tx_num_msg:0x", tx_num_msg, 4); ++ cec_dbg_prints("\n"); ++ ++ do { ++ cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); ++ cnt++; ++ } while (cec_rd_reg(CEC_TX_NUM_MSG)); ++ writel((1 << 1), P_AO_CEC_INTR_CLR); ++ ++ if (cnt > 1) { ++ cec_dbg_printx("WARNING: cec_tx_irq_handler cnt:0x", cnt, 16); ++ cec_dbg_prints("\n"); ++ } ++ ++ return 0; + } + +-unsigned int cec_handler(void) ++static unsigned int cec_rx_irq_handler(void) + { +- unsigned char s_idx; +- static int busy_count = 0; +- if (0xf == cec_rd_reg(CEC_RX_NUM_MSG)) { +- cec_wr_reg(CEC_RX_CLEAR_BUF, 0x1); +- cec_wr_reg(CEC_RX_CLEAR_BUF, 0x0); +- cec_wr_reg(CEC_RX_MSG_CMD, RX_ACK_CURRENT); +- cec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); +- cec_dbg_prints("error:hw_buf overflow\n"); +- } ++ unsigned int cnt = 0; ++ unsigned int rx_msg_status = cec_rd_reg(CEC_RX_MSG_STATUS); ++ unsigned int rx_num_msg = cec_rd_reg(CEC_RX_NUM_MSG); ++ cec_dbg_printx("cec_rx_irq_handler rx_msg_status:0x", rx_msg_status, 4); ++ cec_dbg_printx(", rx_num_msg:0x", rx_num_msg, 4); ++ cec_dbg_prints("\n"); + +- switch (cec_rd_reg(CEC_RX_MSG_STATUS)) { +- case RX_DONE: +- if (1 == cec_rd_reg(CEC_RX_NUM_MSG)) { +- remote_cec_ll_rx(); +- (cec_msg.rx_write_pos == cec_msg.rx_buf_size - 1) ? (cec_msg.rx_write_pos = 0) : (cec_msg.rx_write_pos++); ++ if (rx_num_msg) { ++ unsigned int i, rx_msg_length = cec_rd_reg(CEC_RX_MSG_LENGTH) + 1; ++ cec_dbg_prints(" R:"); ++ for (i = 0; i < rx_msg_length && i < MAX_MSG; i++) { ++ cec_msg.msg[i] = cec_rd_reg(CEC_RX_MSG_0_HEADER + i); ++ cec_dbg_print(" ", cec_msg.msg[i]); + } +- cec_wr_reg(CEC_RX_MSG_CMD, RX_ACK_CURRENT); +- cec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); +- cec_dbg_prints("RX_OK\n"); +- break; +- case RX_ERROR: +- cec_dbg_prints("RX_ERROR\n"); +- if (TX_ERROR == cec_rd_reg(CEC_TX_MSG_STATUS)) { +- cec_dbg_prints("TX_ERROR\n"); +- cec_reset_addr(); +- } else { +- cec_dbg_prints("TX_other\n"); +- cec_wr_reg(CEC_RX_MSG_CMD, RX_ACK_CURRENT); +- cec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); ++ for (; i < MAX_MSG; i++) { ++ cec_msg.msg[i] = 0x0; + } +- break; +- default: +- break; ++ cec_msg.msg_len = rx_msg_length; ++ cec_dbg_prints("\n"); + } + +- switch (cec_rd_reg(CEC_TX_MSG_STATUS)) { +- case TX_DONE: +- cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); +- cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK; +- s_idx = cec_tx_msgs.send_idx; +- if (cec_tx_msgs.send_idx != cec_tx_msgs.queue_idx) { +- cec_dbg_prints("TX_OK\n"); +- cec_triggle_tx(cec_tx_msgs.msg[s_idx].buf, +- cec_tx_msgs.msg[s_idx].len); +- } else { +- cec_dbg_prints("TX_END\n"); +- } +- busy_count = 0; +- break; ++ do { ++ cec_wr_reg(CEC_RX_MSG_CMD, RX_ACK_CURRENT); ++ cec_wr_reg(CEC_RX_MSG_CMD, RX_NO_OP); ++ cnt++; ++ } while (cec_rd_reg(CEC_RX_NUM_MSG)); ++ writel((1 << 2), P_AO_CEC_INTR_CLR); + +- case TX_ERROR: +- cec_dbg_prints("@TX_ERROR\n"); +- if (RX_ERROR == cec_rd_reg(CEC_RX_MSG_STATUS)) { +- cec_dbg_prints("@RX_ERROR\n"); +- cec_reset_addr(); +- } else { +- cec_wr_reg(CEC_TX_MSG_CMD, TX_NO_OP); +- s_idx = cec_tx_msgs.send_idx; +- if (cec_tx_msgs.msg[s_idx].retry < 5) { +- cec_tx_msgs.msg[s_idx].retry++; +- cec_triggle_tx(cec_tx_msgs.msg[s_idx].buf, +- cec_tx_msgs.msg[s_idx].len); +- } else { +- cec_dbg_prints("TX retry too much, abort msg\n"); +- cec_tx_msgs.send_idx = (cec_tx_msgs.send_idx + 1) & CEC_TX_MSG_BUF_MASK; +- } +- } +- busy_count = 0; +- break; ++ if (cnt > 2) { ++ cec_dbg_printx("WARNING: cec_rx_irq_handler cnt:0x", cnt, 16); ++ cec_dbg_prints("\n"); ++ } + +- case TX_IDLE: +- s_idx = cec_tx_msgs.send_idx; +- if (cec_tx_msgs.send_idx != cec_tx_msgs.queue_idx) { // triggle tx if idle +- cec_triggle_tx(cec_tx_msgs.msg[s_idx].buf, +- cec_tx_msgs.msg[s_idx].len); +- } +- busy_count = 0; +- break; ++ if (rx_num_msg) ++ cec_handle_message(); + +- case TX_BUSY: +- busy_count++; +- if (busy_count >= 2000) { +- uart_puts("busy too long, reset hw\n"); +- cec_reset_addr(); +- busy_count = 0; +- } +- break; ++ return 0; ++} + +- default: +- break; ++unsigned int cec_handler(void) ++{ ++ unsigned int intr_stat = readl(P_AO_CEC_INTR_STAT); ++ if (intr_stat & (1<<1)) { ++ cec_tx_irq_handler(); + } +- if (cec_msg.rx_read_pos != cec_msg.rx_write_pos) { +- cec_handle_message(); ++ if (intr_stat & (1<<2)) { ++ cec_rx_irq_handler(); + } +- + return 0; + } + + void cec_node_init(void) + { +- static int i = 0; +- static unsigned int retry = 0; +- static int regist_devs = 0; +- static enum _cec_log_dev_addr_e *probe = NULL; +- +- int tx_stat; +- unsigned char msg[1]; +- unsigned int kern_log_addr = (readl(P_AO_DEBUG_REG1) >> 16) & 0xf; +- enum _cec_log_dev_addr_e player_dev[3][3] = +- {{CEC_PLAYBACK_DEVICE_1_ADDR, CEC_PLAYBACK_DEVICE_2_ADDR, CEC_PLAYBACK_DEVICE_3_ADDR}, +- {CEC_PLAYBACK_DEVICE_2_ADDR, CEC_PLAYBACK_DEVICE_3_ADDR, CEC_PLAYBACK_DEVICE_1_ADDR}, +- {CEC_PLAYBACK_DEVICE_3_ADDR, CEC_PLAYBACK_DEVICE_1_ADDR, CEC_PLAYBACK_DEVICE_2_ADDR}}; +- +- if (retry >= 12) { // retry all device addr +- cec_msg.log_addr = 0x0f; +- uart_puts("failed on retried all possible address\n"); +- return ; +- } +- if (probe == NULL) { +- cec_msg.rx_read_pos = 0; +- cec_msg.rx_write_pos = 0; +- cec_msg.rx_buf_size = 4; +- +- cec_msg.power_status = 1; +- cec_msg.cec_power = 0; +- cec_msg.test = 0x0; +- cec_tx_msgs.send_idx = 0; +- cec_tx_msgs.queue_idx = 0; +- cec_tx_buf_init(); +- cec_buf_clear(); +- cec_wr_reg(CEC_LOGICAL_ADDR0, 0); +- cec_hw_buf_clear(); +- cec_wr_reg(CEC_LOGICAL_ADDR0, 0xf); +- _udelay(100); +- cec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | 0xf); +- /* +- * use kernel cec logic address to detect which logic address is the +- * started one to allocate. +- */ +- cec_dbg_print("kern log_addr:0x", kern_log_addr); +- uart_puts("\n"); +- for (i = 0; i < 3; i++) { +- if (kern_log_addr == player_dev[i][0]) { +- probe = player_dev[i]; +- break; +- } +- } +- if (probe == NULL) { +- probe = player_dev[0]; +- } +- i = 0; +- } ++ unsigned int phy_addr = readl(P_AO_DEBUG_REG1) & 0xffff; ++ unsigned char log_addr = readl(P_AO_DEBUG_REG3) & 0xf; + +- msg[0] = (probe[i]<<4) | probe[i]; +- tx_stat = ping_cec_ll_tx(msg, 1); +- if (tx_stat == TX_BUSY) { // can't get cec bus +- retry++; +- remote_cec_hw_reset(); +- if (!(retry & 0x03)) { +- cec_dbg_print("retry too much, log_addr:0x", probe[i]); +- uart_puts("\n"); +- } else { +- i -= 1; +- } +- } else if (tx_stat == TX_ERROR) { +- cec_wr_reg(CEC_LOGICAL_ADDR0, 0); +- cec_hw_buf_clear(); +- cec_wr_reg(CEC_LOGICAL_ADDR0, probe[i]); +- _udelay(100); +- cec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | probe[i]); +- cec_msg.log_addr = probe[i]; +- cec_dbg_print("Set cec log_addr:0x", cec_msg.log_addr); +- cec_dbg_print(", ADDR0:", cec_rd_reg(CEC_LOGICAL_ADDR0)); +- uart_puts("\n"); +- probe = NULL; +- regist_devs = 0; +- i = 0; +- retry = 0; +- return ; +- } else if (tx_stat == TX_DONE) { +- cec_dbg_print("sombody takes cec log_addr:0x", probe[i]); +- uart_puts("\n"); +- regist_devs |= (1 << i); +- retry += (4 - (retry & 0x03)); +- if (regist_devs == 0x07) { +- // No avilable logical address +- cec_msg.log_addr = 0x0f; +- cec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | 0xf); +- uart_puts("CEC allocate logic address failed\n"); +- } +- } +- i++; +- if (i == 3) { +- i = 0; ++ cec_dbg_print("cec_node_init cec_config:0x", hdmi_cec_func_config); ++ cec_dbg_printx(", log_addr:0x", log_addr, 4); ++ cec_dbg_printx(", phy_addr:0x", phy_addr, 16); ++ cec_dbg_prints("\n"); ++ ++ cec_msg.msg_len = 0; ++ cec_msg.cec_power = 0; ++ cec_msg.log_addr = log_addr; ++ cec_msg.phy_addr = phy_addr; ++ ++ if (!cec_msg.log_addr || !cec_msg.phy_addr) { ++ cec_dbg_prints("WARNING: log/phy_addr is not set, disabling cec wakeup\n"); ++ hdmi_cec_func_config = hdmi_cec_func_config & ~(0x1 << CEC_FUNC_MASK); ++ return; + } ++ ++ cec_wr_reg(CEC_LOGICAL_ADDR0, 0); ++ cec_hw_buf_clear(); ++ cec_wr_reg(CEC_LOGICAL_ADDR0, log_addr); ++ _udelay(100); ++ cec_wr_reg(CEC_LOGICAL_ADDR0, (0x1 << 4) | log_addr); ++ _udelay(100); ++ ++ cec_report_physical_address(); ++ cec_device_vendor_id(); ++ cec_set_osd_name(CEC_TV_ADDR); + } + + #endif +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/suspend.c b/arch/arm/cpu/armv8/gxb/firmware/scp_task/suspend.c +index 5db0e69..b16910c 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/suspend.c ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/suspend.c +@@ -70,15 +70,15 @@ void enter_suspend(unsigned int suspend_from) + p_pwr_op = &pwr_op_d; + pwr_op_init(p_pwr_op); + +-/* + // FIXME : (1) BLUE LED GPIOAO_13 (2) Current issue 12*mA -> 7*mA + #ifdef CONFIG_CEC_WAKEUP +- hdmi_cec_func_config = readl(P_AO_DEBUG_REG0); ++ hdmi_cec_func_config = readl(P_AO_DEBUG_REG0) & 0xff; ++ wait_uart_empty(); + uart_puts("CEC cfg:0x"); +- uart_put_hex(hdmi_cec_func_config, 16); ++ uart_put_hex(hdmi_cec_func_config, 8); + uart_puts("\n"); ++ wait_uart_empty(); + #endif +-*/ + p_pwr_op->power_off_at_clk81(); + p_pwr_op->power_off_at_24M(); + +diff --git a/arch/arm/cpu/armv8/gxb/firmware/scp_task/task_apis.h b/arch/arm/cpu/armv8/gxb/firmware/scp_task/task_apis.h +index fe6bd75..6ec5486 100644 +--- a/arch/arm/cpu/armv8/gxb/firmware/scp_task/task_apis.h ++++ b/arch/arm/cpu/armv8/gxb/firmware/scp_task/task_apis.h +@@ -14,8 +14,8 @@ int uart_puts(const char *s); + + /* #define dbg_print(s,v) */ + /* #define dbg_prints(s) */ +-#define writel(v, addr) (*((unsigned *)addr) = v) +-#define readl(addr) (*((unsigned *)addr)) ++#define writel(v, addr) (*((volatile unsigned *)addr) = v) ++#define readl(addr) (*((volatile unsigned *)addr)) + + #define dbg_print(s, v) {uart_puts(s); uart_put_hex(v, 32); uart_puts("\n"); } + /* #define dbg_prints(s) {uart_puts(s);wait_uart_empty();} */ +diff --git a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +index f6f2a7d..aa902be 100644 +--- a/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c ++++ b/board/hardkernel/odroidc2/firmware/scp_task/pwr_ctrl.c +@@ -8,6 +8,8 @@ + + #ifdef CONFIG_CEC_WAKEUP + #include ++#else ++typedef unsigned int uint32_t; + #endif + + extern int pwm_voltage_table[31][2]; +@@ -227,7 +229,7 @@ unsigned int detect_key(unsigned int suspend_from) + unsigned int init_time = get_time(); + init_remote(); + #ifdef CONFIG_CEC_WAKEUP +- if (hdmi_cec_func_config & 0x1) { ++ if ((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) { + remote_cec_hw_reset(); + cec_node_init(); + } +@@ -236,19 +238,19 @@ unsigned int detect_key(unsigned int suspend_from) + set_custom_gpio_status(); + + do { +- #ifdef CONFIG_CEC_WAKEUP +- if (cec_msg.log_addr) { +- if (hdmi_cec_func_config & 0x1) { ++#ifdef CONFIG_CEC_WAKEUP ++ if ((hdmi_cec_func_config >> CEC_FUNC_MASK) & 0x1) { ++ if (cec_msg.log_addr) { + cec_handler(); + if (cec_msg.cec_power == 0x1) { //cec power key + exit_reason = CEC_WAKEUP; + break; + } ++ } else { ++ cec_node_init(); + } +- } else if (hdmi_cec_func_config & 0x1) { +- cec_node_init(); + } +- #endif ++#endif + #if 0 + if ((readl(AO_GPIO_I) & (1<<3)) == 0) { + exit_reason = POWER_KEY_WAKEUP;