hdmitx: add init code for repeater [2/6]

PD#SWPL-323

Problem:
For TXLX/T962E, it has both HDMI Rx and TX, and lacks of HDMI repeater
functions, including HDCP repeater function.

Solution:
Add the init code for hdmi repeater

Verify:
TXLX/T962E/R321

Change-Id: Iaf17ae62c590ff4f8478dd5556f3ed24b9ff3bb1
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
This commit is contained in:
Zongdong Jiao
2018-09-29 18:20:21 +08:00
committed by Dongjin Kim
parent 80b8564f35
commit 15e30c1693
8 changed files with 673 additions and 226 deletions

View File

@@ -13539,8 +13539,8 @@ F: arch/arm/mach-meson/Makefile.boot
HDMITX OUTPUT DRIVER
M: Yi Zhou <yi.zhou@amlogic.com>
M: Kaifu Hu <kaifu.hu@amlogic.com>
M: Zongdong Jiao <zongdong.jiao@amlogic.com>
M: Kaifu Hu <kaifu.hu@amlogic.com>
S: Maintained
F: drivers/amlogic/media/vout/hdmitx/*
F: drivers/amlogic/media/vout/hdmitx/hdcp/*

View File

@@ -305,14 +305,16 @@ int Edid_Parse_check_HDMI_VSDB(struct hdmitx_dev *hdev,
}
set_vsdb_phy_addr(hdev, &info->vsdb_phy_addr, &buff[BlockAddr]);
if ((check_fbc_special(&hdev->EDID_buf[0])) ||
(check_fbc_special(&hdev->EDID_buf1[0])))
rx_edid_physical_addr(0, 0, 0, 0);
else
rx_edid_physical_addr(info->vsdb_phy_addr.a,
info->vsdb_phy_addr.b,
info->vsdb_phy_addr.c,
info->vsdb_phy_addr.d);
if (hdev->repeater_tx) {
if ((check_fbc_special(&hdev->EDID_buf[0])) ||
(check_fbc_special(&hdev->EDID_buf1[0])))
rx_edid_physical_addr(0, 0, 0, 0);
else
rx_edid_physical_addr(info->vsdb_phy_addr.a,
info->vsdb_phy_addr.b,
info->vsdb_phy_addr.c,
info->vsdb_phy_addr.d);
}
if (temp_addr >= VSpecificBoundary)
ret = -1;
@@ -1203,18 +1205,15 @@ static void Edid_Y420CMDB_Reset(struct hdmitx_info *info)
memset(info->y420cmdb_bitmap, 0x00, Y420CMDB_MAX);
}
static char *rptx_edid_aud;
static char rptx_edid_buf[512];
MODULE_PARM_DESC(rptx_edid_aud, "\n receive_edid\n");
module_param(rptx_edid_aud, charp, 0444);
/* ----------------------------------------------------------- */
int Edid_ParsingCEADataBlockCollection(struct hdmitx_dev *hdmitx_device,
unsigned char *buff)
{
unsigned char AddrTag, D, Addr, Data;
int temp_addr, i, len, pos;
int temp_addr;
int len;
struct hdmitx_info *info = &(hdmitx_device->hdmi_info);
struct rx_cap *pRXCap = &hdmitx_device->RXCap;
/* Byte number offset d where Detailed Timing data begins */
D = buff[2];
@@ -1225,22 +1224,29 @@ int Edid_ParsingCEADataBlockCollection(struct hdmitx_dev *hdmitx_device,
Data = buff[AddrTag];
switch (Data&0xE0) {
case VIDEO_TAG:
if ((Addr + (Data&0x1f)) < D)
if ((Addr + (Data&0x1f)) < D) {
Edid_ParsingVideoDATABlock(info, buff,
Addr + 1, (Data & 0x1F));
len = (Data & 0x1f) + 1;
if ((pRXCap->vsd.len + len) > MAX_RAW_LEN)
break;
memcpy(&pRXCap->vsd.raw[pRXCap->vsd.len],
&buff[AddrTag], len);
pRXCap->vsd.len += len;
}
break;
case AUDIO_TAG:
len = (Data & 0x1f) + 1;
if (hdmitx_device->repeater_tx)
rx_set_receiver_edid(&buff[AddrTag], len);
for (pos = 0, i = 0; i < len; i++)
pos += sprintf(rptx_edid_buf+pos, "%02x",
buff[AddrTag + i]);
rptx_edid_buf[pos + 1] = 0;
/* rx_set_receiver_edid(&buff[AddrTag], len); */
if ((Addr + (Data&0x1f)) < D)
Edid_ParsingAudioDATABlock(info, buff,
Addr + 1, (Data & 0x1F));
len = (Data & 0x1f) + 1;
if ((pRXCap->asd.len + len) > MAX_RAW_LEN)
break;
memcpy(&pRXCap->asd.raw[pRXCap->asd.len],
&buff[AddrTag], len);
pRXCap->asd.len += len;
break;
case SPEAKER_TAG:
@@ -1965,10 +1971,12 @@ int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device)
EDID_MAX_BLOCK * 128);
} else
EDID_buf = hdmitx_device->EDID_buf1;
if (check_dvi_hdmi_edid_valid(hdmitx_device->EDID_buf1))
hdmitx_device->edid_parsing = 1;
hdmitx_device->edid_ptr = EDID_buf;
pr_info(EDID "EDID Parser:\n");
memset(rptx_edid_buf, 0, sizeof(rptx_edid_buf));
rptx_edid_aud = &rptx_edid_buf[0];
/* Calculate the EDID hash for special use */
memset(hdmitx_device->EDID_hash, 0,
ARRAY_SIZE(hdmitx_device->EDID_hash));

View File

@@ -27,7 +27,6 @@
* other devices
*/
extern int hdcp_ksv_valid(unsigned char *dat);
extern unsigned int hdcp_get_downstream_ver(void);
#endif

View File

@@ -125,6 +125,7 @@ static void hdmitx_early_suspend(struct early_suspend *h)
|| strncmp(info->name, "null", 4) == 0))
return;
phdmi->ready = 0;
phdmi->hpd_lock = 1;
msleep(20);
phdmi->HWOp.CntlMisc(phdmi, MISC_AVMUTE_OP, SET_AVMUTE);
@@ -184,7 +185,7 @@ static void hdmitx_late_resume(struct early_suspend *h)
/* update status for hpd and switch/state */
hdmitx_device.hpd_state =
!!(hdmitx_device.HWOp.CntlMisc(&hdmitx_device,
!!(hdmitx_device.HWOp.CntlMisc(&hdmitx_device,
MISC_HPD_GPI_ST, 0));
pr_info("hdmitx hpd state: %d\n", hdmitx_device.hpd_state);
@@ -218,6 +219,7 @@ static int hdmitx_reboot_notifier(struct notifier_block *nb,
{
struct hdmitx_dev *hdev = container_of(nb, struct hdmitx_dev, nb);
hdev->ready = 0;
hdev->HWOp.CntlMisc(hdev, MISC_AVMUTE_OP, SET_AVMUTE);
mdelay(100);
hdev->HWOp.CntlMisc(hdev, MISC_TMDS_PHY_OP, TMDS_PHY_DISABLE);
@@ -447,6 +449,7 @@ static int set_disp_mode_auto(void)
hdev, STAT_VIDEO_VIC, 0);
memset(mode, 0, sizeof(mode));
hdev->ready = 0;
/* get current vinfo */
info = hdmitx_get_current_vinfo();
@@ -633,6 +636,83 @@ void setup_attr(const char *buf)
}
EXPORT_SYMBOL(setup_attr);
/* for android application data exchange / swap */
static char *tmp_swap;
static DEFINE_MUTEX(mutex_swap);
static ssize_t store_swap(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
pr_info("store_swap: %s\n", buf);
mutex_lock(&mutex_swap);
kfree(tmp_swap);
tmp_swap = kzalloc(count + 1, GFP_KERNEL);
if (!tmp_swap) {
mutex_unlock(&mutex_swap);
return count;
}
memcpy(tmp_swap, buf, count);
tmp_swap[count] = '\0'; /* padding end string */
mutex_unlock(&mutex_swap);
return count;
}
static ssize_t show_swap(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i = 0;
int n = 0;
struct hdmitx_dev *hdev = &hdmitx_device;
struct rx_cap *pRXCap = &hdev->RXCap;
struct hdcprp14_topo *topo14 = &hdev->topo_info->topo.topo14;
mutex_lock(&mutex_swap);
if (!tmp_swap ||
(!hdev->edid_parsing && !strstr(tmp_swap, "hdcp.topo"))) {
mutex_unlock(&mutex_swap);
return n;
}
/* VSD: Video Short Descriptor */
if (strstr(tmp_swap, "edid.vsd"))
for (i = 0; i < pRXCap->vsd.len; i++)
n += snprintf(buf + n, PAGE_SIZE - n, "%02x",
pRXCap->vsd.raw[i]);
/* ASD: Audio Short Descriptor */
if (strstr(tmp_swap, "edid.asd"))
for (i = 0; i < pRXCap->asd.len; i++)
n += snprintf(buf + n, PAGE_SIZE - n, "%02x",
pRXCap->asd.raw[i]);
/* CEC: Physical Address */
if (strstr(tmp_swap, "edid.cec"))
n += snprintf(buf + n, PAGE_SIZE - n, "%x%x%x%x",
hdev->hdmi_info.vsdb_phy_addr.a,
hdev->hdmi_info.vsdb_phy_addr.b,
hdev->hdmi_info.vsdb_phy_addr.c,
hdev->hdmi_info.vsdb_phy_addr.d);
/* HDCP TOPO */
if (strstr(tmp_swap, "hdcp.topo")) {
char *tmp = (char *)topo14;
pr_info("max_cascade_exceeded %d\n",
topo14->max_cascade_exceeded);
pr_info("depth %d\n", topo14->depth);
pr_info("max_devs_exceeded %d\n", topo14->max_devs_exceeded);
pr_info("device_count %d\n", topo14->device_count);
for (i = 0; i < sizeof(struct hdcprp14_topo); i++)
n += snprintf(buf + n, PAGE_SIZE - n, "%02x", tmp[i]);
}
kfree(tmp_swap);
tmp_swap = NULL;
mutex_unlock(&mutex_swap);
return n;
}
static ssize_t show_aud_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2596,24 +2676,53 @@ static ssize_t store_avmute(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int cmd = OFF_AVMUTE;
static int mask0;
static int mask1;
static DEFINE_MUTEX(avmute_mutex);
if (strncmp(buf, "-1", 2) == 0)
pr_info("store_avmute %s\n", buf);
mutex_lock(&avmute_mutex);
if (strncmp(buf, "-1", 2) == 0) {
cmd = CLR_AVMUTE;
else if (strncmp(buf, "0", 1) == 0)
mask0 = -1;
} else if (strncmp(buf, "0", 1) == 0) {
cmd = OFF_AVMUTE;
else if (strncmp(buf, "1", 1) == 0)
mask0 = 0;
} else if (strncmp(buf, "1", 1) == 0) {
cmd = SET_AVMUTE;
else
pr_info(SYS "set avmute wrong: %s\n", buf);
mask0 = 1;
}
if (strncmp(buf, "r-1", 3) == 0) {
cmd = CLR_AVMUTE;
mask1 = -1;
} else if (strncmp(buf, "r0", 2) == 0) {
cmd = OFF_AVMUTE;
mask1 = 0;
} else if (strncmp(buf, "r1", 2) == 0) {
cmd = SET_AVMUTE;
mask1 = 1;
}
if ((mask0 == 1) || (mask1 == 1))
cmd = SET_AVMUTE;
else if ((mask0 == -1) && (mask1 == -1))
cmd = CLR_AVMUTE;
hdmitx_device.HWOp.CntlMisc(&hdmitx_device, MISC_AVMUTE_OP, cmd);
mutex_unlock(&avmute_mutex);
return count;
}
static ssize_t show_avmute(struct device *dev,
struct device_attribute *attr, char *buf)
{
return 0;
struct hdmitx_dev *hdev = &hdmitx_device;
int ret = 0;
int pos = 0;
ret = hdev->HWOp.CntlMisc(hdev, MISC_READ_AVMUTE_OP, 0);
pos += snprintf(buf + pos, PAGE_SIZE, "%d", ret);
return pos;
}
/*
@@ -2819,6 +2928,13 @@ static ssize_t show_hdcp_lstore(struct device *dev,
{
int pos = 0;
/* if current TX is RP-TX, then return lstore as 00 */
/* hdcp_lstore is used under only TX */
if (hdmitx_device.repeater_tx == 1) {
pos += snprintf(buf + pos, PAGE_SIZE, "00\n");
return pos;
}
if (hdmitx_device.lstore < 0x10) {
hdmitx_device.lstore = 0;
if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
@@ -2853,6 +2969,53 @@ static ssize_t store_hdcp_lstore(struct device *dev,
return count;
}
static int rptxlstore;
static ssize_t show_hdcp_rptxlstore(struct device *dev,
struct device_attribute *attr, char *buf)
{
int pos = 0;
/* if current TX is not RP-TX, then return rptxlstore as 00 */
/* hdcp_rptxlstore is used under only RP-TX */
if (hdmitx_device.repeater_tx == 0) {
pos += snprintf(buf + pos, PAGE_SIZE, "00\n");
return pos;
}
if (rptxlstore < 0x10) {
rptxlstore = 0;
if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
DDC_HDCP_14_LSTORE, 0))
rptxlstore += 1;
if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
DDC_HDCP_22_LSTORE, 0))
rptxlstore += 2;
}
if (rptxlstore & 0x1)
pos += snprintf(buf + pos, PAGE_SIZE, "14\n");
if (rptxlstore & 0x2)
pos += snprintf(buf + pos, PAGE_SIZE, "22\n");
if ((rptxlstore & 0xf) == 0)
pos += snprintf(buf + pos, PAGE_SIZE, "00\n");
return pos;
}
static ssize_t store_hdcp_rptxlstore(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
pr_info("hdcp: set lstore as %s\n", buf);
if (strncmp(buf, "0", 1) == 0)
rptxlstore = 0x10;
if (strncmp(buf, "11", 2) == 0)
rptxlstore = 0x11;
if (strncmp(buf, "12", 2) == 0)
rptxlstore = 0x12;
if (strncmp(buf, "13", 2) == 0)
rptxlstore = 0x13;
return count;
}
static ssize_t show_div40(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2931,39 +3094,119 @@ static ssize_t store_hdcp_mode(struct device *dev,
return count;
}
void direct_hdcptx14_start(void)
static bool hdcp_sticky_mode;
static ssize_t show_hdcp_stickmode(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("%s[%d]", __func__, __LINE__);
hdmitx_device.hdcp_mode = 1;
hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
DDC_HDCP_OP, HDCP14_ON);
}
EXPORT_SYMBOL(direct_hdcptx14_start);
int pos = 0;
void direct_hdcptx14_stop(void)
{
pr_info("%s[%d]", __func__, __LINE__);
hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
DDC_HDCP_OP, HDCP14_OFF);
pos += snprintf(buf+pos, PAGE_SIZE, "%d\n", hdcp_sticky_mode);
return pos;
}
EXPORT_SYMBOL(direct_hdcptx14_stop);
static ssize_t store_hdcp_stickmode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
if (buf[0] == '0')
hdcp_sticky_mode = 0;
if (buf[0] == '1')
hdcp_sticky_mode = 1;
return count;
}
static unsigned char hdcp_sticky_step;
static ssize_t show_hdcp_stickstep(struct device *dev,
struct device_attribute *attr, char *buf)
{
int pos = 0;
pos += snprintf(buf+pos, PAGE_SIZE, "%x\n", hdcp_sticky_step);
if (hdcp_sticky_step)
hdcp_sticky_step = 0;
return pos;
}
static ssize_t store_hdcp_stickstep(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
if (isdigit(buf[0]))
hdcp_sticky_step = buf[0] - '0';
return count;
}
/* Indicate whether a rptx under repeater */
static ssize_t show_repeater_tx(struct device *dev,
struct device_attribute *attr, char *buf)
{
int pos = 0;
pos += snprintf(buf+pos, PAGE_SIZE, "%d\n",
!!hdmitx_device.repeater_tx);
return pos;
}
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h>
void direct_hdcptx14_opr(enum rptx_hdcp14_cmd cmd, void *args)
{
int rst;
struct hdmitx_dev *hdev = &hdmitx_device;
pr_info("%s[%d] cmd: %d\n", __func__, __LINE__, cmd);
switch (cmd) {
case RPTX_HDCP14_OFF:
hdev->hdcp_mode = 0;
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
break;
case RPTX_HDCP14_ON:
hdev->hdcp_mode = 1;
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_ON);
break;
case RPTX_HDCP14_GET_AUTHST:
rst = hdev->HWOp.CntlDDC(hdev, DDC_HDCP_GET_AUTH, 0);
*(int *)args = rst;
break;
}
}
EXPORT_SYMBOL(direct_hdcptx14_opr);
static ssize_t store_hdcp_ctrl(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
if (hdmitx_device.HWOp.CntlDDC(&hdmitx_device, DDC_HDCP_14_LSTORE,
0) == 0)
struct hdmitx_dev *hdev = &hdmitx_device;
if (hdev->HWOp.CntlDDC(hdev, DDC_HDCP_14_LSTORE, 0) == 0)
return count;
dev_warn(dev, "hdmitx20: %s\n", buf);
/* for repeater */
if (hdev->repeater_tx) {
dev_warn(dev, "hdmitx20: %s\n", buf);
if (strncmp(buf, "rstop", 5) == 0) {
if (strncmp(buf+5, "14", 2) == 0)
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP,
HDCP14_OFF);
if (strncmp(buf+5, "22", 2) == 0)
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP,
HDCP22_OFF);
hdev->hdcp_mode = 0;
hdmitx_hdcp_do_work(hdev);
}
return count;
}
/* for non repeater */
if (strncmp(buf, "stop", 4) == 0) {
dev_warn(dev, "hdmitx20: %s\n", buf);
if (strncmp(buf+4, "14", 2) == 0)
hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
DDC_HDCP_OP, HDCP14_OFF);
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
if (strncmp(buf+4, "22", 2) == 0)
hdmitx_device.HWOp.CntlDDC(&hdmitx_device,
DDC_HDCP_OP, HDCP22_OFF);
hdmitx_device.hdcp_mode = 0;
hdmitx_hdcp_do_work(&hdmitx_device);
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP22_OFF);
hdev->hdcp_mode = 0;
hdmitx_hdcp_do_work(hdev);
}
return count;
@@ -3047,6 +3290,26 @@ static ssize_t show_hpd_state(struct device *dev,
return pos;
}
static ssize_t show_rhpd_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hdmitx_dev *hdev = &hdmitx_device;
int st;
st = hdev->HWOp.CntlMisc(hdev, MISC_HPD_GPI_ST, 0);
return snprintf(buf, PAGE_SIZE, "%d", hdev->rhpd_state);
}
static ssize_t show_max_exceed_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hdmitx_dev *hdev = &hdmitx_device;
return snprintf(buf, PAGE_SIZE, "%d", hdev->hdcp_max_exceed_state);
}
static ssize_t show_hdmi_init(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3105,6 +3368,7 @@ static DEVICE_ATTR(dc_cap, 0444, show_dc_cap, NULL);
static DEVICE_ATTR(valid_mode, 0664, show_valid_mode, store_valid_mode);
static DEVICE_ATTR(aud_ch, 0664, show_aud_ch, store_aud_ch);
static DEVICE_ATTR(avmute, 0664, show_avmute, store_avmute);
static DEVICE_ATTR(swap, 0644, show_swap, store_swap);
static DEVICE_ATTR(vic, 0664, show_vic, store_vic);
static DEVICE_ATTR(phy, 0664, show_phy, store_phy);
static DEVICE_ATTR(sspll, 0664, show_sspll, store_sspll);
@@ -3116,11 +3380,18 @@ static DEVICE_ATTR(hdcp_pwr, 0664, show_hdcp_pwr, store_hdcp_pwr);
static DEVICE_ATTR(hdcp_byp, 0200, NULL, store_hdcp_byp);
static DEVICE_ATTR(hdcp_mode, 0664, show_hdcp_mode, store_hdcp_mode);
static DEVICE_ATTR(hdcp_lstore, 0664, show_hdcp_lstore, store_hdcp_lstore);
static DEVICE_ATTR(hdcp_rptxlstore, 0664, show_hdcp_rptxlstore,
store_hdcp_rptxlstore);
static DEVICE_ATTR(hdcp_repeater, 0644, show_hdcp_repeater,
store_hdcp_repeater);
static DEVICE_ATTR(hdcp_topo_info, 0644, show_hdcp_topo_info,
store_hdcp_topo_info);
static DEVICE_ATTR(hdcp22_type, 0644, show_hdcp22_type, store_hdcp22_type);
static DEVICE_ATTR(hdcp_stickmode, 0664, show_hdcp_stickmode,
store_hdcp_stickmode);
static DEVICE_ATTR(hdcp_stickstep, 0664, show_hdcp_stickstep,
store_hdcp_stickstep);
static DEVICE_ATTR(hdmi_repeater_tx, 0444, show_repeater_tx, NULL);
static DEVICE_ATTR(hdcp22_base, 0444, show_hdcp22_base, NULL);
static DEVICE_ATTR(div40, 0664, show_div40, store_div40);
static DEVICE_ATTR(hdcp_ctrl, 0664, show_hdcp_ctrl, store_hdcp_ctrl);
@@ -3128,6 +3399,8 @@ static DEVICE_ATTR(disp_cap_3d, 0444, show_disp_cap_3d, NULL);
static DEVICE_ATTR(hdcp_ksv_info, 0444, show_hdcp_ksv_info, NULL);
static DEVICE_ATTR(hdcp_ver, 0444, show_hdcp_ver, NULL);
static DEVICE_ATTR(hpd_state, 0444, show_hpd_state, NULL);
static DEVICE_ATTR(rhpd_state, 0444, show_rhpd_state, NULL);
static DEVICE_ATTR(max_exceed, 0444, show_max_exceed_state, NULL);
static DEVICE_ATTR(hdmi_init, 0444, show_hdmi_init, NULL);
static DEVICE_ATTR(ready, 0664, show_ready, store_ready);
static DEVICE_ATTR(support_3d, 0444, show_support_3d, NULL);
@@ -3451,9 +3724,11 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
}
mutex_lock(&setclk_mutex);
pr_info(SYS "plugin\n");
hdev->HWOp.CntlMisc(hdev, MISC_I2C_REACTIVE, 0);
hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGIN;
/* start reading E-EDID */
rx_repeat_hpd_state(1);
if (hdev->repeater_tx)
rx_repeat_hpd_state(1);
hdmitx_get_edid(hdev);
hdmi_physcial_size_update(hdev);
@@ -3478,7 +3753,6 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
}
mutex_lock(&getedid_mutex);
hdev->HWOp.CntlMisc(hdev, MISC_I2C_REACTIVE, 0);
mutex_unlock(&getedid_mutex);
if (hdev->repeater_tx) {
if (check_fbc_special(&hdev->EDID_buf[0])
@@ -3486,7 +3760,6 @@ static void hdmitx_hpd_plugin_handler(struct work_struct *work)
rx_set_repeater_support(0);
else
rx_set_repeater_support(1);
rx_repeat_hdcp_ver(hdcp_get_downstream_ver());
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_GET_BKSV,
(unsigned long int)bksv_buf);
rx_set_receive_hdcp(bksv_buf, 1, 1, 0, 0);
@@ -3539,7 +3812,8 @@ static void hdmitx_hpd_plugout_handler(struct work_struct *work)
return;
hdev->hdcp_mode = 0;
hdev->hdcp_bcaps_repeater = 0;
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_MUX_INIT, 1);
hdev->HWOp.CntlDDC(hdev, DDC_HDCP_OP, HDCP14_OFF);
mutex_lock(&setclk_mutex);
pr_info(SYS "plugout\n");
if (!!(hdev->HWOp.CntlMisc(hdev, MISC_HPD_GPI_ST, 0))) {
@@ -4011,6 +4285,14 @@ static int amhdmitx_get_dt_info(struct platform_device *pdev)
pr_info(SYS "hdmitx_device.chip_type : %d\n",
hdmitx_device.chip_type);
ret = of_property_read_u32(pdev->dev.of_node,
"repeater_tx", &val);
if (!ret)
hdmitx_device.repeater_tx = val;
if (hdmitx_device.repeater_tx == 1)
hdmitx_device.topo_info = kzalloc(
sizeof(*hdmitx_device.topo_info), GFP_KERNEL);
/* Get vendor information */
ret = of_property_read_u32(pdev->dev.of_node,
"vend-data", &val);
@@ -4202,6 +4484,7 @@ static int amhdmitx_probe(struct platform_device *pdev)
ret = device_create_file(dev, &dev_attr_dv_cap);
ret = device_create_file(dev, &dev_attr_aud_ch);
ret = device_create_file(dev, &dev_attr_avmute);
ret = device_create_file(dev, &dev_attr_swap);
ret = device_create_file(dev, &dev_attr_vic);
ret = device_create_file(dev, &dev_attr_phy);
ret = device_create_file(dev, &dev_attr_frac_rate_policy);
@@ -4216,11 +4499,17 @@ static int amhdmitx_probe(struct platform_device *pdev)
ret = device_create_file(dev, &dev_attr_hdcp_repeater);
ret = device_create_file(dev, &dev_attr_hdcp_topo_info);
ret = device_create_file(dev, &dev_attr_hdcp22_type);
ret = device_create_file(dev, &dev_attr_hdcp_stickmode);
ret = device_create_file(dev, &dev_attr_hdcp_stickstep);
ret = device_create_file(dev, &dev_attr_hdmi_repeater_tx);
ret = device_create_file(dev, &dev_attr_hdcp22_base);
ret = device_create_file(dev, &dev_attr_hdcp_lstore);
ret = device_create_file(dev, &dev_attr_hdcp_rptxlstore);
ret = device_create_file(dev, &dev_attr_div40);
ret = device_create_file(dev, &dev_attr_hdcp_ctrl);
ret = device_create_file(dev, &dev_attr_hpd_state);
ret = device_create_file(dev, &dev_attr_rhpd_state);
ret = device_create_file(dev, &dev_attr_max_exceed);
ret = device_create_file(dev, &dev_attr_hdmi_init);
ret = device_create_file(dev, &dev_attr_ready);
ret = device_create_file(dev, &dev_attr_support_3d);
@@ -4296,6 +4585,8 @@ static int amhdmitx_remove(struct platform_device *pdev)
device_remove_file(dev, &dev_attr_dc_cap);
device_remove_file(dev, &dev_attr_valid_mode);
device_remove_file(dev, &dev_attr_hpd_state);
device_remove_file(dev, &dev_attr_rhpd_state);
device_remove_file(dev, &dev_attr_max_exceed);
device_remove_file(dev, &dev_attr_hdmi_init);
device_remove_file(dev, &dev_attr_ready);
device_remove_file(dev, &dev_attr_support_3d);
@@ -4309,7 +4600,11 @@ static int amhdmitx_remove(struct platform_device *pdev)
device_remove_file(dev, &dev_attr_hdcp_repeater);
device_remove_file(dev, &dev_attr_hdcp_topo_info);
device_remove_file(dev, &dev_attr_hdcp22_type);
device_remove_file(dev, &dev_attr_hdcp_stickmode);
device_remove_file(dev, &dev_attr_hdcp_stickstep);
device_remove_file(dev, &dev_attr_hdmi_repeater_tx);
device_remove_file(dev, &dev_attr_hdcp22_base);
device_remove_file(dev, &dev_attr_swap);
cdev_del(&hdmitx_device.cdev);

View File

@@ -59,6 +59,14 @@ static void hdmitx_csc_config(unsigned char input_color_format,
static int hdmitx_hdmi_dvi_config(struct hdmitx_dev *hdev,
unsigned int dvi_mode);
static void hdmitx_set_avi_colorimetry(struct hdmi_format_para *para);
struct ksv_lists_ {
unsigned char valid;
unsigned int no;
unsigned char lists[MAX_KSV_LISTS * 5];
};
static struct ksv_lists_ tmp_ksv_lists;
static void hdmitx_set_packet(int type, unsigned char *DB, unsigned char *HB);
static void hdmitx_setaudioinfoframe(unsigned char *AUD_DB,
unsigned char *CHAN_STAT_BUF);
@@ -269,6 +277,31 @@ static void config_avmute(unsigned int val)
}
}
static int read_avmute(void)
{
int val;
int ret = 0;
val = hdmitx_rd_reg(HDMITX_DWC_FC_GCP) & 0x3;
switch (val) {
case 2:
ret = 1;
break;
case 1:
ret = -1;
break;
case 0:
ret = 0;
break;
default:
ret = 3;
break;
}
return ret;
}
static void config_video_mapping(enum hdmi_color_space cs,
enum hdmi_color_depth cd)
{
@@ -463,6 +496,8 @@ static void hdmi_hwp_init(struct hdmitx_dev *hdev)
/* assign phy_clk_en = control[1]; */
/* Bring HDMITX MEM output of power down */
hd_set_reg_bits(P_HHI_MEM_PD_REG0, 0, 8, 8);
/* enable CLK_TO_DIG */
hd_set_reg_bits(P_HHI_HDMI_PHY_CNTL3, 0x3, 0, 2);
if (hdmitx_uboot_already_display()) {
hdev->ready = 1;
/* Get uboot output color space from AVI */
@@ -580,6 +615,10 @@ static void hdmi_hwi_init(struct hdmitx_dev *hdev)
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0xcf);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_1, 0);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_0, 0xff);
if (hdev->repeater_tx == 1) {
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0x67);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_LCNT_0, 0x78);
}
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_HCNT_1, 0);
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_HCNT_0, 0x0f);
hdmitx_wr_reg(HDMITX_DWC_I2CM_FS_SCL_LCNT_1, 0);
@@ -612,60 +651,63 @@ void HDMITX_Meson_Init(struct hdmitx_dev *hdev)
hdmi_hwp_init(hdev);
hdmi_hwi_init(hdev);
hdev->HWOp.CntlMisc(hdev, MISC_AVMUTE_OP, CLR_AVMUTE);
rptx_ksvs = &rptx_ksv_prbuf[0];
}
static irqreturn_t intr_handler(int irq, void *dev)
{
unsigned int data32 = 0;
/* get interrupt status */
unsigned int dat_top = hdmitx_rd_reg(HDMITX_TOP_INTR_STAT);
unsigned int dat_dwc = hdmitx_rd_reg(HDMITX_DWC_HDCP22REG_STAT);
struct hdmitx_dev *hdev = (struct hdmitx_dev *)dev;
/* get interrupt status */
data32 = hdmitx_rd_reg(HDMITX_TOP_INTR_STAT);
pr_info(HW "irq %x\n", data32);
/* ack INTERNAL_INTR or else we stuck with no interrupts at all */
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, ~0);
hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_STAT, 0xff);
pr_info(SYS "irq %x\n", dat_top);
if (dat_dwc)
pr_info(SYS "irq %x\n", dat_dwc);
if (hdev->hpd_lock == 1) {
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, 0xf);
pr_info(HW "HDMI hpd locked\n");
goto next;
}
/* check HPD status */
if ((data32 & (1 << 1)) && (data32 & (1 << 2))) {
if ((dat_top & (1 << 1)) && (dat_top & (1 << 2))) {
if (hdmitx_hpd_hw_op(HPD_READ_HPD_GPIO))
data32 &= ~(1 << 2);
dat_top &= ~(1 << 2);
else
data32 &= ~(1 << 1);
dat_top &= ~(1 << 1);
}
/* HPD rising */
if (data32 & (1 << 1)) {
if (dat_top & (1 << 1)) {
hdev->hdmitx_event |= HDMI_TX_HPD_PLUGIN;
hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGOUT;
hdev->rhpd_state = 1;
queue_delayed_work(hdev->hdmi_wq,
&hdev->work_hpd_plugin, HZ / 2);
}
/* HPD falling */
if (data32 & (1 << 2)) {
if (dat_top & (1 << 2)) {
queue_delayed_work(hdev->hdmi_wq,
&hdev->work_aud_hpd_plug, 2 * HZ);
hdev->hdmitx_event |= HDMI_TX_HPD_PLUGOUT;
hdev->hdmitx_event &= ~HDMI_TX_HPD_PLUGIN;
hdev->rhpd_state = 0;
queue_delayed_work(hdev->hdmi_wq,
&hdev->work_hpd_plugout, HZ / 20);
}
next:
/* internal interrupt */
if (data32 & (1 << 0)) {
if (dat_top & (1 << 0)) {
hdev->hdmitx_event |= HDMI_TX_INTERNAL_INTR;
queue_work(hdev->hdmi_wq, &hdev->work_internal_intr);
}
if (data32 & (1 << 3)) {
if (dat_top & (1 << 3)) {
unsigned int rd_nonce_mode =
hdmitx_rd_reg(HDMITX_TOP_SKP_CNTL_STAT) & 0x1;
pr_info(HW "hdcp22: Nonce %s Vld: %d\n",
rd_nonce_mode ? "HW" : "SW",
((hdmitx_rd_reg(HDMITX_TOP_SKP_CNTL_STAT) >> 31) & 1));
if (rd_nonce_mode)
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, (1 << 3));
else {
if (!rd_nonce_mode) {
hdmitx_wr_reg(HDMITX_TOP_NONCE_0, 0x32107654);
hdmitx_wr_reg(HDMITX_TOP_NONCE_1, 0xba98fedc);
hdmitx_wr_reg(HDMITX_TOP_NONCE_2, 0xcdef89ab);
@@ -676,13 +718,10 @@ next:
hdmitx_wr_reg(HDMITX_TOP_NONCE_3, 0x01234567);
}
}
if (data32 & (1 << 30)) {
pr_info(HW "hdcp22: reg stat: 0x%x\n",
hdmitx_rd_reg(HDMITX_DWC_HDCP22REG_STAT));
hdmitx_wr_reg(HDMITX_DWC_HDCP22REG_STAT, 0xff);
}
/* ack INTERNAL_INTR or else we stuck with no interrupts at all */
hdmitx_wr_reg(HDMITX_TOP_INTR_STAT_CLR, data32 | 0x7);
if (dat_top & (1 << 30))
pr_info("hdcp22: reg stat: 0x%x\n", dat_dwc);
next:
return IRQ_HANDLED;
}
@@ -2628,8 +2667,14 @@ static void set_aud_samp_pkt(struct hdmitx_dev *hdev,
}
}
static int amute_flag = -1;
static void audio_mute_op(bool flag)
{
if (amute_flag != flag)
amute_flag = flag;
else
return;
if (flag == 0) {
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 0, 2, 2);
hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 0, 0, 1);
@@ -4403,8 +4448,6 @@ static void hdmitx_read_edid(unsigned char *rx_edid)
}
} /* hdmi20_tx_read_edid */
#define HDCP_NMOOFDEVICES 127
static int get_hdcp_depth(void)
{
int ret;
@@ -4453,68 +4496,54 @@ static int get_hdcp_device_count(void)
return ret;
}
static void get_hdcp_bstatus(void)
static void get_hdcp_bstatus(int *ret1, int *ret2)
{
int ret1 = 0;
int ret2 = 0;
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 0, 1);
hdmitx_poll_reg(HDMITX_DWC_A_KSVMEMCTRL, (1<<1), 2 * HZ);
ret1 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
ret2 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
*ret1 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0);
*ret2 = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
pr_info("BSTATUS0 = 0x%x BSTATUS1 = 0x%x\n", ret1, ret2);
}
static void hdcp_ksv_store(unsigned char *dat, int no)
static void hdcp_ksv_store(struct hdcprp_topo *topo,
unsigned char *dat, int no)
{
int i;
int pos;
for (i = 0; i < no; i++) {
rptx_ksv_buf[rptx_ksv_no] = dat[i];
rptx_ksv_no++;
}
}
static void hdcp_ksv_print(void)
{
unsigned int i, pos;
unsigned char *tmp_buf = NULL;
tmp_buf = kmalloc(2000, GFP_ATOMIC);
if (!tmp_buf)
if (!topo)
return;
if (topo->hdcp_ver != 1)
return;
/* must check ksv num to prevent leak */
if (topo->topo.topo14.device_count >= MAX_KSV_LISTS)
return;
pos = 0;
memset(tmp_buf, 0, sizeof(2000));
pos += sprintf(tmp_buf + pos, "Dump ksv test START\n");
for (i = 0; (i < rptx_ksv_no) && (i < 635); i++) {
pos += sprintf(tmp_buf + pos, "%02x", rptx_ksv_buf[i]);
if (((i+1) % 40) == 0) /* print 40bytes a line */
pos += sprintf(tmp_buf + pos, "\n");
}
pos += sprintf(tmp_buf + pos, "\n");
pos += sprintf(tmp_buf + pos, "Dump ksv test END\n");
pr_info("%s\n", tmp_buf);
kfree(tmp_buf);
pos = topo->topo.topo14.device_count * 5;
for (i = 0; (i < no) && (i < MAX_KSV_LISTS * 5); i++)
topo->topo.topo14.ksv_list[pos++] = dat[i];
topo->topo.topo14.device_count += no / 5;
}
static uint8_t *hdcp_mKsvListBuf;
static int ksv_sha_matched;
static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
{
size_t list = 0;
size_t size = 0;
size_t i = 0;
int valid = HDCP_NULL;
unsigned char ksvs[635] = {0}; /* Max 127 * 5 */
char temp[MAX_KSV_LISTS * 5];
int j = 0;
/* 0x165e: Page 95 */
memset(&tmp_ksv_lists, 0, sizeof(tmp_ksv_lists));
memset(&temp[0], 0, sizeof(temp));
hdcp_mKsvListBuf = kmalloc(0x1660, GFP_ATOMIC);
if (hdcp_mKsvListBuf) {
/* KSV_SIZE; */
list = hdmitx_rd_reg(HDMITX_DWC_HDCP_BSTATUS_0) & KSV_MASK;
if (list <= HDCP_NMOOFDEVICES) {
if (list <= MAX_KSV_LISTS) {
size = (list * KSV_SIZE) + HDCP_HEAD + SHA_MAX_SIZE;
for (i = 0; i < size; i++) {
if (i < HDCP_HEAD) { /* BSTATUS & M0 */
@@ -4527,9 +4556,11 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
hdcp_mKsvListBuf[i - HDCP_HEAD] =
hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
ksvs[j] =
tmp_ksv_lists.lists[tmp_ksv_lists.no++]
= hdcp_mKsvListBuf[i -
HDCP_HEAD];
temp[j++] =
hdcp_mKsvListBuf[i - HDCP_HEAD];
j++;
} else { /* SHA */
hdcp_mKsvListBuf[i] = hdmitx_rd_reg(
HDMITX_DWC_HDCP_BSTATUS_0 + i);
@@ -4539,12 +4570,18 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
valid = HDCP_KSVLIST_VALID;
else
valid = HDCP_KSVLIST_INVALID;
ksv_sha_matched = valid;
}
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL,
(valid == HDCP_KSVLIST_VALID) ? 0 : 1, 3, 1);
if (valid == HDCP_KSVLIST_VALID)
hdcp_ksv_store(ksvs, j);
if (valid == HDCP_KSVLIST_VALID) {
tmp_ksv_lists.valid = 1;
for (i = 0; (i < j) &&
(tmp_ksv_lists.no < MAX_KSV_LISTS * 5); i++)
tmp_ksv_lists.lists[tmp_ksv_lists.no++]
= temp[i];
}
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 1, 2, 1);
hdmitx_set_reg_bits(HDMITX_DWC_A_KSVMEMCTRL, 0, 2, 1);
kfree(hdcp_mKsvListBuf);
@@ -4552,15 +4589,50 @@ static void hdcp_ksv_sha1_calc(struct hdmitx_dev *hdev)
pr_info("hdcptx14: KSV List memory not valid\n");
}
static int max_exceed = 200;
MODULE_PARM_DESC(max_exceed, "\nmax_exceed\n");
module_param(max_exceed, int, 0664);
static void hdcptx_events_handle(unsigned long arg)
{
struct hdmitx_dev *hdev = (struct hdmitx_dev *)arg;
unsigned char ksv[5] = {0};
int pos, i;
int i;
unsigned int bcaps_6_rp;
static unsigned int bcaps_5_ksvfifoready;
static unsigned int st_flag = -1;
static unsigned int hdcpobs3_1;
unsigned int hdcpobs3_2;
struct hdcprp14_topo *topo14 = &hdev->topo_info->topo.topo14;
int bstatus0 = 0;
int bstatus1 = 0;
if (hdev->hdcp_max_exceed_cnt == 0) {
hdcpobs3_1 = 0;
bcaps_5_ksvfifoready = 0;
}
hdcpobs3_2 = hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3);
if (hdcpobs3_1 != hdcpobs3_2)
hdcpobs3_1 = hdcpobs3_2;
bcaps_6_rp = !!(hdcpobs3_1 & (1 << 6));
bcaps_5_ksvfifoready = !!(hdcpobs3_1 & (1 << 5));
if (bcaps_6_rp && bcaps_5_ksvfifoready
&& (hdev->hdcp_max_exceed_cnt == 0))
hdev->hdcp_max_exceed_cnt++;
if (hdev->hdcp_max_exceed_cnt)
hdev->hdcp_max_exceed_cnt++;
if (bcaps_6_rp && bcaps_5_ksvfifoready) {
if ((hdev->hdcp_max_exceed_cnt > max_exceed)
&& !ksv_sha_matched) {
topo14->max_devs_exceeded = 1;
topo14->max_cascade_exceeded = 1;
hdev->hdcp_max_exceed_state = 1;
}
}
bcaps_6_rp = !!(hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS3) & (1 << 6));
if (st_flag != hdmitx_rd_reg(HDMITX_DWC_A_APIINTSTAT)) {
st_flag = hdmitx_rd_reg(HDMITX_DWC_A_APIINTSTAT);
pr_info("hdcp14: instat: 0x%x\n", st_flag);
@@ -4568,27 +4640,43 @@ static void hdcptx_events_handle(unsigned long arg)
if (st_flag & (1 << 7)) {
hdmitx_wr_reg(HDMITX_DWC_A_APIINTCLR, 1 << 7);
hdmitx_hdcp_opr(3);
if (bcaps_6_rp)
get_hdcp_bstatus(&bstatus0, &bstatus1);
for (i = 0; i < 5; i++)
ksv[i] = (unsigned char)
hdmitx_rd_reg(HDMITX_DWC_HDCPREG_BKSV0 + i);
hdcp_ksv_store(ksv, 5);
get_hdcp_bstatus();
if (hdev->repeater_tx) {
rx_set_receive_hdcp(rptx_ksv_buf, (rptx_ksv_no + 1) / 5,
(bcaps_6_rp ? get_hdcp_depth() : 0) + 1,
bcaps_6_rp ? get_hdcp_max_cascade() : 0,
bcaps_6_rp ? get_hdcp_max_devs() : 0);
pr_info("%s[%d] ksvs Num = %d device_count = %d\n",
__func__, __LINE__,
(rptx_ksv_no + 1) / 5,
bcaps_6_rp ? get_hdcp_device_count() : 0);
memset(rptx_ksv_prbuf, 0, sizeof(rptx_ksv_prbuf));
for (pos = 0, i = 0; i < rptx_ksv_no; i++)
pos += sprintf(rptx_ksv_prbuf + pos,
"%02x", rptx_ksv_buf[i]);
rptx_ksv_prbuf[pos + 1] = '\0';
if (1)
hdcp_ksv_print();
/* if downstream is only RX */
if ((hdev->repeater_tx == 1) && hdev->topo_info) {
hdcp_ksv_store(hdev->topo_info, ksv, 5);
if (tmp_ksv_lists.valid) {
int cnt = get_hdcp_device_count();
int devs = get_hdcp_max_devs();
int cascade = get_hdcp_max_cascade();
int depth = get_hdcp_depth();
hdcp_ksv_store(hdev->topo_info,
tmp_ksv_lists.lists, tmp_ksv_lists.no);
if (cnt >= 127) {
topo14->device_count = 127;
topo14->max_devs_exceeded = 1;
} else {
topo14->device_count = cnt + 1;
topo14->max_devs_exceeded = devs;
}
if (depth >= 7) {
topo14->depth = 7;
topo14->max_cascade_exceeded = 1;
} else {
topo14->depth = depth + 1;
topo14->max_cascade_exceeded = cascade;
}
} else {
topo14->device_count = 1;
topo14->max_devs_exceeded = 0;
topo14->max_cascade_exceeded = 0;
topo14->depth = 1;
}
}
}
if (st_flag & (1 << 1)) {
@@ -4602,30 +4690,8 @@ static void hdcptx_events_handle(unsigned long arg)
return;
}
hdmitx_wr_reg(HDMITX_DWC_A_KSVMEMCTRL, 0x4);
if (hdev->repeater_tx) {
rptx_ksvlist_retry++;
if (rptx_ksvlist_retry % 4 == 0) {
for (i = 0; i < 5; i++)
ksv[i] = (unsigned char) hdmitx_rd_reg(
HDMITX_DWC_HDCPREG_BKSV0 + i);
hdcp_ksv_store(ksv, 5);
rx_set_receive_hdcp(&ksv[0], 1, 127, 1, 1);
}
}
}
if (hdev->repeater_tx && bcaps_6_rp && (get_hdcp_max_devs() ||
get_hdcp_max_cascade())) {
for (i = 0; i < 5; i++)
ksv[i] = (unsigned char)
hdmitx_rd_reg(HDMITX_DWC_HDCPREG_BKSV0 + i);
hdcp_ksv_store(ksv, 5);
rx_set_receive_hdcp(&ksv[0], 1, 127, 1, 1);
}
if (hdev->hdcp_try_times)
mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
else
return;
hdev->hdcp_try_times--;
mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
}
static void hdcp_start_timer(struct hdmitx_dev *hdev)
@@ -4639,10 +4705,8 @@ static void hdcp_start_timer(struct hdmitx_dev *hdev)
hdev->hdcp_timer.function = hdcptx_events_handle;
hdev->hdcp_timer.expires = jiffies + HZ / 100;
add_timer(&hdev->hdcp_timer);
hdev->hdcp_try_times = 500;
return;
}
hdev->hdcp_try_times = 500;
hdev->hdcp_timer.expires = jiffies + HZ / 100;
mod_timer(&hdev->hdcp_timer, jiffies + HZ / 100);
}
@@ -4672,6 +4736,20 @@ static void set_pkf_duk_nonce(void)
udelay(10);
}
static void check_read_ksv_list_st(void)
{
int cnt = 0;
for (cnt = 0; cnt < 5; cnt++) {
if (((hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS1) & 0x7) == 5) ||
((hdmitx_rd_reg(HDMITX_DWC_A_HDCPOBS1) & 0x7) == 6))
msleep(20);
else
return;
}
pr_info("hdcp14: FSM: A9 read ksv list\n");
}
static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned long argv)
{
@@ -4731,22 +4809,33 @@ static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
}
if (argv == 1)
hdmitx_hdcp_opr(6);
if (argv == 3)
hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 1, 2, 1);
break;
case DDC_HDCP_OP:
hdev->hdcp_max_exceed_state = 0;
hdev->hdcp_max_exceed_cnt = 0;
ksv_sha_matched = 0;
del_timer(&hdev->hdcp_timer);
if (hdev->topo_info)
memset(hdev->topo_info, 0, sizeof(*hdev->topo_info));
if (argv == HDCP14_ON) {
rptx_ksvlist_retry = 0;
rptx_ksv_no = 0;
memset(rptx_ksv_buf, 0, sizeof(rptx_ksv_buf));
check_read_ksv_list_st();
if (hdev->topo_info)
hdev->topo_info->hdcp_ver = HDCPVER_14;
hdmitx_ddc_hw_op(DDC_MUX_DDC);
hdmitx_set_reg_bits(HDMITX_TOP_SKP_CNTL_STAT, 0, 3, 1);
hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 1, 31, 1);
hdmitx_hdcp_opr(6);
hdmitx_hdcp_opr(1);
hdcp_start_timer(hdev);
}
if (argv == HDCP14_OFF) {
rptx_ksvlist_retry = 0;
if (argv == HDCP14_OFF)
hdmitx_hdcp_opr(4);
}
if (argv == HDCP22_ON) {
if (hdev->topo_info)
hdev->topo_info->hdcp_ver = 2;
hdmitx_ddc_hw_op(DDC_MUX_DDC);
hdmitx_hdcp_opr(5);
/* wait for start hdcp22app */
@@ -4754,6 +4843,9 @@ static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, unsigned int cmd,
if (argv == HDCP22_OFF)
hdmitx_hdcp_opr(6);
break;
case DDC_IS_HDCP_ON:
/* argv = !!((hdmitx_rd_reg(TX_HDCP_MODE)) & (1 << 7)); */
break;
case DDC_HDCP_GET_BKSV:
tmp_char = (unsigned char *) argv;
for (i = 0; i < 5; i++)
@@ -4962,6 +5054,8 @@ static int hdmitx_tmds_rxsense(void)
static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
unsigned int argv)
{
static int st;
if ((cmd & CMD_MISC_OFFSET) != CMD_MISC_OFFSET) {
pr_err(HW "misc: w: invalid cmd 0x%x\n", cmd);
return -1;
@@ -5002,16 +5096,24 @@ static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, unsigned int cmd,
case MISC_AVMUTE_OP:
config_avmute(argv);
break;
case MISC_READ_AVMUTE_OP:
return read_avmute();
case MISC_HDCP_CLKDIS:
if (st != !!argv) {
st = !!argv;
pr_info("set hdcp clkdis: %d\n", !!argv);
}
hdmitx_set_reg_bits(HDMITX_DWC_MC_CLKDIS, !!argv, 6, 1);
break;
case MISC_I2C_REACTIVE:
hdmitx_hdcp_opr(4);
hdmitx_set_reg_bits(HDMITX_DWC_A_HDCPCFG1, 0, 0, 1);
hdmitx_set_reg_bits(HDMITX_DWC_HDCP22REG_CTRL, 0, 2, 1);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_1, 0xff);
hdmitx_wr_reg(HDMITX_DWC_I2CM_SS_SCL_HCNT_0, 0xf6);
edid_read_head_8bytes();
hdmi_hwi_init(hdev);
mdelay(5);
break;
default:
break;
@@ -5087,7 +5189,10 @@ static int hdmitx_get_state(struct hdmitx_dev *hdev, unsigned int cmd,
static void hdmi_phy_suspend(void)
{
hd_write_reg(P_HHI_HDMI_PHY_CNTL0, 0x0);
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x0);
/* keep PHY_CNTL3 bit[1:0] as 0b11,
* otherwise may cause HDCP22 boot failed
*/
hd_write_reg(P_HHI_HDMI_PHY_CNTL3, 0x3);
hd_write_reg(P_HHI_HDMI_PHY_CNTL5, 0x800);
}
@@ -5504,7 +5609,8 @@ static void config_hdmi20_tx(enum hdmi_vic vic,
data32 |= (default_phase << 2);
data32 |= (0 << 1);
data32 |= (0 << 0);
hdmitx_wr_reg(HDMITX_DWC_FC_GCP, data32);
if (!hdev->repeater_tx)
hdmitx_wr_reg(HDMITX_DWC_FC_GCP, data32);
/* write AVI Infoframe packet configuration */
data32 = 0;

View File

@@ -131,42 +131,6 @@ enum hdcp_authstate {
HDCP_MAX
};
enum hdcp_ver_e {
HDCPVER_NONE = 0,
HDCPVER_14,
HDCPVER_22,
};
#define HDCP14_MAX_KSV_LISTS 127
struct hdcprp14_topo {
unsigned char max_cascade_exceeded:1;
unsigned char depth:3;
unsigned char max_devs_exceeded:1;
unsigned char device_count:7; /* 1 ~ 127 */
unsigned char ksv_list[HDCP14_MAX_KSV_LISTS * 5];
};
#define HDCP22_MAX_KSV_LISTS 31
struct hdcprp22_topo {
int depth;
int device_count;
int v1_X_device_down;
int v2_0_repeater_down;
int max_devs_exceeded;
int max_cascade_exceeded;
unsigned char id_num;
unsigned char id_lists[HDCP22_MAX_KSV_LISTS * 5];
};
struct hdcprp_topo {
/* hdcp_ver currently used */
enum hdcp_ver_e hdcp_ver;
union {
struct hdcprp14_topo topo14;
struct hdcprp22_topo topo22;
} topo;
};
/* -----------------------HDCP END---------------------------------------- */
/* -----------------------HDMI TX---------------------------------- */

View File

@@ -0,0 +1,29 @@
/*
* include/linux/amlogic/media/vout/hdmi_tx/hdmi_rptx.h
*
* 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.
*
*/
#ifndef _HDMI_RPTX_H_
#define _HDMI_RPTX_H_
enum rptx_hdcp14_cmd {
RPTX_HDCP14_OFF,
RPTX_HDCP14_ON,
RPTX_HDCP14_GET_AUTHST,
};
extern void direct_hdcptx14_opr(enum rptx_hdcp14_cmd cmd, void *args);
#endif

View File

@@ -65,6 +65,12 @@ struct rx_audiocap {
unsigned char cc3;
};
#define MAX_RAW_LEN 64
struct raw_block {
int len;
char raw[MAX_RAW_LEN];
};
enum hd_ctrl {
VID_EN, VID_DIS, AUD_EN, AUD_DIS, EDID_EN, EDID_DIS, HDCP_EN, HDCP_DIS,
};
@@ -145,6 +151,8 @@ struct rx_cap {
unsigned char dtd_idx;
unsigned char flag_vfpdb;
unsigned char number_of_dtd;
struct raw_block asd;
struct raw_block vsd;
/*blk0 check sum*/
unsigned char blk0_chksum;
};
@@ -232,6 +240,48 @@ struct hdmitx_clk_tree_s {
struct clk *venci_1_gate;
};
/* 2kB should be enough to record */
#define HDCP_LOG_SIZE (1024 * 2)
struct hdcplog_buf {
int idx;
unsigned char buf[HDCP_LOG_SIZE + 64]; /* padding 8 bytes */
};
enum hdcp_ver_e {
HDCPVER_NONE = 0,
HDCPVER_14,
HDCPVER_22,
};
#define MAX_KSV_LISTS 127
struct hdcprp14_topo {
unsigned char max_cascade_exceeded:1;
unsigned char depth:3;
unsigned char max_devs_exceeded:1;
unsigned char device_count:7; /* 1 ~ 127 */
unsigned char ksv_list[MAX_KSV_LISTS * 5];
};
struct hdcprp22_topo {
unsigned int depth;
unsigned int device_count;
unsigned int v1_X_device_down;
unsigned int v2_0_repeater_down;
unsigned int max_devs_exceeded;
unsigned int max_cascade_exceeded;
unsigned char id_num;
unsigned char id_lists[MAX_KSV_LISTS * 5];
};
struct hdcprp_topo {
/* hdcp_ver currently used */
enum hdcp_ver_e hdcp_ver;
union {
struct hdcprp14_topo topo14;
struct hdcprp22_topo topo22;
} topo;
};
#define EDID_MAX_BLOCK 4
#define HDMI_TMP_BUF_SIZE 1024
struct hdmitx_dev {
@@ -259,7 +309,6 @@ struct hdmitx_dev {
struct delayed_work cec_work;
#endif
struct timer_list hdcp_timer;
int hdcp_try_times;
int chip_type;
int hdmi_init;
int hpdmode;
@@ -269,7 +318,6 @@ struct hdmitx_dev {
int ready; /* 1, hdmi stable output, others are 0 */
int hdcp_hpd_stick; /* 1 not init & reset at plugout */
int hdcp_tst_sig;
bool hdcp22_type;
unsigned int div40;
unsigned int lstore;
struct {
@@ -335,6 +383,9 @@ struct hdmitx_dev {
/**/
unsigned char hpd_event; /* 1, plugin; 2, plugout */
unsigned char hpd_state; /* 1, connect; 0, disconnect */
unsigned char rhpd_state; /* For repeater use only, no delay */
unsigned char hdcp_max_exceed_state;
unsigned int hdcp_max_exceed_cnt;
unsigned char force_audio_flag;
unsigned char mux_hpd_if_pin_high_flag;
int auth_process_timer;
@@ -352,6 +403,7 @@ struct hdmitx_dev {
unsigned int output_blank_flag;
unsigned int audio_notify_flag;
unsigned int audio_step;
bool hdcp22_type;
unsigned int repeater_tx;
struct hdcprp_topo *topo_info;
/* 0.1% clock shift, 1080p60hz->59.94hz */
@@ -401,6 +453,7 @@ struct hdmitx_dev {
#define HDCP14_OFF 0x2
#define HDCP22_ON 0x3
#define HDCP22_OFF 0x4
#define DDC_IS_HDCP_ON (CMD_DDC_OFFSET + 0x04)
#define DDC_HDCP_GET_AKSV (CMD_DDC_OFFSET + 0x05)
#define DDC_HDCP_GET_BKSV (CMD_DDC_OFFSET + 0x06)
#define DDC_HDCP_GET_AUTH (CMD_DDC_OFFSET + 0x07)
@@ -408,6 +461,7 @@ struct hdmitx_dev {
#define PIN_MUX 0x1
#define PIN_UNMUX 0x2
#define DDC_EDID_READ_DATA (CMD_DDC_OFFSET + 0x0a)
#define DDC_IS_EDID_DATA_READY (CMD_DDC_OFFSET + 0x0b)
#define DDC_EDID_GET_DATA (CMD_DDC_OFFSET + 0x0c)
#define DDC_EDID_CLEAR_RAM (CMD_DDC_OFFSET + 0x0d)
#define DDC_HDCP_MUX_INIT (CMD_DDC_OFFSET + 0x0e)
@@ -417,6 +471,7 @@ struct hdmitx_dev {
#define DDC_HDCP14_GET_BCAPS_RP (CMD_DDC_OFFSET + 0x30)
#define DDC_HDCP14_GET_TOPO_INFO (CMD_DDC_OFFSET + 0x31)
#define DDC_HDCP_SET_TOPO_INFO (CMD_DDC_OFFSET + 0x32)
#define DDC_HDCP14_SAVE_OBS (CMD_DDC_OFFSET + 0x40)
/***********************************************************************
* CONFIG CONTROL //CntlConfig
@@ -487,6 +542,7 @@ struct hdmitx_dev {
#define MISC_HDCP_CLKDIS (CMD_MISC_OFFSET + 0x0e)
#define MISC_TMDS_RXSENSE (CMD_MISC_OFFSET + 0x0f)
#define MISC_I2C_REACTIVE (CMD_MISC_OFFSET + 0x10)
#define MISC_READ_AVMUTE_OP (CMD_MISC_OFFSET + 0x11)
/***********************************************************************
* Get State //GetState
@@ -574,16 +630,6 @@ void __attribute__((weak))rx_set_receiver_edid(unsigned char *data, int len)
{
}
/*
* ver = 22 means downstream supports HDCP22
* ver = 14 means support HDCP14
* ver = 0 means support NO HDCP
*/
extern void rx_repeat_hdcp_ver(unsigned int ver);
void __attribute__((weak))rx_repeat_hdcp_ver(unsigned int ver)
{
}
extern void rx_set_receive_hdcp(unsigned char *data, int len, int depth,
bool max_cascade, bool max_devs);
void __attribute__((weak))rx_set_receive_hdcp(unsigned char *data, int len,