blob: 9c9f053359145761aa387f7225bb69e8ece6cdb7 [file]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/pwm.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include "hdmi_aocec_api.h"
#include "hdmi_ao_cec.h"
#define DEVICE_NAME "aocec"
static const char * const cec_reg_name1[] = {
"CEC_TX_MSG_LENGTH",
"CEC_TX_MSG_CMD",
"CEC_TX_WRITE_BUF",
"CEC_TX_CLEAR_BUF",
"CEC_RX_MSG_CMD",
"CEC_RX_CLEAR_BUF",
"CEC_LOGICAL_ADDR0",
"CEC_LOGICAL_ADDR1",
"CEC_LOGICAL_ADDR2",
"CEC_LOGICAL_ADDR3",
"CEC_LOGICAL_ADDR4",
"CEC_CLOCK_DIV_H",
"CEC_CLOCK_DIV_L"
};
static const char * const cec_reg_name2[] = {
"CEC_RX_MSG_LENGTH",
"CEC_RX_MSG_STATUS",
"CEC_RX_NUM_MSG",
"CEC_TX_MSG_STATUS",
"CEC_TX_NUM_MSG"
};
static const char * const ceca_reg_name3[] = {
"STAT_0_0",
"STAT_0_1",
"STAT_0_2",
"STAT_0_3",
"STAT_1_0",
"STAT_1_1",
"STAT_1_2"
};
static int dump_cec_reg_show(struct seq_file *s, void *p)
{
unsigned int reg32;
int i = 0;
unsigned char reg;
seq_puts(s, "\n--------CEC registers--------\n");
#ifndef CONFIG_AMLOGIC_ZAPPER_CUT
if (cec_dev->plat_data->chip_id == CEC_CHIP_A1) {
seq_printf(s, "[%2x]:%2x\n", 0xe4, read_periphs(0xe4));
seq_printf(s, "[%2x]:%2x\n", 0xe8, read_periphs(0xe8));
seq_printf(s, "[%2x]:%2x\n", 0xec, read_periphs(0xec));
seq_printf(s, "[%2x]:%2x\n", 0xf0, read_periphs(0xf0));
} else
#endif
if (cec_dev->plat_data->chip_id == CEC_CHIP_SC2 ||
cec_dev->plat_data->chip_id == CEC_CHIP_S4) {
seq_printf(s, "[%2x]:%2x\n", 0x22, read_clock(0x22));
seq_printf(s, "[%2x]:%2x\n", 0x23, read_clock(0x23));
seq_printf(s, "[%2x]:%2x\n", 0x24, read_clock(0x24));
seq_printf(s, "[%2x]:%2x\n", 0x25, read_clock(0x25));
}
if (ee_cec == CEC_B) {
reg32 = read_ao(AO_CECB_CLK_CNTL_REG0);
seq_printf(s, "AO_CECB_CLK_CNTL_REG0:0x%08x\n", reg32);
reg32 = read_ao(AO_CECB_CLK_CNTL_REG1);
seq_printf(s, "AO_CECB_CLK_CNTL_REG1:0x%08x\n", reg32);
reg32 = read_ao(AO_CECB_GEN_CNTL);
seq_printf(s, "AO_CECB_GEN_CNTL:0x%08x\n", reg32);
reg32 = read_ao(AO_CECB_RW_REG);
seq_printf(s, "AO_CECB_RW_REG: 0x%08x\n", reg32);
reg32 = read_ao(AO_CECB_INTR_MASKN);
seq_printf(s, "AO_CECB_INTR_MASKN:0x%08x\n", reg32);
reg32 = read_ao(AO_CECB_INTR_STAT);
seq_printf(s, "AO_CECB_INTR_STAT: 0x%08x\n", reg32);
seq_puts(s, "CEC MODULE REGS:\n");
seq_printf(s, "CEC_CTRL = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_CTRL));
if (cec_dev->plat_data->cecb_ver >= CECB_VER_2)
seq_printf(s, "CEC_CTRL2 = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_CTRL2));
seq_printf(s, "CEC_MASK = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_MASK));
seq_printf(s, "CEC_ADDR_L = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_ADDR_L));
seq_printf(s, "CEC_ADDR_H = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_ADDR_H));
seq_printf(s, "CEC_TX_CNT = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_TX_CNT));
seq_printf(s, "CEC_RX_CNT = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_RX_CNT));
if (cec_dev->plat_data->cecb_ver >= CECB_VER_2)
seq_printf(s, "CEC_STAT0 = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_STAT0));
seq_printf(s, "CEC_LOCK = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_LOCK));
seq_printf(s, "CEC_WKUPCTRL = 0x%02x\n",
hdmirx_cec_read(DWC_CEC_WKUPCTRL));
seq_printf(s, "%s", "RX buffer:");
for (i = 0; i < 16; i++) {
reg = hdmirx_cec_read(DWC_CEC_RX_DATA0 + i * 4) & 0xff;
seq_printf(s, " %02x", reg);
}
seq_puts(s, "\n");
seq_printf(s, "%s", "TX buffer:");
for (i = 0; i < 16; i++) {
reg = hdmirx_cec_read(DWC_CEC_TX_DATA0 + i * 4) & 0xff;
seq_printf(s, " %02x", reg);
}
seq_puts(s, "\n");
} else {
reg32 = read_ao(AO_CEC_CLK_CNTL_REG0);
seq_printf(s, "AO_CEC_CLK_CNTL_REG0: 0x%08x\n", reg32);
reg32 = read_ao(AO_CEC_CLK_CNTL_REG1);
seq_printf(s, "AO_CEC_CLK_CNTL_REG1:0x%08x\n", reg32);
reg32 = read_ao(AO_CEC_GEN_CNTL);
seq_printf(s, "AO_CEC_GEN_CNTL: 0x%08x\n", reg32);
reg32 = read_ao(AO_CEC_RW_REG);
seq_printf(s, "AO_CEC_RW_REG: 0x%08x\n", reg32);
reg32 = read_ao(AO_CEC_INTR_MASKN);
seq_printf(s, "AO_CEC_INTR_MASKN:0x%08x\n", reg32);
reg32 = read_ao(AO_CEC_INTR_STAT);
seq_printf(s, "AO_CEC_INTR_STAT: 0x%08x\n", reg32);
seq_puts(s, "CEC MODULE REGS:\n");
for (i = 0; i < ARRAY_SIZE(cec_reg_name1); i++) {
seq_printf(s, "%s:%2x\n",
cec_reg_name1[i], aocec_rd_reg(i + 0x10));
}
for (i = 0; i < ARRAY_SIZE(cec_reg_name2); i++) {
seq_printf(s, "%s:%2x\n",
cec_reg_name2[i], aocec_rd_reg(i + 0x90));
}
if (cec_dev->plat_data->ceca_sts_reg) {
for (i = 0; i < ARRAY_SIZE(ceca_reg_name3); i++) {
seq_printf(s, "%s:%2x\n",
ceca_reg_name3[i], aocec_rd_reg(i + 0xA0));
}
}
}
seq_puts(s, "\n");
return 0;
}
static int dump_reg_open(struct inode *inode, struct file *file)
{
return single_open(file, dump_cec_reg_show, inode->i_private);
}
static const struct file_operations dump_reg_fops = {
.open = dump_reg_open,
.read = seq_read,
.release = single_release,
};
static int dump_cec_status_show(struct seq_file *s, void *p)
{
struct hdmi_port_info *port;
unsigned char i = 0;
unsigned int tmp = 0;
seq_puts(s, "\n--------CEC status--------\n");
seq_printf(s, "driver date:%s\n", CEC_DRIVER_VERSION);
seq_printf(s, "ee_cec:%d\n", ee_cec);
seq_printf(s, "cec_num:%d\n", cec_dev->cec_num);
seq_printf(s, "dev_type:%d\n", (unsigned int)cec_dev->dev_type);
seq_printf(s, "wk_logic_addr:0x%x\n", cec_dev->wakeup_data.wk_logic_addr);
seq_printf(s, "wk_phy_addr:0x%x\n", cec_dev->wakeup_data.wk_phy_addr);
seq_printf(s, "wk_port_id:0x%x\n", cec_dev->wakeup_data.wk_port_id);
seq_printf(s, "wakeup_reason:0x%x\n", cec_dev->wakeup_reason);
seq_printf(s, "phy_addr:0x%x\n", cec_dev->phy_addr);
seq_printf(s, "cec_version:0x%x\n", cec_dev->cec_info.cec_version);
seq_printf(s, "hal_ctl:0x%x\n", cec_dev->cec_info.hal_ctl);
seq_printf(s, "menu_lang:0x%x\n", cec_dev->cec_info.menu_lang);
seq_printf(s, "menu_status:0x%x\n", cec_dev->cec_info.menu_status);
seq_printf(s, "open_count:%d\n", cec_dev->cec_info.open_count.counter);
seq_printf(s, "vendor_id:0x%x\n", cec_dev->cec_info.vendor_id);
seq_printf(s, "port_num:0x%x\n", cec_dev->port_num);
seq_printf(s, "output:0x%x\n", cec_dev->output);
seq_printf(s, "arc_port:0x%x\n", cec_dev->arc_port);
seq_printf(s, "hal_flag:0x%x\n", cec_dev->hal_flag);
seq_printf(s, "hpd_state:0x%x\n", get_hpd_state());
seq_printf(s, "cec_config:0x%x\n", cec_config(0, 0));
seq_printf(s, "log_addr:0x%x\n", cec_dev->cec_info.log_addr);
seq_printf(s, "id:0x%x\n", cec_dev->plat_data->chip_id);
seq_printf(s, "ceca_ver:0x%x\n", cec_dev->plat_data->ceca_ver);
seq_printf(s, "cecb_ver:0x%x\n", cec_dev->plat_data->cecb_ver);
seq_printf(s, "share_io:0x%x\n", cec_dev->plat_data->share_io);
seq_printf(s, "line_bit:0x%x\n", cec_dev->plat_data->line_bit);
seq_printf(s, "ee_to_ao:0x%x\n", cec_dev->plat_data->ee_to_ao);
seq_printf(s, "irq_ceca:0x%x\n", cec_dev->irq_ceca);
seq_printf(s, "irq_cecb:0x%x\n", cec_dev->irq_cecb);
seq_printf(s, "framework_on:0x%x\n", cec_dev->framework_on);
seq_printf(s, "store msg_num:0x%x\n", cec_dev->msg_num);
seq_printf(s, "store msg_idx:0x%x\n", cec_dev->msg_idx);
seq_printf(s, "cec_msg_dbg_en: %d\n", cec_msg_dbg_en);
seq_printf(s, "port_seq: %x\n", cec_dev->port_seq);
seq_printf(s, "cec_log_en: %x\n", cec_dev->cec_log_en);
port = kcalloc(cec_dev->port_num, sizeof(*port), GFP_KERNEL);
if (port) {
init_cec_port_info(port, cec_dev);
for (i = 0; i < cec_dev->port_num; i++) {
/* port_id: 1/2/3 means HDMIRX1/2/3, 0 means HDMITX port */
seq_printf(s, "port_id: %d, ",
port[i].port_id);
seq_printf(s, "port_type: %s, ",
port[i].type == HDMI_INPUT ?
"hdmirx" : "hdmitx");
seq_printf(s, "physical_address: %x, ",
port[i].physical_address);
seq_printf(s, "cec_supported: %s, ",
port[i].cec_supported ? "true" : "false");
seq_printf(s, "arc_supported: %s\n",
port[i].arc_supported ? "true" : "false");
}
kfree(port);
}
#if (defined(CONFIG_AMLOGIC_HDMITX) || defined(CONFIG_AMLOGIC_HDMITX21))
tmp |= (get_hpd_state() << 4);
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_TVIN_HDMI
tmp |= (hdmirx_get_connect_info() & 0xF);
#endif
seq_printf(s, "hdmitx/rx connect status: 0x%x\n", tmp);
if (cec_dev->cec_num > ENABLE_ONE_CEC) {
seq_printf(s, "B addrL 0x%x\n", hdmirx_cec_read(DWC_CEC_ADDR_L));
seq_printf(s, "B addrH 0x%x\n", hdmirx_cec_read(DWC_CEC_ADDR_H));
seq_printf(s, "A addr0 0x%x\n", aocec_rd_reg(CEC_LOGICAL_ADDR0));
seq_printf(s, "A addr1 0x%x\n", aocec_rd_reg(CEC_LOGICAL_ADDR1));
/*seq_printf(s, "addr2 0x%x\n", aocec_rd_reg(CEC_LOGICAL_ADDR2));*/
/*seq_printf(s, "addr3 0x%x\n", aocec_rd_reg(CEC_LOGICAL_ADDR3));*/
/*seq_printf(s, "addr4 0x%x\n", aocec_rd_reg(CEC_LOGICAL_ADDR4));*/
} else {
if (ee_cec == CEC_B) {
seq_printf(s, "addrL 0x%x\n",
hdmirx_cec_read(DWC_CEC_ADDR_L));
seq_printf(s, "addrH 0x%x\n",
hdmirx_cec_read(DWC_CEC_ADDR_H));
} else {
seq_printf(s, "addr0 0x%x\n",
aocec_rd_reg(CEC_LOGICAL_ADDR0));
seq_printf(s, "addr1 0x%x\n",
aocec_rd_reg(CEC_LOGICAL_ADDR1));
seq_printf(s, "addr2 0x%x\n",
aocec_rd_reg(CEC_LOGICAL_ADDR2));
seq_printf(s, "addr3 0x%x\n",
aocec_rd_reg(CEC_LOGICAL_ADDR3));
seq_printf(s, "addr4 0x%x\n",
aocec_rd_reg(CEC_LOGICAL_ADDR4));
}
}
seq_printf(s, "addr_enable:0x%x\n", cec_dev->cec_info.addr_enable);
seq_printf(s, "chk_sig_free_time: %d\n", cec_dev->chk_sig_free_time);
seq_printf(s, "sw_chk_bus: %d\n", cec_dev->sw_chk_bus);
seq_puts(s, "\n");
return 0;
}
static int dump_status_open(struct inode *inode, struct file *file)
{
return single_open(file, dump_cec_status_show, inode->i_private);
}
static const struct file_operations dump_status_fops = {
.open = dump_status_open,
.read = seq_read,
.release = single_release,
};
struct cec_dbg_files_s {
const char *name;
const umode_t mode;
const struct file_operations *fops;
};
static struct cec_dbg_files_s cec_dbg_files[] = {
{"cec_reg", S_IFREG | 0444, &dump_reg_fops},
{"cec_status", S_IFREG | 0444, &dump_status_fops},
};
static struct dentry *cec_dbg_fs;
void cec_debug_fs_init(void)
{
struct dentry *entry;
int i;
if (cec_dbg_fs)
return;
cec_dbg_fs = debugfs_create_dir(DEVICE_NAME, NULL);
if (!cec_dbg_fs) {
pr_err("can't create %s debugfs dir\n", DEVICE_NAME);
return;
}
for (i = 0; i < ARRAY_SIZE(cec_dbg_files); i++) {
entry = debugfs_create_file(cec_dbg_files[i].name,
cec_dbg_files[i].mode,
cec_dbg_fs, NULL,
cec_dbg_files[i].fops);
if (!entry)
pr_err("debugfs create file %s failed\n",
cec_dbg_files[i].name);
}
}