blob: 423b46a84eb0681dea123e1aad0b10f38da331fa [file] [log] [blame]
/*
* drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_hdcp.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/irq.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/interrupt.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/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/spinlock_types.h>
#include <linux/extcon.h>
/* #include <mach/am_regs.h> */
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
#include "hw/common.h"
#include "hdmi_tx_hdcp.h"
/*
* hdmi_tx_hdcp.c
* version 1.1
*/
static int hdmi_authenticated;
unsigned int hdcp_get_downstream_ver(void)
{
unsigned int ret = 14;
struct hdmitx_dev *hdev = get_hdmitx_device();
/* if TX don't have HDCP22 key, skip RX hdcp22 ver */
if (hdev->HWOp.CntlDDC(hdev,
DDC_HDCP_22_LSTORE, 0) == 0)
if (hdcp_rd_hdcp22_ver())
ret = 22;
else
ret = 14;
else
ret = 14;
return ret;
}
/* Notic: the HDCP key setting has been moved to uboot
* On MBX project, it is too late for HDCP get from
* other devices
*/
/* verify ksv, 20 ones and 20 zeroes */
int hdcp_ksv_valid(unsigned char *dat)
{
int i, j, one_num = 0;
for (i = 0; i < 5; i++) {
for (j = 0; j < 8; j++) {
if ((dat[i] >> j) & 0x1)
one_num++;
}
}
return one_num == 20;
}
static void _hdcp_do_work(struct work_struct *work)
{
struct hdmitx_dev *hdev =
container_of(work, struct hdmitx_dev, work_do_hdcp.work);
if (hdev->hdcp_mode == 2) {
/* hdev->HWOp.CntlMisc(hdev, MISC_HDCP_CLKDIS, 1); */
/* schedule_delayed_work(&hdev->work_do_hdcp, HZ / 50); */
} else
hdev->HWOp.CntlMisc(hdev, MISC_HDCP_CLKDIS, 0);
}
void hdmitx_hdcp_do_work(struct hdmitx_dev *hdev)
{
_hdcp_do_work(&hdev->work_do_hdcp.work);
}
static int hdmitx_hdcp_task(void *data)
{
struct hdmitx_dev *hdev = (struct hdmitx_dev *)data;
INIT_DELAYED_WORK(&hdev->work_do_hdcp, _hdcp_do_work);
while (hdev->hpd_event != 0xff) {
hdmi_authenticated = hdev->HWOp.CntlDDC(hdev,
DDC_HDCP_GET_AUTH, 0);
hdmitx_hdcp_status(hdmi_authenticated);
msleep_interruptible(200);
}
return 0;
}
static int __init hdmitx_hdcp_init(void)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
pr_info(HDCP "hdmitx_hdcp_init\n");
if (hdev->hdtx_dev == NULL) {
pr_info(HDCP "exit for null device of hdmitx!\n");
return -ENODEV;
}
hdev->task_hdcp = kthread_run(hdmitx_hdcp_task, (void *)hdev,
"kthread_hdcp");
return 0;
}
static void __exit hdmitx_hdcp_exit(void)
{
struct hdmitx_dev *hdev = get_hdmitx_device();
if (hdev)
cancel_delayed_work_sync(&hdev->work_do_hdcp);
}
MODULE_PARM_DESC(hdmi_authenticated, "\n hdmi_authenticated\n");
module_param(hdmi_authenticated, int, 0444);
module_init(hdmitx_hdcp_init);
module_exit(hdmitx_hdcp_exit);
MODULE_DESCRIPTION("AMLOGIC HDMI TX HDCP driver");
MODULE_LICENSE("GPL");