oleavr-rgl-a500-mini-linux-.../drivers/video/sunxi/disp2/hdmi2/hdmi_tx.c
Ole André Vadla Ravnås 169c65d57e Initial commit
2022-05-07 01:01:45 +02:00

2597 lines
62 KiB
C

/*
* Allwinner SoCs hdmi2.0 driver.
*
* Copyright (C) 2016 Allwinner.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include "config.h"
#if defined(__LINUX_PLAT__)
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/of_irq.h>
#include <linux/clk-private.h>
#include <linux/clkdev.h>
#include <linux/switch.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/power/scenelock.h>
#endif
#include "hdmi_tx.h"
/*#include "hdmi_test.h"*/
#define DDC_PIN_ACTIVE "ddc_active"
#define DDC_PIN_SLEEP "ddc_sleep"
#define CEC_PIN_ACTIVE "cec_active"
#define CEC_PIN_SLEEP "cec_sleep"
#define ESM_REG_BASE_OFFSET 0x8000
#define HDCP22_FIRMWARE_SIZE (1024 * 256)
#define HDCP22_DATA_SIZE (1024 * 128)
#if defined(__LINUX_PLAT__)
static dev_t devid;
static struct cdev *hdmi_cdev;
static struct class *hdmi_class;
static struct device *hdev;
#endif
static struct hdmi_tx_drv *hdmi_drv;
/*0x10: force unplug;
* 0x11: force plug;
* 0x1xx: unreport hpd state
* 0x1xxx: mask hpd
*/
u32 hdmi_hpd_mask_pre;
u32 hdmi_hpd_mask;
static u32 hpd_out_count;
static u32 re_read_edid_delay_count;
u32 hdmi_clk_enable_mask;
static u32 hdmi_pin_config_mask;
u32 hdmi_enable_mask;
u32 hdmi_suspend_mask;
static struct scene_lock hdmi_standby_lock;
static bool boot_hdmi;
static bool video_on;
static u32 hpd_state;
static u8 hdcp_encrypt_status;
static u8 cec_wakeup;
u32 hdmi_printf;
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
static struct switch_dev hdmi_switch_dev = {
.name = "hdmi",
};
#endif
#if defined(__LINUX_PLAT__)
static int hdmi_run_thread(void *parg);
#endif
struct hdmi_tx_drv *get_hdmi_drv(void)
{
return hdmi_drv;
}
u32 get_drv_hpd_state(void)
{
return hpd_state;
}
/**
* @short List of the devices
* Linked list that contains the installed devices
*/
static LIST_HEAD(devlist_global);
#ifdef CONFIG_AW_AXP
int hdmi_power_enable(char *name)
{
struct regulator *regu = NULL;
int ret = -1;
regu = regulator_get(NULL, name);
if (IS_ERR(regu)) {
pr_err("%s: some error happen, fail to get regulator %s\n", __func__, name);
goto exit;
}
/* enalbe regulator */
ret = regulator_enable(regu);
if (0 != ret) {
pr_err("%s: some error happen, fail to enable regulator %s!\n", __func__, name);
goto exit1;
} else {
VIDEO_INF("suceess to enable regulator %s!\n", name);
}
exit1:
/* put regulater, when module exit */
regulator_put(regu);
exit:
return ret;
}
int hdmi_power_disable(char *name)
{
struct regulator *regu = NULL;
int ret = 0;
regu = regulator_get(NULL, name);
if (IS_ERR(regu)) {
pr_err("%s: some error happen, fail to get regulator %s\n", __func__, name);
goto exit;
}
/*disalbe regulator*/
ret = regulator_disable(regu);
if (0 != ret) {
pr_err("%s: some error happen, fail to disable regulator %s!\n", __func__, name);
goto exit1;
} else {
VIDEO_INF("suceess to disable regulator %s!\n", name);
}
exit1:
/*put regulater, when module exit*/
regulator_put(regu);
exit:
return ret;
}
#else
int hdmi_power_enable(char *name) {return 0; }
int hdmi_power_disable(char *name) {return 0; }
#endif
#if defined(__LINUX_PLAT__)
static void hdmi_clk_enable(void)
{
if (hdmi_clk_enable_mask)
return;
clk_set_rate(hdmi_drv->hdmi_hdcp_clk, 300000000);
if (hdmi_drv->hdmi_clk != NULL)
if (clk_prepare_enable(hdmi_drv->hdmi_clk) != 0)
pr_info("hdmi clk enable failed!\n");
if (hdmi_drv->hdmi_ddc_clk != NULL)
if (clk_prepare_enable(hdmi_drv->hdmi_ddc_clk) != 0)
pr_info("hdmi ddc clk enable failed!\n");
if (hdmi_drv->hdmi_hdcp_clk != NULL)
if (clk_prepare_enable(hdmi_drv->hdmi_hdcp_clk) != 0)
pr_info("hdmi ddc clk enable failed!\n");
if (hdmi_drv->hdmi_cec_clk != NULL) {
struct clk *cec_clk_parent = NULL;
cec_clk_parent = clk_get(NULL, "periph32k");
if (cec_clk_parent == NULL || IS_ERR(cec_clk_parent)) {
pr_err("periph32k clk get failed\n");
} else {
if (clk_set_parent(hdmi_drv->hdmi_cec_clk, cec_clk_parent) != 0)
pr_err("hdmi ddc clk set parent clk 'periph32k' failed\n");
}
if (clk_prepare_enable(hdmi_drv->hdmi_cec_clk) != 0)
pr_info("hdmi cec clk enable failed!\n");
}
hdmi_clk_enable_mask = 1;
}
static void hdmi_resume_clk_enable(void)
{
if (hdmi_clk_enable_mask)
return;
clk_set_rate(hdmi_drv->hdmi_hdcp_clk, 300000000);
if (hdmi_drv->hdmi_clk != NULL)
if (clk_prepare_enable(hdmi_drv->hdmi_clk) != 0)
pr_info("hdmi clk enable failed!\n");
if ((hdmi_drv->hdmi_ddc_clk != NULL) && (!hdmi_drv->cec_super_standby))
if (clk_prepare_enable(hdmi_drv->hdmi_ddc_clk) != 0)
pr_info("hdmi ddc clk enable failed!\n");
if (hdmi_drv->hdmi_hdcp_clk != NULL)
if (clk_prepare_enable(hdmi_drv->hdmi_hdcp_clk) != 0)
pr_info("hdmi ddc clk enable failed!\n");
if ((hdmi_drv->hdmi_cec_clk != NULL) &&
(!hdmi_drv->cec_super_standby)) {
struct clk *cec_clk_parent = NULL;
cec_clk_parent = clk_get(NULL, "periph32k");
if (cec_clk_parent == NULL || IS_ERR(cec_clk_parent)) {
pr_err("periph32k clk get failed\n");
} else {
if (clk_set_parent(hdmi_drv->hdmi_cec_clk, cec_clk_parent) != 0)
pr_err("hdmi ddc clk set parent clk 'periph32k' failed\n");
}
if (clk_prepare_enable(hdmi_drv->hdmi_cec_clk) != 0)
pr_info("hdmi cec clk enable failed!\n");
}
hdmi_clk_enable_mask = 1;
}
static void hdmi_clk_disable(void)
{
if (!hdmi_clk_enable_mask)
return;
hdmi_clk_enable_mask = 0;
if (hdmi_drv->hdmi_hdcp_clk != NULL)
clk_disable_unprepare(hdmi_drv->hdmi_hdcp_clk);
if (hdmi_drv->hdmi_ddc_clk != NULL)
clk_disable_unprepare(hdmi_drv->hdmi_ddc_clk);
if (hdmi_drv->hdmi_clk != NULL)
clk_disable_unprepare(hdmi_drv->hdmi_clk);
if (hdmi_drv->hdmi_cec_clk != NULL)
clk_disable_unprepare(hdmi_drv->hdmi_cec_clk);
}
static void hdmi_suspend_clk_disable(void)
{
if (!hdmi_clk_enable_mask)
return;
hdmi_clk_enable_mask = 0;
if (hdmi_drv->hdmi_hdcp_clk != NULL)
clk_disable_unprepare(hdmi_drv->hdmi_hdcp_clk);
if ((hdmi_drv->hdmi_ddc_clk != NULL)
&& (!hdmi_drv->cec_super_standby))
clk_disable_unprepare(hdmi_drv->hdmi_ddc_clk);
if (hdmi_drv->hdmi_clk != NULL)
clk_disable_unprepare(hdmi_drv->hdmi_clk);
if ((hdmi_drv->hdmi_cec_clk != NULL)
&& (!hdmi_drv->cec_super_standby))
clk_disable_unprepare(hdmi_drv->hdmi_cec_clk);
}
static void hdmi_pin_configure(void)
{
s32 ret = 0;
struct pinctrl_state *state, *cec_state;
if (hdmi_pin_config_mask)
return;
/*pin configuration for ddc*/
if (hdmi_drv->pctl != NULL) {
state = pinctrl_lookup_state(hdmi_drv->pctl, DDC_PIN_ACTIVE);
if (IS_ERR(state)) {
pr_info("pinctrl_lookup_state for HDMI2.0 SCL fail\n");
return;
}
ret = pinctrl_select_state(hdmi_drv->pctl, state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 DDC fail\n");
cec_state = pinctrl_lookup_state(hdmi_drv->pctl, CEC_PIN_ACTIVE);
if (IS_ERR(state))
pr_info("pinctrl_lookup_state for HDMI2.0 CEC active fail\n");
ret = pinctrl_select_state(hdmi_drv->pctl, cec_state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 CEC active fail\n");
}
hdmi_pin_config_mask = 1;
}
static void hdmi_resume_pin_configure(void)
{
s32 ret = 0;
struct pinctrl_state *state, *cec_state;
if (hdmi_pin_config_mask)
return;
/*pin configuration for ddc*/
if (hdmi_drv->pctl != NULL) {
state = pinctrl_lookup_state(hdmi_drv->pctl, DDC_PIN_ACTIVE);
if (IS_ERR(state)) {
pr_info("pinctrl_lookup_state for HDMI2.0 SCL fail\n");
return;
}
ret = pinctrl_select_state(hdmi_drv->pctl, state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 DDC fail\n");
if (!hdmi_drv->cec_super_standby) {
cec_state = pinctrl_lookup_state(hdmi_drv->pctl, CEC_PIN_ACTIVE);
if (IS_ERR(state))
pr_info("pinctrl_lookup_state for HDMI2.0 CEC active fail\n");
ret = pinctrl_select_state(hdmi_drv->pctl, cec_state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 CEC active fail\n");
}
}
hdmi_pin_config_mask = 1;
}
static void hdmi_pin_release(void)
{
s32 ret = 0;
struct pinctrl_state *state;
if (!hdmi_pin_config_mask)
return;
/*pin configuration for ddc*/
if (hdmi_drv->pctl != NULL) {
state = pinctrl_lookup_state(hdmi_drv->pctl, DDC_PIN_SLEEP);
if (IS_ERR(state))
pr_info("pinctrl_lookup_state for HDMI2.0 SCL fail\n");
ret = pinctrl_select_state(hdmi_drv->pctl, state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 DDC fail\n");
state = pinctrl_lookup_state(hdmi_drv->pctl, CEC_PIN_SLEEP);
if (IS_ERR(state))
pr_info("pinctrl_lookup_state for HDMI2.0 CEC SLEEP fail\n");
ret = pinctrl_select_state(hdmi_drv->pctl, state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 CEC SLEEP fail\n");
}
hdmi_pin_config_mask = 0;
}
static void hdmi_suspend_pin_release(void)
{
s32 ret = 0;
struct pinctrl_state *state;
if (!hdmi_pin_config_mask)
return;
/*pin configuration for ddc*/
if (hdmi_drv->pctl != NULL) {
state = pinctrl_lookup_state(hdmi_drv->pctl, DDC_PIN_SLEEP);
if (IS_ERR(state))
pr_info("pinctrl_lookup_state for HDMI2.0 SCL fail\n");
ret = pinctrl_select_state(hdmi_drv->pctl, state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 DDC fail\n");
if (!hdmi_drv->cec_super_standby) {
state = pinctrl_lookup_state(hdmi_drv->pctl, CEC_PIN_SLEEP);
if (IS_ERR(state))
pr_info("pinctrl_lookup_state for HDMI2.0 CEC SLEEP fail\n");
ret = pinctrl_select_state(hdmi_drv->pctl, state);
if (ret < 0)
pr_info("pinctrl_select_state for HDMI2.0 CEC SLEEP fail\n");
}
}
hdmi_pin_config_mask = 0;
}
static void hdmi_sys_source_configure(void)
{
LOG_TRACE();
hdmi_clk_enable();
hdmi_pin_configure();
}
static void hdmi_resume_sys_source_configure(void)
{
LOG_TRACE();
hdmi_resume_clk_enable();
hdmi_resume_pin_configure();
}
static void hdmi_sys_source_release(void)
{
LOG_TRACE();
hdmi_clk_disable();
hdmi_pin_release();
}
static void hdmi_suspend_sys_source_release(void)
{
LOG_TRACE();
hdmi_suspend_clk_disable();
hdmi_suspend_pin_release();
}
static void hdmi_clk_reset(void)
{
hdmi_clk_disable();
udelay(10);
hdmi_clk_enable();
hdmi_clk_disable();
udelay(10);
hdmi_clk_enable();
}
/*static void hdmi_sys_source_reset(void)
{
hdmi_sys_source_release();
mdelay(10);
hdmi_sys_source_configure();
}*/
#endif
static void set_hdcp_status(u8 status)
{
hdcp_encrypt_status = status;
}
static s32 hdmi_enable(void)
{
s32 ret = 0;
LOG_TRACE();
mutex_lock(&hdmi_drv->ctrl_mutex);
if (hdmi_enable_mask == 1) {
mutex_unlock(&hdmi_drv->ctrl_mutex);
return 0;
}
if (hpd_state && (!video_on)) {
ret = hdmi_enable_core();
video_on = true;
}
hdmi_enable_mask = 1;
mutex_unlock(&hdmi_drv->ctrl_mutex);
return ret;
}
static s32 hdmi_smooth_enable(void)
{
s32 ret = 0;
LOG_TRACE();
mutex_lock(&hdmi_drv->ctrl_mutex);
if (hpd_state && video_on)
ret = hdmi_smooth_enable_core();
mutex_unlock(&hdmi_drv->ctrl_mutex);
return ret;
}
static s32 hdmi_disable(void)
{
s32 ret;
LOG_TRACE();
mutex_lock(&hdmi_drv->ctrl_mutex);
if (hdmi_enable_mask == 0) {
mutex_unlock(&hdmi_drv->ctrl_mutex);
return 0;
}
#if defined(__LINUX_PLAT__)
ret = hdmi_disable_core();
#endif
video_on = false;
hdmi_enable_mask = 0;
mutex_unlock(&hdmi_drv->ctrl_mutex);
return ret;
}
#if defined(CONFIG_SND_SUNXI_SOC_HDMIAUDIO)
s32 hdmi_audio_enable(u8 enable, u8 channel)
{
s32 ret = 0;
ret = hdmi_core_audio_enable(enable, channel);
return ret;
}
#endif
#if defined(__LINUX_PLAT__)
static s32 hdmi_suspend(void)
{
LOG_TRACE();
if (hdmi_suspend_mask)
return 0;
if (hdmi_drv->cec_support) {
hdmi_cec_send_inactive_source();
if (!hdmi_drv->cec_super_standby)
hdmi_cec_enable(0);
else
hdmi_cec_soft_disable();
cec_thread_exit();
}
if (hdmi_drv->hdmi_core->mode.pHdcp.hdcp_on)
set_hdcp_status(HDCP_ING);
if (hdmi_drv->hdmi_core->mode.pHdcp.use_hdcp)
hdmi_drv->hdmi_core->dev_func.hdcp_close();
if (hdmi_drv->hdmi_task) {
kthread_stop(hdmi_drv->hdmi_task);
hdmi_drv->hdmi_task = NULL;
}
hdmi_suspend_sys_source_release();
if (hdmi_drv->cec_support
&& hdmi_drv->cec_super_standby) {
enable_wakeup_src(CPUS_HDMICEC_SRC, 0);
scene_lock(&hdmi_standby_lock);
}
if (hdmi_drv->power_use)
hdmi_power_disable(hdmi_drv->power);
mutex_lock(&hdmi_drv->ctrl_mutex);
hdmi_suspend_mask = 1;
cec_wakeup = 0;
mutex_unlock(&hdmi_drv->ctrl_mutex);
return 0;
}
extern int sunxi_smc_refresh_hdcp(void);
static s32 hdmi_resume(void)
{
s32 ret = 0;
/*u32 hpd_state = 0;*/
LOG_TRACE();
#ifdef CONFIG_SUNXI_SMC
if (sunxi_smc_refresh_hdcp()) {
pr_err("refresh hdcp key failed!!!\n");
}
#endif
mutex_lock(&hdmi_drv->ctrl_mutex);
if (hdmi_suspend_mask == 0) {
mutex_unlock(&hdmi_drv->ctrl_mutex);
return 0;
}
if (hdmi_drv->cec_support
&& hdmi_drv->cec_super_standby) {
scene_unlock(&hdmi_standby_lock);
disable_wakeup_src(CPUS_HDMICEC_SRC, 0);
}
if (hdmi_drv->power_use)
hdmi_power_enable(hdmi_drv->power);
hdmi_resume_sys_source_configure();
hdmi_clk_reset();
/*enable hpd sense*/
hpd_sense_enbale_core(hdmi_drv->hdmi_core);
hpd_state = 0;
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
switch_set_state(&hdmi_switch_dev, hpd_state);
#endif
hdmi_drv->hdmi_task = kthread_create(hdmi_run_thread, (void *)0, "hdmi proc");
if (IS_ERR(hdmi_drv->hdmi_task)) {
pr_info("Unable to start kernel thread %s.\n\n", "hdmi proc");
hdmi_drv->hdmi_task = NULL;
}
wake_up_process(hdmi_drv->hdmi_task);
if (hdmi_drv->cec_support)
cec_thread_init(hdmi_drv->parent_dev);
#if defined(__LINUX_PLAT__)
if (hdmi_drv->cec_support) {
hdmi_cec_enable(1);
if (!cec_wakeup) {
hdmi_cec_wakup_request();
cec_wakeup = 1;
}
}
#endif
hdmi_suspend_mask = 0;
mutex_unlock(&hdmi_drv->ctrl_mutex);
return ret;
}
/*static void hdcp_handler(struct work_struct *work)
{
LOG_TRACE();
hdcp_handler_core();
}*/
static void edid_check(void)
{
LOG_TRACE();
if (!hdmi_drv->hdmi_core->mode.edid_done) {
mutex_lock(&hdmi_drv->hdcp_mutex);
edid_read_cap();
mutex_unlock(&hdmi_drv->hdcp_mutex);
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
if (!(hdmi_hpd_mask & 0x100))
switch_set_state(&hdmi_switch_dev, 1);
#endif
edid_correct_hardware_config();
}
}
static void hdmi_configure(struct hdmi_tx_drv *drv)
{
resistor_calibration_core(drv->hdmi_core, 0x10004, 0x80c00000);
hdmi_configure_core(drv->hdmi_core);
}
/*sys_config.fex setting for hpd*/
static void hdmi_hpd_sys_config_set(void)
{
/*To enhance the ddc ability*/
if (hdmi_drv->ddc_ctrl_en == 1) {
if (0 != gpio_direction_output(hdmi_drv->ddc_ctrl.gpio, 1)) {
pr_info("ddc ctrl gpio set 1 error!\n");
return;
}
}
}
/*release sys_config.fex setting for hpd*/
static void hdmi_hpd_sys_config_release(void)
{
pr_info("%s\n", __func__);
if (hdmi_drv->ddc_ctrl_en == 1) {
if (0 != gpio_direction_output(hdmi_drv->ddc_ctrl.gpio, 0)) {
pr_info("ddc ctrl gpio set 0 error!\n");
return;
}
}
}
static void hdmi_plugin_proc(void)
{
LOG_TRACE();
pr_info("HDMI cable is connected\n");
if (!(hdmi_hpd_mask & 0x10))
hpd_state = 1;
hdmi_hpd_sys_config_set();
mutex_lock(&hdmi_drv->hdcp_mutex);
edid_read_cap();
mutex_unlock(&hdmi_drv->hdcp_mutex);
if (hdmi_drv->cec_support) {
hdmi_cec_enable(1);
if (!cec_wakeup) {
hdmi_cec_wakup_request();
cec_wakeup = 1;
}
}
if (hdmi_drv->hdmi_core->mode.edid_done)
edid_set_video_prefered_core();/*update some configs by edid*/
mutex_lock(&hdmi_drv->ctrl_mutex);
if ((!video_on) && (hdmi_enable_mask)) {
hdmi_configure(hdmi_drv);
video_on = true;
}
mutex_unlock(&hdmi_drv->ctrl_mutex);
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
if ((!(hdmi_hpd_mask & 0x100)) && hdmi_drv->hdmi_core->mode.edid_done)
switch_set_state(&hdmi_switch_dev, 1);
#endif
edid_correct_hardware_config();
}
static void hdmi_plugout_proc(void)
{
LOG_TRACE();
pr_info("HDMI cable is disconnected\n");
if (!(hdmi_hpd_mask & 0x10))
hpd_state = 0;
video_on = false;
cec_wakeup = 0;
if (hdmi_drv->cec_support)
hdmi_cec_enable(0);
if (hdmi_drv->hdmi_core->mode.pHdcp.hdcp_on) {
hdmi_drv->hdmi_core->dev_func.hdcp_disconfigure();
set_hdcp_status(HDCP_ING);
}
hdmi_hpd_out_core_process(hdmi_drv->hdmi_core);
hdmi_clk_reset();
hpd_sense_enbale_core(hdmi_drv->hdmi_core);
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
if (!(hdmi_hpd_mask & 0x100))
switch_set_state(&hdmi_switch_dev, 0);
#endif
}
static void hdmi_hpd_mask_process(void)
{
if (hdmi_hpd_mask == 0x10) {
hdmi_plugout_proc();
} else if (hdmi_hpd_mask == 0x11) {
msleep(400);
hdmi_plugin_proc();
} else {
pr_info("Unknow hpd event\n");
}
/*hdmi_hpd_mask &= 0x0f0f;*/
}
static int hdmi_run_thread(void *parg)
{
u32 hpd_state_now = 0;
u32 hdcp_status = 0;
u32 i;
while (1) {
if (kthread_should_stop())
break;
if (hdmi_hpd_mask & 0x1000) {
msleep(200);
continue;
}
if (hdmi_hpd_mask & 0x10) {
if (hdmi_hpd_mask != hdmi_hpd_mask_pre) {
hdmi_hpd_mask_pre = hdmi_hpd_mask;
hdmi_hpd_mask_process();
}
msleep(80);
continue;
}
hpd_state_now = hdmi_core_get_hpd_state();
if (hpd_state_now != hpd_state) {
/*HPD Event Happen*/
if (!hpd_state_now) {
re_read_edid_delay_count = 20;
hdmi_plugout_proc();
hpd_out_count = 0;
} else {
for (i = 0; i < 2; i++) {
msleep(200);
hpd_state_now = hdmi_core_get_hpd_state();
if (hpd_state_now == hpd_state)
break;/*it's not a real hpd event*/
}
if (i >= 2) {
hpd_out_count = 41;
/*it's a real hpd event*/
hdmi_plugin_proc();
re_read_edid_delay_count = 0;
}
}
} else {
if (hpd_state_now && (hpd_state || (hdmi_hpd_mask == 0x1)) &&
hdmi_drv->hdmi_core->mode.pHdcp.hdcp_on &&
hdmi_drv->hdmi_core->mode.pHdcp.use_hdcp) {
mutex_lock(&hdmi_drv->hdcp_mutex);
hdcp_status = get_hdcp_status_core();
if (hdcp_status == 0)
set_hdcp_status(HDCP_SUCCESS);
else if (hdcp_status == -1)
set_hdcp_status(HDCP_FAILED);
else if (hdcp_status == 1)
set_hdcp_status(HDCP_ING);
else
;/*pr_info("Error: Unkown hdcp status\n");*/
mutex_unlock(&hdmi_drv->hdcp_mutex);
}
}
msleep(80);
hpd_out_count++;
if (hpd_out_count == 0)
hpd_out_count = 41;
if ((!hpd_state) && (hpd_out_count == 40))
hdmi_hpd_sys_config_release();
re_read_edid_delay_count++;
if (re_read_edid_delay_count == 0)
re_read_edid_delay_count = 20;
if (hpd_state && (re_read_edid_delay_count == 19))
edid_check();
}
return 0;
}
#endif
static void drv_global_value_init(void)
{
hdmi_printf = 0;
hdmi_hpd_mask_pre = 0;
hdmi_hpd_mask = 0;
hpd_out_count = 0;
re_read_edid_delay_count = 0;
hdmi_clk_enable_mask = 0;
hdmi_pin_config_mask = 0;
hdmi_enable_mask = 0;
hdmi_suspend_mask = 0;
boot_hdmi = false;
video_on = false;
hpd_state = 0;
hdcp_encrypt_status = HDCP_DISABLE;
}
#if defined(__LINUX_PLAT__)
static int hdmi_tx_init(struct platform_device *pdev)
#else
s32 hdmi_init(void)
#endif
{
int ret = 0;
int phy_model = 301;
uintptr_t reg_base = 0x0;
struct disp_device_func disp_func;
const char *hdmi_power;
#if defined(__LINUX_PLAT__)
unsigned int value/*, value0[10]*/;
unsigned int output_type0, output_mode0, output_type1, output_mode1;
struct clk *hdmi_parent_clk = NULL, *ddc_parent_clk = NULL;
struct device_node *esm_np;
u32 dts_esm_buff_phy_addr = 0, dts_esm_size_phy_addr = 0;
void *dts_esm_buff_vir_addr = NULL, *dts_esm_size_vir_addr = NULL;
u8 *esm_firm_vir_addr = NULL, *esm_data_vir_addr = NULL;
hdcpParams_t hdcp;
/*unsigned int boot_type;
struct disp_device_config config;*/
#endif
#if defined(CONFIG_SND_SUNXI_SOC_HDMIAUDIO)
__audio_hdmi_func audio_func;
#if defined(CONFIG_SND_SUNXI_SOC_AUDIOHUB_INTERFACE)
__audio_hdmi_func audio_func_muti;
#endif
#endif
LOG_TRACE();
pr_info("HDMI 2.0 driver init start!\n");
drv_global_value_init();
hdmi_drv = kmalloc(sizeof(struct hdmi_tx_drv), GFP_KERNEL);
if (!hdmi_drv) {
pr_err("%s:Could not allocated hdmi_tx_dev\n", FUNC_NAME);
return -1;
}
memset(hdmi_drv, 0, sizeof(struct hdmi_tx_drv));
hdmi_drv->hdmi_core = kmalloc(sizeof(struct hdmi_tx_core), GFP_KERNEL);
if (!hdmi_drv->hdmi_core) {
pr_err("%s:Could not allocated hdmi_tx_core\n", __func__);
goto free_mem;
}
memset(hdmi_drv->hdmi_core, 0, sizeof(struct hdmi_tx_core));
esm_firm_vir_addr = dma_alloc_coherent(&pdev->dev,
HDCP22_FIRMWARE_SIZE,
&hdcp.esm_firm_phy_addr,
GFP_KERNEL | __GFP_ZERO);
hdcp.esm_firm_vir_addr = (unsigned long)esm_firm_vir_addr;
hdcp.esm_firm_size = HDCP22_FIRMWARE_SIZE;
esm_data_vir_addr = dma_alloc_coherent(&pdev->dev,
HDCP22_DATA_SIZE,
&hdcp.esm_data_phy_addr,
GFP_KERNEL | __GFP_ZERO);
hdcp.esm_data_size = HDCP22_DATA_SIZE;
hdcp.esm_data_vir_addr = (unsigned long)esm_data_vir_addr;
hdmi_drv->hdmi_core->blacklist_sink = -1;
#if defined(__LINUX_PLAT__)
hdmi_drv->pdev = pdev;
hdmi_drv->parent_dev = &pdev->dev;
/*Read video booting params from disp device tree*/
value = disp_boot_para_parse("boot_disp");
/*To check if hdmi has been configured in uboot*/
output_type0 = (value >> 8) & 0xff;
output_mode0 = (value) & 0xff;
output_type1 = (value >> 24) & 0xff;
output_mode1 = (value >> 16) & 0xff;
if ((output_type0 == DISP_OUTPUT_TYPE_HDMI) ||
(output_type1 == DISP_OUTPUT_TYPE_HDMI))
boot_hdmi = true;
pr_info("boot_hdmi=%s\n", boot_hdmi ? "ture" : "false");
/*parse the booting video params*/
/*boot_type = output_type0;
config.mode = output_mode0;
config.format = value1 & 0xff;
config.bits = (value1 >> 8) & 0xff;
config.cs = (value1 >> 16) & 0xffff;
config.eotf = value2 & 0xff;*/
/* iomap */
reg_base = (uintptr_t __force)of_iomap(pdev->dev.of_node, 0);
if (0 == reg_base) {
pr_err("unable to map hdmi registers\n");
ret = -EINVAL;
goto free_mem;
}
#else
/* iomap */
reg_base = disp_getprop_regbase("hdmi", "reg", 0);
if (0 == reg_base) {
pr_err("unable to map hdmi registers\n");
ret = -1;
kfree(hdmi_drv);
return -1;
}
#endif
hdmi_core_set_base_addr(reg_base);
hdmi_drv->reg_base = reg_base;
hdcp.esm_hpi_base = reg_base + ESM_REG_BASE_OFFSET;
pr_info("hdmi reg base:0x%llx esm_hpi_base:0x%llx\n", __pa(reg_base),
__pa(hdcp.esm_hpi_base));
#if defined(__LINUX_PLAT__)
/***********************get dts value configs*************************/
/*get ddc control gpio enable config*/
if (of_property_read_u32(pdev->dev.of_node,
"ddc_en_io_ctrl",
&hdmi_drv->ddc_ctrl_en))
pr_info("ERROR: can not get ddc_en_io_ctrl\n");
/*get cec config*/
if (of_property_read_u32(pdev->dev.of_node,
"hdmi_cec_support",
&hdmi_drv->cec_support))
pr_err("ERROR: can not get hdmi_cec_support node\n");
if (of_property_read_u32(pdev->dev.of_node,
"hdmi_cec_super_standby",
&hdmi_drv->cec_super_standby))
pr_err("ERROR: can not get hdmi_cec_super_standby node\n");
hdmi_drv->hdmi_core->cec_super_standby = hdmi_drv->cec_super_standby;
/*get hdcp configs*/
if (of_property_read_u32_array(pdev->dev.of_node, "hdmi_hdcp_enable",
(u32 *)&hdcp.use_hdcp, 1))
pr_info("ERROR: can not get hdmi_hdcp_enable\n");
if (of_property_read_u32_array(pdev->dev.of_node, "hdmi_hdcp22_enable",
(u32 *)&hdcp.use_hdcp22, 1))
pr_info("ERROR: can not get hdmi_hdcp22_enable\n");
esm_np = of_find_node_by_name(NULL, "esm");
if (esm_np == NULL) {
pr_info("hdmi2.0 error: could not find the node of esm\n");
} else if (hdcp.use_hdcp22) {
if (!of_property_read_u32_array(esm_np,
"esm_img_size_addr",
&dts_esm_size_phy_addr,
1)) {
/*obtain esm firmware size*/
dts_esm_size_vir_addr = __va(dts_esm_size_phy_addr);
memcpy((void *)(&hdcp.esm_firm_size), dts_esm_size_vir_addr, 4);
if (!of_property_read_u32_array(esm_np,
"esm_img_buff_addr",
&dts_esm_buff_phy_addr,
1)) {
/*obtain esm firmware*/
dts_esm_buff_vir_addr = __va(dts_esm_buff_phy_addr);
if (hdcp.esm_firm_size <= HDCP22_FIRMWARE_SIZE)
memcpy(esm_firm_vir_addr,
dts_esm_buff_vir_addr,
hdcp.esm_firm_size);
else
pr_info("WARN: esm_firm_size is too big\n");
} else {
pr_info("ERROR: Can not read esm_img_buff_addr\n");
}
} else {
pr_info("ERROR: Can not read esm_img_size_addr\n");
}
}
/******************get dts pin ctrl and gpio configs******************/
/*Get DCC GPIO*/
hdmi_drv->pctl = pinctrl_get(&pdev->dev);
if (IS_ERR(hdmi_drv->pctl))
pr_err("ERROR: pinctrl_get for HDMI2.0 DDC fail\n");
hdmi_drv->ddc_ctrl.gpio = of_get_named_gpio_flags(pdev->dev.of_node, "ddc_io_ctrl", 0,
(enum of_gpio_flags *)(&(hdmi_drv->ddc_ctrl)));
if (0 != gpio_request(hdmi_drv->ddc_ctrl.gpio, NULL)) {
pr_info("ddc ctrl gpio_request is failed\n");
return 0;
}
/**********************get dts clk configs****************************/
hdmi_drv->hdmi_clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(hdmi_drv->hdmi_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi\n");
goto free_mem;
}
hdmi_drv->hdmi_ddc_clk = of_clk_get(pdev->dev.of_node, 1);
if (IS_ERR(hdmi_drv->hdmi_ddc_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi ddc\n");
goto free_mem;
}
hdmi_drv->hdmi_hdcp_clk = of_clk_get(pdev->dev.of_node, 2);
if (IS_ERR(hdmi_drv->hdmi_hdcp_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi hdcp\n");
goto free_mem;
}
hdmi_drv->hdmi_cec_clk = of_clk_get(pdev->dev.of_node, 3);
if (IS_ERR(hdmi_drv->hdmi_cec_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi ddc\n");
goto free_mem;
}
if (of_property_read_string(pdev->dev.of_node,
"hdmi_power",
&hdmi_power)) {
pr_err("Error: get hdmi power node failed\n");
} else {
hdmi_drv->power_use = 1;
memcpy((void *)hdmi_drv->power, hdmi_power,
strlen(hdmi_power) + 1);
pr_info("get hdmi_power:%s successfully\n",
hdmi_drv->power);
hdmi_power_enable(hdmi_drv->power);
}
#else
int node_offset = 0;
char io_name[32];
disp_gpio_set_t gpio_info;
node_offset = disp_fdt_nodeoffset("hdmi");
of_periph_clk_config_setup(node_offset);
/* get clk */
hdmi_drv->hdmi_clk = of_clk_get(node_offset, 0);
if (IS_ERR(hdmi_drv->hdmi_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi\n");
kfree(hdmi_drv);
return -1;
}
hdmi_drv->hdmi_ddc_clk = of_clk_get(node_offset, 1);
if (IS_ERR(hdmi_drv->hdmi_ddc_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi ddc\n");
kfree(hdmi_drv);
return -1;
}
hdmi_drv->hdmi_hdcp_clk = of_clk_get(node_offset, 2);
if (IS_ERR(hdmi_drv->hdmi_hdcp_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi hdcp\n");
kfree(hdmi_drv);
return -1;
}
hdmi_drv->hdmi_cec_clk = of_clk_get(node_offset, 3);
if (IS_ERR(hdmi_drv->hdmi_cec_clk)) {
dev_err(&pdev->dev, "fail to get clk for hdmi cec\n");
kfree(hdmi_drv);
return -1;
}
clk_set_rate(hdmi_drv->hdmi_hdcp_clk, 300000000);
ret = clk_prepare_enable(hdmi_drv->hdmi_clk);
if (ret != 0)
pr_info("hdmi clk enable failed!\n");
ret = clk_prepare_enable(hdmi_drv->hdmi_ddc_clk);
if (ret != 0)
pr_info("hdmi ddc clk enable failed!\n");
ret = clk_prepare_enable(hdmi_drv->hdmi_cec_clk);
if (ret != 0)
pr_info("hdmi cec clk enable failed!\n");
ret = clk_prepare_enable(hdmi_drv->hdmi_hdcp_clk);
if (ret != 0)
pr_info("hdmi hdcp clk enable failed!\n");
sprintf(io_name, "ddc_scl");
ret = disp_sys_script_get_item("hdmi",
io_name,
(int *)&gpio_info,
sizeof(disp_gpio_set_t)/sizeof(int));
if (ret == 3) {
disp_sys_gpio_request_simple(&gpio_info, 1);
pr_info("enable ddc_scl pin\n");
}
memset(io_name, 0, 32);
memset(&gpio_info, 0, sizeof(gpio_info));
sprintf(io_name, "ddc_sda");
ret = disp_sys_script_get_item("hdmi",
io_name,
(int *)&gpio_info,
sizeof(disp_gpio_set_t)/sizeof(int));
if (ret == 3) {
disp_sys_gpio_request_simple(&gpio_info, 1);
pr_info("enable ddc_sda pin\n");
}
/* cec pin */
memset(io_name, 0, 32);
memset(&gpio_info, 0, sizeof(gpio_info));
sprintf(io_name, "cec_io");
ret = disp_sys_script_get_item("hdmi",
io_name,
(int *)&gpio_info,
sizeof(disp_gpio_set_t)/sizeof(int));
if (ret == 3) {
disp_sys_gpio_request_simple(&gpio_info, 1);
pr_info("enable hmid cec pin\n");
} else {
pr_info("hmid cec pin not config\n");
}
hdmi_clk_enable_mask = 1;
#endif
#if defined(__LINUX_PLAT__)
/*init hdmi params*/
/*set_static_config(&config);*/
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
switch_dev_register(&hdmi_switch_dev);
#endif
/*Check if hdmi has been configured during booting*/
if (boot_hdmi) {
VIDEO_INF("uboot has configured hdmi\n");
video_on = true;
hdmi_clk_enable_mask = 1;
hdmi_pin_config_mask = 1;
hdmi_enable_mask = 1;
#if !defined(CONFIG_COMMON_CLK_ENABLE_SYNCBOOT)
hdmi_drv->hdmi_clk->enable_count = 1;
hdmi_drv->hdmi_ddc_clk->enable_count = 1;
hdmi_drv->hdmi_clk->prepare_count = 1;
hdmi_drv->hdmi_ddc_clk->prepare_count = 1;
hdmi_parent_clk = clk_get_parent(hdmi_drv->hdmi_clk);
hdmi_parent_clk->enable_count++;
hdmi_parent_clk->prepare_count++;
ddc_parent_clk = clk_get_parent(hdmi_drv->hdmi_ddc_clk);
ddc_parent_clk->enable_count++;
ddc_parent_clk->prepare_count++;
#endif
if (hdmi_drv->hdmi_hdcp_clk != NULL)
if (clk_prepare_enable(hdmi_drv->hdmi_hdcp_clk) != 0)
pr_info("hdmi hdcp clk enable failed!\n");
if (hdmi_drv->hdmi_cec_clk != NULL) {
struct clk *cec_clk_parent = NULL;
cec_clk_parent = clk_get(NULL, "periph32k");
if (cec_clk_parent == NULL || IS_ERR(cec_clk_parent)) {
pr_err("periph32k clk get failed\n");
} else {
if (clk_set_parent(hdmi_drv->hdmi_cec_clk, cec_clk_parent) != 0)
pr_err("hdmi ddc clk set parent clk 'periph32k' failed\n");
}
if (clk_prepare_enable(hdmi_drv->hdmi_cec_clk) != 0)
pr_info("hdmi cec clk enable failed!\n");
}
} else {
VIDEO_INF("uboot has not configured hdmi\n");
video_on = false;
hdmi_clk_enable_mask = 0;
hdmi_pin_config_mask = 0;
hdmi_sys_source_configure();
}
/*Init hdmi core and core params*/
if (hdmi_tx_core_init(hdmi_drv->hdmi_core,
phy_model, NULL,
NULL, &hdcp)) {
pr_err("Application init failed\n");
goto free_mem;
}
resistor_calibration_core(hdmi_drv->hdmi_core, 0x10004, 0x80c00000);
if (!boot_hdmi)
/*enable hpd sense*/
hpd_sense_enbale_core(hdmi_drv->hdmi_core);
#if defined(CONFIG_SWITCH) || defined(CONFIG_ANDROID_SWITCH)
if (!(hdmi_hpd_mask & 0x100))
switch_set_state(&hdmi_switch_dev, hpd_state);
#endif
/*Now that everything is fine, let's add it to device list*/
list_add_tail(&hdmi_drv->devlist, &devlist_global);
mutex_init(&hdmi_drv->ctrl_mutex);
mutex_init(&hdmi_drv->hdcp_mutex);
if (hdmi_drv->cec_super_standby)
scene_lock_init(&hdmi_standby_lock, SCENE_HDMI_CEC_STANDBY, "hdmi_cec_standby");
/*Create hdmi thread to poll hpd and hdcp status and handle hdcp and hpd event*/
hdmi_drv->hdmi_task = kthread_create(hdmi_run_thread, (void *)0, "hdmi proc");
if (IS_ERR(hdmi_drv->hdmi_task)) {
pr_info("Unable to start kernel thread %s.\n\n", "hdmi proc");
hdmi_drv->hdmi_task = NULL;
goto free_mem;
}
wake_up_process(hdmi_drv->hdmi_task);
cec_thread_init(hdmi_drv->parent_dev);
#endif
memset(&disp_func, 0, sizeof(struct disp_device_func));
disp_func.enable = hdmi_enable;
disp_func.smooth_enable = hdmi_smooth_enable;
disp_func.disable = hdmi_disable;
#if defined(__LINUX_PLAT__)
disp_func.mode_support = hdmi_mode_support;
#endif
disp_func.get_HPD_status = hdmi_get_HPD_status;
disp_func.get_input_csc = hdmi_core_get_csc_type;
disp_func.get_video_timing_info = hdmi_get_video_timming_info;
#if defined(__LINUX_PLAT__)
disp_func.suspend = hdmi_suspend;
disp_func.resume = hdmi_resume;
#endif
disp_func.set_static_config = set_static_config;
disp_func.get_static_config = get_static_config;
#if defined(__LINUX_PLAT__)
disp_func.set_dynamic_config = set_dynamic_config;
disp_func.get_dynamic_config = get_dynamic_config;
#endif
disp_set_hdmi_func(&disp_func);
#if defined(CONFIG_SND_SUNXI_SOC_HDMIAUDIO)
audio_func.hdmi_audio_enable = hdmi_audio_enable;
audio_func.hdmi_set_audio_para = hdmi_set_audio_para;
audio_set_hdmi_func(&audio_func);
AUDIO_INF("audio_set_hdmi_func\n");
#if defined(CONFIG_SND_SUNXI_SOC_AUDIOHUB_INTERFACE)
audio_func_muti.hdmi_audio_enable = hdmi_audio_enable;
audio_func_muti.hdmi_set_audio_para = hdmi_set_audio_para;
audio_set_muti_hdmi_func(&audio_func_muti);
#endif
#endif
VIDEO_INF("HDMI2.0 DRIVER PROBE END\n");
return ret;
free_mem:
kfree(hdmi_drv->hdmi_core);
kfree(hdmi_drv);
pr_info("Free core and drv memory\n");
return -1;
}
#if defined(__LINUX_PLAT__)
static int hdmi_tx_exit(struct platform_device *pdev)
{
struct hdmi_tx_drv *dev;
struct list_head *list;
cec_thread_exit();
while (!list_empty(&devlist_global)) {
list = devlist_global.next;
list_del(list);
dev = list_entry(list, struct hdmi_tx_drv, devlist);
if (dev == NULL)
continue;
}
if (hdmi_drv->hdmi_task) {
kthread_stop(hdmi_drv->hdmi_task);
hdmi_drv->hdmi_task = NULL;
}
scene_lock_destroy(&hdmi_standby_lock);
if (hdmi_drv->power_use)
hdmi_power_enable(hdmi_drv->power);
hdmi_sys_source_release();
return 0;
}
/**
* @short of_device_id structure
*/
static const struct of_device_id dw_hdmi_tx[] = {
{ .compatible = "allwinner,sunxi-hdmi" },
{ }
};
MODULE_DEVICE_TABLE(of, dw_hdmi_tx);
/**
* @short Platform driver structure
*/
static struct platform_driver __refdata dwc_hdmi_tx_pdrv = {
.remove = hdmi_tx_exit,
.probe = hdmi_tx_init,
.driver = {
.name = "allwinner,sunxi-hdmi",
.owner = THIS_MODULE,
.of_match_table = dw_hdmi_tx,
},
};
static int hdmi_open(struct inode *inode, struct file *file)
{
return 0;
}
static int hdmi_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t hdmi_read(struct file *file, char __user *buf,
size_t count,
loff_t *ppos)
{
return -EINVAL;
}
static ssize_t hdmi_write(struct file *file, const char __user *buf,
size_t count,
loff_t *ppos)
{
return -EINVAL;
}
static int hdmi_mmap(struct file *file, struct vm_area_struct *vma)
{
return 0;
}
static long hdmi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return 0;
}
static const struct file_operations hdmi_fops = {
.owner = THIS_MODULE,
.open = hdmi_open,
.release = hdmi_release,
.write = hdmi_write,
.read = hdmi_read,
.unlocked_ioctl = hdmi_ioctl,
.mmap = hdmi_mmap,
};
static int __parse_dump_str(const char *buf, size_t size,
unsigned long *start, unsigned long *end)
{
char *ptr = NULL;
char *ptr2 = (char *)buf;
int ret = 0, times = 0;
/* Support single address mode, some time it haven't ',' */
next:
/*Default dump only one register(*start =*end).
If ptr is not NULL, we will cover the default value of end.*/
if (times == 1)
*start = *end;
if (!ptr2 || (ptr2 - buf) >= size)
goto out;
ptr = ptr2;
ptr2 = strnchr(ptr, size - (ptr - buf), ',');
if (ptr2) {
*ptr2 = '\0';
ptr2++;
}
ptr = strim(ptr);
if (!strlen(ptr))
goto next;
ret = kstrtoul(ptr, 16, end);
if (!ret) {
times++;
goto next;
} else
pr_warn("String syntax errors: \"%s\"\n", ptr);
out:
return ret;
}
static ssize_t hdmi_test_reg_read_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(count)] > hdmi_test_reg_read");
}
ssize_t hdmi_test_reg_read_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long start_reg = 0;
unsigned long read_count = 0;
u32 i;
u8 *separator;
u32 data = 0;
separator = strchr(buf, ',');
if (separator != NULL) {
if (__parse_dump_str(buf, count, &start_reg, &read_count))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("start_reg=0x%lx read_count=%ld\n", start_reg, read_count);
for (i = 0; i < read_count; i++) {
pr_info("hdmi_addr_offset: 0x%lx = 0x%x\n", start_reg,
hdmitx_read(start_reg * 4));
start_reg++;
}
} else {
separator = strchr(buf, ' ');
if (separator != NULL) {
start_reg = simple_strtoul(buf, NULL, 0);
read_count = simple_strtoul(separator + 1, NULL, 0);
for (i = 0; i < read_count; i += 4) {
data = (u8)hdmitx_read((start_reg + i) * 4);
data |= ((u8)hdmitx_read((start_reg + i + 1) * 4)) << 8;
data |= ((u8)hdmitx_read((start_reg + i + 2) * 4)) << 16;
data |= ((u8)hdmitx_read((start_reg + i + 3) * 4)) << 24;
if ((i % 16) == 0)
printk("\n0x%08lx: 0x%08x",
(start_reg + i), data);
else
printk(" 0x%08x", data);
}
} else {
start_reg = simple_strtoul(buf, NULL, 0);
pr_info("hdmi_addr_offset: 0x%lx = 0x%x\n", start_reg,
hdmitx_read(start_reg * 4));
}
}
pr_info("\n");
return count;
}
static DEVICE_ATTR(read, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_test_reg_read_show,
hdmi_test_reg_read_store);
static ssize_t hdmi_test_reg_write_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(value)] > hdmi_test_write");
}
ssize_t hdmi_test_reg_write_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long reg_addr = 0;
unsigned long value = 0;
u8 *separator1 = NULL;
u8 *separator2 = NULL;
separator1 = strchr(buf, ',');
separator2 = strchr(buf, ' ');
if (separator1 != NULL) {
if (__parse_dump_str(buf, count, &reg_addr, &value))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("reg_addr=0x%lx write_value=0x%lx\n", reg_addr, value);
hdmitx_write((reg_addr * 4), value);
mdelay(1);
pr_info("after write,red(%lx)=%x\n", reg_addr,
hdmitx_read(reg_addr * 4));
} else if (separator2 != NULL) {
reg_addr = simple_strtoul(buf, NULL, 0);
value = simple_strtoul(separator2 + 1, NULL, 0);
pr_info("reg_addr=0x%lx write_value=0x%lx\n", reg_addr, value);
hdmitx_write((reg_addr * 4), value);
mdelay(1);
pr_info("after write,red(%lx)=%x\n", reg_addr,
hdmitx_read(reg_addr * 4));
} else {
pr_info("ERROR:error input\n");
}
return count;
}
static DEVICE_ATTR(write, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_test_reg_write_show,
hdmi_test_reg_write_store);
static ssize_t phy_write_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
pr_info("OPMODE_PLLCFG-0x16\n");
pr_info("CKSYMTXCTRL-0x09\n");
pr_info("PLLCURRCTRL-0x10\n");
pr_info("VLEVCTRL-0x0E\n");
pr_info("PLLGMPCTRL-0x15\n");
pr_info("TXTERM-0x19\n");
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(value)] > phy_write");
}
static ssize_t phy_write_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 reg_addr = 0;
u16 value = 0;
struct hdmi_tx_core *core = NULL;
core = hdmi_drv->hdmi_core;
if (__parse_dump_str(buf, count, (unsigned long *)&reg_addr, (unsigned long *)&value))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("reg_addr=0x%x write_value=0x%x\n", (u32)reg_addr, (u32)value);
core->dev_func.phy_write(reg_addr, value);
return count;
}
static DEVICE_ATTR(phy_write, S_IRUGO|S_IWUSR|S_IWGRP,
phy_write_show,
phy_write_store);
/*static DEVICE_ATTR(hdmi_test_print_core_structure, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_test_print_core_structure_show,
NULL);*/
static ssize_t phy_read_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
pr_info("OPMODE_PLLCFG-0x16\n");
pr_info("CKSYMTXCTRL-0x09\n");
pr_info("PLLCURRCTRL-0x10\n");
pr_info("VLEVCTRL-0x0E\n");
pr_info("PLLGMPCTRL-0x15\n");
pr_info("TXTERM-0x19\n");
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(count)] > phy_read");
}
ssize_t phy_read_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 start_reg = 0;
u16 value = 0;
unsigned long read_count = 0;
u32 i;
struct hdmi_tx_core *core = get_platform();
if (__parse_dump_str(buf, count, (unsigned long *)&start_reg, &read_count))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("start_reg=0x%x read_count=%ld\n", (u32)start_reg, read_count);
for (i = 0; i < read_count; i++) {
core->dev_func.phy_read(start_reg, &value);
pr_info("hdmi_addr_offset: 0x%x = 0x%x\n", (u32)start_reg, value);
start_reg++;
}
pr_info("\n");
return count;
}
static DEVICE_ATTR(phy_read, S_IRUGO|S_IWUSR|S_IWGRP,
phy_read_show,
phy_read_store);
static ssize_t scdc_read_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(count)] > scdc_read");
}
ssize_t scdc_read_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 start_reg = 0;
u8 value = 0;
unsigned long read_count = 0;
u32 i;
struct hdmi_tx_core *core = get_platform();
if (__parse_dump_str(buf, count, (unsigned long *)&start_reg, &read_count))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("start_reg=0x%x read_count=%ld\n", (u32)start_reg, read_count);
for (i = 0; i < read_count; i++) {
core->dev_func.scdc_read(start_reg, 1, &value);
pr_info("hdmi_addr_offset: 0x%x = 0x%x\n", (u32)start_reg, value);
start_reg++;
}
pr_info("\n");
return count;
}
static DEVICE_ATTR(scdc_read, S_IRUGO|S_IWUSR|S_IWGRP,
scdc_read_show,
scdc_read_store);
static ssize_t scdc_write_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(value)] > scdc_write");
}
static ssize_t scdc_write_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 reg_addr = 0;
u8 value = 0;
struct hdmi_tx_core *core = NULL;
core = hdmi_drv->hdmi_core;
if (__parse_dump_str(buf, count, (unsigned long *)&reg_addr, (unsigned long *)&value))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("reg_addr=0x%x write_value=0x%x\n", reg_addr, value);
core->dev_func.scdc_write(reg_addr, 1, &value);
return count;
}
static DEVICE_ATTR(scdc_write, S_IRUGO|S_IWUSR|S_IWGRP,
scdc_write_show,
scdc_write_store);
static ssize_t hdmi_debug_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "debug=%d\n", hdmi_printf);
}
static ssize_t hdmi_debug_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "9", 1) == 0)
hdmi_printf = 9;
else if (strnicmp(buf, "8", 1) == 0)
hdmi_printf = 8;
else if (strnicmp(buf, "7", 1) == 0)
hdmi_printf = 7;
else if (strnicmp(buf, "6", 1) == 0)
hdmi_printf = 6;
else if (strnicmp(buf, "5", 1) == 0)
hdmi_printf = 5;
else if (strnicmp(buf, "4", 1) == 0)
hdmi_printf = 4;
else if (strnicmp(buf, "3", 1) == 0)
hdmi_printf = 3;
else if (strnicmp(buf, "2", 1) == 0)
hdmi_printf = 2;
else if (strnicmp(buf, "1", 1) == 0)
hdmi_printf = 1;
else if (strnicmp(buf, "0", 1) == 0)
hdmi_printf = 0;
else
pr_err("Error Input!\n");
pr_info("debug=%d\n", hdmi_printf);
return count;
}
static DEVICE_ATTR(debug, S_IRUGO|S_IWUSR|S_IWGRP, hdmi_debug_show,
hdmi_debug_store);
static ssize_t hdmi_one_touch_play_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static ssize_t hdmi_one_touch_play_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0)
hdmi_cec_send_one_touch_paly();
else
pr_err("Error Input!\n");
return count;
}
static DEVICE_ATTR(one_touch_play, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_one_touch_play_show,
hdmi_one_touch_play_store);
static ssize_t hdmi_cec_local_standby_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t ret = sprintf(buf, "%d",
(unsigned int)cec_get_local_standby());
return ret;
}
static ssize_t hdmi_cec_local_standby_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0)
cec_set_local_standby(true);
else if (strnicmp(buf, "1", 0) == 0)
cec_set_local_standby(false);
else
pr_err("Error Input!\n");
return count;
}
static DEVICE_ATTR(cec_local_standby_mode, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_cec_local_standby_show,
hdmi_cec_local_standby_store);
static ssize_t hdmi_cec_dump_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t n = 0;
n += cec_dump_core(buf + n);
return n;
}
static DEVICE_ATTR(cec_dump, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_cec_dump_show, NULL);
static ssize_t hdmi_hdcp_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
char hdcp_type = (char)get_hdcp_type_core(hdmi_drv->hdmi_core);
mutex_lock(&hdmi_drv->hdcp_mutex);
memcpy(buf, &hdcp_type, 1);
mutex_unlock(&hdmi_drv->hdcp_mutex);
return 1;
}
static ssize_t hdmi_hdcp_type_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return count;
}
static DEVICE_ATTR(hdcp_type, S_IRUGO|S_IWUSR|S_IWGRP, hdmi_hdcp_type_show,
hdmi_hdcp_type_store);
static ssize_t hdmi_cec_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n",
hdmi_drv->cec_support);
}
static ssize_t hdmi_cec_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0) {
hdmi_drv->cec_support = 1;
hdmi_cec_enable(1);
} else {
hdmi_drv->cec_support = 0;
hdmi_cec_enable(0);
}
return count;
}
static DEVICE_ATTR(cec_enable, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_cec_enable_show,
hdmi_cec_enable_store);
static ssize_t hdmi_hpd_mask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "0x%x\n", hdmi_hpd_mask);
}
static ssize_t hdmi_hpd_mask_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int err;
unsigned long val;
if (count < 1)
return -EINVAL;
err = kstrtoul(buf, 16, &val);
if (err) {
pr_info("Invalid size\n");
return err;
}
pr_info("val=0x%x\n", (u32)val);
hdmi_hpd_mask = val;
return count;
}
static DEVICE_ATTR(hpd_mask, S_IRUGO|S_IWUSR|S_IWGRP, hdmi_hpd_mask_show,
hdmi_hpd_mask_store);
static ssize_t hdmi_edid_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
u8 pedid[1024];
if ((hdmi_drv->hdmi_core->mode.edid != NULL) &&
(hdmi_drv->hdmi_core->mode.edid_ext != NULL)) {
/*EDID_block0*/
memcpy(pedid, hdmi_drv->hdmi_core->mode.edid, 0x80);
/*EDID_block1*/
memcpy(pedid+0x80, hdmi_drv->hdmi_core->mode.edid_ext, 0x380);
memcpy(buf, pedid, 0x400);
return 0x400;
} else {
return 0;
}
}
static ssize_t hdmi_edid_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return count;
}
static DEVICE_ATTR(edid, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_edid_show,
hdmi_edid_store);
static ssize_t hdmi_hdcp_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n",
hdmi_drv->hdmi_core->mode.pHdcp.hdcp_on);
}
static ssize_t hdmi_hdcp_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
mutex_lock(&hdmi_drv->hdcp_mutex);
if (strnicmp(buf, "1", 1) == 0) {
set_hdcp_status(HDCP_ING);
hdcp_enable_core(hdmi_drv->hdmi_core, 1);
} else {
hdcp_enable_core(hdmi_drv->hdmi_core, 0);
set_hdcp_status(HDCP_DISABLE);
}
mutex_unlock(&hdmi_drv->hdcp_mutex);
return count;
}
static DEVICE_ATTR(hdcp_enable, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_hdcp_enable_show,
hdmi_hdcp_enable_store);
static ssize_t hpi_write_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(value)] > hpi_write");
}
static ssize_t hpi_write_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u32 reg_addr = 0;
u32 value = 0;
struct hdmi_tx_core *core = NULL;
core = hdmi_drv->hdmi_core;
if (__parse_dump_str(buf, count, (unsigned long *)&reg_addr, (unsigned long *)&value))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("reg_addr=0x%x write_value=0x%x\n", reg_addr, value);
*((u32 *)(core->mode.pHdcp.esm_hpi_base + reg_addr)) = (u32)value;
return count;
}
static DEVICE_ATTR(hpi_write, S_IRUGO|S_IWUSR|S_IWGRP,
hpi_write_show,
hpi_write_store);
static ssize_t hpi_read_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n", "echo [0x(address offset), 0x(count)] > hpi_read");
}
ssize_t hpi_read_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u32 start_reg = 0;
u32 value = 0;
unsigned long read_count = 0;
u32 i;
struct hdmi_tx_core *core = get_platform();
if (__parse_dump_str(buf, count, (unsigned long *)&start_reg, &read_count))
pr_err("%s,%d err, invalid para!\n", __func__, __LINE__);
pr_info("start_reg=0x%x read_count=%ld\n", (u32)start_reg, read_count);
for (i = 0; i < read_count; i++) {
value = *((u32 *)(core->mode.pHdcp.esm_hpi_base + start_reg));
pr_info("hdmi_addr_offset: 0x%x = 0x%x\n", (u32)start_reg, value);
start_reg++;
}
pr_info("\n");
return count;
}
static DEVICE_ATTR(hpi_read, S_IRUGO|S_IWUSR|S_IWGRP,
hpi_read_show,
hpi_read_store);
static ssize_t hdcp_status_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u32 count = sizeof(u8);
mutex_lock(&hdmi_drv->hdcp_mutex);
memcpy(buf, &hdcp_encrypt_status, count);
mutex_unlock(&hdmi_drv->hdcp_mutex);
return count;
}
static ssize_t hdcp_status_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0) {
} else {
}
return count;
}
static DEVICE_ATTR(hdcp_status, S_IRUGO|S_IWUSR|S_IWGRP, hdcp_status_show, hdcp_status_store);
struct hdmi_debug_video_mode {
int hdmi_mode;/* vic */
char *name;
};
static struct hdmi_debug_video_mode debug_video_mode[] = {
{HDMI_VIC_720x480I_4_3, "480I"},
{HDMI_VIC_720x480I_16_9, "480I"},
{HDMI_VIC_720x576I_4_3, "576I"},
{HDMI_VIC_720x576I_16_9, "576I"},
{HDMI_VIC_720x480P60_4_3, "720x480P"},
{HDMI_VIC_720x480P60_16_9, "720x480P"},
{HDMI_VIC_640x480P60, "640x480P"},
{HDMI_VIC_720x576P_4_3, "576P"},
{HDMI_VIC_720x576P_16_9, "576P"},
{HDMI_VIC_1280x720P24, "720P24"},
{HDMI_VIC_1280x720P25, "720P25"},
{HDMI_VIC_1280x720P30, "720P30"},
{HDMI_VIC_1280x720P50, "720P50"},
{HDMI_VIC_1280x720P60, "720P60"},
{HDMI_VIC_1920x1080I50, "1080I50"},
{HDMI_VIC_1920x1080I60, "1080I60"},
{HDMI_VIC_1920x1080P24, "1080P24"},
{HDMI_VIC_1920x1080P50, "1080P50"},
{HDMI_VIC_1920x1080P60, "1080P60"},
{HDMI_VIC_1920x1080P25, "1080P25"},
{HDMI_VIC_1920x1080P30, "1080P30"},
{HDMI_VIC_3840x2160P30, "2160P30"},
{HDMI_VIC_3840x2160P25, "2160PP25"},
{HDMI_VIC_3840x2160P24, "2160P24"},
{HDMI_VIC_4096x2160P24, "4096x2160P24"},
{HDMI_VIC_4096x2160P25, "4096x2160P25"},
{HDMI_VIC_4096x2160P30, "4096x2160P30"},
{HDMI_VIC_3840x2160P50, "2160P50"},
{HDMI_VIC_4096x2160P50, "4096x2160P50"},
{HDMI_VIC_3840x2160P60, "2160P60"},
{HDMI_VIC_4096x2160P60, "4096x2160P60"},
};
static char *hdmi_vic_name[] = {
"2160P30",
"2160P25",
"2160P24",
"4096x2160P24",
};
static char *hdmi_audio_code_name[] = {
"LPCM",
"AC-3",
"MPEG1",
"MP3",
"MPEG2",
"AAC",
"DTS",
"ATRAC",
"OneBitAudio",
"DolbyDigital+",
"DTS-HD",
"MAT",
"DST",
"WMAPro",
};
static char *debug_get_video_name(int hdmi_mode)
{
int i = 0;
for (i = 0;
i < sizeof(debug_video_mode)/sizeof(struct hdmi_debug_video_mode);
i++) {
if (debug_video_mode[i].hdmi_mode == hdmi_mode)
return debug_video_mode[i].name;
}
return NULL;
}
static ssize_t hdmi_sink_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t n = 0;
int i = 0;
sink_edid_t *sink_cap = hdmi_drv->hdmi_core->mode.sink_cap;
if (!sink_cap) {
n += sprintf(buf+n, "%s\n", "Do not read edid from sink");
return n;
}
/* Video Data Block */
n += sprintf(buf+n, "\n\n%s", "Video Mode:");
for (i = 0; i < sink_cap->edid_mSvdIndex; i++) {
if (sink_cap->edid_mSvd[i].mLimitedToYcc420
|| sink_cap->edid_mSvd[i].mYcc420)
continue;
n += sprintf(buf+n, " %s",
debug_get_video_name(
(int)sink_cap->edid_mSvd[i].mCode));
if (sink_cap->edid_mSvd[i].mNative)
n += sprintf(buf+n, "%s", "(native)");
}
for (i = 0; i < sink_cap->edid_mHdmivsdb.mHdmiVicCount; i++) {
if (sink_cap->edid_mHdmivsdb.mHdmiVic[i] <= 0x4) {
n += sprintf(buf+n, "%s",
hdmi_vic_name[
sink_cap->edid_mHdmivsdb.mHdmiVic[i]-1]);
}
}
/* YCC420 VDB */
n += sprintf(buf+n, "\n\n%s", "Only Support YUV420:");
for (i = 0; i < sink_cap->edid_mSvdIndex; i++) {
if (sink_cap->edid_mSvd[i].mLimitedToYcc420) {
n += sprintf(buf+n, " %s",
debug_get_video_name(
(int)sink_cap->edid_mSvd[i].mCode));
}
}
/*YCC420 CMDB */
n += sprintf(buf+n, "\n\n%s", "Also Support YUV420:");
for (i = 0; i < sink_cap->edid_mSvdIndex; i++) {
if (sink_cap->edid_mSvd[i].mYcc420) {
n += sprintf(buf+n, " %s",
debug_get_video_name(
(int)sink_cap->edid_mSvd[i].mCode));
}
}
/*video pixel format */
n += sprintf(buf+n, "\n\n%s", "Pixel Format: RGB");
if (sink_cap->edid_mYcc444Support)
n += sprintf(buf+n, " %s", "YUV444");
if (sink_cap->edid_mYcc422Support)
n += sprintf(buf+n, " %s", "YUV422");
/*deepcolor */
n += sprintf(buf+n, "\n\n%s", "Deep Color:");
if (sink_cap->edid_mHdmivsdb.mDeepColor30) {
n += sprintf(buf+n, " %s", "RGB444_30bit");
if (sink_cap->edid_mHdmivsdb.mDeepColorY444)
n += sprintf(buf+n, " %s", "YUV444_30bit");
}
if (sink_cap->edid_mHdmivsdb.mDeepColor36) {
n += sprintf(buf+n, " %s", "RGB444_36bit");
if (sink_cap->edid_mHdmivsdb.mDeepColorY444)
n += sprintf(buf+n, " %s", "YUV444_36bit");
}
if (sink_cap->edid_mHdmivsdb.mDeepColor48) {
n += sprintf(buf+n, " %s", "RGB444_48bit");
if (sink_cap->edid_mHdmivsdb.mDeepColorY444)
n += sprintf(buf+n, " %s", "YUV444_48bit");
}
if (sink_cap->edid_mHdmiForumvsdb.mDC_30bit_420)
n += sprintf(buf+n, " %s", "YUV420_30bit");
if (sink_cap->edid_mHdmiForumvsdb.mDC_36bit_420)
n += sprintf(buf+n, " %s", "YUV420_36bit");
if (sink_cap->edid_mHdmiForumvsdb.mDC_48bit_420)
n += sprintf(buf+n, " %s", "YUV420_48bit");
/*3D format */
if (sink_cap->edid_mHdmivsdb.m3dPresent) {
n += sprintf(buf+n, "\n\n%s", "3D Mode:");
for (i = 0; i < 16; i++) {
if (sink_cap->edid_mHdmivsdb.mVideo3dStruct[i][0] == 1
&& i < sink_cap->edid_mSvdIndex) {
n += sprintf(buf+n, " %s_FP",
debug_get_video_name(
(int)sink_cap->edid_mSvd[i].mCode));
}
if (sink_cap->edid_mHdmivsdb.mVideo3dStruct[i][6] == 1
&& i < sink_cap->edid_mSvdIndex) {
n += sprintf(buf+n, " %s_SBS",
debug_get_video_name(
(int)sink_cap->edid_mSvd[i].mCode));
}
if (sink_cap->edid_mHdmivsdb.mVideo3dStruct[i][8] == 1
&& i < sink_cap->edid_mSvdIndex) {
n += sprintf(buf+n, " %s_TAB",
debug_get_video_name(
(int)sink_cap->edid_mSvd[i].mCode));
}
}
}
/*TMDS clk rate */
if (sink_cap->edid_mHdmiForumvsdb.mValid) {
n += sprintf(buf+n, "\n\n%s", "MaxTmdsCharRate:");
n += sprintf(buf+n, " %d",
sink_cap->edid_mHdmiForumvsdb.mMaxTmdsCharRate);
}
/*audio*/
n += sprintf(buf+n, "\n\n%s", "Basic Audio Support:");
n += sprintf(buf+n, " %s",
sink_cap->edid_mBasicAudioSupport ? "YES" : "NO");
if (sink_cap->edid_mBasicAudioSupport) {
n += sprintf(buf+n, "\n\n%s", "Audio Code:");
for (i = 0; i < sink_cap->edid_mSadIndex; i++) {
n += sprintf(buf+n, " %s",
hdmi_audio_code_name[sink_cap->edid_mSad[i].mFormat-1]);
}
}
/*hdcp*/
n += sprintf(buf+n, "\n\n%s", "HDCP Tpye:");
n += sprintf(buf+n, "%c", '\n');
return n;
}
static DEVICE_ATTR(hdmi_sink, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_sink_show,
NULL);
static char *pixel_format_name[] = {
"RGB",
"YUV422",
"YUV444",
"YUV420",
};
static char *colorimetry_name[] = {
"NULL",
"ITU601",
"ITU709",
"XV_YCC601",
"XV_YCC709",
"S_YCC601",
"ADOBE_YCC601",
"ADOBE_RGB",
"BT2020_Yc_Cbc_Crc",
"BT2020_Y_CB_CR",
};
static ssize_t hdmi_source_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t n = 0;
n += sprintf(buf+n, "\n%s%d\n",
"HPD: ",
hdmi_core_get_hpd_state());
n += sprintf(buf+n, "\n%s%d\n",
"RxSense: ",
hdmi_core_get_rxsense_state());
n += sprintf(buf+n, "\n%s%d\n",
"PhyLock: ",
hdmi_core_get_phy_pll_lock_state());
n += sprintf(buf+n, "\n%s%d\n",
"PhyPower: ",
hdmi_core_get_phy_power_state());
n += sprintf(buf+n, "\n%s%s\n",
"TmdsMode: ",
hdmi_core_get_tmds_mode() ? "HDMI" : "DVI");
n += sprintf(buf+n, "\n%s%d\n",
"Scramble: ",
hdmi_core_get_scramble_state());
n += sprintf(buf+n, "\n%s%d\n",
"AvMute: ",
hdmi_core_get_avmute_state());
n += sprintf(buf+n, "\n%s%d\n",
"PixelRepetion: ",
hdmi_core_get_pixelrepetion());
n += sprintf(buf+n, "\n%s%d\n",
"BitDepth: ",
hdmi_core_get_color_depth());
n += sprintf(buf+n, "\n%s%s\n",
"PixelFormat: ",
pixel_format_name[hdmi_core_get_pixel_format()]);
n += sprintf(buf+n, "\n%s%s\n",
"Colorimetry: ",
colorimetry_name[hdmi_core_get_colorimetry()]);
n += sprintf(buf+n, "\n%s%s\n",
"VideoFormat: ",
debug_get_video_name((int)hdmi_core_get_video_code()));
n += sprintf(buf+n, "\n%s%d\n",
"AudioLayout: ",
hdmi_core_get_audio_layout());
n += sprintf(buf+n, "\n%s%d\n",
"AudioChannelCnt: ",
hdmi_core_get_audio_channel_count());
n += sprintf(buf+n, "\n%s%d\n",
"AudioSamplingFreq: ",
hdmi_core_get_audio_sample_freq());
n += sprintf(buf+n, "\n%s%d\n",
"AudioSampleSize: ",
hdmi_core_get_audio_sample_size());
n += sprintf(buf+n, "\n%s%d\n",
"AudioNvalue: ",
hdmi_core_get_audio_n());
return n;
}
static DEVICE_ATTR(hdmi_source, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_source_show,
NULL);
static ssize_t hdcp_dump_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t ret = 0;
ret += hdcp_dump_core(buf + ret);
ret += sprintf(buf + ret, "\n");
ret += hdmi_drv->hdmi_core->dev_func.hdcp_config_dump(buf + ret);
return ret;
}
static DEVICE_ATTR(hdcp_dump, S_IRUGO|S_IWUSR|S_IWGRP,
hdcp_dump_show,
NULL);
static ssize_t hdmi_avmute_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n%s\n",
"echo [value] > avmute",
"-----value =1:avmute on; =0:avmute off");
}
static ssize_t hdmi_avmute_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0)
hdmi_core_avmute_enable(1);
else
hdmi_core_avmute_enable(0);
return count;
}
static DEVICE_ATTR(avmute, S_IRUGO|S_IWUSR|S_IWGRP,
hdmi_avmute_show,
hdmi_avmute_store);
static ssize_t phy_power_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%s\n%s\n",
"echo [value] > phy_power",
"-----value =1:phy power on; =0:phy power off");
}
static ssize_t phy_power_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0)
hdmi_core_phy_power_enable(1);
else
hdmi_core_phy_power_enable(0);
return count;
}
static DEVICE_ATTR(phy_power, S_IRUGO|S_IWUSR|S_IWGRP,
phy_power_show,
phy_power_store);
static ssize_t dvi_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t n = 0;
n += sprintf(buf + n, "%s\n%s\n",
"echo [value] > dvi_mode",
"-----value =0:HDMI mode; =1:DVI mode");
return n;
}
static ssize_t dvi_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (count < 1)
return -EINVAL;
if (strnicmp(buf, "1", 1) == 0)
hdmi_core_dvimode_enable(1);
else
hdmi_core_dvimode_enable(0);
return count;
}
static DEVICE_ATTR(dvi_mode, S_IRUGO|S_IWUSR|S_IWGRP,
dvi_mode_show,
dvi_mode_store);
static struct attribute *hdmi_attributes[] = {
&dev_attr_read.attr,
&dev_attr_write.attr,
&dev_attr_phy_write.attr,
&dev_attr_phy_read.attr,
&dev_attr_scdc_read.attr,
&dev_attr_scdc_write.attr,
&dev_attr_hdcp_status.attr,
&dev_attr_hpi_read.attr,
&dev_attr_hpi_write.attr,
&dev_attr_one_touch_play.attr,
&dev_attr_cec_local_standby_mode.attr,
&dev_attr_cec_dump.attr,
&dev_attr_cec_enable.attr,
/*&dev_attr_hdmi_test_print_core_structure.attr,*/
&dev_attr_debug.attr,
&dev_attr_hdcp_type.attr,
&dev_attr_hpd_mask.attr,
&dev_attr_edid.attr,
&dev_attr_hdcp_enable.attr,
&dev_attr_hdmi_sink.attr,
&dev_attr_hdmi_source.attr,
&dev_attr_avmute.attr,
&dev_attr_phy_power.attr,
&dev_attr_dvi_mode.attr,
&dev_attr_hdcp_dump.attr,
NULL
};
static struct attribute_group hdmi_attribute_group = {
.name = "attr",
.attrs = hdmi_attributes
};
static int __init hdmi_module_init(void)
{
int ret = 0, err;
/*Create and add a character device*/
alloc_chrdev_region(&devid, 0, 1, "hdmi");/*corely for device number*/
hdmi_cdev = cdev_alloc();
cdev_init(hdmi_cdev, &hdmi_fops);
hdmi_cdev->owner = THIS_MODULE;
err = cdev_add(hdmi_cdev, devid, 1);/*/proc/device/hdmi*/
if (err) {
pr_err("Error: hdmi cdev_add fail.\n");
return -1;
}
/*Create a path: sys/class/hdmi*/
hdmi_class = class_create(THIS_MODULE, "hdmi");
if (IS_ERR(hdmi_class)) {
pr_err("Error:hdmi class_create fail\n");
return -1;
}
/*Create a path "sys/class/hdmi/hdmi"*/
hdev = device_create(hdmi_class, NULL, devid, NULL, "hdmi");
/*Create a path: sys/class/hdmi/hdmi/attr*/
ret = sysfs_create_group(&hdev->kobj, &hdmi_attribute_group);
if (ret)
pr_err("Error: hdmi sysfs_create_group failed!\n");
ret = platform_driver_register(&dwc_hdmi_tx_pdrv);
if (ret)
pr_err("Error: hdmi driver register fail\n");
pr_info("HDMI2.0 module init end\n");
return ret;
}
static void __exit hdmi_module_exit(void)
{
pr_info("hdmi_module_exit\n");
hdmi_tx_exit(hdmi_drv->pdev);
dma_free_coherent(hdmi_drv->parent_dev,
HDCP22_DATA_SIZE,
&hdmi_drv->hdmi_core->mode.pHdcp.esm_data_phy_addr,
GFP_KERNEL | __GFP_ZERO);
dma_free_coherent(hdmi_drv->parent_dev,
HDCP22_FIRMWARE_SIZE,
&hdmi_drv->hdmi_core->mode.pHdcp.esm_firm_phy_addr,
GFP_KERNEL | __GFP_ZERO);
hdmi_core_exit(hdmi_drv->hdmi_core);
kfree(hdmi_drv);
platform_driver_unregister(&dwc_hdmi_tx_pdrv);
sysfs_remove_group(&hdev->kobj, &hdmi_attribute_group);
device_destroy(hdmi_class, devid);
class_destroy(hdmi_class);
cdev_del(hdmi_cdev);
}
late_initcall(hdmi_module_init);
module_exit(hdmi_module_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("zhengwanyu");
MODULE_DESCRIPTION("HDMI_TX20 module driver");
MODULE_VERSION("1.0");
#endif