diff options
Diffstat (limited to 'drivers/video/wmt/cec.c')
-rw-r--r-- | drivers/video/wmt/cec.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/drivers/video/wmt/cec.c b/drivers/video/wmt/cec.c new file mode 100644 index 00000000..8d2115fb --- /dev/null +++ b/drivers/video/wmt/cec.c @@ -0,0 +1,323 @@ +/*++ + * linux/drivers/video/wmt/cec.c + * WonderMedia video post processor (VPP) driver + * + * Copyright c 2013 WonderMedia Technologies, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * WonderMedia Technologies, Inc. + * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C +--*/ + +#define CEC_C +/* #define DEBUG */ +/*----------------------- DEPENDENCE -----------------------------------------*/ +#include "cec.h" + +/*----------------------- PRIVATE MACRO --------------------------------------*/ + +/*----------------------- PRIVATE CONSTANTS ----------------------------------*/ +/* #define CEC_XXXX 1 *//*Example*/ + +/*----------------------- PRIVATE TYPE --------------------------------------*/ +/* typedef xxxx cec_xxx_t; *//*Example*/ + +/*----------EXPORTED PRIVATE VARIABLES are defined in cec.h -------------*/ +/*----------------------- INTERNAL PRIVATE VARIABLES - -----------------------*/ +/* int cec_xxx; *//*Example*/ +int cec_logical_addr; +int cec_physical_addr; + +/*--------------------- INTERNAL PRIVATE FUNCTIONS ---------------------------*/ +/* void cec_xxx(void); *//*Example*/ + +/*----------------------- Function Body --------------------------------------*/ +/*---------------------------- CEC COMMON API -------------------------------*/ + +#ifdef WMT_FTBLK_CEC +/*---------------------------- CEC HAL --------------------------------------*/ +void wmt_cec_tx_data(char *buf, int size) +{ + int i; + unsigned int addr, reg; + int wait_idle; + +#ifdef DEBUG + DPRINT("[CEC] tx data(%d):", size); + for (i = 0; i < size; i++) + DPRINT(" 0x%x", buf[i]); + DPRINT("\n"); +#endif + + if (size > 16) { + DPRINT("[CEC] *W* size max 16\n"); + return; + } + + wait_idle = 0; + while (vppif_reg32_read(CEC_WR_START)) { /* wait idle */ + if (wait_idle >= 10) { + DPRINT("[CEC] wait idle timeout\n"); + return; + } + wait_idle++; + mdelay(10); + return; + } + + addr = REG_CEC_ENCODE_HEADER; + for (i = 0; i < size; i++) { + reg = (buf[i] << 4) + 0x1; + if (i == (size - 1)) + reg |= BIT1; + vppif_reg32_out(addr, reg); +#ifdef DEBUG + DPRINT("[CEC] wr 0x%x = 0x%x\n", addr, reg); +#endif + addr += 4; + } + vppif_reg32_write(CEC_WR_NUM, (size * 10) + 0x1); + vppif_reg32_write(CEC_WR_START, 1); +} + +int wmt_cec_rx_data(char *buf) +{ + int i, size; + unsigned int addr, reg; + + addr = REG_CEC_DECODE_HEADER; + for (i = 0; i < 16; i++) { + reg = vppif_reg32_in(addr); + buf[i] = (reg & 0xFF0) >> 4; + if (reg & BIT1) /* EOM */ + break; + addr += 4; + } + vppif_reg32_write(CEC_FINISH_RESET, 1); + mdelay(1); + vppif_reg32_write(CEC_FINISH_RESET, 0); + size = i + 1; +#ifdef DEBUG + DPRINT("[CEC] rx data(%d):\n", size); + for (i = 0; i < size; i++) + DPRINT(" 0x%x", buf[i]); + DPRINT("\n"); +#endif + return size; +} + +void wmt_cec_set_clock(void) +{ + #define CEC_CLOCK (1000000 / 7984) + + vppif_reg32_out(REG_CEC_WR_START_SET0, 370 * CEC_CLOCK); /* 3.7 ms */ + vppif_reg32_out(REG_CEC_WR_START_SET1, 450 * CEC_CLOCK); /* 4.5 ms */ + vppif_reg32_out(REG_CEC_WR_LOGIC0_SET0, 150 * CEC_CLOCK); /* 1.5 ms */ + vppif_reg32_out(REG_CEC_WR_LOGIC0_SET1, 240 * CEC_CLOCK); /* 2.4 ms */ + vppif_reg32_out(REG_CEC_WR_LOGIC1_SET0, 60 * CEC_CLOCK); /* 0.6 ms */ + vppif_reg32_out(REG_CEC_WR_LOGIC1_SET1, 240 * CEC_CLOCK); /* 2.4 ms */ + vppif_reg32_out(REG_CEC_RD_START_L_SET0, 350 * CEC_CLOCK); /* 3.5 ms */ + vppif_reg32_out(REG_CEC_RD_START_R_SET0, 390 * CEC_CLOCK); /* 3.9 ms */ + vppif_reg32_out(REG_CEC_RD_START_L_SET1, 430 * CEC_CLOCK); /* 4.3 ms */ + vppif_reg32_out(REG_CEC_RD_START_R_SET1, 470 * CEC_CLOCK); /* 4.7 ms */ + vppif_reg32_out(REG_CEC_RD_LOGIC0_L_SET0, 130 * CEC_CLOCK); /* 1.3 ms */ + vppif_reg32_out(REG_CEC_RD_LOGIC0_R_SET0, 170 * CEC_CLOCK); /* 1.7 ms */ + vppif_reg32_out(REG_CEC_RD_LOGIC0_L_SET1, 205 * CEC_CLOCK); /* 2.05 ms*/ + vppif_reg32_out(REG_CEC_RD_LOGIC0_R_SET1, 275 * CEC_CLOCK); /* 2.75 ms*/ + vppif_reg32_out(REG_CEC_RD_LOGIC1_L_SET0, 40 * CEC_CLOCK); /* 0.4 ms */ + vppif_reg32_out(REG_CEC_RD_LOGIC1_R_SET0, 80 * CEC_CLOCK); /* 0.8 ms */ + vppif_reg32_out(REG_CEC_RD_LOGIC1_L_SET1, 205 * CEC_CLOCK); /* 2.05 ms*/ + vppif_reg32_out(REG_CEC_RD_LOGIC1_R_SET1, 275 * CEC_CLOCK); /* 2.75 ms*/ + vppif_reg32_out(REG_CEC_RD_L_SET0_ERROR, 182 * CEC_CLOCK); /* 1.82 ms */ + vppif_reg32_out(REG_CEC_RD_R_SET1_ERROR, 238 * CEC_CLOCK); /* 2.38 ms */ + vppif_reg32_out(REG_CEC_RD_L_ERROR, 287 * CEC_CLOCK); /* 2.87 ms */ + vppif_reg32_out(REG_CEC_RX_SAMPLE_L_RANGE, 85 * CEC_CLOCK); /* 0.85 ms*/ + vppif_reg32_out(REG_CEC_RX_SAMPLE_R_RANGE, 125 * CEC_CLOCK); /*1.25 ms*/ + vppif_reg32_out(REG_CEC_WR_SET0_ERROR, 225 * CEC_CLOCK); /* 2.25 ms */ + vppif_reg32_out(REG_CEC_WR_SET1_ERROR, 225 * CEC_CLOCK); /* 2.25 ms ?*/ +} + +void wmt_cec_set_logical_addr(int no, char addr, int enable) +{ + unsigned int mask; + + if (no > 5) { + DPRINT("[CEC] *W* max 5\n"); + return; + } + mask = 0xF << (4 * no); + vppif_reg32_write(REG_CEC_LOGICAL_ADDR, mask, 4 * no, addr); + mask = BIT24 << no; + vppif_reg32_write(REG_CEC_LOGICAL_ADDR, mask, 24 + no, enable); + DBGMSG("[CEC] set logical addr %d,0x%x\n", no, addr); +} + +void wmt_cec_rx_enable(int enable) +{ + vppif_reg32_write(CEC_REJECT_NEXT_DECODE, (enable) ? 0 : 1); + /* GPIO4 disable GPIO function */ + vppif_reg32_write(GPIO_BASE_ADDR + 0x40, BIT4, 4, (enable) ? 0 : 1); +} + +void wmt_cec_enable_int(int no, int enable) +{ + vppif_reg32_write(REG_CEC_INT_ENABLE, 0x1 << no, no, enable); +} + +void wmt_cec_clr_int(int sts) +{ + vppif_reg32_out(REG_CEC_STATUS, sts); +} + +int wmt_cec_get_int(void) +{ + int reg; + + reg = vppif_reg32_in(REG_CEC_STATUS); + return reg; +} + +void wmt_cec_enable_loopback(int enable) +{ + /* 1 : read self write and all dest data */ + vppif_reg32_write(CEC_RD_ENCODE_ENABLE, enable); +} + +void wmt_cec_init_hw(void) +{ + wmt_cec_set_clock(); + vppif_reg32_write(CEC_WR_RETRY, 3); + vppif_reg32_out(REG_CEC_RX_TRIG_RANGE, 2); + + vppif_reg32_write(CEC_FREE_3X, 3); + vppif_reg32_write(CEC_FREE_5X, 5); + vppif_reg32_write(CEC_FREE_7X, 7); + + vppif_reg32_write(CEC_COMP_DISABLE, 1); + vppif_reg32_write(CEC_ERR_HANDLE_DISABLE, 0); + vppif_reg32_write(CEC_NO_ACK_DISABLE, 0); + vppif_reg32_write(CEC_DECODE_FULL_DISABLE, 0); + vppif_reg32_write(CEC_STATUS4_START_DISABLE, 1); + vppif_reg32_write(CEC_STATUS4_LOGIC0_DISABLE, 1); + vppif_reg32_write(CEC_STATUS4_LOGIC1_DISABLE, 1); + /* 1 : read self write and all dest data */ + vppif_reg32_write(CEC_RD_ENCODE_ENABLE, 0); +} + +/*---------------------------- CEC API --------------------------------------*/ +void wmt_cec_reg_dump(void) +{ + DPRINT("========== CEC register dump ==========\n"); + vpp_reg_dump(REG_CEC_BEGIN, REG_CEC_END - REG_CEC_BEGIN); + + DPRINT("---------- CEC Tx ----------\n"); + DPRINT("wr start %d,wr num %d\n", + vppif_reg32_read(CEC_WR_START), + vppif_reg32_read(CEC_WR_NUM)); + DPRINT("wr header ack %d,EOM %d,data 0x%x\n", + vppif_reg32_read(CEC_WR_HEADER_ACK), + vppif_reg32_read(CEC_WR_HEADER_EOM), + vppif_reg32_read(CEC_WR_HEADER_DATA)); + DPRINT("wr data ack %d,EOM %d,data 0x%x\n", + vppif_reg32_read(CEC_WR_DATA_ACK), + vppif_reg32_read(CEC_WR_DATA_EOM), + vppif_reg32_read(CEC_WR_DATA)); + DPRINT("finish reset %d,wr retry %d\n", + vppif_reg32_read(CEC_FINISH_RESET), + vppif_reg32_read(CEC_WR_RETRY)); + DPRINT("---------- CEC Rx ----------\n"); + DPRINT("rd start %d,all ack %d,finish %d\n", + vppif_reg32_read(CEC_RD_START), + vppif_reg32_read(CEC_RD_ALL_ACK), + vppif_reg32_read(CEC_RD_FINISH)); + DPRINT("rd header ack %d,EOM %d,data 0x%x\n", + vppif_reg32_read(CEC_RD_HEADER_ACK), + vppif_reg32_read(CEC_RD_HEADER_ACK), + vppif_reg32_read(CEC_RD_HEADER_DATA)); + DPRINT("rd data ack %d,EOM %d,data 0x%x\n", + vppif_reg32_read(CEC_RD_DATA_ACK), + vppif_reg32_read(CEC_RD_DATA_EOM), + vppif_reg32_read(CEC_RD_DATA)); + + DPRINT("---------- Logical addr ----------\n"); + DPRINT("addr1 0x%x,valid %d\n", + vppif_reg32_read(CEC_LOGICAL_ADDR1), + vppif_reg32_read(CEC_ADDR_VALID1)); + DPRINT("addr2 0x%x,valid %d\n", + vppif_reg32_read(CEC_LOGICAL_ADDR2), + vppif_reg32_read(CEC_ADDR_VALID2)); + DPRINT("addr3 0x%x,valid %d\n", + vppif_reg32_read(CEC_LOGICAL_ADDR3), + vppif_reg32_read(CEC_ADDR_VALID3)); + DPRINT("addr4 0x%x,valid %d\n", + vppif_reg32_read(CEC_LOGICAL_ADDR4), + vppif_reg32_read(CEC_ADDR_VALID4)); + DPRINT("addr5 0x%x,valid %d\n", + vppif_reg32_read(CEC_LOGICAL_ADDR5), + vppif_reg32_read(CEC_ADDR_VALID5)); + + DPRINT("---------- Misc ----------\n"); + DPRINT("free 3x %d,5x %d,7x %d\n", vppif_reg32_read(CEC_FREE_3X), + vppif_reg32_read(CEC_FREE_5X), vppif_reg32_read(CEC_FREE_7X)); + DPRINT("reject next decode %d,comp disable %d\n", + vppif_reg32_read(CEC_REJECT_NEXT_DECODE), + vppif_reg32_read(CEC_COMP_DISABLE)); + DPRINT("err handle disable %d,no ack disable %d\n", + vppif_reg32_read(CEC_ERR_HANDLE_DISABLE), + vppif_reg32_read(CEC_NO_ACK_DISABLE)); + DPRINT("r1 enc ok %d,r1 dec ok %d,r1 err %d\n", + vppif_reg32_read(CEC_R1_ENCODE_OK), + vppif_reg32_read(CEC_R1_DECODE_OK), + vppif_reg32_read(CEC_R1_ERROR)); + DPRINT("r1 arb fail %d,r1 no ack %d\n", + vppif_reg32_read(CEC_R1_ARB_FAIL), + vppif_reg32_read(CEC_R1_NO_ACK)); + DPRINT("dec full disable %d,self rd enable %d\n", + vppif_reg32_read(CEC_DECODE_FULL_DISABLE), + vppif_reg32_read(CEC_RD_ENCODE_ENABLE)); +} + +#ifdef CONFIG_PM +static unsigned int *wmt_cec_pm_bk; +void wmt_cec_do_suspend(void) +{ + /* Suspend GPIO output high */ + vppif_reg32_write(GPIO_BASE_ADDR+0xC0, BIT23, 23, 0); + wmt_cec_pm_bk = vpp_backup_reg(REG_CEC_BEGIN, + (REG_CEC_END - REG_CEC_BEGIN)); +} + +void wmt_cec_do_resume(void) +{ + vppif_reg32_out(REG_VPP_SWRST2_SEL, 0x1011111); + /* disable GPIO function */ + vppif_reg32_write(GPIO_BASE_ADDR + 0x40, BIT4, 4, 0); + /* GPIO4 disable GPIO out */ + vppif_reg32_write(GPIO_BASE_ADDR + 0x80, BIT4, 4, 0); + /* GPIO4 disable pull ctrl */ + vppif_reg32_write(GPIO_BASE_ADDR + 0x480, BIT4, 4, 0); + /* Suspend GPIO output enable */ + vppif_reg32_write(GPIO_BASE_ADDR + 0x80, BIT23, 23, 1); + /* Suspend GPIO output high */ + vppif_reg32_write(GPIO_BASE_ADDR + 0xC0, BIT23, 23, 1); + /* Wake3 disable pull ctrl */ + vppif_reg32_write(GPIO_BASE_ADDR + 0x480, BIT19, 19, 0); + vpp_restore_reg(REG_CEC_BEGIN, + (REG_CEC_END - REG_CEC_BEGIN), wmt_cec_pm_bk); + wmt_cec_pm_bk = 0; +} +#endif +#endif /* WMT_FTBLK_CEC */ + |