blob: bcc7174a0f3c77521cff3ef22cde1bbaff8cce51 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.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/slab.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/compiler.h>
#include <linux/arm-smccc.h>
#include <linux/spinlock.h>
#include <linux/seq_file.h>
#include <linux/amlogic/media/vout/vinfo.h>
#include <linux/amlogic/media/vout/hdmi_tx21/enc_clk_config.h>
#include <linux/amlogic/media/vout/hdmi_tx21/hdmi_info_global.h>
#include <linux/amlogic/media/vout/hdmi_tx21/hdmi_tx_module.h>
#include <linux/amlogic/media/vout/hdmi_tx21/hdmi_tx_ddc.h>
#include "common.h"
#include "../hdmi_tx.h"
static DEFINE_SPINLOCK(tpi_lock);
static void tpi_info_send(u8 sel, u8 *data)
{
u8 checksum = 0;
int i;
unsigned long flags;
spin_lock_irqsave(&tpi_lock, flags);
hdmitx21_wr_reg(TPI_INFO_FSEL_IVCTX, sel); // buf selection
if (!data) {
hdmitx21_wr_reg(TPI_INFO_EN_IVCTX, 0);
spin_unlock_irqrestore(&tpi_lock, flags);
return;
}
/* do checksum */
data[3] = 0;
for (i = 0; i < 31; i++)
checksum += data[i];
checksum = 0 - checksum;
data[3] = checksum;
for (i = 0; i < 31; i++)
hdmitx21_wr_reg(TPI_INFO_B0_IVCTX + i, data[i]);
hdmitx21_wr_reg(TPI_INFO_EN_IVCTX, 0xe0); //TPI Info enable
spin_unlock_irqrestore(&tpi_lock, flags);
}
/* packet no need checksum */
static void tpi_packet_send(u8 sel, u8 *data)
{
int i;
unsigned long flags;
spin_lock_irqsave(&tpi_lock, flags);
hdmitx21_wr_reg(TPI_INFO_FSEL_IVCTX, sel); // buf selection
if (!data) {
hdmitx21_wr_reg(TPI_INFO_EN_IVCTX, 0);
spin_unlock_irqrestore(&tpi_lock, flags);
return;
}
for (i = 0; i < 31; i++)
hdmitx21_wr_reg(TPI_INFO_B0_IVCTX + i, data[i]);
hdmitx21_wr_reg(TPI_INFO_EN_IVCTX, 0xe0); //TPI Info enable
spin_unlock_irqrestore(&tpi_lock, flags);
}
static int tpi_info_get(u8 sel, u8 *data)
{
int i;
unsigned long flags;
spin_lock_irqsave(&tpi_lock, flags);
hdmitx21_wr_reg(TPI_INFO_FSEL_IVCTX, sel); // buf selection
if (!data) {
spin_unlock_irqrestore(&tpi_lock, flags);
return -1;
}
if (hdmitx21_rd_reg(TPI_INFO_EN_IVCTX) == 0) {
spin_unlock_irqrestore(&tpi_lock, flags);
return 0;
}
for (i = 0; i < 31; i++)
data[i] = hdmitx21_rd_reg(TPI_INFO_B0_IVCTX + i);
spin_unlock_irqrestore(&tpi_lock, flags);
return 31; /* fixed value */
}
void dump_infoframe_packets(struct seq_file *s)
{
int i, j;
u8 body[32] = {0};
for (i = 0; i < 17; i++) {
tpi_info_get(i, body);
body[31] = hdmitx21_rd_reg(TPI_INFO_EN_IVCTX);
seq_printf(s, "dump hdmi infoframe[%d]\n", i);
for (j = 0; j < 32; j += 8)
seq_printf(s, "%02x%02x%02x%02x%02x%02x%02x%02x\n",
body[j + 0], body[j + 1],
body[j + 2], body[j + 3],
body[j + 4], body[j + 5],
body[j + 6], body[j + 7]);
memset(body, 0, sizeof(body));
}
}
static int _tpi_infoframe_wrrd(u8 wr, u8 info_type, u8 *body)
{
u8 sel;
/* the bank index is fixed */
switch (info_type) {
case HDMI_INFOFRAME_TYPE_AVI:
sel = 0;
break;
case HDMI_INFOFRAME_TYPE_AUDIO:
sel = 2;
break;
case HDMI_INFOFRAME_TYPE_SPD:
sel = 3;
break;
case HDMI_INFOFRAME_TYPE_VENDOR:
sel = 5;
break;
case HDMI_INFOFRAME_TYPE_DRM:
sel = 6;
break;
case HDMI_PACKET_TYPE_GCP:
sel = 7;
tpi_packet_send(sel, body);
return 0;
default:
pr_info("%s[%d] wrong info_type %d\n", __func__, __LINE__, info_type);
return -1;
}
if (wr) {
if (!body) {
tpi_info_send(sel, NULL);
return 0;
}
/* do checksum */
tpi_info_send(sel, body);
return 0;
} else {
return tpi_info_get(sel, body);
}
}
void hdmitx_infoframe_send(u8 info_type, u8 *body)
{
_tpi_infoframe_wrrd(1, info_type, body);
}
int hdmitx_infoframe_rawget(u8 info_type, u8 *body)
{
return _tpi_infoframe_wrrd(0, info_type, body);
}