blob: 871b75f210852474efdb11a4491b6609ee696ac2 [file] [log] [blame]
/*
* drivers/amlogic/media/vin/tvin/hdmirx/hdmi_rx_hw.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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.
*
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/amlogic/media/frame_provider/tvin/tvin.h>
#include <linux/arm-smccc.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
/* Local include */
#include "hdmi_rx_eq.h"
#include "hdmi_rx_repeater.h"
#include "hdmi_rx_drv.h"
#include "hdmi_rx_hw.h"
#include "hdmi_rx_edid.h"
#include "hdmi_rx_wrapper.h"
/*------------------------marco define------------------------------*/
#define SCRAMBLE_SEL 1
#define HYST_HDMI_TO_DVI 5
/* must = 0, other agilent source fail */
#define HYST_DVI_TO_HDMI 1
#define GCP_GLOBAVMUTE_EN 1 /* ag506 must clear this bit */
#define EDID_CLK_DIV 9 /* sys clk/(9+1) = 20M */
#define HDCP_KEY_WR_TRIES (5)
/*------------------------variable define------------------------------*/
static DEFINE_SPINLOCK(reg_rw_lock);
/* should enable fast switching, since some devices in non-current port */
/* will suspend because of RxSense = 0, such as xiaomi-mtk box */
static bool phy_fast_switching;
static bool phy_fsm_enhancement = true;
/*unsigned int last_clk_rate;*/
static uint32_t modet_clk = 24000;
int hdcp_enc_mode;
/* top_irq_en bit[16:13] hdcp_sts */
int top_intr_maskn_value = 1;
bool hdcp_enable = 1;
int acr_mode;
int auto_aclk_mute = 2;
int aud_avmute_en = 1;
int aud_mute_sel = 2;
int force_clk_rate;
int md_ists_en = VIDEO_MODE;
int pdec_ists_en;/* = AVI_CKS_CHG | DVIDET | DRM_CKS_CHG | DRM_RCV_EN;*/
uint32_t packet_fifo_cfg;
int pd_fifo_start_cnt = 0x80;
/* Controls equalizer reference voltage. */
int hdcp22_on;
MODULE_PARM_DESC(hdcp22_on, "\n hdcp22_on\n");
module_param(hdcp22_on, int, 0664);
/* test for HBR CTS, audio module can set it to force 8ch */
int hbr_force_8ch = 1;
/*
* hdcp14_key_mode:hdcp1.4 key handle method select
* NORMAL_MODE:systemcontrol path
* SECURE_MODE:secure OS path
*/
int hdcp14_key_mode = NORMAL_MODE;
int aud_ch_map;
int ignore_sscp_charerr = 1;
int ignore_sscp_tmds = 1;
int find_best_eq;
int eq_try_cnt = 20;
int pll_rst_max = 10;
/*------------------------variable define end------------------------------*/
static int check_regmap_flag(unsigned int addr)
{
return 1;
}
/*
* hdmirx_rd_dwc - Read data from HDMI RX CTRL
* @addr: register address
*
* return data read value
*/
unsigned int hdmirx_rd_dwc(unsigned int addr)
{
ulong flags;
int data;
unsigned long dev_offset = 0x10;
if (rx.chip_id == CHIP_ID_TL1) {
spin_lock_irqsave(&reg_rw_lock, flags);
data = rd_reg(MAP_ADDR_MODULE_TOP,
addr + reg_maps[MAP_ADDR_MODULE_TOP].phy_addr);
spin_unlock_irqrestore(&reg_rw_lock, flags);
} else {
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_addr_port | dev_offset, addr);
data = rd_reg(MAP_ADDR_MODULE_TOP,
hdmirx_data_port | dev_offset);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
return data;
}
/*
* hdmirx_rd_bits_dwc - read specfied bits of HDMI RX CTRL reg
* @addr: register address
* @mask: bits mask
*
* return masked bits of register value
*/
unsigned int hdmirx_rd_bits_dwc(unsigned int addr, unsigned int mask)
{
return rx_get_bits(hdmirx_rd_dwc(addr), mask);
}
/*
* hdmirx_wr_dwc - Write data to HDMI RX CTRL
* @addr: register address
* @data: new register value
*/
void hdmirx_wr_dwc(unsigned int addr, unsigned int data)
{
ulong flags;
unsigned int dev_offset = 0x10;
if (rx.chip_id == CHIP_ID_TL1) {
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_TOP,
addr + reg_maps[MAP_ADDR_MODULE_TOP].phy_addr, data);
spin_unlock_irqrestore(&reg_rw_lock, flags);
} else {
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_addr_port | dev_offset, addr);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_data_port | dev_offset, data);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
}
/*
* hdmirx_wr_bits_dwc - write specfied bits of HDMI RX CTRL reg
* @addr: register address
* @mask: bits mask
* @value: new register value
*/
void hdmirx_wr_bits_dwc(unsigned int addr,
unsigned int mask, unsigned int value)
{
hdmirx_wr_dwc(addr, rx_set_bits(hdmirx_rd_dwc(addr), mask, value));
}
/*
* hdmirx_rd_phy - Read data from HDMI RX phy
* @addr: register address
*
* return data read value
*/
unsigned int hdmirx_rd_phy(unsigned int reg_address)
{
int cnt = 0;
/* hdmirx_wr_dwc(DWC_I2CM_PHYG3_SLAVE, 0x39); */
hdmirx_wr_dwc(DWC_I2CM_PHYG3_ADDRESS, reg_address);
hdmirx_wr_dwc(DWC_I2CM_PHYG3_OPERATION, 0x02);
do {
if ((cnt % 10) == 0) {
/* wait i2cmpdone */
if (hdmirx_rd_dwc(DWC_HDMI_ISTS)&(1<<28)) {
hdmirx_wr_dwc(DWC_HDMI_ICLR, 1<<28);
break;
}
}
cnt++;
if (cnt > 50000) {
rx_pr("[HDMIRX err]: %s(%x,%x) timeout\n",
__func__, 0x39, reg_address);
break;
}
} while (1);
return (unsigned int)(hdmirx_rd_dwc(DWC_I2CM_PHYG3_DATAI));
}
/*
* hdmirx_rd_bits_phy - read specfied bits of HDMI RX phy reg
* @addr: register address
* @mask: bits mask
*
* return masked bits of register value
*/
unsigned int hdmirx_rd_bits_phy(unsigned int addr, unsigned int mask)
{
return rx_get_bits(hdmirx_rd_phy(addr), mask);
}
/*
* hdmirx_wr_phy - Write data to HDMI RX phy
* @addr: register address
* @data: new register value
*
* return 0 on write succeed, return -1 otherwise.
*/
unsigned int hdmirx_wr_phy(unsigned int reg_address, unsigned int data)
{
int error = 0;
int cnt = 0;
/* hdmirx_wr_dwc(DWC_I2CM_PHYG3_SLAVE, 0x39); */
hdmirx_wr_dwc(DWC_I2CM_PHYG3_ADDRESS, reg_address);
hdmirx_wr_dwc(DWC_I2CM_PHYG3_DATAO, data);
hdmirx_wr_dwc(DWC_I2CM_PHYG3_OPERATION, 0x01);
do {
/* wait i2cmpdone */
if ((cnt % 10) == 0) {
if (hdmirx_rd_dwc(DWC_HDMI_ISTS)&(1<<28)) {
hdmirx_wr_dwc(DWC_HDMI_ICLR, 1<<28);
break;
}
}
cnt++;
if (cnt > 50000) {
error = -1;
rx_pr("[err-%s]:(%x,%x)timeout\n",
__func__, reg_address, data);
break;
}
} while (1);
return error;
}
/*
* hdmirx_wr_bits_phy - write specfied bits of HDMI RX phy reg
* @addr: register address
* @mask: bits mask
* @value: new register value
*
* return 0 on write succeed, return -1 otherwise.
*/
int hdmirx_wr_bits_phy(uint16_t addr, uint32_t mask, uint32_t value)
{
return hdmirx_wr_phy(addr, rx_set_bits(hdmirx_rd_phy(addr),
mask, value));
}
/*
* hdmirx_rd_top - read hdmirx top reg
* @addr: register address
*
* return data read value
*/
unsigned int hdmirx_rd_top(unsigned int addr)
{
ulong flags;
int data;
unsigned int dev_offset = 0;
unsigned int tempaddr = 0;
if (rx.chip_id == CHIP_ID_TL1) {
spin_lock_irqsave(&reg_rw_lock, flags);
dev_offset = TOP_DWC_BASE_OFFSET +
reg_maps[MAP_ADDR_MODULE_TOP].phy_addr;
if ((addr >= TOP_EDID_OFFSET) &&
(addr <= (TOP_EDID_OFFSET + 0x1ff))) {
/*edid address range*/
tempaddr = TOP_EDID_ADDR_S + (addr - 0x200);
data = rd_reg_b(MAP_ADDR_MODULE_TOP,
dev_offset + tempaddr);
} else {
data = rd_reg(MAP_ADDR_MODULE_TOP,
dev_offset + (addr<<2));
}
spin_unlock_irqrestore(&reg_rw_lock, flags);
} else {
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_addr_port | dev_offset, addr);
data = rd_reg(MAP_ADDR_MODULE_TOP,
hdmirx_data_port | dev_offset);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
return data;
}
/*
* hdmirx_rd_bits_top - read specified bits of hdmirx top reg
* @addr: register address
* @mask: bits mask
*
* return masked bits of register value
*/
uint32_t hdmirx_rd_bits_top(uint16_t addr, uint32_t mask)
{
return rx_get_bits(hdmirx_rd_top(addr), mask);
}
/*
* hdmirx_wr_top - Write data to hdmirx top reg
* @addr: register address
* @data: new register value
*/
void hdmirx_wr_top(unsigned int addr, unsigned int data)
{
ulong flags;
unsigned long dev_offset = 0;
unsigned int tempaddr = 0;
if (rx.chip_id == CHIP_ID_TL1) {
spin_lock_irqsave(&reg_rw_lock, flags);
dev_offset = TOP_DWC_BASE_OFFSET +
reg_maps[MAP_ADDR_MODULE_TOP].phy_addr;
if ((addr >= TOP_EDID_OFFSET) &&
(addr <= (TOP_EDID_OFFSET + 0x1ff))) {
/*edid address range*/
tempaddr = TOP_EDID_ADDR_S + (addr - 0x200);
wr_reg_b(MAP_ADDR_MODULE_TOP,
dev_offset + tempaddr, (unsigned char)data);
} else {
wr_reg(MAP_ADDR_MODULE_TOP,
dev_offset + (addr<<2), data);
}
spin_unlock_irqrestore(&reg_rw_lock, flags);
} else {
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_addr_port | dev_offset, addr);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_data_port | dev_offset, data);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
}
/*
* hdmirx_wr_bits_top - write specified bits of hdmirx top reg
* @addr: register address
* @mask: bits mask
* @value: new register value
*/
void hdmirx_wr_bits_top(unsigned int addr,
unsigned int mask, unsigned int value)
{
hdmirx_wr_top(addr, rx_set_bits(hdmirx_rd_top(addr), mask, value));
}
/*
* rd_reg_hhi
* @offset: offset address of hhi physical addr
*
* returns unsigned int bytes read from the addr
*/
unsigned int rd_reg_hhi(unsigned int offset)
{
unsigned int ret;
unsigned long flags;
unsigned int addr;
spin_lock_irqsave(&reg_rw_lock, flags);
addr = offset +
reg_maps[MAP_ADDR_MODULE_HIU].phy_addr;
ret = rd_reg(MAP_ADDR_MODULE_HIU, addr);
spin_unlock_irqrestore(&reg_rw_lock, flags);
return ret;
}
/*
* rd_reg_hhi_bits - read specfied bits of HHI reg
* @addr: register address
* @mask: bits mask
*
* return masked bits of register value
*/
unsigned int rd_reg_hhi_bits(unsigned int offset, unsigned int mask)
{
return rx_get_bits(rd_reg_hhi(offset), mask);
}
/*
* wr_reg_hhi
* @offset: offset address of hhi physical addr
* @val: value being written
*/
void wr_reg_hhi(unsigned int offset, unsigned int val)
{
unsigned long flags;
unsigned int addr;
spin_lock_irqsave(&reg_rw_lock, flags);
addr = offset +
reg_maps[MAP_ADDR_MODULE_HIU].phy_addr;
wr_reg(MAP_ADDR_MODULE_HIU, addr, val);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
/*
* wr_reg_hhi_bits
* @offset: offset address of hhi physical addr
* @mask: modify bits mask
* @val: value being written
*/
void wr_reg_hhi_bits(unsigned int offset, unsigned int mask, unsigned int val)
{
wr_reg_hhi(offset, rx_set_bits(rd_reg_hhi(offset), mask, val));
}
/*
* rd_reg - regisger read
* @module: module index of the reg_map table
* @reg_addr: offset address of specified phy addr
*
* returns unsigned int bytes read from the addr
*/
unsigned int rd_reg(enum map_addr_module_e module,
unsigned int reg_addr)
{
unsigned int val = 0;
if ((module < MAP_ADDR_MODULE_NUM)
&& check_regmap_flag(reg_addr))
val = readl(reg_maps[module].p +
(reg_addr - reg_maps[module].phy_addr));
else
rx_pr("rd reg %x error,md %d\n", reg_addr, module);
return val;
}
/*
* wr_reg - regisger write
* @module: module index of the reg_map table
* @reg_addr: offset address of specified phy addr
* @val: value being written
*/
void wr_reg(enum map_addr_module_e module,
unsigned int reg_addr, unsigned int val)
{
if ((module < MAP_ADDR_MODULE_NUM)
&& check_regmap_flag(reg_addr))
writel(val, reg_maps[module].p +
(reg_addr - reg_maps[module].phy_addr));
else
rx_pr("wr reg %x err\n", reg_addr);
}
/*
* rd_reg_b - regisger read byte mode
* @module: module index of the reg_map table
* @reg_addr: offset address of specified phy addr
*
* returns unsigned char bytes read from the addr
*/
unsigned char rd_reg_b(enum map_addr_module_e module,
unsigned int reg_addr)
{
unsigned char val = 0;
if ((module < MAP_ADDR_MODULE_NUM)
&& check_regmap_flag(reg_addr))
val = readb(reg_maps[module].p +
(reg_addr - reg_maps[module].phy_addr));
else
rx_pr("rd reg %x error,md %d\n", reg_addr, module);
return val;
}
/*
* wr_reg_b - regisger write byte mode
* @module: module index of the reg_map table
* @reg_addr: offset address of specified phy addr
* @val: value being written
*/
void wr_reg_b(enum map_addr_module_e module,
unsigned int reg_addr, unsigned char val)
{
if ((module < MAP_ADDR_MODULE_NUM)
&& check_regmap_flag(reg_addr))
writeb(val, reg_maps[module].p +
(reg_addr - reg_maps[module].phy_addr));
else
rx_pr("wr reg %x err\n", reg_addr);
}
/*
* rx_hdcp22_wr_only
*/
void rx_hdcp22_wr_only(unsigned int addr, unsigned int data)
{
unsigned long flags;
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_HDMIRX_CAPB3,
reg_maps[MAP_ADDR_MODULE_HDMIRX_CAPB3].phy_addr | addr,
data);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
unsigned int rx_hdcp22_rd(unsigned int addr)
{
unsigned int data;
unsigned long flags;
spin_lock_irqsave(&reg_rw_lock, flags);
data = rd_reg(MAP_ADDR_MODULE_HDMIRX_CAPB3,
reg_maps[MAP_ADDR_MODULE_HDMIRX_CAPB3].phy_addr | addr);
spin_unlock_irqrestore(&reg_rw_lock, flags);
return data;
}
void rx_hdcp22_rd_check(unsigned int addr,
unsigned int exp_data, unsigned int mask)
{
unsigned int rd_data;
rd_data = rx_hdcp22_rd(addr);
if ((rd_data | mask) != (exp_data | mask))
rx_pr("addr=0x%02x rd_data=0x%08x\n", addr, rd_data);
}
void rx_hdcp22_wr(unsigned int addr, unsigned int data)
{
rx_hdcp22_wr_only(addr, data);
rx_hdcp22_rd_check(addr, data, 0);
}
/*
* rx_hdcp22_rd_reg - hdcp2.2 reg write
* @addr: register address
* @value: new register value
*/
void rx_hdcp22_wr_reg(unsigned int addr, unsigned int data)
{
rx_sec_reg_write((unsigned int *)(unsigned long)
(reg_maps[MAP_ADDR_MODULE_HDMIRX_CAPB3].phy_addr + addr),
data);
}
/*
* rx_hdcp22_rd_reg - hdcp2.2 reg read
* @addr: register address
*/
unsigned int rx_hdcp22_rd_reg(unsigned int addr)
{
return (uint32_t)rx_sec_reg_read((unsigned int *)(unsigned long)
(reg_maps[MAP_ADDR_MODULE_HDMIRX_CAPB3].phy_addr + addr));
}
/*
* rx_hdcp22_rd_reg_bits - hdcp2.2 reg masked bits read
* @addr: register address
* @mask: bits mask
*/
unsigned int rx_hdcp22_rd_reg_bits(unsigned int addr, unsigned int mask)
{
return rx_get_bits(rx_hdcp22_rd_reg(addr), mask);
}
/*
* rx_hdcp22_wr_reg_bits - hdcp2.2 reg masked bits write
* @addr: register address
* @mask: bits mask
* @value: new register value
*/
void rx_hdcp22_wr_reg_bits(unsigned int addr,
unsigned int mask, unsigned int value)
{
rx_hdcp22_wr_reg(addr, rx_set_bits(rx_hdcp22_rd_reg(addr),
mask, value));
}
/*
* hdcp22_wr_top - hdcp2.2 top reg write
* @addr: register address
* @data: new register value
*/
void rx_hdcp22_wr_top(unsigned int addr, unsigned int data)
{
sec_top_write((unsigned int *)(unsigned long)addr, data);
}
/*
* hdcp22_rd_top - hdcp2.2 top reg read
* @addr: register address
*/
unsigned int rx_hdcp22_rd_top(uint32_t addr)
{
return (unsigned int)sec_top_read((unsigned int *)(unsigned long)addr);
}
/*
* sec_top_write - secure top write
*/
void sec_top_write(unsigned int *addr, unsigned int value)
{
struct arm_smccc_res res;
arm_smccc_smc(HDMIRX_WR_SEC_TOP, (unsigned long)(uintptr_t)addr,
value, 0, 0, 0, 0, 0, &res);
}
/*
* sec_top_read - secure top read
*/
unsigned int sec_top_read(unsigned int *addr)
{
struct arm_smccc_res res;
arm_smccc_smc(HDMIRX_RD_SEC_TOP, (unsigned long)(uintptr_t)addr,
0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
/*
* rx_sec_reg_write - secure region write
*/
void rx_sec_reg_write(unsigned int *addr, unsigned int value)
{
struct arm_smccc_res res;
arm_smccc_smc(HDCP22_RX_ESM_WRITE, (unsigned long)(uintptr_t)addr,
value, 0, 0, 0, 0, 0, &res);
}
/*
* rx_sec_reg_read - secure region read
*/
unsigned int rx_sec_reg_read(unsigned int *addr)
{
struct arm_smccc_res res;
arm_smccc_smc(HDCP22_RX_ESM_READ, (unsigned long)(uintptr_t)addr,
0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
/*
* rx_sec_set_duk
*/
unsigned int rx_sec_set_duk(bool repeater)
{
struct arm_smccc_res res;
if (repeater)
arm_smccc_smc(HDCP22_RP_SET_DUK_KEY, 0, 0, 0, 0, 0, 0, 0, &res);
else
arm_smccc_smc(HDCP22_RX_SET_DUK_KEY, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
/*
* rx_set_hdcp14_secure_key
*/
unsigned int rx_set_hdcp14_secure_key(void)
{
struct arm_smccc_res res;
/* 0x8200002d is the SMC cmd defined in BL31,this CMD
* will call set hdcp1.4 key function
*/
arm_smccc_smc(HDCP14_RX_SETKEY, 0, 0, 0, 0, 0, 0, 0, &res);
return (unsigned int)((res.a0)&0xffffffff);
}
/*
* hdmirx_phy_pddq - phy pddq config
* @enable: enable phy pddq up
*/
void hdmirx_phy_pddq(unsigned int enable)
{
uint32_t term_value =
hdmirx_rd_top(TOP_HPD_PWR5V) & 0x7;
if (rx.chip_id == CHIP_ID_TL1) {
wr_reg_hhi_bits(HHI_HDMIRX_PHY_MISC_CNTL2, _BIT(1), enable);
/* set rxsense */
if (enable)
wr_reg_hhi_bits(HHI_HDMIRX_PHY_MISC_CNTL0,
MSK(3, 0), 0);
else
wr_reg_hhi_bits(HHI_HDMIRX_PHY_MISC_CNTL0,
MSK(3, 0), term_value);
}
else
hdmirx_wr_bits_dwc(DWC_SNPS_PHYG3_CTRL,
MSK(1, 1), enable);
}
/*
* hdmirx_wr_ctl_port
*/
void hdmirx_wr_ctl_port(unsigned int offset, unsigned int data)
{
unsigned long flags;
if (rx.chip_id < CHIP_ID_TL1) {
spin_lock_irqsave(&reg_rw_lock, flags);
wr_reg(MAP_ADDR_MODULE_TOP, hdmirx_ctrl_port+offset, data);
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
}
/*
* hdmirx_top_sw_reset
*/
void hdmirx_top_sw_reset(void)
{
ulong flags;
unsigned long dev_offset = 0;
spin_lock_irqsave(&reg_rw_lock, flags);
if (rx.chip_id == CHIP_ID_TL1) {
dev_offset = TOP_DWC_BASE_OFFSET +
reg_maps[MAP_ADDR_MODULE_TOP].phy_addr;
wr_reg(MAP_ADDR_MODULE_TOP,
dev_offset + TOP_SW_RESET, 1);
udelay(1);
wr_reg(MAP_ADDR_MODULE_TOP,
dev_offset + TOP_SW_RESET, 0);
} else {
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_addr_port | dev_offset, TOP_SW_RESET);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_data_port | dev_offset, 1);
udelay(1);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_addr_port | dev_offset, TOP_SW_RESET);
wr_reg(MAP_ADDR_MODULE_TOP,
hdmirx_data_port | dev_offset, 0);
}
spin_unlock_irqrestore(&reg_rw_lock, flags);
}
/*
* rx_irq_en - hdmirx controller irq config
* @enable - irq set or clear
*/
void rx_irq_en(bool enable)
{
unsigned int data32 = 0;
if (enable) {
if (rx.chip_id == CHIP_ID_TL1) {
data32 |= 1 << 31; /* DRC_CKS_CHG */
data32 |= 1 << 30; /* DRC_RCV */
data32 |= 0 << 29; /* AUD_TYPE_CHG */
data32 |= 0 << 28; /* DVI_DET */
data32 |= 1 << 27; /* VSI_CKS_CHG */
data32 |= 0 << 26; /* GMD_CKS_CHG */
data32 |= 0 << 25; /* AIF_CKS_CHG */
data32 |= 1 << 24; /* AVI_CKS_CHG */
data32 |= 0 << 23; /* ACR_N_CHG */
data32 |= 0 << 22; /* ACR_CTS_CHG */
data32 |= 1 << 21; /* GCP_AV_MUTE_CHG */
data32 |= 0 << 20; /* GMD_RCV */
data32 |= 0 << 19; /* AIF_RCV */
data32 |= 0 << 18; /* AVI_RCV */
data32 |= 0 << 17; /* ACR_RCV */
data32 |= 0 << 16; /* GCP_RCV */
data32 |= 1 << 15; /* VSI_RCV */
data32 |= 0 << 14; /* AMP_RCV */
data32 |= 0 << 13; /* AMP_CHG */
data32 |= 0 << 9; /* EMP_RCV*/
data32 |= 0 << 8; /* PD_FIFO_NEW_ENTRY */
data32 |= 0 << 4; /* PD_FIFO_OVERFL */
data32 |= 0 << 3; /* PD_FIFO_UNDERFL */
data32 |= 0 << 2; /* PD_FIFO_TH_START_PASS */
data32 |= 0 << 1; /* PD_FIFO_TH_MAX_PASS */
data32 |= 0 << 0; /* PD_FIFO_TH_MIN_PASS */
data32 |= pdec_ists_en;
} else if (rx.chip_id == CHIP_ID_TXLX) {
data32 |= 1 << 31; /* DRC_CKS_CHG */
data32 |= 1 << 30; /* DRC_RCV */
data32 |= 0 << 29; /* AUD_TYPE_CHG */
data32 |= 0 << 28; /* DVI_DET */
data32 |= 1 << 27; /* VSI_CKS_CHG */
data32 |= 0 << 26; /* GMD_CKS_CHG */
data32 |= 0 << 25; /* AIF_CKS_CHG */
data32 |= 1 << 24; /* AVI_CKS_CHG */
data32 |= 0 << 23; /* ACR_N_CHG */
data32 |= 0 << 22; /* ACR_CTS_CHG */
data32 |= 1 << 21; /* GCP_AV_MUTE_CHG */
data32 |= 0 << 20; /* GMD_RCV */
data32 |= 0 << 19; /* AIF_RCV */
data32 |= 0 << 18; /* AVI_RCV */
data32 |= 0 << 17; /* ACR_RCV */
data32 |= 0 << 16; /* GCP_RCV */
data32 |= 1 << 15; /* VSI_RCV */
data32 |= 0 << 14; /* AMP_RCV */
data32 |= 0 << 13; /* AMP_CHG */
data32 |= 0 << 8; /* PD_FIFO_NEW_ENTRY */
data32 |= 0 << 4; /* PD_FIFO_OVERFL */
data32 |= 0 << 3; /* PD_FIFO_UNDERFL */
data32 |= 0 << 2; /* PD_FIFO_TH_START_PASS */
data32 |= 0 << 1; /* PD_FIFO_TH_MAX_PASS */
data32 |= 0 << 0; /* PD_FIFO_TH_MIN_PASS */
data32 |= pdec_ists_en;
} else if (rx.chip_id == CHIP_ID_TXHD) {
/* data32 |= 1 << 31; DRC_CKS_CHG */
/* data32 |= 1 << 30; DRC_RCV */
data32 |= 0 << 29; /* AUD_TYPE_CHG */
data32 |= 0 << 28; /* DVI_DET */
data32 |= 1 << 27; /* VSI_CKS_CHG */
data32 |= 0 << 26; /* GMD_CKS_CHG */
data32 |= 0 << 25; /* AIF_CKS_CHG */
data32 |= 1 << 24; /* AVI_CKS_CHG */
data32 |= 0 << 23; /* ACR_N_CHG */
data32 |= 0 << 22; /* ACR_CTS_CHG */
data32 |= 1 << 21; /* GCP_AV_MUTE_CHG */
data32 |= 0 << 20; /* GMD_RCV */
data32 |= 0 << 19; /* AIF_RCV */
data32 |= 0 << 18; /* AVI_RCV */
data32 |= 0 << 17; /* ACR_RCV */
data32 |= 0 << 16; /* GCP_RCV */
data32 |= 1 << 15; /* VSI_RCV */
/* data32 |= 0 << 14; AMP_RCV */
/* data32 |= 0 << 13; AMP_CHG */
data32 |= 0 << 8; /* PD_FIFO_NEW_ENTRY */
data32 |= 0 << 4; /* PD_FIFO_OVERFL */
data32 |= 0 << 3; /* PD_FIFO_UNDERFL */
data32 |= 0 << 2; /* PD_FIFO_TH_START_PASS */
data32 |= 0 << 1; /* PD_FIFO_TH_MAX_PASS */
data32 |= 0 << 0; /* PD_FIFO_TH_MIN_PASS */
data32 |= pdec_ists_en;
} else { /* TXL and previous Chip */
data32 = 0;
data32 |= 0 << 29; /* AUD_TYPE_CHG */
data32 |= 0 << 28; /* DVI_DET */
data32 |= 1 << 27; /* VSI_CKS_CHG */
data32 |= 0 << 26; /* GMD_CKS_CHG */
data32 |= 0 << 25; /* AIF_CKS_CHG */
data32 |= 1 << 24; /* AVI_CKS_CHG */
data32 |= 0 << 23; /* ACR_N_CHG */
data32 |= 0 << 22; /* ACR_CTS_CHG */
data32 |= 1 << 21; /* GCP_AV_MUTE_CHG */
data32 |= 0 << 20; /* GMD_RCV */
data32 |= 0 << 19; /* AIF_RCV */
data32 |= 0 << 18; /* AVI_RCV */
data32 |= 0 << 17; /* ACR_RCV */
data32 |= 0 << 16; /* GCP_RCV */
data32 |= 0 << 15; /* VSI_RCV */
data32 |= 0 << 14; /* AMP_RCV */
data32 |= 0 << 13; /* AMP_CHG */
/* diff */
data32 |= 1 << 10; /* DRC_CKS_CHG */
data32 |= 1 << 9; /* DRC_RCV */
/* diff */
data32 |= 0 << 8; /* PD_FIFO_NEW_ENTRY */
data32 |= 0 << 4; /* PD_FIFO_OVERFL */
data32 |= 0 << 3; /* PD_FIFO_UNDERFL */
data32 |= 0 << 2; /* PD_FIFO_TH_START_PASS */
data32 |= 0 << 1; /* PD_FIFO_TH_MAX_PASS */
data32 |= 0 << 0; /* PD_FIFO_TH_MIN_PASS */
data32 |= pdec_ists_en;
}
hdmirx_wr_dwc(DWC_PDEC_IEN_SET, data32);
hdmirx_wr_dwc(DWC_AUD_FIFO_IEN_SET, OVERFL|UNDERFL);
} else {
/* clear enable */
hdmirx_wr_dwc(DWC_PDEC_IEN_CLR, ~0);
hdmirx_wr_dwc(DWC_AUD_CEC_IEN_CLR, ~0);
hdmirx_wr_dwc(DWC_AUD_FIFO_IEN_CLR, ~0);
hdmirx_wr_dwc(DWC_MD_IEN_CLR, ~0);
/* clear status */
hdmirx_wr_dwc(DWC_PDEC_ICLR, ~0);
hdmirx_wr_dwc(DWC_AUD_CEC_ICLR, ~0);
hdmirx_wr_dwc(DWC_AUD_FIFO_ICLR, ~0);
hdmirx_wr_dwc(DWC_MD_ICLR, ~0);
}
}
/*
* hdmirx_irq_hdcp_enable - hdcp irq enalbe
*/
void hdmirx_irq_hdcp_enable(bool enable)
{
if (enable) {
/* hdcp2.2 */
if (hdcp22_on)
hdmirx_wr_dwc(DWC_HDMI2_IEN_SET, 0x1f);
/* hdcp1.4 */
hdmirx_wr_dwc(DWC_HDMI_IEN_SET, AKSV_RCV);
} else {
/* hdcp2.2 */
if (hdcp22_on) {
/* clear enable */
hdmirx_wr_dwc(DWC_HDMI2_IEN_CLR, ~0);
/* clear status */
hdmirx_wr_dwc(DWC_HDMI2_ICLR, ~0);
}
/* hdcp1.4 */
/* clear enable */
hdmirx_wr_dwc(DWC_HDMI_IEN_CLR, ~0);
/* clear status */
hdmirx_wr_dwc(DWC_HDMI_ICLR, ~0);
}
}
/*
* rx_get_audinfo - get aduio info
*/
void rx_get_audinfo(struct aud_info_s *audio_info)
{
audio_info->coding_type =
hdmirx_rd_bits_dwc(DWC_PDEC_AIF_PB0, CODING_TYPE);
audio_info->channel_count =
hdmirx_rd_bits_dwc(DWC_PDEC_AIF_PB0, CHANNEL_COUNT);
audio_info->sample_frequency =
hdmirx_rd_bits_dwc(DWC_PDEC_AIF_PB0, SAMPLE_FREQ);
audio_info->sample_size =
hdmirx_rd_bits_dwc(DWC_PDEC_AIF_PB0, SAMPLE_SIZE);
audio_info->coding_extension =
hdmirx_rd_bits_dwc(DWC_PDEC_AIF_PB0, AIF_DATA_BYTE_3);
audio_info->auds_ch_alloc =
hdmirx_rd_bits_dwc(DWC_PDEC_AIF_PB0, CH_SPEAK_ALLOC);
audio_info->auds_layout =
hdmirx_rd_bits_dwc(DWC_PDEC_STS, PD_AUD_LAYOUT);
audio_info->aud_hbr_rcv =
hdmirx_rd_dwc(DWC_PDEC_AUD_STS) & AUDS_HBR_RCV;
audio_info->aud_packet_received =
hdmirx_rd_dwc(DWC_PDEC_AUD_STS) &
(AUDS_RCV | AUDS_HBR_RCV);
audio_info->cts = hdmirx_rd_dwc(DWC_PDEC_ACR_CTS);
audio_info->n = hdmirx_rd_dwc(DWC_PDEC_ACR_N);
if (audio_info->cts != 0) {
audio_info->arc =
(rx_measure_clock(MEASURE_CLK_TMDS)/audio_info->cts)*
audio_info->n/128;
} else
audio_info->arc = 0;
}
/*
* rx_get_audio_status - interface for audio module
*/
void rx_get_audio_status(struct rx_audio_stat_s *aud_sts)
{
if ((rx.state == FSM_SIG_READY) &&
(rx.pre.sw_vic != HDMI_UNKNOWN) &&
(rx.pre.sw_vic != HDMI_UNSUPPORT) &&
(rx.avmute_skip == 0)) {
aud_sts->aud_rcv_packet = rx.aud_info.aud_packet_received;
aud_sts->aud_stb_flag = true;
aud_sts->aud_alloc = rx.aud_info.auds_ch_alloc;
aud_sts->aud_sr = rx.aud_info.real_sr;
aud_sts->aud_channel_cnt = rx.aud_info.channel_count;
aud_sts->aud_type = rx.aud_info.coding_type;
aud_sts->afifo_thres_pass =
((hdmirx_rd_dwc(DWC_AUD_FIFO_STS) &
THS_PASS_STS) == 0) ? false : true;
} else {
memset(aud_sts, 0,
sizeof(struct rx_audio_stat_s));
}
}
EXPORT_SYMBOL(rx_get_audio_status);
/*
* rx_get_audio_status - interface for audio module
*/
int rx_set_audio_param(uint32_t param)
{
hbr_force_8ch = param & 1;
return 1;
}
EXPORT_SYMBOL(rx_set_audio_param);
bool is_tl1_former(void)
{
if (is_meson_tl1_cpu() &&
is_meson_rev_a())
return 1;
return 0;
}
/*
* rx_get_hdmi5v_sts - get current pwr5v status on all ports
*/
unsigned int rx_get_hdmi5v_sts(void)
{
return (hdmirx_rd_top(TOP_HPD_PWR5V) >> 20) & 0xf;
}
/*
* rx_get_hpd_sts - get current hpd status on all ports
*/
unsigned int rx_get_hpd_sts(void)
{
return hdmirx_rd_top(TOP_HPD_PWR5V) & 0xf;
}
/*
* rx_get_scdc_clkrate_sts - get tmds clk ratio
*/
unsigned int rx_get_scdc_clkrate_sts(void)
{
uint32_t clk_rate = 0;
if (rx.chip_id == CHIP_ID_TXHD)
return 0;
else {
if (force_clk_rate & 0x10)
clk_rate = force_clk_rate & 1;
else
clk_rate = (hdmirx_rd_dwc(DWC_SCDC_REGS0) >> 17) & 1;
}
return clk_rate;
}
/*
* rx_get_pll_lock_sts - tmds pll lock indication
* return true if tmds pll locked, false otherwise.
*/
unsigned int rx_get_pll_lock_sts(void)
{
return hdmirx_rd_dwc(DWC_HDMI_PLL_LCK_STS) & 1;
}
/*
* rx_get_aud_pll_lock_sts - audio pll lock indication
* no use
*/
bool rx_get_aud_pll_lock_sts(void)
{
/* if ((hdmirx_rd_dwc(DWC_AUD_PLL_CTRL) & (1 << 31)) == 0) */
if ((rd_reg_hhi(HHI_AUD_PLL_CNTL_I) & (1 << 31)) == 0)
return false;
else
return true;
}
/*
* is_clk_stable - phy clock stable detection
*/
bool is_clk_stable(void)
{
int clk = false;
if (rx.chip_id == CHIP_ID_TL1) {
/* sqofclk */
clk = hdmirx_rd_top(TOP_MISC_STAT0) & 0x1;
} else {
/* phy clk */
clk = hdmirx_rd_phy(PHY_MAINFSM_STATUS1) & 0x100;
}
if (clk)
return true;
else
return false;
}
void rx_afifo_store_all_subpkt(bool all_pkt)
{
static bool flag = true;
if (all_pkt) {
if (log_level & AUDIO_LOG)
rx_pr("afifo store all subpkts: %d\n", flag);
/* when afifo overflow, try afifo store
* configuration alternatively
*/
if (flag)
hdmirx_wr_bits_dwc(DWC_AUD_FIFO_CTRL,
AFIF_SUBPACKETS, 0);
else
hdmirx_wr_bits_dwc(DWC_AUD_FIFO_CTRL,
AFIF_SUBPACKETS, 1);
flag = !flag;
} else
hdmirx_wr_bits_dwc(DWC_AUD_FIFO_CTRL,
AFIF_SUBPACKETS, 1);
}
/*
* hdmirx_audio_fifo_rst - reset afifo
*/
unsigned int hdmirx_audio_fifo_rst(void)
{
int error = 0;
hdmirx_wr_bits_dwc(DWC_AUD_FIFO_CTRL, AFIF_INIT, 1);
udelay(20);
hdmirx_wr_bits_dwc(DWC_AUD_FIFO_CTRL, AFIF_INIT, 0);
hdmirx_wr_dwc(DWC_DMI_SW_RST, 0x10);
if (log_level & AUDIO_LOG)
rx_pr("%s\n", __func__);
return error;
}
/*
* hdmirx_control_clk_range
*/
int hdmirx_control_clk_range(unsigned long min, unsigned long max)
{
int error = 0;
unsigned int evaltime = 0;
unsigned long ref_clk;
ref_clk = modet_clk;
evaltime = (ref_clk * 4095) / 158000;
min = (min * evaltime) / ref_clk;
max = (max * evaltime) / ref_clk;
hdmirx_wr_bits_dwc(DWC_HDMI_CKM_F, MINFREQ, min);
hdmirx_wr_bits_dwc(DWC_HDMI_CKM_F, CKM_MAXFREQ, max);
return error;
}
/*
* set_scdc_cfg
*/
void set_scdc_cfg(int hpdlow, int pwrprovided)
{
if (rx.chip_id == CHIP_ID_TXHD)
return;
hdmirx_wr_dwc(DWC_SCDC_CONFIG,
(hpdlow << 1) | (pwrprovided << 0));
}
/*
* packet_init - packet receiving config
*/
int packet_init(void)
{
int error = 0;
int data32 = 0;
data32 |= 1 << 12; /* emp_err_filter, tl1*/
data32 |= 1 << 9; /* amp_err_filter */
data32 |= 1 << 8; /* isrc_err_filter */
data32 |= 1 << 7; /* gmd_err_filter */
data32 |= 1 << 6; /* aif_err_filter */
data32 |= 1 << 5; /* avi_err_filter */
data32 |= 1 << 4; /* vsi_err_filter */
data32 |= 1 << 3; /* gcp_err_filter */
data32 |= 1 << 2; /* acrp_err_filter */
data32 |= 1 << 1; /* ph_err_filter */
data32 |= 0 << 0; /* checksum_err_filter */
hdmirx_wr_dwc(DWC_PDEC_ERR_FILTER, data32);
data32 = hdmirx_rd_dwc(DWC_PDEC_CTRL);
data32 |= 1 << 31; /* PFIFO_STORE_FILTER_EN */
data32 |= 1 << 30; /* Enable packet FIFO store EMP pkt*/
data32 |= 1 << 4; /* PD_FIFO_WE */
data32 |= 0 << 1; /* emp pkt rev int,0:last 1:every */
data32 |= 1 << 0; /* PDEC_BCH_EN */
data32 &= (~GCP_GLOBAVMUTE);
data32 |= GCP_GLOBAVMUTE_EN << 15;
data32 |= packet_fifo_cfg;
hdmirx_wr_dwc(DWC_PDEC_CTRL, data32);
data32 = 0;
data32 |= pd_fifo_start_cnt << 20; /* PD_start */
data32 |= 640 << 10; /* PD_max */
data32 |= 8 << 0; /* PD_min */
hdmirx_wr_dwc(DWC_PDEC_FIFO_CFG, data32);
return error;
}
/*
* pd_fifo_irq_ctl
*/
void pd_fifo_irq_ctl(bool en)
{
int i = hdmirx_rd_dwc(DWC_PDEC_IEN);
if (en == 0)
hdmirx_wr_bits_dwc(DWC_PDEC_IEN_CLR, _BIT(2), 1);
else
hdmirx_wr_dwc(DWC_PDEC_IEN_SET, (_BIT(2) | i));
}
/*
* hdmirx_packet_fifo_rst - reset packet fifo
*/
unsigned int hdmirx_packet_fifo_rst(void)
{
int error = 0;
hdmirx_wr_bits_dwc(DWC_PDEC_CTRL,
PD_FIFO_FILL_INFO_CLR|PD_FIFO_CLR, ~0);
hdmirx_wr_bits_dwc(DWC_PDEC_CTRL,
PD_FIFO_FILL_INFO_CLR|PD_FIFO_CLR, 0);
return error;
}
/*
* TOP_init - hdmirx top initialization
*/
static int 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);
if (rx.chip_id != CHIP_ID_TXHD) {
data32 = 0;
data32 |= 0 << 20;
data32 |= 0 << 8;
data32 |= 0x0a << 0;
hdmirx_wr_top(TOP_VID_CNTL2, data32);
}
data32 = 0;
if (rx.chip_id == CHIP_ID_TL1) {
/* n_cts_auto_mode: */
/* 0-every ACR packet */
/* 1-on N or CTS value change */
data32 |= 0 << 4;
}
/* delay cycles before n/cts update pulse */
data32 |= 7 << 0;
if (rx.chip_id == CHIP_ID_TL1)
hdmirx_wr_top(TOP_TL1_ACR_CNTL2, data32);
else
hdmirx_wr_top(TOP_ACR_CNTL2, data32);
if (rx.chip_id == CHIP_ID_TL1) {
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;
if (rx.chip_id == CHIP_ID_GXTVBB)
data32 |= 0 << 5;
else
data32 |= 1 << 5;
/* pull down all the hpd */
hdmirx_wr_top(TOP_HPD_PWR5V, data32);
return err;
}
/*
* DWC_init - DWC controller initialization
*/
static int DWC_init(void)
{
int err = 0;
unsigned long data32;
unsigned int evaltime = 0;
evaltime = (modet_clk * 4095) / 158000;
/* enable all */
hdmirx_wr_dwc(DWC_HDMI_OVR_CTRL, ~0);
/* recover to default value.*/
/* remain code for some time.*/
/* if no side effect then remove it */
/*hdmirx_wr_bits_dwc(DWC_HDMI_SYNC_CTRL,*/
/* VS_POL_ADJ_MODE, VS_POL_ADJ_AUTO);*/
/*hdmirx_wr_bits_dwc(DWC_HDMI_SYNC_CTRL,*/
/* HS_POL_ADJ_MODE, HS_POL_ADJ_AUTO);*/
hdmirx_wr_bits_dwc(DWC_HDMI_CKM_EVLTM,
EVAL_TIME, evaltime);
hdmirx_control_clk_range(TMDS_CLK_MIN,
TMDS_CLK_MAX);
/* hdmirx_wr_bits_dwc(DWC_SNPS_PHYG3_CTRL,*/
/*((1 << 2) - 1) << 2, port); */
data32 = 0;
data32 |= 0 << 20;
data32 |= 1 << 19;
data32 |= 5 << 16; /* [18:16] valid_mode */
data32 |= 0 << 12; /* [13:12] ctrl_filt_sens */
data32 |= 3 << 10; /* [11:10] vs_filt_sens */
data32 |= 0 << 8; /* [9:8] hs_filt_sens */
data32 |= 2 << 6; /* [7:6] de_measure_mode */
data32 |= 0 << 5; /* [5] de_regen */
data32 |= 3 << 3; /* [4:3] de_filter_sens */
hdmirx_wr_dwc(DWC_HDMI_ERROR_PROTECT, data32);
data32 = 0;
data32 |= 0 << 8; /* [10:8] hact_pix_ith */
data32 |= 0 << 5; /* [5] hact_pix_src */
data32 |= 1 << 4; /* [4] htot_pix_src */
hdmirx_wr_dwc(DWC_MD_HCTRL1, data32);
data32 = 0;
data32 |= 1 << 12; /* [14:12] hs_clk_ith */
data32 |= 7 << 8; /* [10:8] htot32_clk_ith */
data32 |= 1 << 5; /* [5] vs_act_time */
data32 |= 3 << 3; /* [4:3] hs_act_time */
data32 |= 0 << 0; /* [1:0] h_start_pos */
hdmirx_wr_dwc(DWC_MD_HCTRL2, data32);
data32 = 0;
data32 |= 1 << 4; /* [4] v_offs_lin_mode */
data32 |= 1 << 1; /* [1] v_edge */
data32 |= 0 << 0; /* [0] v_mode */
hdmirx_wr_dwc(DWC_MD_VCTRL, data32);
data32 = 0;
data32 |= 1 << 10; /* [11:10] vofs_lin_ith */
data32 |= 3 << 8; /* [9:8] vact_lin_ith */
data32 |= 0 << 6; /* [7:6] vtot_lin_ith */
data32 |= 7 << 3; /* [5:3] vs_clk_ith */
data32 |= 2 << 0; /* [2:0] vtot_clk_ith */
hdmirx_wr_dwc(DWC_MD_VTH, data32);
data32 = 0;
data32 |= 1 << 2; /* [2] fafielddet_en */
data32 |= 0 << 0; /* [1:0] field_pol_mode */
hdmirx_wr_dwc(DWC_MD_IL_POL, data32);
data32 = 0;
data32 |= 0 << 1;
data32 |= 1 << 0;
hdmirx_wr_dwc(DWC_HDMI_RESMPL_CTRL, data32);
data32 = 0;
data32 |= (hdmirx_rd_dwc(DWC_HDMI_MODE_RECOVER) & 0xf8000000);
data32 |= (0 << 24);
data32 |= (0 << 18);
data32 |= (HYST_HDMI_TO_DVI << 13);
data32 |= (HYST_DVI_TO_HDMI << 8);
data32 |= (0 << 6);
data32 |= (0 << 4);
/* EESS_OESS */
/* 0: new auto mode,check on HDMI mode or 1.1 features en */
/* 1: force OESS */
/* 2: force EESS */
/* 3: auto mode,check CTL[3:0]=d9/d8 during WOO */
data32 |= (hdcp_enc_mode << 2);
data32 |= (0 << 0);
hdmirx_wr_dwc(DWC_HDMI_MODE_RECOVER, 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);
return err;
}
void rx_hdcp14_set_normal_key(const struct hdmi_rx_hdcp *hdcp)
{
unsigned int i = 0;
unsigned int k = 0;
int error = 0;
for (i = 0; i < HDCP_KEYS_SIZE; i += 2) {
for (k = 0; k < HDCP_KEY_WR_TRIES; k++) {
if (hdmirx_rd_bits_dwc(DWC_HDCP_STS,
HDCP_KEY_WR_OK_STS) != 0) {
break;
}
}
if (k < HDCP_KEY_WR_TRIES) {
hdmirx_wr_dwc(DWC_HDCP_KEY1, hdcp->keys[i + 0]);
hdmirx_wr_dwc(DWC_HDCP_KEY0, hdcp->keys[i + 1]);
} else {
error = -EAGAIN;
break;
}
}
hdmirx_wr_dwc(DWC_HDCP_BKSV1, hdcp->bksv[0]);
hdmirx_wr_dwc(DWC_HDCP_BKSV0, hdcp->bksv[1]);
}
/*
* hdmi_rx_ctrl_hdcp_config - config hdcp1.4 keys
*/
void rx_hdcp14_config(const struct hdmi_rx_hdcp *hdcp)
{
unsigned int data32 = 0;
/* I2C_SPIKE_SUPPR */
data32 |= 1 << 16;
/* FAST_I2C */
data32 |= 0 << 12;
/* ONE_DOT_ONE */
data32 |= 0 << 9;
/* FAST_REAUTH */
data32 |= 0 << 8;
/* DDC_ADDR */
data32 |= 0x3a << 1;
hdmirx_wr_dwc(DWC_HDCP_SETTINGS, data32);
/* hdmirx_wr_bits_dwc(DWC_HDCP_SETTINGS, HDCP_FAST_MODE, 0); */
/* Enable hdcp bcaps bit(bit7). In hdcp1.4 spec: Use of
* this bit is reserved, hdcp Receivers not capable of
* supporting HDMI must clear this bit to 0. For YAMAHA
* RX-V377 amplifier, enable this bit is needed, in case
* the amplifier won't do hdcp1.4 interaction occasionally.
*/
hdmirx_wr_bits_dwc(DWC_HDCP_SETTINGS, HDCP_BCAPS, 1);
hdmirx_wr_bits_dwc(DWC_HDCP_CTRL, ENCRIPTION_ENABLE, 0);
/* hdmirx_wr_bits_dwc(ctx, DWC_HDCP_CTRL, KEY_DECRYPT_ENABLE, 1); */
hdmirx_wr_bits_dwc(DWC_HDCP_CTRL, KEY_DECRYPT_ENABLE, 0);
hdmirx_wr_dwc(DWC_HDCP_SEED, hdcp->seed);
if (hdcp14_key_mode == SECURE_MODE) {
rx_set_hdcp14_secure_key();
rx_pr("hdcp1.4 secure mode\n");
} else {
rx_hdcp14_set_normal_key(&rx.hdcp);
rx_pr("hdcp1.4 normal mode\n");
}
if (rx.chip_id != CHIP_ID_TXHD) {
hdmirx_wr_bits_dwc(DWC_HDCP_RPT_CTRL,
REPEATER, hdcp->repeat ? 1 : 0);
/* nothing attached downstream */
hdmirx_wr_dwc(DWC_HDCP_RPT_BSTATUS, 0);
}
hdmirx_wr_bits_dwc(DWC_HDCP_CTRL, ENCRIPTION_ENABLE, 1);
}
#if 0
void rx_set_term_enable(bool enable)
{
if (rx.chip_id == CHIP_ID_TL1) {
/* need to do : for tl1 */
} else
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
PHY_TERM_OVERRIDE, enable);
}
#endif
void rx_set_term_value(unsigned char port, bool value)
{
unsigned int data32;
if (rx.chip_id == CHIP_ID_TL1) {
/* need to do : for tl1 */
data32 = rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0);
if (port < E_PORT3) {
if (value)
data32 |= (1 << port);
else
data32 &= ~(1 << port);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
} else if (port == ALL_PORTS) {
if (value)
data32 |= 0x7;
else
data32 &= 0xfffffff8;
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
} else
rx_pr("%s port num overflow\n", __func__);
} else {
if (port < E_PORT_NUM) {
if (value)
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
_BIT(port + 4), 1);
else
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
_BIT(port + 4), 0);
} else if (port == ALL_PORTS) {
if (value)
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
PHY_TERM_OV_VALUE, 0xF);
else
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
PHY_TERM_OV_VALUE, 0);
} else
rx_pr("%s port num overflow\n", __func__);
}
}
int rx_set_port_hpd(uint8_t port_id, bool val)
{
if (port_id < E_PORT_NUM) {
if (val) {
hdmirx_wr_bits_top(TOP_HPD_PWR5V, _BIT(port_id), 1);
rx_set_term_value(port_id, 1);
} else {
hdmirx_wr_bits_top(TOP_HPD_PWR5V, _BIT(port_id), 0);
rx_set_term_value(port_id, 0);
}
} else if (port_id == ALL_PORTS) {
if (val) {
hdmirx_wr_bits_top(TOP_HPD_PWR5V, MSK(4, 0), 0xF);
rx_set_term_value(port_id, 1);
} else {
hdmirx_wr_bits_top(TOP_HPD_PWR5V, MSK(4, 0), 0x0);
rx_set_term_value(port_id, 0);
}
} else
return -1;
if (log_level & LOG_EN)
rx_pr("%s, port:%d, val:%d\n", __func__,
port_id, val);
return 0;
}
void rx_set_cur_hpd(uint8_t val)
{
rx_set_port_hpd(rx.port, val);
}
/*
* rx_force_hpd_config - force config hpd level on all ports
* @hpd_level: hpd level
*/
void rx_force_hpd_cfg(uint8_t hpd_level)
{
unsigned int hpd_value;
if (hpd_level) {
if (disable_port_en)
hpd_value = (~(1 << disable_port_num)) & 0xF;
else
hpd_value = 0xF;
hdmirx_wr_bits_top(TOP_HPD_PWR5V,
MSK(4, 0), hpd_value);
} else
hdmirx_wr_bits_top(TOP_HPD_PWR5V, MSK(4, 0), 0x0);
}
/*
* rx_force_rxsense_cfg - force config rxsense level on all ports
* @level: rxsense level
*/
void rx_force_rxsense_cfg(uint8_t level)
{
unsigned int term_ovr_value;
unsigned int data32;
if (rx.chip_id == CHIP_ID_TL1) {
/* enable terminal connect */
data32 = rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0);
if (level) {
if (disable_port_en)
term_ovr_value =
(~(1 << disable_port_num)) & 0x7;
else
term_ovr_value = 0x7;
data32 |= term_ovr_value;
} else {
data32 &= 0xfffffff8;
}
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
} else {
if (level) {
if (disable_port_en)
term_ovr_value =
(~(1 << disable_port_num)) & 0xF;
else
term_ovr_value = 0xF;
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
PHY_TERM_OV_VALUE, term_ovr_value);
} else
hdmirx_wr_bits_phy(PHY_MAIN_FSM_OVERRIDE1,
PHY_TERM_OV_VALUE, 0x0);
}
}
/*
* rx_force_hpd_rxsense_cfg - force config
* hpd & rxsense level on all ports
* @level: hpd & rxsense level
*/
void rx_force_hpd_rxsense_cfg(uint8_t level)
{
rx_force_hpd_cfg(level);
rx_force_rxsense_cfg(level);
if (log_level & LOG_EN)
rx_pr("hpd & rxsense force val:%d\n", level);
}
/*
* control_reset - hdmirx controller reset
*/
void control_reset(void)
{
unsigned long data32;
/* disable functional modules */
hdmirx_top_sw_reset();
/* Enable functional modules */
data32 = 0;
data32 |= 1 << 5; /* [5] cec_enable */
data32 |= 1 << 4; /* [4] aud_enable */
data32 |= 1 << 3; /* [3] bus_enable */
data32 |= 1 << 2; /* [2] hdmi_enable */
data32 |= 1 << 1; /* [1] modet_enable */
data32 |= 1 << 0; /* [0] cfg_enable */
hdmirx_wr_dwc(DWC_DMI_DISABLE_IF, data32);
mdelay(1);
hdmirx_wr_dwc(DWC_DMI_SW_RST, 0x0000001F);
}
void rx_esm_tmdsclk_en(bool en)
{
hdmirx_wr_bits_top(TOP_CLK_CNTL, HDCP22_TMDSCLK_EN, en);
if (log_level & HDCP_LOG)
rx_pr("%s:%d\n", __func__, en);
}
/*
* hdcp22_clk_en - clock gating for hdcp2.2
* @en: enable or disable clock
*/
void hdcp22_clk_en(bool en)
{
if (en) {
wr_reg_hhi(HHI_HDCP22_CLK_CNTL,
(rd_reg_hhi(HHI_HDCP22_CLK_CNTL) & 0xffff0000) |
/* [10: 9] fclk_div7=2000/7=285.71 MHz */
((0 << 9) |
/* [ 8] clk_en. Enable gated clock */
(1 << 8) |
/* [ 6: 0] Divide by 1. = 285.71/1 = 285.71 MHz */
(0 << 0)));
wr_reg_hhi(HHI_HDCP22_CLK_CNTL,
(rd_reg_hhi(HHI_HDCP22_CLK_CNTL) & 0x0000ffff) |
/* [26:25] select cts_oscin_clk=24 MHz */
((0 << 25) |
(1 << 24) | /* [ 24] Enable gated clock */
(0 << 16)));
if (rx.chip_id == CHIP_ID_TL1)
/* TL1:esm related clk bit9-11 */
hdmirx_wr_bits_top(TOP_CLK_CNTL, MSK(3, 9), 0x7);
else
/* TL1:esm related clk bit3-5 */
hdmirx_wr_bits_top(TOP_CLK_CNTL, MSK(3, 3), 0x7);
} else {
hdmirx_wr_bits_top(TOP_CLK_CNTL, MSK(3, 3), 0x0);
wr_reg_hhi(HHI_HDCP22_CLK_CNTL, 0);
}
}
/*
* hdmirx_hdcp22_esm_rst - software reset esm
*/
void hdmirx_hdcp22_esm_rst(void)
{
/* For TL1,the sw_reset_hdcp22 bit is top reg 0x0,bit'12 */
if (rx.chip_id == CHIP_ID_TL1)
hdmirx_wr_top(TOP_SW_RESET, 0x1000);
else
/* For txlx and previous chips,the sw_reset_hdcp22 is bit'8 */
hdmirx_wr_top(TOP_SW_RESET, 0x100);
mdelay(1);
hdmirx_wr_top(TOP_SW_RESET, 0x0);
rx_pr("esm rst\n");
}
/*
* hdmirx_hdcp22_init - hdcp2.2 initialization
*/
int rx_is_hdcp22_support(void)
{
int ret = 0;
if (rx_sec_set_duk(hdmirx_repeat_support()) == 1) {
rx_hdcp22_wr_top(TOP_SKP_CNTL_STAT, 7);
ret = 1;
} else
ret = 0;
rx_pr("hdcp22 == %d\n", ret);
return ret;
}
/*
* hdmirx_hdcp22_hpd - set hpd level for hdcp2.2
* @value: whether to set hpd high
*/
void hdmirx_hdcp22_hpd(bool value)
{
unsigned long data32 = hdmirx_rd_dwc(DWC_HDCP22_CONTROL);
if (value)
data32 |= 0x1000;
else
data32 &= (~0x1000);
hdmirx_wr_dwc(DWC_HDCP22_CONTROL, data32);
}
/*
* hdcp_22_off
*/
void hdcp_22_off(void)
{
hdcp22_clk_en(0);
/* note: can't pull down hpd before enter suspend */
/* it will stop cec wake up func if EE domain still working */
/* rx_set_cur_hpd(0); */
hpd_to_esm = 0;
hdmirx_wr_dwc(DWC_HDCP22_CONTROL,
0x0);
if (hdcp22_kill_esm == 0)
hdmirx_hdcp22_esm_rst();
else
hdcp22_kill_esm = 0;
rx_pr("hdcp22 off\n");
}
/*
* hdcp_22_on
*/
void hdcp_22_on(void)
{
hdcp22_kill_esm = 0;
/* switch_set_state(&rx.hpd_sdev, 0x0); */
extcon_set_state_sync(rx.rx_excton_rx22, EXTCON_DISP_HDMI, 0);
hdcp22_clk_en(1);
hdmirx_wr_dwc(DWC_HDCP22_CONTROL,
0x1000);
/* rx_hdcp22_wr_top(TOP_SKP_CNTL_STAT, 0x1); */
/* hdmirx_hw_config(); */
/* switch_set_state(&rx.hpd_sdev, 0x1); */
extcon_set_state_sync(rx.rx_excton_rx22, EXTCON_DISP_HDMI, 1);
hpd_to_esm = 1;
/* dont need to delay 900ms to wait sysctl start hdcp_rx22,*/
/*sysctl is userspace it wakes up later than driver */
/* mdelay(900); */
/* rx_set_cur_hpd(1); */
rx_pr("hdcp22 on\n");
}
/*
* clk_init - clock initialization
* config clock for hdmirx module
*/
void 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 */
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: */
#if 0
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);
#endif
if ((rx.chip_id == CHIP_ID_TXLX) ||
(rx.chip_id == CHIP_ID_TXHD) ||
(rx.chip_id == CHIP_ID_TL1)) {
/* [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 */
if (rx.chip_id == CHIP_ID_TL1) {
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 */
} else {
data32 |= 1 << 2; /* [2] hdmirx_cecclk_en */
data32 |= 0 << 1; /* [1] bus_clk_inv */
data32 |= 0 << 0; /* [0] hdmi_clk_inv */
}
hdmirx_wr_top(TOP_CLK_CNTL, data32); /* DEFAULT: {32'h0} */
}
/*
* hdmirx_20_init - hdmi2.0 config
*/
void hdmirx_20_init(void)
{
unsigned long data32;
data32 = 0;
data32 |= 1 << 12; /* [12] vid_data_checken */
data32 |= 1 << 11; /* [11] data_island_checken */
data32 |= 1 << 10; /* [10] gb_checken */
data32 |= 1 << 9; /* [9] preamb_checken */
data32 |= 1 << 8; /* [8] ctrl_checken */
data32 |= 1 << 4; /* [4] scdc_enable */
/* To support some TX that sends out SSCP even when not scrambling:
* 0: Original behaviour
* 1: During TMDS character error detection, treat SSCP character
* as normal TMDS character.
* Note: If scramble is turned on, this bit will not take effect,
* revert to original IP behaviour.
*/
data32 |= ignore_sscp_charerr << 3; /* [3]ignore sscp character err */
/* To support some TX that sends out SSCP even when not scrambling:
* 0: Original behaviour
* 1: During TMDS decoding, treat SSCP character
* as normal TMDS character
* Note: If scramble is turned on, this bit will not take effect,
* revert to original IP behaviour.
*/
data32 |= ignore_sscp_tmds << 2; /* [2] ignore sscp tmds */
data32 |= SCRAMBLE_SEL << 0; /* [1:0] scramble_sel */
hdmirx_wr_dwc(DWC_HDMI20_CONTROL, data32);
data32 = 0;
data32 |= 1 << 24; /* [25:24] i2c_spike_suppr */
data32 |= 0 << 20; /* [20] i2c_timeout_en */
data32 |= 0 << 0; /* [19:0] i2c_timeout_cnt */
hdmirx_wr_dwc(DWC_SCDC_I2CCONFIG, data32);
data32 = 0;
data32 |= 0 << 1; /* [1] hpd_low */
data32 |= 1 << 0; /* [0] power_provided */
hdmirx_wr_dwc(DWC_SCDC_CONFIG, data32);
data32 = 0;
data32 |= 0xabcdef << 8; /* [31:8] manufacture_oui */
data32 |= 1 << 0; /* [7:0] sink_version */
hdmirx_wr_dwc(DWC_SCDC_WRDATA0, data32);
data32 = 0;
data32 |= 10 << 20; /* [29:20] chlock_max_err */
data32 |= 24000 << 0; /* [15:0] milisec_timer_limit */
hdmirx_wr_dwc(DWC_CHLOCK_CONFIG, data32);
/* hdcp2.2 ctl */
if (hdcp22_on)
hdmirx_wr_dwc(DWC_HDCP22_CONTROL, 0x1000);
else
hdmirx_wr_dwc(DWC_HDCP22_CONTROL, 2);
}
/*
* hdmirx_audio_init - audio initialization
*/
int hdmirx_audio_init(void)
{
/* 0=I2S 2-channel; 1=I2S 4 x 2-channel. */
int err = 0;
unsigned long data32 = 0;
data32 |= 7 << 13;
data32 |= 0 << 12;
data32 |= 1 << 11;
data32 |= 0 << 10;
data32 |= 0 << 9;
data32 |= 1 << 8;
data32 |= 1 << 6;
data32 |= 3 << 4;
data32 |= 0 << 3;
data32 |= acr_mode << 2;
data32 |= acr_mode << 1;
data32 |= acr_mode << 0;
hdmirx_wr_top(TOP_ACR_CNTL_STAT, data32);
if (rx.chip_id == CHIP_ID_TL1) {
data32 = 0;
data32 |= 0 << 2;/*meas_mode*/
data32 |= 1 << 1;/*enable*/
data32 |= 1 << 0;/*reset*/
if (acr_mode)
data32 |= 2 << 16;/*aud pll*/
else
data32 |= 500 << 16;/*acr*/
hdmirx_wr_top(TOP_AUDMEAS_CTRL, data32);
hdmirx_wr_top(TOP_AUDMEAS_CYCLES_M1, 65535);
/*start messure*/
hdmirx_wr_top(TOP_AUDMEAS_CTRL, data32 & (~0x1));
}
/*
*recover to default value, bit[27:24]
*set aud_pll_lock filter
*data32 = 0;
*data32 |= 0 << 28;
*data32 |= 0 << 24;
*hdmirx_wr_dwc(DWC_AUD_PLL_CTRL, data32);
*/
/* AFIFO depth 1536word.*/
/*increase start threshold to middle position */
data32 = 0;
data32 |= 160 << 18; /* start */
data32 |= 200 << 9; /* max */
data32 |= 8 << 0; /* min */
hdmirx_wr_dwc(DWC_AUD_FIFO_TH, data32);
/* recover to default value.*/
/*remain code for some time.*/
/*if no side effect then remove it */
/*
*data32 = 0;
*data32 |= 1 << 16;
*data32 |= 0 << 0;
*hdmirx_wr_dwc(DWC_AUD_FIFO_CTRL, data32);
*/
data32 = 0;
data32 |= 0 << 8;
data32 |= 1 << 7;
data32 |= aud_ch_map << 2;
data32 |= 1 << 0;
hdmirx_wr_dwc(DWC_AUD_CHEXTR_CTRL, data32);
data32 = 0;
/* [22:21] aport_shdw_ctrl */
data32 |= 3 << 21;
/* [20:19] auto_aclk_mute */
data32 |= auto_aclk_mute << 19;
/* [16:10] aud_mute_speed */
data32 |= 1 << 10;
/* [7] aud_avmute_en */
data32 |= aud_avmute_en << 7;
/* [6:5] aud_mute_sel */
data32 |= aud_mute_sel << 5;
/* [4:3] aud_mute_mode */
data32 |= 1 << 3;
/* [2:1] aud_ttone_fs_sel */
data32 |= 0 << 1;
/* [0] testtone_en */
data32 |= 0 << 0;
hdmirx_wr_dwc(DWC_AUD_MUTE_CTRL, data32);
/* recover to default value.*/
/*remain code for some time.*/
/*if no side effect then remove it */
/*
*data32 = 0;
*data32 |= 0 << 16;
*data32 |= 0 << 12;
*data32 |= 0 << 4;
*data32 |= 0 << 1;
*data32 |= 0 << 0;
*hdmirx_wr_dwc(DWC_AUD_PAO_CTRL, data32);
*/
/* recover to default value.*/
/*remain code for some time.*/
/*if no side effect then remove it */
/*
*data32 = 0;
*data32 |= 0 << 8;
*hdmirx_wr_dwc(DWC_PDEC_AIF_CTRL, data32);
*/
data32 = 0;
/* [4:2] deltacts_irqtrig */
data32 |= 0 << 2;
/* [1:0] cts_n_meas_mode */
data32 |= 0 << 0;
/* DEFAULT: {27'd0, 3'd0, 2'd1} */
hdmirx_wr_dwc(DWC_PDEC_ACRM_CTRL, data32);
/* unsupport HBR serial mode. invalid bit */
/* hdmirx_wr_bits_dwc(DWC_AUD_CTRL, DWC_AUD_HBR_ENABLE, 1); */
/* SAO cfg, disable I2S output, no use */
data32 = 0;
data32 |= 1 << 10;
data32 |= 0 << 9;
data32 |= 0x0f << 5;
data32 |= 0 << 1;
data32 |= 1 << 0;
hdmirx_wr_dwc(DWC_AUD_SAO_CTRL, data32);
data32 = 0;
data32 |= 1 << 6;
data32 |= 0xf << 2;
hdmirx_wr_dwc(DWC_PDEC_ASP_CTRL, data32);
return err;
}
/*
* snps phy g3 initial
*/
void snps_phyg3_init(void)
{
unsigned int data32;
unsigned int term_value =
hdmirx_rd_top(TOP_HPD_PWR5V);
data32 = 0;
data32 |= 1 << 6;
data32 |= 1 << 4;
data32 |= rx.port << 2;
data32 |= 1 << 1;
data32 |= 1 << 0;
hdmirx_wr_dwc(DWC_SNPS_PHYG3_CTRL, data32);
mdelay(1);
data32 = 0;
data32 |= 1 << 6;
data32 |= 1 << 4;
data32 |= rx.port << 2;
data32 |= 1 << 1;
data32 |= 0 << 0;
hdmirx_wr_dwc(DWC_SNPS_PHYG3_CTRL, data32);
data32 = 0;
data32 |= 6 << 10;
data32 |= 1 << 9;
data32 |= ((24000 * 4) / 1000);
hdmirx_wr_phy(PHY_CMU_CONFIG, data32);
hdmirx_wr_phy(PHY_VOLTAGE_LEVEL, 0x1ea);
data32 = 0;
data32 |= 0 << 15;
data32 |= 0 << 13;
data32 |= 0 << 12;
data32 |= phy_fast_switching << 11;
data32 |= 0 << 10;
data32 |= phy_fsm_enhancement << 9;
data32 |= 0 << 8;
data32 |= 0 << 7;
data32 |= 0 << 5;
data32 |= 0 << 3;
data32 |= 0 << 2;
data32 |= 0 << 0;
hdmirx_wr_phy(PHY_SYSTEM_CONFIG, data32);
hdmirx_wr_phy(MPLL_PARAMETERS2, 0x1c94);
hdmirx_wr_phy(MPLL_PARAMETERS3, 0x3713);
/*default 0x24da , EQ optimizing for kaiboer box */
hdmirx_wr_phy(MPLL_PARAMETERS4, 0x24dc);
hdmirx_wr_phy(MPLL_PARAMETERS5, 0x5492);
hdmirx_wr_phy(MPLL_PARAMETERS6, 0x4b0d);
hdmirx_wr_phy(MPLL_PARAMETERS7, 0x4760);
hdmirx_wr_phy(MPLL_PARAMETERS8, 0x008c);
hdmirx_wr_phy(MPLL_PARAMETERS9, 0x0010);
hdmirx_wr_phy(MPLL_PARAMETERS10, 0x2d20);
hdmirx_wr_phy(MPLL_PARAMETERS11, 0x2e31);
hdmirx_wr_phy(MPLL_PARAMETERS12, 0x4b64);
hdmirx_wr_phy(MPLL_PARAMETERS13, 0x2493);
hdmirx_wr_phy(MPLL_PARAMETERS14, 0x676d);
hdmirx_wr_phy(MPLL_PARAMETERS15, 0x23e0);
hdmirx_wr_phy(MPLL_PARAMETERS16, 0x001b);
hdmirx_wr_phy(MPLL_PARAMETERS17, 0x2218);
hdmirx_wr_phy(MPLL_PARAMETERS18, 0x1b25);
hdmirx_wr_phy(MPLL_PARAMETERS19, 0x2492);
hdmirx_wr_phy(MPLL_PARAMETERS20, 0x48ea);
hdmirx_wr_phy(MPLL_PARAMETERS21, 0x0011);
hdmirx_wr_phy(MPLL_PARAMETERS22, 0x04d2);
hdmirx_wr_phy(MPLL_PARAMETERS23, 0x0414);
/* Configuring I2C to work in fastmode */
hdmirx_wr_dwc(DWC_I2CM_PHYG3_MODE, 0x1);
/* disable overload protect for Philips DVD */
/* NOTE!!!!! don't remove below setting */
hdmirx_wr_phy(OVL_PROT_CTRL, 0xa);
/* clear clkrate cfg */
hdmirx_wr_bits_phy(PHY_CDR_CTRL_CNT, CLK_RATE_BIT, 0);
/*last_clk_rate = 0;*/
rx.phy.clk_rate = 0;
/* enable all ports's termination */
data32 = 0;
data32 |= 1 << 8;
data32 |= ((term_value & 0xF) << 4);
hdmirx_wr_phy(PHY_MAIN_FSM_OVERRIDE1, data32);
data32 = 0;
data32 |= 1 << 6;
data32 |= 1 << 4;
data32 |= rx.port << 2;
data32 |= 0 << 1;
data32 |= 0 << 0;
hdmirx_wr_dwc(DWC_SNPS_PHYG3_CTRL, data32);
}
void rx_run_eq(void)
{
if (rx.chip_id < CHIP_ID_TL1)
rx_eq_algorithm();
else
hdmirx_phy_init();
}
bool rx_eq_done(void)
{
bool ret = true;
if (rx.chip_id < CHIP_ID_TL1) {
if (rx_get_eq_run_state() == E_EQ_START)
ret = false;
}
return ret;
}
/*
* hdmirx_phy_init - hdmirx phy initialization
*/
void hdmirx_phy_init(void)
{
/* uint32_t data32; */
/* uint32_t cur_cable_clk; */
if (rx.chip_id == CHIP_ID_TL1)
aml_phy_bw_switch();
else
snps_phyg3_init();
}
/*
* rx_clkrate_monitor - clock ratio monitor
* detect SCDC tmds clk ratio changes and
* update phy setting
*/
bool rx_clkrate_monitor(void)
{
uint32_t clk_rate, phy_band, pll_band;
bool changed = false;
int i;
int error = 0;
clk_rate = rx_get_scdc_clkrate_sts();
if (rx.state < FSM_WAIT_CLK_STABLE)
return changed;
if (is_clk_stable()) {
rx.phy.cable_clk = rx_measure_clock(MEASURE_CLK_CABLE);
rx.phy.tmds_clk = rx_measure_clock(MEASURE_CLK_TMDS);
pll_band = aml_phy_pll_band(rx.phy.cable_clk, clk_rate);
phy_band = aml_cable_clk_band(rx.phy.cable_clk, clk_rate);
if ((rx.phy.pll_bw != pll_band) ||
(rx.phy.phy_bw != phy_band)) {
rx.phy.cablesel = 0;
rx.phy.phy_bw = phy_band;
rx.phy.pll_bw = pll_band;
}
}
if (clk_rate != rx.phy.clk_rate) {
changed = true;
if (rx.chip_id != CHIP_ID_TL1) {
for (i = 0; i < 3; i++) {
error = hdmirx_wr_bits_phy(PHY_CDR_CTRL_CNT,
CLK_RATE_BIT, clk_rate);
if (error == 0)
break;
}
} else {
aml_phy_bw_switch();
}
if (log_level & VIDEO_LOG)
rx_pr("clk_rate:%d, last_clk_rate: %d\n",
clk_rate, rx.phy.clk_rate);
rx.phy.clk_rate = clk_rate;
}
if (changed) {
if (rx.state >= FSM_WAIT_CLK_STABLE)
rx.state = FSM_WAIT_CLK_STABLE;
}
return changed;
}
/*
* rx_hdcp_init - hdcp1.4 init and enable
*/
void rx_hdcp_init(void)
{
if (hdcp_enable)
rx_hdcp14_config(&rx.hdcp);
else
hdmirx_wr_bits_dwc(DWC_HDCP_CTRL, ENCRIPTION_ENABLE, 0);
}
/*type 1 pull down hpd,reset hdcp2.2
*type 2 only pull down hpd
*/
void hdmirx_load_firm_reset(int type)
{
int ret = 0;
rx_pr("%s\n", __func__);
rx_pr("3firm_change:%d,repeat_plug:%d,repeat:%d\n",
rx.firm_change, repeat_plug, rx.hdcp.repeat);
/*wait the fsm end*/
rx.firm_change = 1;
msleep(20);
/*External_Mute(1);rx_aud_pll_ctl(0);*/
rx_set_cur_hpd(0);
/*type 2 only pull down hpd*/
if (type == 2) {
downstream_hpd_flag = 0;
fsm_restart();
return;
}
if (!repeat_plug)
downstream_hpd_flag = 1;
else
downstream_hpd_flag = 0;
ret = rx_sec_set_duk(hdmirx_repeat_support());
rx_pr("ret = %d\n", ret);
if (ret == 1) {
hdmirx_wr_dwc(DWC_HDCP22_CONTROL, 0x0);
hdmirx_hdcp22_esm_rst();
mdelay(100);
hdmirx_wr_dwc(DWC_HDCP22_CONTROL,
0x1000);
rx_hdcp22_wr_top(TOP_SKP_CNTL_STAT, 0x1);
fsm_restart();
rx_is_hdcp22_support();
}
rx_pr("4firm_change:%d,repeat_plug:%d,repeat:%d\n",
rx.firm_change, repeat_plug, rx.hdcp.repeat);
}
/* need reset bandgap when
* aud_clk=0 & req_clk!=0
* according to analog team's request
*/
void rx_audio_bandgap_rst(void)
{
vdac_enable(0, 0x10);
udelay(20);
vdac_enable(1, 0x10);
if (log_level & AUDIO_LOG)
rx_pr("%s\n", __func__);
}
void rx_sw_reset(int level)
{
unsigned long data32 = 0;
if (level == 1) {
data32 |= 0 << 7; /* [7]vid_enable */
data32 |= 0 << 5; /* [5]cec_enable */
data32 |= 0 << 4; /* [4]aud_enable */
data32 |= 0 << 3; /* [3]bus_enable */
data32 |= 0 << 2; /* [2]hdmi_enable */
data32 |= 1 << 1; /* [1]modet_enable */
data32 |= 0 << 0; /* [0]cfg_enable */
} else if (level == 2) {
data32 |= 0 << 7; /* [7]vid_enable */
data32 |= 0 << 5; /* [5]cec_enable */
data32 |= 1 << 4; /* [4]aud_enable */
data32 |= 0 << 3; /* [3]bus_enable */
data32 |= 1 << 2; /* [2]hdmi_enable */
data32 |= 1 << 1; /* [1]modet_enable */
data32 |= 0 << 0; /* [0]cfg_enable */
}
hdmirx_wr_dwc(DWC_DMI_SW_RST, data32);
}
void hdmirx_hw_config(void)
{
rx_pr("%s port:%d\n", __func__, rx.port);
control_reset();
/* hdmi_rx_top_edid_update(); */
rx_hdcp_init();
hdmirx_audio_init();
packet_init();
if (rx.chip_id != CHIP_ID_TXHD)
hdmirx_20_init();
DWC_init();
hdmirx_irq_hdcp_enable(true);
if (rx.chip_id == CHIP_ID_TL1)
aml_phy_switch_port();
hdmirx_phy_init();
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
rx_pr("%s %d Done!\n", __func__, rx.port);
/* hdmi reset will cause cec not working*/
/* cec modult need reset */
if (rx.chip_id <= CHIP_ID_TXL)
cec_hw_reset(1);/*1:snps cec*/
}
/*
* hdmirx_hw_probe - hdmirx top/controller/phy init
*/
void hdmirx_hw_probe(void)
{
hdmirx_wr_top(TOP_MEM_PD, 0);
hdmirx_wr_top(TOP_INTR_MASKN, 0);
hdmirx_wr_top(TOP_SW_RESET, 0);
clk_init();
TOP_init();
control_reset();
DWC_init();
rx_emp_to_ddr_init();
hdmi_rx_top_edid_update();
/*hdmirx_irq_enable(FALSE);*/
/*hdmirx_irq_hdcp22_enable(FALSE);*/
hdcp22_clk_en(1);
hdmirx_audio_init();
packet_init();
if (rx.chip_id != CHIP_ID_TXHD)
hdmirx_20_init();
if (rx.chip_id == CHIP_ID_TL1)
aml_phy_switch_port();
hdmirx_phy_init();
hdmirx_wr_top(TOP_PORT_SEL, 0x10);
hdmirx_wr_top(TOP_INTR_STAT_CLR, ~0);
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
/* rx_pr("%s Done!\n", __func__); */
}
/*
* rx_audio_pll_sw_update
* Sent an update pulse to audio pll module.
* Indicate the ACR info is changed.
*/
void rx_audio_pll_sw_update(void)
{
hdmirx_wr_bits_top(TOP_ACR_CNTL_STAT, _BIT(11), 1);
}
/*
* func: rx_acr_info_update
* refresh aud_pll by manual N/CTS changing
*/
void rx_acr_info_sw_update(void)
{
hdmirx_wr_dwc(DWC_AUD_CLK_CTRL, 0x10);
udelay(100);
hdmirx_wr_dwc(DWC_AUD_CLK_CTRL, 0x0);
}
/*
* is_afifo_error - audio fifo unnormal detection
* check if afifo block or not
* bit4: indicate FIFO is overflow
* bit3: indicate FIFO is underflow
* bit2: start threshold pass
* bit1: wr point above max threshold
* bit0: wr point below mix threshold
*
* return true if afifo under/over flow, false otherwise.
*/
bool is_afifo_error(void)
{
bool ret = false;
if ((hdmirx_rd_dwc(DWC_AUD_FIFO_STS) &
(OVERFL_STS | UNDERFL_STS)) != 0) {
ret = true;
if (log_level & AUDIO_LOG)
rx_pr("afifo err\n");
}
return ret;
}
/*
* is_aud_pll_error - audio clock range detection
* noraml mode: aud_pll = aud_sample_rate * 128
* HBR: aud_pll = aud_sample_rate * 128 * 4
*
* return true if audio clock is in range, false otherwise.
*/
bool is_aud_pll_error(void)
{
bool ret = true;
int32_t clk = rx_measure_clock(MEASURE_CLK_AUD_PLL);
int32_t aud_128fs = rx.aud_info.real_sr * 128;
int32_t aud_512fs = rx.aud_info.real_sr * 512;
if (rx.aud_info.real_sr == 0)
return false;
if ((abs(clk - aud_128fs) < AUD_PLL_THRESHOLD) ||
(abs(clk - aud_512fs) < AUD_PLL_THRESHOLD)) {
ret = false;
}
if ((ret) && (log_level & AUDIO_LOG))
rx_pr("clk:%d,128fs:%d,512fs:%d,\n", clk, aud_128fs, aud_512fs);
return ret;
}
/*
* rx_aud_pll_ctl - audio pll config
*/
void rx_aud_pll_ctl(bool en)
{
int tmp = 0;
/*unsigned int od, od2;*/
if (rx.chip_id == CHIP_ID_TL1) {
if (en) {
/* AUD_CLK=N/CTS*TMDS_CLK */
/* bandgap enable */
wr_reg_hhi(HHI_VDAC_CNTL0, 0x906001);
wr_reg_hhi(HHI_VDAC_CNTL1, 0x0);
wr_reg_hhi(HHI_AUD_PLL_CNTL, 0x40001540);
#if 1
/* use mpll */
tmp = 0;
tmp |= 2 << 2; /* 0:tmds_clk 1:ref_clk 2:mpll_clk */
wr_reg_hhi(HHI_AUD_PLL_CNTL2, tmp);
/* cntl3 2:0 000=1*cts 001=2*cts 010=4*cts 011=8*cts */
wr_reg_hhi(HHI_AUD_PLL_CNTL3, rx.phy.aud_div);
#else
/* use tmds clk */
tmp = 0;
tmp |= 0 << 2; /* 0:tmds_clk 1:ref_clk 2:mpll_clk */
wr_reg_hhi(HHI_AUD_PLL_CNTL2, tmp);
/* cntl3 2:0 000=1*cts 001=2*cts 010=4*cts 011=8*cts */
wr_reg_hhi(HHI_AUD_PLL_CNTL3, 0);
#endif
rx_pr("aud div=%d\n", rd_reg_hhi(HHI_AUD_PLL_CNTL3));
wr_reg_hhi(HHI_AUD_PLL_CNTL, 0x60001540);
rx_pr("audio pll lock:0x%x\n",
rd_reg_hhi(HHI_AUD_PLL_CNTL_I));
/*rx_audio_pll_sw_update();*/
} else {
/* disable pll, into reset mode */
External_Mute(1);
wr_reg_hhi(HHI_AUD_PLL_CNTL, 0x0);
}
} else {
if (en) {
tmp = hdmirx_rd_phy(PHY_MAINFSM_STATUS1);
wr_reg_hhi(HHI_AUD_PLL_CNTL, 0x20000000);
/* audio pll div depends on input freq */
wr_reg_hhi(HHI_AUD_PLL_CNTL6, (tmp >> 9 & 3) << 28);
/* audio pll div fixed to N/CTS as below*/
/* wr_reg_hhi(HHI_AUD_PLL_CNTL6, 0x40000000); */
wr_reg_hhi(HHI_AUD_PLL_CNTL5, 0x0000002e);
wr_reg_hhi(HHI_AUD_PLL_CNTL4, 0x30000000);
wr_reg_hhi(HHI_AUD_PLL_CNTL3, 0x00000000);
wr_reg_hhi(HHI_AUD_PLL_CNTL, 0x40000000);
wr_reg_hhi(HHI_ADC_PLL_CNTL4, 0x805);
rx_audio_pll_sw_update();
/*External_Mute(0);*/
} else{
/* disable pll, into reset mode */
External_Mute(1);
wr_reg_hhi(HHI_AUD_PLL_CNTL, 0x20000000);
}
}
}
unsigned char rx_get_hdcp14_sts(void)
{
return (unsigned char)((hdmirx_rd_dwc(DWC_HDCP_STS) >> 8) & 3);
}
/*
* rx_get_video_info - get current avi info
*/
void rx_get_video_info(void)
{
const unsigned int factor = 100;
unsigned int divider = 0;
uint32_t tmp = 0;
/* DVI mode */
rx.cur.hw_dvi = hdmirx_rd_bits_dwc(DWC_PDEC_STS, DVIDET) != 0;
if (hdcp22_on) {
/* hdcp encrypted state */
tmp = hdmirx_rd_dwc(DWC_HDCP22_STATUS);
rx.cur.hdcp_type = (tmp >> 4) & 1;
} else {
rx.cur.hdcp_type = 0;
}
if (rx.cur.hdcp_type == 0) {
rx.cur.hdcp14_state = (hdmirx_rd_dwc(DWC_HDCP_STS) >> 8) & 3;
rx.cur.hdcp22_state = 0xff;
} else {
rx.cur.hdcp14_state = 0xff;
rx.cur.hdcp22_state = tmp & 1;
}
/* AVI parameters */
rx.cur.hw_vic =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, VID_IDENT_CODE);
rx.cur.cn_type =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_HB, CONETNT_TYPE);
rx.cur.repeat =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_HB, PIX_REP_FACTOR);
rx.cur.colorspace =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, VIDEO_FORMAT);
rx.cur.it_content =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, IT_CONTENT);
rx.cur.rgb_quant_range =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, RGB_QUANT_RANGE);
rx.cur.yuv_quant_range =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_HB, YUV_QUANT_RANGE);
#if 0
rx.cur.active_valid =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, ACT_INFO_PRESENT);
rx.cur.bar_valid =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, BAR_INFO_VALID);
rx.cur.scan_info =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, SCAN_INFO);
rx.cur.colorimetry =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, COLORIMETRY);
rx.cur.picture_ratio =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, PIC_ASPECT_RATIO);
rx.cur.active_ratio =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, ACT_ASPECT_RATIO);
rx.cur.it_content =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, IT_CONTENT);
rx.cur.ext_colorimetry =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, EXT_COLORIMETRY);
rx.cur.rgb_quant_range =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, RGB_QUANT_RANGE);
rx.cur.n_uniform_scale =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, NON_UNIF_SCALE);
rx.cur.hw_vic =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_PB, VID_IDENT_CODE);
rx.cur.repeat =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_HB, PIX_REP_FACTOR);
/** @note HW does not support AVI YQ1-0, */
/* YCC quantization range */
/** @note HW does not support AVI CN1-0, */
/* IT content type */
rx.cur.bar_end_top =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_TBB, LIN_END_TOP_BAR);
rx.cur.bar_start_bottom =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_TBB, LIN_ST_BOT_BAR);
rx.cur.bar_end_left =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_LRB, PIX_END_LEF_BAR);
rx.cur.bar_start_right =
hdmirx_rd_bits_dwc(DWC_PDEC_AVI_LRB, PIX_ST_RIG_BAR);
#endif
/* refresh rate */
tmp = hdmirx_rd_bits_dwc(DWC_MD_VTC, VTOT_CLK);
/* tmp = (tmp == 0)? 0: (ctx->md_clk * 100000) / tmp; */
/* if((params->vtotal == 0) || (params->htotal == 0)) */
if (tmp == 0)
rx.cur.frame_rate = 0;
else
rx.cur.frame_rate = (modet_clk * 100000) / tmp;
/* else { */
/* params->frame_rate = (hdmirx_get_pixel_clock() /*/
/* (params->vtotal * params->htotal / 100)); */
/* } */
/* deep color mode */
tmp = hdmirx_rd_bits_dwc(DWC_HDMI_STS, DCM_CURRENT_MODE);
switch (tmp) {
case DCM_CURRENT_MODE_48b:
rx.cur.colordepth = E_COLORDEPTH_16;
/* divide by 2 */
divider = 2.00 * factor;
break;
case DCM_CURRENT_MODE_36b:
rx.cur.colordepth = E_COLORDEPTH_12;
divider = 1.50 * factor; /* divide by 1.5 */
break;
case DCM_CURRENT_MODE_30b:
rx.cur.colordepth = E_COLORDEPTH_10;
divider = 1.25 * factor; /* divide by 1.25 */
break;
default:
rx.cur.colordepth = E_COLORDEPTH_8;
divider = 1.00 * factor;
break;
}
/* pixel clock */
rx.cur.pixel_clk = rx_measure_clock(MEASURE_CLK_PIXEL) / divider;
/* image parameters */
rx.cur.interlaced = hdmirx_rd_bits_dwc(DWC_MD_STS, ILACE) != 0;
rx.cur.voffset = hdmirx_rd_bits_dwc(DWC_MD_VOL, VOFS_LIN);
rx.cur.vactive = hdmirx_rd_bits_dwc(DWC_MD_VAL, VACT_LIN);
rx.cur.vtotal = hdmirx_rd_bits_dwc(DWC_MD_VTL, VTOT_LIN);
rx.cur.hoffset = hdmirx_rd_bits_dwc(DWC_MD_HT1, HOFS_PIX);
rx.cur.hactive = hdmirx_rd_bits_dwc(DWC_MD_HACT_PX, HACT_PIX);
rx.cur.htotal = hdmirx_rd_bits_dwc(DWC_MD_HT1, HTOT_PIX);
rx.cur.pixel_clk = (rx.cur.pixel_clk * factor) / divider;
rx.cur.hoffset = (rx.cur.hoffset * factor) / divider;
rx.cur.hactive = (rx.cur.hactive * factor) / divider;
rx.cur.htotal = (rx.cur.htotal * factor) / divider;
}
/*
* hdmirx_set_video_mute - video mute
* @mute: mute enable or disable
*/
void hdmirx_set_video_mute(bool mute)
{
/* bluescreen cfg */
if (rx.pre.colorspace == E_COLOR_RGB) {
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH2, MSK(16, 0), 0x00);
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH_0_1, MSK(16, 0), 0x00);
} else if (rx.pre.colorspace == E_COLOR_YUV420) {
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH2, MSK(16, 0), 0x1000);
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH_0_1, MSK(16, 0), 0x8000);
} else {
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH2, MSK(16, 0), 0x8000);
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH_0_1, MSK(16, 0), 0x8000);
}
hdmirx_wr_bits_dwc(DWC_HDMI_VM_CFG_CH2, _BIT(16), mute);
if (log_level & VIDEO_LOG)
rx_pr("%s-mute:%d\n", __func__, mute);
}
/*
* hdmirx_config_video - video mute config
*/
void hdmirx_config_video(void)
{
hdmirx_set_video_mute(0);
}
/*
* hdmirx_config_audio - audio channel map
*/
void hdmirx_config_audio(void)
{
/* if audio layout bit = 1, set audio channel map
* according to audio speaker allocation, if layout
* bit = 0, use ch1 & ch2 by default.
*/
if (rx.aud_info.aud_hbr_rcv && hbr_force_8ch) {
hdmirx_wr_dwc(DWC_AUD_CHEXTR_CTRL, 0xff);
if (log_level & AUDIO_LOG)
rx_pr("HBR rcv, force 8ch\n");
} else if (rx.aud_info.auds_layout) {
hdmirx_wr_bits_dwc(DWC_AUD_CHEXTR_CTRL,
AUD_CH_MAP_CFG,
rx.aud_info.auds_ch_alloc);
} else {
hdmirx_wr_bits_dwc(DWC_AUD_CHEXTR_CTRL,
AUD_CH_MAP_CFG, 0);
}
}
/*
* rx_get_clock: git clock from hdmi top
* tl1: have hdmi, cable clock
* other: have hdmi clock
*/
int rx_get_clock(enum measure_clk_top_e clk_src)
{
int clock = -1;
uint32_t tmp_data = 0;
uint32_t meas_cycles = 0;
uint64_t tmp_data2 = 0;
uint32_t audclk = 0;
if (clk_src == TOP_HDMI_TMDSCLK)
tmp_data = hdmirx_rd_top(TOP_METER_HDMI_STAT);
else if (clk_src == TOP_HDMI_CABLECLK) {
if (rx.chip_id == CHIP_ID_TL1)
tmp_data = hdmirx_rd_top(TOP_METER_CABLE_STAT);
} else if (clk_src == TOP_HDMI_AUDIOCLK) {
if (rx.chip_id == CHIP_ID_TL1) {
/*get audio clk*/
tmp_data = hdmirx_rd_top(TOP_AUDMEAS_REF_CYCLES_STAT0);
tmp_data2 = hdmirx_rd_top(TOP_AUDMEAS_REF_CYCLES_STAT1);
audclk = ((tmp_data2 & 0xffff) << 32)|tmp_data;
if (tmp_data2 & (0x1 << 17))
audclk = (24000 * 65536) / ((audclk + 1)/1000);
else
rx_pr("audio clk measure fail\n");
}
return audclk;
} else
tmp_data = 0;
/* measure stable */
if (tmp_data & 0x80000000) {
meas_cycles = tmp_data & 0xffffff;
clock = (2930 * meas_cycles);/*Hz*/
/*clock = (24000000 * meas_cycles) / 8192;*/
/*rx_pr("hdmi_clk cycle cnt=%d,frq=%d\n",cycle_cnt,clock);*/
}
/*reset hdmi,cable clk meter*/
hdmirx_wr_top(TOP_SW_RESET, 0x60);
hdmirx_wr_top(TOP_SW_RESET, 0x0);
return clock;
}
#if 0
/*
* clk_util_clk_msr
*/
unsigned int clk_util_clk_msr(unsigned int clk_mux)
{
return meson_clk_measure(clk_mux);
}
/*
* hdmirx_get_clock - get clock interface
* @index - clock index
*/
unsigned int hdmirx_get_clock(int index)
{
return clk_util_clk_msr(index);
}
/*
* hdmirx_get_tmds_clock - get tmds clock
*/
unsigned int hdmirx_get_tmds_clock(void)
{
uint32_t clk = clk_util_clk_msr(25);
if (clk == 0) {
clk = hdmirx_rd_dwc(DWC_HDMI_CKM_RESULT) & 0xffff;
clk = clk * 158000 / 4095 * 1000;
if (log_level & VIDEO_LOG)
rx_pr("use DWC internal tmds clk msr\n");
}
return clk;
}
/*
* hdmirx_get_pixel_clock - get pixel clock
*/
unsigned int hdmirx_get_pixel_clock(void)
{
return clk_util_clk_msr(29);
}
/*
* hdmirx_get_audio_clock - get audio pll clock
*/
unsigned int hdmirx_get_audio_clock(void)
{
return clk_util_clk_msr(24);
}
/*
* hdmirx_get_mpll_div_clk - get mpll div clock
*/
unsigned int hdmirx_get_mpll_div_clk(void)
{
return clk_util_clk_msr(27);
}
/*
* hdmirx_get_esm_clock - get esm clock
*/
unsigned int hdmirx_get_esm_clock(void)
{
return clk_util_clk_msr(68);
}
#endif
/*
* function - get clk related with hdmirx
*/
unsigned int rx_measure_clock(enum measure_clk_src_e clksrc)
{
unsigned int clock = 0;
/* from clock measure: txlx_clk_measure
* cable [x] need read from hdmitop
* tmds clock [25] Hdmirx_tmds_clk
* pixel clock [29] Hdmirx_pix_clk
* audio clock [24] Hdmirx_aud_pll_clk
* cts audio [98] cts_hdmirx_aud_pll_clk
* mpll clock [27] Hdmirx_mpll_div_clk
* esm clock [68] Cts_hdcp22_esm
*/
/* from clock measure: tl1_table
* cable clock [30] hdmirx_cable_clk
* tmds clock [63] hdmirx_tmds_clk
* pixel clock [29] hdmirx_apll_clk_out_div
* audio clock [74] hdmirx_aud_pll_clk
* cts audio [60] cts_hdmirx_aud_pll_clk
* mpll clock [67] hdmirx_apll_clk_audio
* esm clock [68] Cts_hdcp22_esm
*/
if (clksrc == MEASURE_CLK_CABLE) {
if (rx.chip_id == CHIP_ID_TL1) {
clock = meson_clk_measure(30);
/*clock = rx_get_clock(TOP_HDMI_CABLECLK);*/
}
} else if (clksrc == MEASURE_CLK_TMDS) {
if (rx.chip_id == CHIP_ID_TL1)
clock = meson_clk_measure(63);
else {
clock = meson_clk_measure(25);
if (clock == 0) {
clock =
hdmirx_rd_dwc(DWC_HDMI_CKM_RESULT) & 0xffff;
clock = clock * 158000 / 4095 * 1000;
}
}
} else if (clksrc == MEASURE_CLK_PIXEL) {
clock = meson_clk_measure(29);
} else if (clksrc == MEASURE_CLK_AUD_PLL) {
if (rx.chip_id == CHIP_ID_TL1)
clock = meson_clk_measure(74);/*audio vid out*/
else
clock = meson_clk_measure(24);
} else if (clksrc == MEASURE_CLK_AUD_DIV) {
if (rx.chip_id == CHIP_ID_TL1)
clock = meson_clk_measure(67);/*apll_clk_audio*/
else
clock = meson_clk_measure(98);
} else if (clksrc == MEASURE_CLK_MPLL) {
if (rx.chip_id == CHIP_ID_TL1)
clock = meson_clk_measure(29);/*apll_clk_out_div*/
else
clock = meson_clk_measure(27);
} else if (clksrc == MEASURE_CLK_ESM) {
clock = meson_clk_measure(68);
}
return clock;
}
static const unsigned int wr_only_register[] = {
0x0c, 0x3c, 0x60, 0x64, 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c, 0x8c, 0xa0,
0xac, 0xc8, 0xd8, 0xdc, 0x184, 0x188, 0x18c, 0x190, 0x194, 0x198, 0x19c,
0x1a0, 0x1a4, 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4,
0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, 0x1e8, 0x1ec,
0x1f0, 0x1f4, 0x1f8, 0x1fc, 0x204, 0x20c, 0x210, 0x214, 0x218, 0x21c,
0x220, 0x224, 0x228, 0x22c, 0x230, 0x234, 0x238, 0x268, 0x26c, 0x270,
0x274, 0x278, 0x290, 0x294, 0x298, 0x29c, 0x2a8, 0x2ac, 0x2b0, 0x2b4,
0x2b8, 0x2bc, 0x2d4, 0x2dc, 0x2e8, 0x2ec, 0x2f0, 0x2f4, 0x2f8, 0x2fc,
0x314, 0x318, 0x328, 0x32c, 0x348, 0x34c, 0x350, 0x354, 0x358, 0x35c,
0x384, 0x388, 0x38c, 0x398, 0x39c, 0x3d8, 0x3dc, 0x400, 0x404, 0x408,
0x40c, 0x410, 0x414, 0x418, 0x810, 0x814, 0x818, 0x830, 0x834, 0x838,
0x83c, 0x854, 0x858, 0x85c, 0xf60, 0xf64, 0xf70, 0xf74, 0xf78, 0xf7c,
0xf88, 0xf8c, 0xf90, 0xf94, 0xfa0, 0xfa4, 0xfa8, 0xfac, 0xfb8, 0xfbc,
0xfc0, 0xfc4, 0xfd0, 0xfd4, 0xfd8, 0xfdc, 0xfe8, 0xfec, 0xff0, 0x1f04,
0x1f0c, 0x1f10, 0x1f24, 0x1f28, 0x1f2c, 0x1f30, 0x1f34, 0x1f38, 0x1f3c
};
bool is_wr_only_reg(uint32_t addr)
{
int i;
/*sizeof(wr_only_register)/sizeof(uint32_t)*/
for (i = 0; i < sizeof(wr_only_register)/sizeof(uint32_t); i++) {
if (addr == wr_only_register[i])
return true;
}
return false;
}
void rx_debug_load22key(void)
{
int ret = 0;
int wait_kill_done_cnt = 0;
ret = rx_sec_set_duk(hdmirx_repeat_support());
rx_pr("22 = %d\n", ret);
if (ret == 1) {
rx_pr("load 2.2 key\n");
sm_pause = 1;
rx_set_cur_hpd(0);
hdcp22_on = 1;
hdcp22_kill_esm = 1;
while (wait_kill_done_cnt++ < 10) {
if (!hdcp22_kill_esm)
break;
msleep(20);
}
hdcp22_kill_esm = 0;
extcon_set_state_sync(rx.rx_excton_rx22,
EXTCON_DISP_HDMI, 0);
hdmirx_wr_dwc(DWC_HDCP22_CONTROL, 0x0);
hdmirx_hdcp22_esm_rst();
mdelay(110);
rx_is_hdcp22_support();
hdmirx_wr_dwc(DWC_HDCP22_CONTROL,
0x1000);
rx_hdcp22_wr_top(TOP_SKP_CNTL_STAT, 0x1);
hdcp22_clk_en(1);
extcon_set_state_sync(rx.rx_excton_rx22,
EXTCON_DISP_HDMI, 1);
mdelay(100);
hdmirx_hw_config();
hdmi_rx_top_edid_update();
hpd_to_esm = 1;
/* mdelay(900); */
rx_set_cur_hpd(1);
sm_pause = 0;
}
}
void rx_debug_loadkey(void)
{
rx_pr("load hdcp key\n");
hdmirx_hw_config();
hdmi_rx_top_edid_update();
pre_port = 0xfe;
}
void print_reg(uint start_addr, uint end_addr)
{
int i;
if (end_addr < start_addr)
return;
for (i = start_addr; i <= end_addr; i += sizeof(uint)) {
if ((i - start_addr) % (sizeof(uint)*4) == 0)
rx_pr("[0x%-4x] ", i);
if (!is_wr_only_reg(i))
rx_pr("0x%-8x,", hdmirx_rd_dwc(i));
else
rx_pr("xxxxxx ,");
if ((i - start_addr) % (sizeof(uint)*4) == sizeof(uint)*3)
rx_pr("\n");
}
if ((end_addr - start_addr + sizeof(uint)) % (sizeof(uint)*4) != 0)
rx_pr("\n");
}
void dump_reg(void)
{
int i = 0;
rx_pr("\n***Top registers***\n");
rx_pr("[addr ] addr + 0x0,");
rx_pr("addr + 0x1, addr + 0x2, addr + 0x3\n");
for (i = 0; i <= 0x24;) {
rx_pr("[0x%-3x]", i);
rx_pr("0x%-8x", hdmirx_rd_top(i));
rx_pr("0x%-8x,0x%-8x,0x%-8x\n",
hdmirx_rd_top(i + 1),
hdmirx_rd_top(i + 2),
hdmirx_rd_top(i + 3));
i = i + 4;
}
if (rx.chip_id == CHIP_ID_TL1) {
for (i = 0x25; i <= 0x84;) {
rx_pr("[0x%-3x]", i);
rx_pr("0x%-8x", hdmirx_rd_top(i));
rx_pr("0x%-8x,0x%-8x,0x%-8x\n",
hdmirx_rd_top(i + 1),
hdmirx_rd_top(i + 2),
hdmirx_rd_top(i + 3));
i = i + 4;
}
}
if (rx.chip_id < CHIP_ID_TL1) {
rx_pr("\n***PHY registers***\n");
rx_pr("[addr ] addr + 0x0,");
rx_pr("addr + 0x1,addr + 0x2,");
rx_pr("addr + 0x3\n");
for (i = 0; i <= 0x9a;) {
rx_pr("[0x%-3x]", i);
rx_pr("0x%-8x", hdmirx_rd_phy(i));
rx_pr("0x%-8x,0x%-8x,0x%-8x\n",
hdmirx_rd_phy(i + 1),
hdmirx_rd_phy(i + 2),
hdmirx_rd_phy(i + 3));
i = i + 4;
}
} else if (rx.chip_id == CHIP_ID_TL1) {
/* dump phy register */
rx_pr("\n***AML PHY registers***\n");
for (i = HHI_HDMIRX_APLL_CNTL0;
i <= HHI_HDMIRX_APLL_CNTL4;) {
rx_pr("apll cntl 0x%x:0x%8x\n", i >> 2, rd_reg_hhi(i));
i = i + 4;
}
rx_pr("MISC_CNTL0:0x%8x\n",
rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0));
rx_pr("MISC_CNTL1:0x%8x\n",
rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL1));
for (i = HHI_HDMIRX_PHY_MISC_CNTL2;
i <= HHI_HDMIRX_PHY_DCHD_CNTL2;) {
rx_pr("phy 0x%x:0x%8x\n", i >> 2, rd_reg_hhi(i));
i = i + 4;
}
rx_pr("MISC_STAT0:0x%8x\n",
hdmirx_rd_top(TOP_MISC_STAT0));
rx_pr("DCHD_STAT:0x%8x\n",
rd_reg_hhi(HHI_HDMIRX_PHY_DCHD_STAT));
}
rx_pr("\n**Controller registers**\n");
rx_pr("[addr ] addr + 0x0,");
rx_pr("addr + 0x4, addr + 0x8,");
rx_pr("addr + 0xc\n");
print_reg(0, 0xfc);
print_reg(0x140, 0x3ac);
print_reg(0x3c0, 0x418);
print_reg(0x480, 0x4bc);
print_reg(0x600, 0x610);
print_reg(0x800, 0x87c);
print_reg(0x8e0, 0x8e0);
print_reg(0x8fc, 0x8fc);
print_reg(0xf60, 0xffc);
/* print_reg(0x2000, 0x21fc); */
/* print_reg(0x2700, 0x2714); */
/* print_reg(0x2f00, 0x2f14); */
/* print_reg(0x3000, 0x3020); */
/* print_reg(0x3040, 0x3054); */
/* print_reg(0x3080, 0x3118); */
/* print_reg(0x3200, 0x32e4); */
}
void dump_edid_reg(void)
{
int i = 0;
int j = 0;
rx_pr("\n***********************\n");
rx_pr("0x1 1.4 edid\n");
rx_pr("0x2 1.4 edid with audio blocks\n");
rx_pr("0x3 1.4 edid with 420 capability\n");
rx_pr("0x4 1.4 edid with 420 video data\n");
rx_pr("0x5 2.0 edid with HDR,DV,420\n");
rx_pr("********************************\n");
for (i = 0; i < 16; i++) {
rx_pr("[%2d] ", i);
for (j = 0; j < 16; j++) {
rx_pr("0x%02lx, ",
hdmirx_rd_top(TOP_EDID_OFFSET +
(i * 16 + j)));
}
rx_pr("\n");
}
}
int rx_debug_wr_reg(const char *buf, char *tmpbuf, int i)
{
uint32_t adr = 0;
uint32_t value = 0;
if (kstrtou32(tmpbuf + 3, 16, &adr) < 0)
return -EINVAL;
rx_pr("adr = %#x\n", adr);
if (kstrtou32(buf + i + 1, 16, &value) < 0)
return -EINVAL;
rx_pr("value = %#x\n", value);
if (tmpbuf[1] == 'h') {
if (buf[2] == 't') {
hdmirx_wr_top(adr, value);
rx_pr("write %x to TOP [%x]\n",
value, adr);
} else if (buf[2] == 'd') {
hdmirx_wr_dwc(adr, value);
rx_pr("write %x to DWC [%x]\n",
value, adr);
} else if (buf[2] == 'p') {
hdmirx_wr_phy(adr, value);
rx_pr("write %x to PHY [%x]\n",
value, adr);
} else if (buf[2] == 'u') {
wr_reg_hhi(adr, value);
rx_pr("write %x to hiu [%x]\n",
value, adr);
} else if (buf[2] == 'h') {
rx_hdcp22_wr_top(adr, value);
rx_pr("write %x to hdcp [%x]\n",
value, adr);
} else if (buf[2] == 'c') {
rx_hdcp22_wr_reg(adr, value);
rx_pr("write %x to chdcp [%x]\n",
value, adr);
}
}
return 0;
}
int rx_debug_rd_reg(const char *buf, char *tmpbuf)
{
uint32_t adr = 0;
uint32_t value = 0;
if (tmpbuf[1] == 'h') {
if (kstrtou32(tmpbuf + 3, 16, &adr) < 0)
return -EINVAL;
if (tmpbuf[2] == 't') {
value = hdmirx_rd_top(adr);
rx_pr("TOP [%x]=%x\n", adr, value);
} else if (tmpbuf[2] == 'd') {
value = hdmirx_rd_dwc(adr);
rx_pr("DWC [%x]=%x\n", adr, value);
} else if (tmpbuf[2] == 'p') {
value = hdmirx_rd_phy(adr);
rx_pr("PHY [%x]=%x\n", adr, value);
} else if (tmpbuf[2] == 'u') {
value = rd_reg_hhi(adr);
rx_pr("HIU [%x]=%x\n", adr, value);
} else if (tmpbuf[2] == 'h') {
value = rx_hdcp22_rd_top(adr);
rx_pr("HDCP [%x]=%x\n", adr, value);
} else if (tmpbuf[2] == 'c') {
value = rx_hdcp22_rd_reg(adr);
rx_pr("chdcp [%x]=%x\n", adr, value);
}
}
return 0;
}
int rx_get_aud_pll_err_sts(void)
{
int ret = E_AUDPLL_OK;
int32_t req_clk = rx_measure_clock(MEASURE_CLK_MPLL);
int32_t aud_clk = rx_measure_clock(MEASURE_CLK_AUD_PLL);
uint32_t phy_pll_rate = (hdmirx_rd_phy(PHY_MAINFSM_STATUS1)>>9)&0x3;
uint32_t aud_pll_cntl = (rd_reg_hhi(HHI_AUD_PLL_CNTL6)>>28)&0x3;
if (rx.chip_id == CHIP_ID_TL1) {
/* need to do something ...*/
} else {
if (req_clk > PHY_REQUEST_CLK_MAX ||
req_clk < PHY_REQUEST_CLK_MIN) {
ret = E_REQUESTCLK_ERR;
if (log_level & AUDIO_LOG)
rx_pr("request clk err:%d\n", req_clk);
} else if (phy_pll_rate != aud_pll_cntl) {
ret = E_PLLRATE_CHG;
if (log_level & AUDIO_LOG)
rx_pr("pll rate chg,phy=%d,pll=%d\n",
phy_pll_rate, aud_pll_cntl);
} else if (aud_clk == 0) {
ret = E_AUDCLK_ERR;
if (log_level & AUDIO_LOG)
rx_pr("aud_clk=0\n");
}
}
return ret;
}
uint32_t aml_cable_clk_band(uint32_t cableclk,
uint32_t clkrate)
{
uint32_t bw;
uint32_t cab_clk = cableclk;
if (rx.chip_id != CHIP_ID_TL1)
return phy_frq_band_2;
/*rx_pr("cable clk=%d, clkrate=%d\n", cableclk, clkrate);*/
/* 1:40 */
if (clkrate)
cab_clk = cableclk << 2;
/* 1:10 */
if (cab_clk < (45*MHz))
bw = phy_frq_band_0;
else if (cab_clk < (77*MHz))
bw = phy_frq_band_1;
else if (cab_clk < (155*MHz))
bw = phy_frq_band_2;
else if (cab_clk < (340*MHz))
bw = phy_frq_band_3;
else if (cab_clk < (525*MHz))
bw = phy_frq_band_4;
else if (cab_clk < (600*MHz))
bw = phy_frq_band_5;
else {
bw = phy_frq_band_2;
rx_pr("bw err,clk=%d\n", cableclk/MHz);
}
return bw;
}
uint32_t aml_phy_pll_band(uint32_t cableclk,
uint32_t clkrate)
{
uint32_t bw;
uint32_t cab_clk = cableclk;
if (clkrate)
cab_clk = cableclk << 2;
/* 1:10 */
if (cab_clk < (35*MHz))
bw = pll_frq_band_0;
else if (cab_clk < (77*MHz))
bw = pll_frq_band_1;
else if (cab_clk < (155*MHz))
bw = pll_frq_band_2;
else if (cab_clk < (300*MHz))
bw = pll_frq_band_3;
else if (cab_clk < (600*MHz))
bw = pll_frq_band_4;
else
bw = pll_frq_band_2;
return bw;
}
void aml_phy_switch_port(void)
{
uint32_t data32;
/* reset and select data port */
data32 = 0x00000010;
data32 |= ((1 << rx.port) << 6);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL3, data32);
/* release reset */
data32 |= (1 << 11);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL3, data32);
udelay(5);
data32 = 0;
data32 |= rx.port << 2;
hdmirx_wr_dwc(DWC_SNPS_PHYG3_CTRL, data32);
}
static const uint32_t phy_misci[][4] = {
/* 0xd7 0xd8 0xe0 0xe1 */
{ /* 24~45M */
0x3003707f, 0x00000080, 0x02218000, 0x00000010,
},
{ /* 45~74.5M */
0x3003707f, 0x00000080, 0x02218000, 0x00000010,
},
{ /* 77~155M */
0x3003707f, 0x00000080, 0x02218000, 0x00000010,
},
{ /* 155~340M */
0x3003707f, 0x00000080, 0x02218000, 0x00000010,
},
{ /* 340~525M */
0x3003707f, 0x007f0080, 0x02218000, 0x00000010,
},
{ /* 525~600M */
0x3003707f, 0x007f0080, 0x02218000, 0x00000010,
},
};
static const uint32_t phy_dcha[][3] = {
/* 0xe2 0xe3 0xe4 */
{ /* 24~45M */
0x00000280, 0x4400c202, 0x030088a2,
},
{ /* 45~74.5M */
0x00000280, 0x4400c202, 0x030088a2,
},
{ /* 77~155M */
0x000002a2, 0x6800c202, 0x01009126,
},
{ /* 155~340M */
0x000002a2, 0x0800c202, 0x0100cc31,
},
{ /* 340~525M */
0x000002a2, 0x0700003c, 0x1d00cc31,
},
{ /* 525~600M */
0x000002a2, 0x0700003c, 0x1d00cc31,
},
};
static const uint32_t phy_dcha_reva[][3] = {
/* 0xe2 0xe3 0xe4 */
{ /* 24~45M */
0x00000280, 0x2400c202, 0x030088a2,
},
{ /* 45~74.5M */
0x00000280, 0x2400c202, 0x030088a2,
},
{ /* 77~155M */
0x000002a2, 0x4800c202, 0x01009126,
},
{ /* 155~340M */
0x000002a2, 0x0800c202, 0x0100cc31,
},
{ /* 340~525M */
0x000002a2, 0x0700003c, 0x1d00cc31,
},
{ /* 525~600M */
0x000002a2, 0x0700003c, 0x1d00cc31,
},
};
/* long cable */
static const uint32_t phy_dchd_1[][3] = {
/* 0xe5 0xe6 0xe7 */
{ /* 24~45M */
0x002e714a, 0x1e051630, 0x00018000,
},
{ /* 45~74.5M */
0x002e714a, 0x1e051630, 0x00018000,
},
{ /* 77~155M */
0x002c714a, 0x1e062620, 0x00018000,
},
{ /* 155~340M */
0x002c714a, 0x1e062620, 0x00018000,
},
{ /* 340~525M */
0x002c714a, 0x1e051650, 0x00018000,
},
{ /* 525~600M */
0x002c714a, 0x1e051650, 0x00018000,
},
};
/* short cable */
static const uint32_t phy_dchd_2[][3] = {
/* 0xe5 0xe6 0xe7 */
{ /* 24~45M */
0x002e714a, 0x1e022220, 0x00018000,
},
{ /* 45~74.5M */
0x002e714a, 0x1e022220, 0x00018000,
},
{ /* 77~155M */
0x002c714a, 0x1e022220, 0x00018000,
},
{ /* 155~340M */
0x002c714a, 0x1e022220, 0x00018000,
},
{ /* 340~525M */
0x002c714a, 0x1e022220, 0x0001a000,
},
{ /* 525~600M */
0x002c714a, 0x1e022220, 0x00018000,
},
};
/* long cable */
static const uint32_t phy_dchd_3[][3] = {
/* 0xe5 0xe6 0xe7 */
{ /* 24~45M */
0x002e712a, 0x1e062620, 0x00018000,
},
{ /* 45~74.5M */
0x002e714a, 0x1e062620, 0x00018000,
},
{ /* 77~155M */
0x002c715a, 0x1e062620, 0x00018000,
},
{ /* 155~340M */
0x002c715a, 0x1e062620, 0x00018000,
},
{ /* 340~525M */
0x002c715a, 0x1e051650, 0x00018000,
},
{ /* 525~600M */
0x002c715a, 0x1e051650, 0x00018000,
},
};
/* short cable */
static const uint32_t phy_dchd_4[][3] = {
/* 0xe5 0xe6 0xe7 */
{ /* 24~45M */
0x002e712a, 0x1e022220, 0x00018000,
},
{ /* 45~74.5M */
0x002e714a, 0x1e022220, 0x00018000,
},
{ /* 77~155M */
0x002c715a, 0x1e022220, 0x00018000,
},
{ /* 155~340M */
0x002c715a, 0x1e022220, 0x00018000,
},
{ /* 340~525M */
0x002c715a, 0x1e012330, 0x0001a000,
},
{ /* 525~600M */
0x002c715a, 0x1e022220, 0x00018000,
},
};
void aml_phy_init_1(void)
{
uint32_t idx = rx.phy.phy_bw;
uint32_t data32;
data32 = phy_misci[idx][1];
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL1, data32);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL2,
phy_misci[idx][2]);
/* reset and select data port */
data32 = phy_misci[idx][3];
data32 |= ((1 << rx.port) << 6);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL3, data32);
/* release reset */
data32 |= (1 << 11);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL3, data32);
udelay(5);
if (is_tl1_former()) {
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL0,
phy_dcha_reva[idx][0]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL1,
phy_dcha_reva[idx][1]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL2,
phy_dcha_reva[idx][2]);
} else {
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL0,
phy_dcha[idx][0]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL1,
phy_dcha[idx][1]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL2,
phy_dcha[idx][2]);
}
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL0,
phy_dchd_1[idx][0]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL2,
phy_dchd_1[idx][2]);
if ((rx.phy.cablesel % 2) == 0)
data32 = phy_dchd_1[idx][1];
else if ((rx.phy.cablesel % 2) == 1)
data32 = phy_dchd_2[idx][1];
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL1, data32);/*398*/
udelay(5);
data32 |= 0x00400000;
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL1, data32);/*398*/
data32 = rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0);
data32 &= ~(0xf << 7);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
udelay(5);
/* data channel release reset */
data32 |= (0xf << 7);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
}
void aml_phy_init(void)
{
uint32_t idx = rx.phy.phy_bw;
uint32_t data32;
uint32_t term_value =
hdmirx_rd_top(TOP_HPD_PWR5V) & 0x7;
data32 = phy_misci[idx][0];
data32 = (data32 & (~0x7)) | term_value;
/* terminal en */
data32 &= ~(disable_port_num & 0x07);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
udelay(2);
/* data channel and common block reset */
data32 |= 0xf << 7;
udelay(5);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data32);
udelay(2);
data32 = phy_misci[idx][1];
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL1, data32);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL2, phy_misci[idx][2]);
/* reset and select data port */
data32 = phy_misci[idx][3];
data32 |= ((1 << rx.port) << 6);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL3, data32);
/* release reset */
data32 |= (1 << 11);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL3, data32);
udelay(5);
if (is_tl1_former()) {
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL0,
phy_dcha_reva[idx][0]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL1,
phy_dcha_reva[idx][1]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL2,
phy_dcha_reva[idx][2]);
} else {
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL0,
phy_dcha[idx][0]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL1,
phy_dcha[idx][1]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHA_CNTL2,
phy_dcha[idx][2]);
}
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL0, phy_dchd_1[idx][0]);
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL2, phy_dchd_1[idx][2]);
if ((rx.phy.cablesel % 2) == 0)
data32 = phy_dchd_1[idx][1];
else if ((rx.phy.cablesel % 2) == 1)
data32 = phy_dchd_2[idx][1];
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL1, data32);/*398*/
udelay(5);
data32 |= 0x00400000;
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL1, data32);/*398*/
}
void aml_eq_setting(void)
{
uint32_t data32 = 0;
uint32_t idx = rx.phy.phy_bw;
if (find_best_eq) {
data32 = phy_dchd_1[idx][1] & (~(MSK(16, 4)));
data32 |= find_best_eq << 4;
} else if ((rx.phy.cablesel % 4) == 0)
data32 = phy_dchd_1[idx][1];
else if ((rx.phy.cablesel % 4) == 1)
data32 = phy_dchd_2[idx][1];
else if ((rx.phy.cablesel % 4) == 2)
data32 = phy_dchd_3[idx][1];
else if ((rx.phy.cablesel % 4) == 3)
data32 = phy_dchd_4[idx][1];
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL1, data32);
udelay(5);
data32 |= 0x00400000;
wr_reg_hhi(HHI_HDMIRX_PHY_DCHD_CNTL1, data32);
}
void rx_get_best_eq_setting(void)
{
uint32_t ch0, ch1, ch2;
static uint32_t err_sum;
static uint32_t time_cnt;
static uint32_t array_cnt;
if ((rx.chip_id != CHIP_ID_TL1) ||
(!find_best_eq))
return;
if ((find_best_eq >= 0x7777) ||
(array_cnt >= 255)) {
rx_pr("eq traversal completed.\n");
rx_pr("best eq value:%d\n", array_cnt);
if (array_cnt) {
do {
rx_pr("%x:\n", rx.phy.eq_data[array_cnt]);
} while (array_cnt--);
} else
rx_pr("%x:\n", rx.phy.eq_data[array_cnt]);
find_best_eq = 0;
array_cnt = 0;
return;
}
if (time_cnt == 0) {
aml_phy_init();
udelay(1);
wr_reg_hhi_bits(HHI_HDMIRX_PHY_DCHD_CNTL1,
MSK(16, 4),
find_best_eq);
udelay(2);
wr_reg_hhi_bits(HHI_HDMIRX_PHY_DCHD_CNTL1, _BIT(22), 1);
rx_pr("set eq:%x\n", find_best_eq);
err_sum = 0;
do {
find_best_eq++;
} while (((find_best_eq & 0xf) > 7) ||
(((find_best_eq >> 4) & 0xf) > 7) ||
(((find_best_eq >> 8) & 0xf) > 7) ||
(((find_best_eq >> 12) & 0xf) > 7));
}
time_cnt++;
if (time_cnt > 2) {
if (!is_tmds_valid())
return;
}
if (time_cnt > 4) {
rx_get_error_cnt(&ch0, &ch1, &ch2);
err_sum += (ch0 + ch1 + ch2);
}
if (time_cnt > eq_try_cnt) {
time_cnt = 0;
if (err_sum < rx.phy.err_sum) {
rx.phy.err_sum = err_sum;
rx_pr("err_sum = %d\n", err_sum);
array_cnt = 0;
rx.phy.eq_data[array_cnt] = find_best_eq;
} else if ((err_sum == rx.phy.err_sum) ||
(err_sum == 0)) {
rx.phy.err_sum = err_sum;
array_cnt++;
rx_pr("array = %x\n", array_cnt);
rx.phy.eq_data[array_cnt] = find_best_eq;
}
//if (ch0 || ch1 || ch2)
//rx_pr("err cnt:%d,%d,%d\n", ch0, ch1, ch2); ;
}
}
bool is_tmds_clk_stable(void)
{
bool ret = true;
uint32_t cableclk;
uint32_t pixel_clk;
if (rx.phy.clk_rate)
cableclk = rx.phy.cable_clk * 4;
else
cableclk = rx.phy.cable_clk;
pixel_clk = meson_clk_measure(29);
if (abs(cableclk - pixel_clk) > 5 * MHz) {
if (log_level & VIDEO_LOG)
rx_pr("cableclk=%d,tmdsclk=%d,pixelclk=%d\n",
cableclk/MHz, rx.phy.tmds_clk/MHz,
meson_clk_measure(29)/MHz);
ret = false;
} else
ret = true;
return ret;
}
/*
* for tl1 phy function
*/
struct apll_param apll_tab[] = {
/*od for tmds: 2/4/8/16/32*/
/*od2 for audio: 1/2/4/8/16*/
/* bw M, N, od, od_div, od2, od2_div */
{pll_frq_band_0, 160, 1, 0x5, 32, 0x2, 8},/*tmdsx4*/
{pll_frq_band_1, 80, 1, 0x4, 16, 0x2, 8},/*tmdsx2*/
{pll_frq_band_2, 40, 1, 0x3, 8, 0x2, 8},/*tmds*/
{pll_frq_band_3, 40, 2, 0x2, 4, 0x1, 4},/*tmds*/
{pll_frq_band_4, 40, 1, 0x1, 2, 0x0, 2},/*tmds*/
{pll_frq_null, 40, 1, 0x3, 8, 0x2, 8},
};
void aml_phy_pll_setting(void)
{
uint32_t M, N;
uint32_t od, od_div;
uint32_t od2, od2_div;
uint32_t bw = rx.phy.pll_bw;
uint32_t vco_clk;
uint32_t apll_out;
uint32_t aud_pll_out;
uint32_t data, data2;
uint32_t aud_div;
uint32_t cableclk = rx.phy.cable_clk / KHz;
int pll_rst_cnt = 0;
od_div = apll_tab[bw].od_div;
od = apll_tab[bw].od;
M = apll_tab[bw].M;
N = apll_tab[bw].N;
od2_div = apll_tab[bw].od2_div;
od2 = apll_tab[bw].od2;
vco_clk = (cableclk * M) / N; /*KHz*/
if ((vco_clk < (2970 * KHz)) || (vco_clk > (6000 * KHz))) {
if (log_level & VIDEO_LOG)
rx_pr("err: M=%d,N=%d,vco_clk=%d\n", M, N, vco_clk);
}
/*tmds clk out*/
apll_out = (vco_clk/od_div)/5;
aud_pll_out = ((vco_clk/od2_div)/5);
if (is_tl1_former())
od2 += 1;
do {
/*cntl0 M <7:0> N<14:10>*/
data = 0x00090400 & 0xffff8300;
data |= M;
data |= (N << 10);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL0, data|0x20000000);
udelay(5);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL0, data|0x30000000);
udelay(5);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL1, 0x00000000);
udelay(5);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL2, 0x00001118);
udelay(5);
data2 = 0x10058f30|od2;
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL3, data2);
/* verB: bit'27=1 */
if (is_tl1_former())
data2 = 0x000100c0;
else
data2 = 0x080100c0;
data2 |= (od << 24);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL4, data2);
udelay(5);
/*apll_vctrl_mon_en*/
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL4, data2|0x00800000);
udelay(5);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL0, data|0x34000000);
udelay(5);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL0, data|0x14000000);
udelay(5);
/* bit'5: force lock bit'2: improve ldo voltage:pll 0.8v->0.9 */
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL2, 0x0000303c);
udelay(5);
/* common block release reset */
data = rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0);
data &= ~(0xf << 7);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data);
udelay(5);
/* data channel release reset */
data |= (0xf << 7);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data);
mdelay(1);
if (pll_rst_cnt++ > pll_rst_max) {
rx_pr("pll rst error\n");
return;
}
if (log_level & VIDEO_LOG)
rx_pr("pll init-cableclk=%d,pixelclk=%d,sq=%d\n",
rx.phy.cable_clk/MHz,
meson_clk_measure(29)/MHz,
hdmirx_rd_top(TOP_MISC_STAT0) & 0x1);
} while ((!is_tmds_clk_stable()) && is_clk_stable());
/*set audio pll divider*/
aud_div = aud_pll_out/apll_out;
if (aud_div == 1)
data = 0;
else if (aud_div == 2)
data = 1;
else if (aud_div == 4)
data = 2;
else if (aud_div == 8)
data = 3;
else if (aud_div == 16)
data = 4;
rx.phy.aud_div = data;
}
void aml_phy_pw_onoff(uint32_t onoff)
{
uint32_t data = rd_reg_hhi(HHI_HDMIRX_APLL_CNTL0);
if (onoff) {
/* apll power down */
data &= ~(1 << 26);
data &= ~(1 << 28);
data |= (1 << 29);
wr_reg_hhi(HHI_HDMIRX_APLL_CNTL0, data);
/*phy */
data = rd_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0);
data &= ~(1 << 7);
data &= ~(1 << 8);
data &= ~(1 << 9);
wr_reg_hhi(HHI_HDMIRX_PHY_MISC_CNTL0, data);
} else {
aml_phy_init();
/*tl1_apll_setting(apll_frq_band_2);*/
}
}
/*
* aml phy initial
*/
void aml_phy_bw_switch(void)
{
aml_phy_init();
udelay(10);
aml_phy_pll_setting();
udelay(10);
aml_phy_init_1();
}
unsigned int aml_phy_pll_lock(void)
{
if (rd_reg_hhi(HHI_HDMIRX_APLL_CNTL0) & 0x80000000)
return true;
else
return false;
}
bool is_tmds_valid(void)
{
if (force_vic)
return true;
if (rx.chip_id == CHIP_ID_TL1)
return (aml_phy_tmds_valid() == 1) ? true : false;
else
return (rx_get_pll_lock_sts() == 1) ? true : false;
}
unsigned int aml_phy_tmds_valid(void)
{
unsigned int tmds_valid;
/* unsigned int tmdsclk_valid; */
unsigned int sqofclk;
/* unsigned int pll_lock; */
unsigned int tmds_align;
tmds_valid = hdmirx_rd_dwc(DWC_HDMI_PLL_LCK_STS) & 0x01;
sqofclk = hdmirx_rd_top(TOP_MISC_STAT0) & 0x1;
/*pll_lock = rd_reg_hhi(HHI_HDMIRX_APLL_CNTL0) & 0x80000000;*/
/* tmdsclk_valid = is_tmds_clk_stable(); */
tmds_align = hdmirx_rd_top(TOP_TMDS_ALIGN_STAT) & 0x3f000000;
if (tmds_valid && sqofclk &&
(tmds_align == 0x3f000000))
return true;
else {
if (log_level & VIDEO_LOG) {
rx_pr("tmds:%x,sqo:%x,align:%x\n",
tmds_valid, sqofclk, tmds_align);
rx_pr("cable clk0:%d\n",
rx_measure_clock(MEASURE_CLK_CABLE));
rx_pr("cable clk1:%d\n",
rx_get_clock(TOP_HDMI_CABLECLK));
}
return false;
}
}
void rx_phy_rxsense_pulse(unsigned int t1, unsigned int t2, bool en)
{
/* set rxsense pulse */
hdmirx_phy_pddq(!en);
mdelay(t1);
hdmirx_phy_pddq(en);
mdelay(t2);
}
void rx_phy_power_on(unsigned int onoff)
{
if (onoff)
hdmirx_phy_pddq(0);
else
hdmirx_phy_pddq(1);
if (rx.chip_id == CHIP_ID_TL1) {
/*the enable of these regs are in phy init*/
if (onoff == 0) {
wr_reg_hhi_bits(HHI_HDMIRX_APLL_CNTL0, _BIT(28), onoff);
/*close termination 3.3v*/
wr_reg_hhi_bits(HHI_HDMIRX_PHY_MISC_CNTL0,
MSK(3, 0), onoff);
}
}
}
void rx_emp_to_ddr_init(void)
{
unsigned int data;
if (rx.chip_id != CHIP_ID_TL1)
return;
if (rx.empbuff.pg_addr) {
rx_pr("rx_emp_to_ddr_init\n");
/*disable field done and last pkt interrupt*/
top_intr_maskn_value &= ~(1 << 25);
top_intr_maskn_value &= ~(1 << 26);
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
if (rx.empbuff.p_addr_a) {
/* emp int enable */
/* config ddr buffer */
hdmirx_wr_top(TOP_EMP_DDR_START_A,
rx.empbuff.p_addr_a);
hdmirx_wr_top(TOP_EMP_DDR_START_B,
rx.empbuff.p_addr_b);
}
#if 0
/* instead by clk tree */
data = 0;
/*[10: 9] HDMIRX AXI clock mux select: fclk_div3=667MHz*/
data |= (2 << 9);
/*[ 8] HDMIRX AXI clock enable*/
data |= (1 << 8);
/*[ 6: 0] HDMIRX AXI clock divider: 667/1=667MHz*/
data |= (0 << 0);
wr_reg_hhi(HHI_HDMIRX_AXI_CLK_CNTL, data);
#endif
/* enable store EMP pkt type */
data = 0;
data |= 0x1 << 15;/* ddr_store_emp */
hdmirx_wr_top(TOP_EMP_DDR_FILTER, data);
/* max pkt count */
hdmirx_wr_top(TOP_EMP_CNTMAX, EMP_BUFF_MAX_PKT_CNT);
data = 0;
data |= 0xf << 16;/*[23:16] hs_beat_rate=0xf */
data |= 0x0 << 14;/*[14] buffer_info_mode=0 */
data |= 0x1 << 13;/*[13] reset_on_de=1 */
data |= 0x1 << 12;/*[12] burst_end_on_last_emp=1 */
data |= 0x0 << 2;/*[11:2] de_rise_delay=0 */
data |= 0x0 << 0;/*[1:0] Endian = 0 */
hdmirx_wr_top(TOP_EMP_CNTL_0, data);
data = 0;
data |= 0 << 1;/*ddr_mode[1] 0: emp 1: tmds*/
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
data = 0;
data |= 1; /*ddr_en[0] 1:enable*/
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
/* emp int enable TOP_INTR_MASKN*/
/* emp field end done at DE rist bit[25]*/
/* emp last EMP pkt recv done bit[26]*/
top_intr_maskn_value |= _BIT(25);
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
}
rx.empbuff.ready = NULL;
rx.empbuff.irqcnt = 0;
rx.empbuff.emppktcnt = 0;
rx.empbuff.tmdspktcnt = 720*480;
}
void rx_emp_field_done_irq(void)
{
phys_addr_t p_addr;
unsigned int recv_pkt_cnt, recv_byte_cnt, recv_pagenum;
unsigned int emp_pkt_cnt = 0;
unsigned char *src_addr = 0;
unsigned char *dts_addr;
unsigned int i, j, k;
unsigned int datacnt = 0;
struct page *cur_start_pg_addr;
/*emp data start physical address*/
p_addr = hdmirx_rd_top(TOP_EMP_DDR_PTR_S_BUF);
/*buffer number*/
recv_pkt_cnt = hdmirx_rd_top(TOP_EMP_RCV_CNT_BUF);
recv_byte_cnt = recv_pkt_cnt * 32;
recv_pagenum = (recv_byte_cnt >> PAGE_SHIFT) + 1;
if (rx.empbuff.irqcnt & 0x1)
dts_addr = rx.empbuff.storeB;
else
dts_addr = rx.empbuff.storeA;
if (recv_pkt_cnt >= EMP_BUFF_MAX_PKT_CNT) {
recv_pkt_cnt = EMP_BUFF_MAX_PKT_CNT - 1;
rx_pr("pkt cnt err:%d\n", recv_pkt_cnt);
}
for (i = 0; i < recv_pagenum;) {
/*one page 4k*/
cur_start_pg_addr = phys_to_page(p_addr + i*PAGE_SIZE);
src_addr = kmap_atomic(cur_start_pg_addr);
dma_sync_single_for_cpu(hdmirx_dev, (p_addr + i*PAGE_SIZE),
PAGE_SIZE, DMA_TO_DEVICE);
if (recv_byte_cnt >= PAGE_SIZE) {
for (j = 0; j < PAGE_SIZE;) {
if (src_addr[j] == 0x7f) {
emp_pkt_cnt++;
/*32 bytes per emp pkt*/
for (k = 0; k < 32; k++) {
dts_addr[datacnt] =
src_addr[PAGE_SIZE * i + j + k];
datacnt++;
}
}
j += 32;
}
recv_byte_cnt -= PAGE_SIZE;
} else {
for (j = 0; j < recv_byte_cnt;) {
if (src_addr[j] == 0x7f) {
emp_pkt_cnt++;
/*32 bytes per emp pkt*/
for (k = 0; k < 32; k++) {
dts_addr[datacnt] =
src_addr[PAGE_SIZE * i + j + k];
datacnt++;
}
}
j += 32;
}
}
/*release*/
/*__kunmap_atomic(src_addr);*/
kunmap_atomic(src_addr);
i++;
}
/*ready address*/
rx.empbuff.ready = dts_addr;
/*ready pkt cnt*/
rx.empbuff.emppktcnt = emp_pkt_cnt;
/*emp field dont irq counter*/
rx.empbuff.irqcnt++;
}
void rx_emp_status(void)
{
rx_pr("p_addr_a=0x%x\n", rx.empbuff.p_addr_a);
rx_pr("p_addr_b=0x%x\n", rx.empbuff.p_addr_b);
rx_pr("storeA=0x%x\n", rx.empbuff.storeB);
rx_pr("storeB=0x%x\n", rx.empbuff.storeB);
rx_pr("irq cnt =0x%x\n", rx.empbuff.irqcnt);
rx_pr("ready=0x%p\n", rx.empbuff.ready);
rx_pr("dump_mode =0x%x\n", rx.empbuff.dump_mode);
rx_pr("recv tmp pkt cnt=0x%x\n", rx.empbuff.emppktcnt);
rx_pr("recv tmds pkt cnt=0x%x\n", rx.empbuff.tmdspktcnt);
}
void rx_tmds_to_ddr_init(void)
{
unsigned int data, data2;
unsigned int i = 0;
if (rx.chip_id != CHIP_ID_TL1)
return;
if (rx.empbuff.pg_addr) {
rx_pr("rx_tmds_to_ddr_init\n");
/*disable field done and last pkt interrupt*/
top_intr_maskn_value &= ~(1 << 25);
top_intr_maskn_value &= ~(1 << 26);
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
/* disable emp rev */
data = hdmirx_rd_top(TOP_EMP_CNTL_1);
data &= ~0x1;
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
/* wait until emp finish */
data2 = hdmirx_rd_top(TOP_EMP_STAT_0) & 0x7fffffff;
data = hdmirx_rd_top(TOP_EMP_STAT_1);
while (data2 || data) {
mdelay(1);
data2 = hdmirx_rd_top(TOP_EMP_STAT_0) & 0x7fffffff;
data = hdmirx_rd_top(TOP_EMP_STAT_1);
if (i++ > 100) {
rx_pr("warning: wait emp timeout\n");
break;
}
}
if (rx.empbuff.p_addr_a) {
/* config ddr buffer */
hdmirx_wr_top(TOP_EMP_DDR_START_A,
rx.empbuff.p_addr_a);
hdmirx_wr_top(TOP_EMP_DDR_START_B,
rx.empbuff.p_addr_a);
rx_pr("cfg hw addr=0x%x\n", rx.empbuff.p_addr_a);
}
/* max pkt count to avoid buffer overflow */
/* one pixel 4bytes */
data = ((rx.empbuff.tmdspktcnt/8) * 8) - 1;
hdmirx_wr_top(TOP_EMP_CNTMAX, data);
rx_pr("pkt max cnt limit=0x%x\n", data);
data = 0;
data |= 0x0 << 16;/*[23:16] hs_beat_rate=0xf */
data |= 0x1 << 14;/*[14] buffer_info_mode=0 */
data |= 0x1 << 13;/*[13] reset_on_de=1 */
data |= 0x0 << 12;/*[12] burst_end_on_last_emp=1 */
data |= 0x0 << 2;/*[11:2] de_rise_delay=0 */
data |= 0x0 << 0;/*[1:0] Endian = 0 */
hdmirx_wr_top(TOP_EMP_CNTL_0, data);
/* working mode: tmds data to ddr enable */
data = hdmirx_rd_top(TOP_EMP_CNTL_1);
data |= 0x1 << 1;/*ddr_mode[1] 0: emp 1: tmds*/
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
/* emp int enable TOP_INTR_MASKN*/
/* emp field end done at DE rist bit[25]*/
/* emp last EMP pkt recv done bit[26]*/
top_intr_maskn_value |= _BIT(26);
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
/*start record*/
data |= 0x1; /*ddr_en[0] 1:enable*/
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
}
}
void rx_emp_lastpkt_done_irq(void)
{
unsigned int data;
/* disable record */
data = hdmirx_rd_top(TOP_EMP_CNTL_1);
data &= ~0x1; /*ddr_en[0] 1:enable*/
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
/*need capture data*/
rx_pr(">> lastpkt_done_irq >\n");
}
void rx_emp_capture_stop(void)
{
unsigned int i = 0, data, data2;
/*disable field done and last pkt interrupt*/
top_intr_maskn_value &= ~(1 << 25);
top_intr_maskn_value &= ~(1 << 26);
hdmirx_wr_top(TOP_INTR_MASKN, top_intr_maskn_value);
/* disable emp rev */
data = hdmirx_rd_top(TOP_EMP_CNTL_1);
data &= ~0x1;
hdmirx_wr_top(TOP_EMP_CNTL_1, data);
/* wait until emp finish */
data2 = hdmirx_rd_top(TOP_EMP_STAT_0) & 0x7fffffff;
data = hdmirx_rd_top(TOP_EMP_STAT_1);
while (data2 || data) {
mdelay(1);
data2 = hdmirx_rd_top(TOP_EMP_STAT_0) & 0x7fffffff;
data = hdmirx_rd_top(TOP_EMP_STAT_1);
if (i++ > 100) {
rx_pr("warning: wait emp timeout\n");
break;
}
}
rx_pr("emp capture stop\n");
}
/*
* get hdmi data error counter
* for tl1
* return:
* ch0 , ch1 , ch2 error counter value
*/
void rx_get_error_cnt(uint32_t *ch0, uint32_t *ch1,
uint32_t *ch2)
{
uint32_t val;
val = hdmirx_rd_top(TOP_CHAN01_ERRCNT);
*ch0 = val & 0xffff;
*ch1 = (val >> 16) & 0xffff;
val = hdmirx_rd_top(TOP_CHAN2_ERRCNT);
*ch2 = val & 0xffff;
}
/*
* get hdmi audio N CTS
* for tl1
* return:
* audio ACR N
* audio ACR CTS
*/
void rx_get_audio_N_CTS(uint32_t *N, uint32_t *CTS)
{
*N = hdmirx_rd_top(TOP_ACR_N_STAT);
*CTS = hdmirx_rd_top(TOP_ACR_CTS_STAT);
}