| /* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ |
| /* |
| * arch/arm/cpu/armv8/tl1/hdmirx/hdmirx.c |
| * |
| * Copyright (C) 2020 Amlogic, Inc. All rights reserved. |
| * |
| */ |
| |
| #include <config.h> |
| #include <common.h> |
| #include <command.h> |
| #include <asm/cpu_id.h> |
| #include <asm/arch/io.h> |
| #include <asm/arch/hdmirx_reg.h> |
| #include "hdmirx.h" |
| |
| struct hdmirx_data_s hdmirx_data; |
| |
| unsigned char edid_14[] = { |
| 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x05, 0xAC, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, |
| 0x2B, 0x1B, 0x01, 0x03, 0x80, 0x73, 0x41, 0x78, 0x0A, 0xCF, 0x74, 0xA3, 0x57, 0x4C, 0xB0, 0x23, |
| 0x09, 0x48, 0x4C, 0x21, 0x08, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
| 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, |
| 0x45, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x01, 0x1D, 0x00, 0xBC, 0x52, 0xD0, 0x1E, 0x20, |
| 0xB8, 0x28, 0x55, 0x40, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x41, |
| 0x4D, 0x4C, 0x20, 0x54, 0x56, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFD, |
| 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x94, |
| 0x02, 0x03, 0x3E, 0xF0, 0x53, 0x10, 0x1F, 0x14, 0x05, 0x13, 0x04, 0x20, 0x22, 0x3C, 0x3E, 0x12, |
| 0x16, 0x03, 0x07, 0x11, 0x15, 0x02, 0x06, 0x01, 0x2F, 0x09, 0x7F, 0x05, 0x15, 0x07, 0x50, 0x57, |
| 0x07, 0x01, 0x3D, 0x07, 0xC0, 0x5F, 0x7E, 0x01, 0x83, 0x01, 0x00, 0x00, 0x6E, 0x03, 0x0C, 0x00, |
| 0x10, 0x00, 0xB8, 0x3C, 0x2F, 0x80, 0x80, 0x01, 0x02, 0x03, 0x04, 0xE2, 0x00, 0xFB, 0x01, 0x1D, |
| 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, 0x28, 0x55, 0x00, 0x20, 0xC2, 0x31, 0x00, 0x00, 0x1E, |
| 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0x13, 0x8E, 0x21, 0x00, |
| 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, |
| }; |
| |
| static unsigned first_bit_set(uint32_t data) |
| { |
| unsigned n = 32; |
| |
| if (data != 0) { |
| for (n = 0; (data & 1) == 0; n++) |
| data >>= 1; |
| } |
| return n; |
| } |
| |
| uint32_t get(uint32_t data, uint32_t mask) |
| { |
| return (data & mask) >> first_bit_set(mask); |
| } |
| |
| uint32_t set(uint32_t data, uint32_t mask, uint32_t value) |
| { |
| return ((value << first_bit_set(mask)) & mask) | (data & ~mask); |
| } |
| |
| unsigned int rx_rd_reg(unsigned long reg_addr) |
| { |
| unsigned int val = 0; |
| |
| val = readl(reg_addr); |
| |
| return val; |
| } |
| |
| void rx_wr_reg(unsigned long reg_addr, unsigned int val) |
| { |
| writel(val, reg_addr); |
| } |
| |
| unsigned int rx_rd_reg_b(unsigned long reg_addr) |
| { |
| unsigned int val = 0; |
| |
| val = readb(reg_addr); |
| |
| return val; |
| } |
| |
| void rx_wr_reg_b(unsigned long reg_addr, unsigned int val) |
| { |
| writeb(val, reg_addr); |
| } |
| |
| uint32_t hdmirx_rd_dwc(unsigned long addr) |
| { |
| int data; |
| |
| data = rx_rd_reg(HDMIRX_DWC_BASE_OFFSET + addr); |
| return data; |
| } |
| |
| uint32_t hdmirx_rd_bits_dwc(unsigned long addr, uint32_t mask) |
| { |
| return get(hdmirx_rd_dwc(addr), mask); |
| } |
| |
| /** |
| * Write data to HDMI RX CTRL |
| * @param[in] addr register address |
| * @param[in] data new register value |
| */ |
| void hdmirx_wr_dwc(unsigned long addr, uint32_t data) |
| { |
| rx_wr_reg(HDMIRX_DWC_BASE_OFFSET + addr, data); |
| } |
| |
| void hdmirx_wr_bits_dwc(unsigned long addr, uint32_t mask, uint32_t value) |
| { |
| hdmirx_wr_dwc(addr, set(hdmirx_rd_dwc(addr), mask, value)); |
| } |
| |
| unsigned int hdmirx_rd_top(unsigned long addr) |
| { |
| int data; |
| unsigned int dev_offset = 0; |
| |
| dev_offset = TOP_DWC_BASE_OFFSET + |
| HDMIRX_DWC_BASE_OFFSET; |
| if ((addr >= TOP_EDID_ADDR_S) && |
| (addr <= TOP_EDID_PORT3_ADDR_E)) { |
| data = rx_rd_reg_b(dev_offset + addr); |
| } else { |
| data = rx_rd_reg(dev_offset + (addr << 2)); |
| } |
| |
| return data; |
| } |
| |
| uint32_t hdmirx_rd_bits_top(unsigned long addr, uint32_t mask) |
| { |
| return get(hdmirx_rd_top(addr), mask); |
| } |
| |
| void hdmirx_wr_top(unsigned long addr, unsigned long data) |
| { |
| unsigned long dev_offset = 0; |
| |
| dev_offset = TOP_DWC_BASE_OFFSET + |
| HDMIRX_DWC_BASE_OFFSET; |
| if ((addr >= TOP_EDID_ADDR_S) && |
| (addr <= TOP_EDID_PORT3_ADDR_E)) { |
| rx_wr_reg_b(dev_offset + addr, (unsigned char)data); |
| } else { |
| rx_wr_reg(dev_offset + (addr << 2), data); |
| } |
| } |
| |
| void hdmirx_wr_bits_top(unsigned long addr, uint32_t mask, uint32_t value) |
| { |
| hdmirx_wr_top(addr, set(hdmirx_rd_top(addr), mask, value)); |
| } |
| |
| unsigned int rd_reg_hhi(unsigned long offset) |
| { |
| unsigned long addr = offset + HHI_BASE_ADDR; |
| |
| return rx_rd_reg(addr); |
| } |
| |
| void wr_reg_hhi(unsigned long offset, unsigned int val) |
| { |
| unsigned long addr = offset + HHI_BASE_ADDR; |
| rx_wr_reg(addr, val); |
| } |
| |
| bool hdmirx_repeat_support(void) |
| { |
| return hdmirx_data.repeater; |
| } |
| |
| unsigned char *rx_get_edid(void) |
| { |
| if (hdmirx_data.edid_buf != NULL) |
| return hdmirx_data.edid_buf; |
| else |
| return edid_14; |
| } |
| |
| unsigned int rx_exchange_bits(unsigned int value) |
| { |
| unsigned int temp; |
| printf("bfe:%#x\n", value); |
| temp = value & 0xF; |
| value = (((value >> 4) & 0xF) | (value & 0xFFF0)); |
| value = ((value & 0xFF0F) | (temp << 4)); |
| temp = value & 0xF00; |
| value = (((value >> 4) & 0xF00) | (value & 0xF0FF)); |
| value = ((value & 0x0FFF) | (temp << 4)); |
| printf("aft:%#x\n", value); |
| return value; |
| } |
| |
| unsigned int rx_edid_cal_phy_addr( |
| unsigned int brepeat, |
| unsigned int up_addr, |
| unsigned int portmap, |
| unsigned char *pedid, |
| unsigned int *phy_offset, |
| unsigned int *phy_addr) |
| { |
| unsigned int root_offset = 0; |
| unsigned int i; |
| unsigned int flag = 0; |
| |
| if (!(pedid && phy_offset && phy_addr)) |
| return -1; |
| |
| for (i = 0; i <= 255; i++) { |
| /*find phy_addr_offset*/ |
| if (pedid[i] == 0x03) { |
| if ((pedid[i+1] == 0x0c) && |
| (pedid[i+2] == 0x00)) { |
| if (brepeat) |
| pedid[i+3] = 0x00; |
| else |
| pedid[i+3] = 0x10; |
| *phy_offset = i+3; |
| flag = 1; |
| break; |
| } |
| } |
| } |
| |
| if (brepeat) { |
| /*get the root index*/ |
| i = 0; |
| while (i < 4) { |
| if (((up_addr << (i*4)) & 0xf000) != 0) { |
| root_offset = i; |
| break; |
| } |
| i++; |
| } |
| if (i == 4) |
| root_offset = 4; |
| |
| for (i = 0; i < E_PORT_NUM; i++) { |
| if (root_offset == 0) |
| phy_addr[i] = 0xFFFF; |
| else |
| phy_addr[i] = (up_addr | |
| ((((portmap >> i*4) & 0xf) << 12) >> |
| (root_offset - 1)*4)); |
| |
| phy_addr[i] = rx_exchange_bits(phy_addr[i]); |
| } |
| } else { |
| for (i = 0; i < E_PORT_NUM; i++) |
| phy_addr[i] = ((portmap >> i*4) & 0xf) << 4; |
| } |
| |
| return flag; |
| } |
| |
| void rx_edid_fill_to_register( |
| unsigned char *pedid, |
| unsigned int brepeat, |
| unsigned int *pphy_addr, |
| unsigned char *pchecksum) |
| { |
| unsigned int i; |
| unsigned int checksum = 0; |
| unsigned int value = 0; |
| unsigned int tmp_addr; |
| |
| if (!(pedid && pphy_addr && pchecksum)) |
| return; |
| |
| /*printf("rx_edid_fill_to_register start\n");*/ |
| |
| /* clear all and disable all overlay register 0~7*/ |
| for (i = TOP_EDID_RAM_OVR0; i <= TOP_EDID_RAM_OVR7; ) { |
| hdmirx_wr_top(i, 0); |
| i += 2; |
| } |
| |
| /* physical address info at second block */ |
| for (i = 128; i <= 255; i++) { |
| value = pedid[i]; |
| if (i < 255) { |
| checksum += pedid[i]; |
| checksum &= 0xff; |
| } else if (i == 255) { |
| value = (0x100 - checksum)&0xff; |
| } |
| } |
| |
| /* physical address info at second block */ |
| tmp_addr = TOP_EDID_ADDR_S; |
| for (i = 0; i <= 255; i++) { |
| /* fill first edid buffer */ |
| hdmirx_wr_top(tmp_addr + i, pedid[i]); |
| /* fill second edid buffer */ |
| hdmirx_wr_top(0x100 + tmp_addr + i, pedid[i]); |
| } |
| /* caculate 4 port check sum */ |
| if (brepeat) { |
| for (i = 0; i < E_PORT_NUM; i++) { |
| pchecksum[i] = (0x100 + value - (pphy_addr[i] & 0xFF) - |
| ((pphy_addr[i] >> 8) & 0xFF)) & 0xff; |
| /*printf("port %d phy:%d\n", i, pphy_addr[i]);*/ |
| } |
| } else { |
| for (i = 0; i < E_PORT_NUM; i++) { |
| pchecksum[i] = (0x100 - (checksum + |
| (pphy_addr[i] - 0x10))) & 0xff; |
| } |
| } |
| } |
| |
| void rx_edid_update_overlay( |
| unsigned int phy_addr_offset, |
| unsigned int *pphy_addr, |
| unsigned char *pchecksum) |
| { |
| /*unsigned int i;*/ |
| |
| if (!(pphy_addr && pchecksum)) |
| return; |
| /*printf("rx_edid_update_overlay statrt\n");*/ |
| |
| /* replace the first edid ram data */ |
| /* physical address byte 1 */ |
| hdmirx_wr_top(TOP_EDID_RAM_OVR2, |
| (phy_addr_offset + 1) | (0x0f<<16)); |
| hdmirx_wr_top(TOP_EDID_RAM_OVR2_DATA, |
| ((pphy_addr[E_PORT0] >> 8) & 0xFF) | |
| (((pphy_addr[E_PORT1] >> 8) & 0xFF)<<8) |
| | (((pphy_addr[E_PORT2] >> 8) & 0xFF)<<16) |
| | (((pphy_addr[E_PORT3] >> 8) & 0xFF)<<24)); |
| /* physical address byte 0 */ |
| hdmirx_wr_top(TOP_EDID_RAM_OVR1, |
| phy_addr_offset | (0x0f<<16)); |
| hdmirx_wr_top(TOP_EDID_RAM_OVR1_DATA, |
| (pphy_addr[E_PORT0] & 0xFF) | |
| ((pphy_addr[E_PORT1] & 0xFF)<<8) | |
| ((pphy_addr[E_PORT2] & 0xFF)<<16) | |
| ((pphy_addr[E_PORT3] & 0xFF) << 24)); |
| |
| /* checksum */ |
| hdmirx_wr_top(TOP_EDID_RAM_OVR0, |
| 0xff | (0x0f<<16)); |
| hdmirx_wr_top(TOP_EDID_RAM_OVR0_DATA, |
| pchecksum[E_PORT0]|(pchecksum[E_PORT1]<<8) | |
| (pchecksum[E_PORT2]<<16) | (pchecksum[E_PORT3] << 24)); |
| |
| |
| /* replace the second edid ram data */ |
| /* physical address byte 1 */ |
| hdmirx_wr_top(TOP_EDID_RAM_OVR5, |
| (phy_addr_offset + 0x101) | (0x0f<<16)); |
| hdmirx_wr_top(TOP_EDID_RAM_OVR5_DATA, |
| ((pphy_addr[E_PORT0] >> 8) & 0xFF) | |
| (((pphy_addr[E_PORT1] >> 8) & 0xFF)<<8) |
| | (((pphy_addr[E_PORT2] >> 8) & 0xFF)<<16) |
| | (((pphy_addr[E_PORT3] >> 8) & 0xFF)<<24)); |
| /* physical address byte 0 */ |
| hdmirx_wr_top(TOP_EDID_RAM_OVR4, |
| (phy_addr_offset + 0x100) | (0x0f<<16)); |
| hdmirx_wr_top(TOP_EDID_RAM_OVR4_DATA, |
| (pphy_addr[E_PORT0] & 0xFF) | |
| ((pphy_addr[E_PORT1] & 0xFF)<<8) | |
| ((pphy_addr[E_PORT2] & 0xFF)<<16) | |
| ((pphy_addr[E_PORT3] & 0xFF) << 24)); |
| /* checksum */ |
| hdmirx_wr_top(TOP_EDID_RAM_OVR3, |
| (0xff + 0x100) | (0x0f<<16)); |
| hdmirx_wr_top(TOP_EDID_RAM_OVR3_DATA, |
| pchecksum[E_PORT0]|(pchecksum[E_PORT1]<<8) | |
| (pchecksum[E_PORT2]<<16) | (pchecksum[E_PORT3] << 24)); |
| |
| /*for (i = 0; i < E_PORT_NUM; i++) { |
| printf(">port %d,addr 0x%x,checksum 0x%x\n", |
| i, pphy_addr[i], pchecksum[i]); |
| }*/ |
| } |
| |
| int rx_get_tag_code(uint8_t *edid_data) |
| { |
| int tag_code; |
| |
| if ((*edid_data >> 5) != 7) |
| tag_code = (*edid_data >> 5); |
| else |
| tag_code = (7 << 8) | *(edid_data + 1);/*extern tag*/ |
| |
| return tag_code; |
| } |
| |
| int rx_get_ceadata_offset(uint8_t *cur_edid, uint8_t *addition) |
| { |
| int i; |
| int type; |
| |
| if ((cur_edid == NULL) || (addition == NULL)) |
| return 0; |
| |
| type = rx_get_tag_code(addition); |
| i = EDID_DEFAULT_START;/*block check start index*/ |
| while (i < 255) { |
| if (type == rx_get_tag_code(cur_edid + i)) |
| return i; |
| else |
| i += (1 + (*(cur_edid + i) & 0x1f)); |
| } |
| if (hdmirx_data.dbg_en) |
| printf("type: %#x, start addr: %#x\n", type, i); |
| |
| return 0; |
| } |
| |
| int hdmirx_ctrl_edid_update(void) |
| { |
| bool brepeat = hdmirx_repeat_support(); |
| unsigned char *pedid_data; |
| unsigned int sts; |
| unsigned int phy_addr_offset; |
| unsigned int phy_addr[E_PORT_NUM] = {0, 0, 0, 0}; |
| unsigned char checksum[E_PORT_NUM] = {0, 0, 0, 0}; |
| |
| /* get edid from buffer, return buffer addr */ |
| pedid_data = rx_get_edid(); |
| |
| /* caculate physical address and checksum */ |
| sts = rx_edid_cal_phy_addr(brepeat, |
| hdmirx_data.up_phy_addr, |
| hdmirx_data.port_map, |
| pedid_data, &phy_addr_offset, |
| phy_addr); |
| if (!sts) { |
| /* not find physical address info */ |
| printf("err: not finded phy addr info\n"); |
| } |
| |
| /* write edid to edid register */ |
| rx_edid_fill_to_register(pedid_data, brepeat, |
| phy_addr, checksum); |
| if (sts) { |
| /* update physical and checksum */ |
| rx_edid_update_overlay(phy_addr_offset, phy_addr, checksum); |
| } |
| return true; |
| } |
| |
| static int rx_top_init(void) |
| { |
| int err = 0; |
| int data32 = 0; |
| |
| data32 |= (0xf << 13); /* bit[16:13] */ |
| data32 |= 0 << 11; |
| data32 |= 0 << 10; |
| data32 |= 0 << 9; |
| data32 |= 0 << 8; |
| data32 |= EDID_CLK_DIV << 0; |
| hdmirx_wr_top(TOP_EDID_GEN_CNTL, data32); |
| |
| data32 = 0; |
| /* SDA filter internal clk div */ |
| data32 |= 1 << 29; |
| /* SDA sampling clk div */ |
| data32 |= 1 << 16; |
| /* SCL filter internal clk div */ |
| data32 |= 1 << 13; |
| /* SCL sampling clk div */ |
| data32 |= 1 << 0; |
| hdmirx_wr_top(TOP_INFILTER_HDCP, data32); |
| hdmirx_wr_top(TOP_INFILTER_I2C0, data32); |
| hdmirx_wr_top(TOP_INFILTER_I2C1, data32); |
| hdmirx_wr_top(TOP_INFILTER_I2C2, data32); |
| hdmirx_wr_top(TOP_INFILTER_I2C3, data32); |
| |
| data32 = 0; |
| /* conversion mode of 422 to 444 */ |
| data32 |= 0 << 19; |
| /* !!!!dolby vision 422 to 444 ctl bit */ |
| data32 |= 0 << 0; |
| hdmirx_wr_top(TOP_VID_CNTL, data32); |
| |
| data32 = 0; |
| data32 |= 0 << 20; |
| data32 |= 0 << 8; |
| data32 |= 0x0a << 0; |
| hdmirx_wr_top(TOP_VID_CNTL2, data32); |
| |
| data32 = 0; |
| /* n_cts_auto_mode: */ |
| /* 0-every ACR packet */ |
| /* 1-on N or CTS value change */ |
| data32 |= 1 << 4; |
| /* delay cycles before n/cts update pulse */ |
| data32 |= 7 << 0; |
| |
| hdmirx_wr_top(TOP_TL1_ACR_CNTL2, data32); |
| |
| data32 = hdmirx_rd_dwc(DWC_HDCP_CTRL); |
| /* 0: Original behaviour */ |
| /* 1: Balance path delay between non-HDCP and HDCP */ |
| data32 |= 1 << 27; /* none & hdcp */ |
| /* 0: Original behaviour */ |
| /* 1: Balance path delay between HDCP14 and HDCP22. */ |
| data32 |= 1 << 26; /* 1.4 & 2.2 */ |
| hdmirx_wr_dwc(DWC_HDCP_CTRL, data32); |
| |
| /* Configure channel switch */ |
| data32 = 0; |
| data32 |= (0 << 4); /* [ 4] valid_always*/ |
| data32 |= (7 << 0); /* [3:0] decoup_thresh*/ |
| hdmirx_wr_top(TOP_CHAN_SWITCH_1, data32); |
| |
| data32 = 0; |
| data32 |= (2 << 28); /* [29:28] source_2 */ |
| data32 |= (1 << 26); /* [27:26] source_1 */ |
| data32 |= (0 << 24); /* [25:24] source_0 */ |
| hdmirx_wr_top(TOP_CHAN_SWITCH_0, data32); |
| |
| /* Configure TMDS algin */ |
| data32 = 0; |
| hdmirx_wr_top(TOP_TMDS_ALIGN_CNTL0, data32); |
| data32 = 0; |
| hdmirx_wr_top(TOP_TMDS_ALIGN_CNTL1, data32); |
| |
| /* Enable channel output */ |
| data32 = hdmirx_rd_top(TOP_CHAN_SWITCH_0); |
| hdmirx_wr_top(TOP_CHAN_SWITCH_0, data32 | (1<<0)); |
| |
| /* configure cable clock measure */ |
| data32 = 0; |
| data32 |= (1 << 28); /* [31:28] meas_tolerance */ |
| data32 |= (8192 << 0); /* [23: 0] ref_cycles */ |
| hdmirx_wr_top(TOP_METER_CABLE_CNTL, data32); |
| |
| /* configure hdmi clock measure */ |
| data32 = 0; |
| data32 |= (1 << 28); /* [31:28] meas_tolerance */ |
| data32 |= (8192 << 0); /* [23: 0] ref_cycles */ |
| hdmirx_wr_top(TOP_METER_HDMI_CNTL, data32); |
| |
| data32 = 0; |
| /* bit4: hpd override, bit5: hpd reverse */ |
| data32 |= 1 << 4; |
| data32 |= 1 << 5; |
| /* pull down all the hpd */ |
| hdmirx_wr_top(TOP_HPD_PWR5V, data32); |
| return err; |
| } |
| |
| void rx_clk_init(void) |
| { |
| unsigned int data32; |
| |
| /* DWC clock enable */ |
| /* Turn on clk_hdmirx_pclk, also = sysclk */ |
| wr_reg_hhi(HHI_GCLK_MPEG0, |
| rd_reg_hhi(HHI_GCLK_MPEG0) | (1 << 21)); |
| |
| /* Enable APB3 fail on error */ |
| /* APB3 to HDMIRX-TOP err_en */ |
| /* default 0x3ff, | bit15 = 1 | bit12 = 1 */ |
| /* no need for chip from TL1 */ |
| /* hdmirx_wr_ctl_port(0, 0x93ff); */ |
| /* hdmirx_wr_ctl_port(0x10, 0x93ff); */ |
| |
| /* turn on clocks: md, cfg... */ |
| /* G9 clk tree */ |
| /* fclk_div5 400M ----- mux sel = 3 */ |
| /* fclk_div3 850M ----- mux sel = 2 */ |
| /* fclk_div4 637M ----- mux sel = 1 */ |
| /* XTAL 24M ----- mux sel = 0 */ |
| /* [26:25] HDMIRX mode detection clock mux select: osc_clk */ |
| /* [24] HDMIRX mode detection clock enable */ |
| /* [22:16] HDMIRX mode detection clock divider */ |
| /* [10: 9] HDMIRX config clock mux select: */ |
| /* [ 8] HDMIRX config clock enable */ |
| /* [ 6: 0] HDMIRX config clock divider: */ |
| data32 = 0; |
| data32 |= 0 << 25; |
| data32 |= 1 << 24; |
| data32 |= 0 << 16; |
| data32 |= 3 << 9; |
| data32 |= 1 << 8; |
| data32 |= 2 << 0; |
| wr_reg_hhi(HHI_HDMIRX_CLK_CNTL, data32); |
| |
| data32 = 0; |
| data32 |= 2 << 25; |
| data32 |= ACR_MODE << 24; |
| data32 |= 0 << 16; |
| data32 |= 2 << 9; |
| data32 |= 1 << 8; |
| data32 |= 2 << 0; |
| wr_reg_hhi(HHI_HDMIRX_AUD_CLK_CNTL, data32); |
| /* [15] hdmirx_aud_pll4x_en override enable */ |
| /* [14] hdmirx_aud_pll4x_en override value */ |
| /* [6:5] clk_sel for cts_hdmirx_aud_pll_clk: */ |
| /* 0=hdmirx_aud_pll_clk */ |
| /* [4] clk_en for cts_hdmirx_aud_pll_clk */ |
| /* [2:0] clk_div for cts_hdmirx_aud_pll_clk */ |
| data32 = 0; |
| data32 |= (0 << 15); |
| data32 |= (1 << 14); |
| data32 |= (0 << 5); |
| data32 |= (0 << 4); |
| data32 |= (0 << 0); |
| wr_reg_hhi(HHI_AUDPLL_CLK_OUT_CNTL, data32); |
| data32 |= (1 << 4); |
| wr_reg_hhi(HHI_AUDPLL_CLK_OUT_CNTL, data32); |
| |
| data32 = hdmirx_rd_top(TOP_CLK_CNTL); |
| data32 |= 0 << 31; /* [31] disable clkgating */ |
| data32 |= 1 << 17; /* [17] audfifo_rd_en */ |
| data32 |= 1 << 16; /* [16] pktfifo_rd_en */ |
| data32 |= 0 << 8; /* [8] tmds_ch2_clk_inv */ |
| data32 |= 0 << 7; /* [7] tmds_ch1_clk_inv */ |
| data32 |= 0 << 6; /* [6] tmds_ch0_clk_inv */ |
| data32 |= 0 << 5; /* [5] pll4x_cfg */ |
| /* force_pll4x: |
| * 1=Force pll4x_en value to be pll4x_cfg. |
| * 0=Use auto detect. |
| */ |
| data32 |= 0 << 4; /* [4] force_pll4x */ |
| data32 |= 0 << 3; /* [3] phy_clk_inv: 1-invert */ |
| hdmirx_wr_top(TOP_CLK_CNTL, data32); /* DEFAULT: {32'h0} */ |
| } |
| |
| /* pinmux SCL/SDA/HPD/PWR5V of all port */ |
| void rx_set_pinmux(void) |
| { |
| unsigned int mux = readl(P_PERIPHS_PIN_MUX_B); |
| writel(0x11111111, P_PERIPHS_PIN_MUX_A); |
| writel((mux & 0xFFFF0000) | 0x1111 , P_PERIPHS_PIN_MUX_B); |
| printf("set pinmux A:0x%x\n", readl(P_PERIPHS_PIN_MUX_A)); |
| printf("set pinmux B:0x%x\n", readl(P_PERIPHS_PIN_MUX_B)); |
| } |
| |
| void hdmirx_hw_init(unsigned int port_map, |
| unsigned char *pedid_data, |
| int edid_size) |
| { |
| /*int i, j;*/ |
| if ((pedid_data != NULL) && (edid_size >= EDID_DEFAULT_LEN)) { |
| printf("load %#x,len:%d\n", pedid_data[0], edid_size); |
| hdmirx_data.edid_buf = pedid_data; |
| hdmirx_data.edid_size = edid_size; |
| } else { |
| hdmirx_data.edid_buf = edid_14; |
| hdmirx_data.edid_size = sizeof(edid_14); |
| } |
| hdmirx_wr_top(TOP_MEM_PD, 0); |
| hdmirx_wr_top(TOP_INTR_MASKN, 0); |
| hdmirx_wr_top(TOP_SW_RESET, 0); |
| rx_clk_init(); |
| rx_top_init(); |
| hdmirx_data.port_map = port_map; |
| hdmirx_ctrl_edid_update(); |
| /* for (i = 0; i < 16; i++) { */ |
| /* printf("[%2d] ", i); */ |
| /* for (j = 0; j < 16; j++) { */ |
| /* printf("0x%02lx, ", */ |
| /* hdmirx_rd_top(TOP_EDID_ADDR_S + */ |
| /* (i * 16 + j))); */ |
| /* } */ |
| /* printf("\n"); */ |
| /* } */ |
| |
| hdmirx_wr_top(TOP_PORT_SEL, 0x10); |
| hdmirx_wr_bits_top(TOP_HPD_PWR5V, MSK(4, 0), 0xF); |
| rx_set_pinmux(); |
| printf("%s Done port map:%#x !\n", __func__, port_map); |
| } |
| |