mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
In Android's user-build, debugfs is not configured. This has led to
multiple warning errors related to Debugfs usage in the nvidia-oot
build. Add CONFIG_DEBUG_FS conditional compilation around the
functions that use it.
drivers/scsi/ufs/ufs-tegra-common.c:39:13: error: unused function
'ufs_tegra_init_debugfs' [-Werror,-Wunused-function]
static void ufs_tegra_init_debugfs(struct ufs_hba *hba)
^
1 error generated.
drivers/platform/tegra/aon/tegra-aon-debug.c:732:13:
error: unused function 'tegra_aondbg_recv_msg'
[-Werror,-Wunused-function]
static void tegra_aondbg_recv_msg(struct mbox_client *cl, void *rx_msg)
^
drivers/platform/tegra/aon/tegra-aon-debug.c:749:12:
error: unused function 'aon_dbg_init' [-Werror,-Wunused-function]
static int aon_dbg_init(struct tegra_aondbg *aon)
^
2 errors generated.
Bug 4230728
Change-Id: I4210c3574b4d76205fdca45990e9ccc02c18620a
Signed-off-by: Jian-Min Liu <jianminl@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2964635
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
869 lines
18 KiB
C
869 lines
18 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/tegra-aon.h>
|
|
#include <linux/mailbox_client.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/firmware.h>
|
|
|
|
#include <aon.h>
|
|
|
|
#include "aon-ivc-dbg-messages.h"
|
|
|
|
#define AON_REQUEST_MASK 0xF
|
|
#define AON_REQUESTS_TOTAL (AON_REQUEST_TYPE_MAX + 1)
|
|
|
|
#define TX_BLOCK_PERIOD 20
|
|
|
|
#define AON_ROOT 0
|
|
#define AON_MODS 1
|
|
#define AON_ADCC 2
|
|
|
|
#define IVC_DBG_CH_FRAME_SIZE 64
|
|
#define MODS_DEFAULT_VAL 0xFFFF
|
|
#define MODS_DEFAULT_LOOPS 10
|
|
#define MODS_DEFAULT_CHANS 0x1
|
|
#define MODS_BASIC_TEST 0x0
|
|
#define MODS_DMA_MEM2MEM 0x1
|
|
#define MODS_DMA_IO2MEM 0x2
|
|
#define MODS_ADCC_SINGLE 0x3
|
|
#define MODS_ADCC_CONT 0x4
|
|
|
|
#define ADCC_MODE_SINGLE_SHOT 1
|
|
#define ADCC_MODE_CONT 0
|
|
#define ADCC_CLK_SRC_OSC 0
|
|
#define ADCC_CLK_SRC_PLLP 1
|
|
|
|
#define AONFW_BOOT 1
|
|
|
|
struct tegra_aondbg {
|
|
struct device *dev;
|
|
struct tegra_aon *aon;
|
|
struct mbox_client cl;
|
|
struct mbox_chan *mbox;
|
|
struct dentry *aon_root;
|
|
bool supports_adcc;
|
|
};
|
|
|
|
static struct tegra_aondbg aondbg_dev;
|
|
|
|
struct aon_dbgfs_node {
|
|
char *name;
|
|
u32 id;
|
|
u8 pdr_id;
|
|
mode_t mode;
|
|
struct completion *wait_on;
|
|
const struct file_operations *fops;
|
|
char data[IVC_DBG_CH_FRAME_SIZE];
|
|
};
|
|
|
|
struct dbgfs_dir {
|
|
const char *name;
|
|
struct dentry *dir;
|
|
struct dbgfs_dir *parent;
|
|
};
|
|
|
|
static struct dbgfs_dir aon_dbgfs_dirs[] = {
|
|
{.name = "aon", .parent = NULL},
|
|
{.name = "aon_mods", .parent = &aon_dbgfs_dirs[AON_ROOT]},
|
|
{.name = "adcc", .parent = &aon_dbgfs_dirs[AON_MODS]}
|
|
};
|
|
|
|
static u32 mods_result = MODS_DEFAULT_VAL;
|
|
static u32 mods_dma_chans = MODS_DEFAULT_CHANS;
|
|
static u32 mods_adcc_chans = MODS_DEFAULT_CHANS;
|
|
static u32 mods_case = MODS_BASIC_TEST;
|
|
static u32 mods_loops = MODS_DEFAULT_LOOPS;
|
|
static u32 mods_adcc_smpl_dur = 16;
|
|
static u32 mods_adcc_avg_window = 1024;
|
|
static u32 mods_adcc_clk_src = ADCC_CLK_SRC_OSC;
|
|
static u64 mods_adcc_chans_data;
|
|
static u64 mods_adcc_dac_lb_data;
|
|
|
|
static unsigned int completion_timeout = 50;
|
|
|
|
static DEFINE_MUTEX(aon_mutex);
|
|
static DEFINE_SPINLOCK(mods);
|
|
static DEFINE_SPINLOCK(completion);
|
|
static DEFINE_SPINLOCK(loops);
|
|
static DEFINE_SPINLOCK(mods_dma);
|
|
static DEFINE_SPINLOCK(mods_adcc);
|
|
|
|
static struct aon_dbgfs_node aon_nodes[];
|
|
|
|
static void set_mods_result(u32 result)
|
|
{
|
|
spin_lock(&mods);
|
|
mods_result = result;
|
|
spin_unlock(&mods);
|
|
}
|
|
|
|
static unsigned int get_mods_result(void)
|
|
{
|
|
u32 val;
|
|
|
|
spin_lock(&mods);
|
|
val = mods_result;
|
|
spin_unlock(&mods);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_completion_timeout(unsigned int timeout)
|
|
{
|
|
spin_lock(&completion);
|
|
completion_timeout = timeout;
|
|
spin_unlock(&completion);
|
|
}
|
|
|
|
static unsigned int get_completion_timeout(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&completion);
|
|
val = completion_timeout;
|
|
spin_unlock(&completion);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_loops(u32 count)
|
|
{
|
|
spin_lock(&loops);
|
|
mods_loops = count;
|
|
spin_unlock(&loops);
|
|
}
|
|
|
|
static unsigned int get_mods_loops(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&loops);
|
|
val = mods_loops;
|
|
spin_unlock(&loops);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_dma_chans(u32 dma_chans)
|
|
{
|
|
spin_lock(&mods_dma);
|
|
mods_dma_chans = dma_chans;
|
|
spin_unlock(&mods_dma);
|
|
}
|
|
|
|
static unsigned int get_mods_dma_chans(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&mods_dma);
|
|
val = mods_dma_chans;
|
|
spin_unlock(&mods_dma);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_adcc_chans(u64 chans)
|
|
{
|
|
spin_lock(&mods_adcc);
|
|
mods_adcc_chans = (u32) (chans & 0xFFFFFFFFUL);
|
|
spin_unlock(&mods_adcc);
|
|
}
|
|
|
|
static unsigned int get_mods_adcc_chans(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&mods_adcc);
|
|
val = mods_adcc_chans;
|
|
spin_unlock(&mods_adcc);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_adcc_smpl_dur(u64 dur)
|
|
{
|
|
spin_lock(&mods_adcc);
|
|
mods_adcc_smpl_dur = (u32)(dur & 0xFFFFFFFFUL);
|
|
spin_unlock(&mods_adcc);
|
|
}
|
|
|
|
static unsigned int get_mods_adcc_smpl_dur(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&mods_adcc);
|
|
val = mods_adcc_smpl_dur;
|
|
spin_unlock(&mods_adcc);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_adcc_avg_window(u64 avg)
|
|
{
|
|
spin_lock(&mods_adcc);
|
|
mods_adcc_avg_window = (u32) (avg & 0xFFFFFFFFUL);
|
|
spin_unlock(&mods_adcc);
|
|
}
|
|
|
|
static unsigned int get_mods_adcc_avg_window(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&mods_adcc);
|
|
val = mods_adcc_avg_window;
|
|
spin_unlock(&mods_adcc);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_adcc_clk_src(u64 src)
|
|
{
|
|
spin_lock(&mods_adcc);
|
|
mods_adcc_clk_src = (u32)(src & 0xFFFFFFFFUL);
|
|
spin_unlock(&mods_adcc);
|
|
}
|
|
|
|
static u64 get_mods_adcc_chans_data(void)
|
|
{
|
|
u32 val;
|
|
|
|
spin_lock(&mods_adcc);
|
|
val = (u32)(mods_adcc_chans_data & 0xFFFFFFFFUL);
|
|
spin_unlock(&mods_adcc);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_adcc_chans_data(u64 adcc_data)
|
|
{
|
|
spin_lock(&mods_adcc);
|
|
mods_adcc_chans_data = adcc_data;
|
|
spin_unlock(&mods_adcc);
|
|
}
|
|
|
|
static u64 get_mods_adcc_dac_lb_data(void)
|
|
{
|
|
u64 val;
|
|
|
|
spin_lock(&mods_adcc);
|
|
val = mods_adcc_dac_lb_data;
|
|
spin_unlock(&mods_adcc);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void set_mods_adcc_dac_lb_data(u64 lb_data)
|
|
{
|
|
spin_lock(&mods_adcc);
|
|
mods_adcc_dac_lb_data = lb_data;
|
|
spin_unlock(&mods_adcc);
|
|
}
|
|
|
|
static unsigned int get_mods_adcc_clk_src(void)
|
|
{
|
|
unsigned int val;
|
|
|
|
spin_lock(&mods_adcc);
|
|
val = mods_adcc_clk_src;
|
|
spin_unlock(&mods_adcc);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void aon_create_mods_req(struct aon_dbg_request *req, u32 data)
|
|
{
|
|
switch (data) {
|
|
case MODS_BASIC_TEST:
|
|
break;
|
|
case MODS_DMA_MEM2MEM:
|
|
case MODS_DMA_IO2MEM:
|
|
req->data.mods_req.dma_chans = get_mods_dma_chans();
|
|
break;
|
|
case MODS_ADCC_SINGLE:
|
|
req->data.mods_req.adcc.chans = get_mods_adcc_chans();
|
|
req->data.mods_req.adcc.mode = ADCC_MODE_SINGLE_SHOT;
|
|
req->data.mods_req.adcc.sampling_dur = get_mods_adcc_smpl_dur();
|
|
req->data.mods_req.adcc.avg_window = get_mods_adcc_avg_window();
|
|
req->data.mods_req.adcc.clk_src = get_mods_adcc_clk_src();
|
|
req->data.mods_req.adcc.lb_data = get_mods_adcc_dac_lb_data();
|
|
break;
|
|
case MODS_ADCC_CONT:
|
|
req->data.mods_req.adcc.chans = get_mods_adcc_chans();
|
|
req->data.mods_req.adcc.mode = ADCC_MODE_CONT;
|
|
req->data.mods_req.adcc.sampling_dur = get_mods_adcc_smpl_dur();
|
|
req->data.mods_req.adcc.avg_window = get_mods_adcc_avg_window();
|
|
req->data.mods_req.adcc.clk_src = get_mods_adcc_clk_src();
|
|
req->data.mods_req.adcc.lb_data = get_mods_adcc_dac_lb_data();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static struct aon_dbg_response *aon_create_ivc_dbg_req(u32 request,
|
|
u32 flag,
|
|
u32 data)
|
|
{
|
|
struct tegra_aondbg *aondbg = &aondbg_dev;
|
|
struct aon_dbg_request req;
|
|
struct aon_dbg_response *resp;
|
|
struct tegra_aon_mbox_msg msg;
|
|
int ret = 0;
|
|
unsigned int timeout = 0;
|
|
|
|
if (aondbg->dev == NULL)
|
|
return (void *)-EPROBE_DEFER;
|
|
|
|
req.req_type = request & AON_REQUEST_MASK;
|
|
switch (req.req_type) {
|
|
case AON_MODS_CASE:
|
|
req.data.mods_req.loops = get_mods_loops();
|
|
req.data.mods_req.mods_case = data;
|
|
aon_create_mods_req(&req, data);
|
|
break;
|
|
case AON_MODS_CRC:
|
|
case AON_PING:
|
|
break;
|
|
case AON_QUERY_TAG:
|
|
break;
|
|
default:
|
|
dev_err(aondbg->dev, "Invalid aon dbg request\n");
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
msg.length = sizeof(struct aon_dbg_request);
|
|
msg.data = (void *)&req;
|
|
ret = mbox_send_message(aondbg->mbox, (void *)&msg);
|
|
if (ret < 0) {
|
|
dev_err(aondbg->dev, "mbox_send_message failed\n");
|
|
return ERR_PTR(ret);
|
|
}
|
|
timeout = get_completion_timeout();
|
|
ret = wait_for_completion_timeout(aon_nodes[req.req_type].wait_on,
|
|
msecs_to_jiffies(timeout));
|
|
if (!ret) {
|
|
dev_err(aondbg->dev, "No response\n");
|
|
return ERR_PTR(-ETIMEDOUT);
|
|
}
|
|
resp = (void *)aon_nodes[req.req_type].data;
|
|
if (resp->resp_type > AON_REQUEST_TYPE_MAX) {
|
|
dev_err(aondbg->dev, "Invalid aon dbg response\n");
|
|
return ERR_PTR(-EIO);
|
|
}
|
|
if (resp->status != AON_DBG_STATUS_OK) {
|
|
dev_err(aondbg->dev, "Request failed\n");
|
|
return ERR_PTR(-EIO);
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
|
|
static int aon_boot_show(void *data, u64 *val)
|
|
{
|
|
struct tegra_aon *aon = aondbg_dev.aon;
|
|
|
|
if (aon->ast_config_complete &&
|
|
aon->reset_complete && aon->load_complete)
|
|
*val = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_boot_store(void *data, u64 val)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_boot_fops, aon_boot_show,
|
|
aon_boot_store, "%lld\n");
|
|
|
|
static ssize_t aon_get_fwtag(u32 context, char **data)
|
|
{
|
|
struct aon_dbg_response *resp;
|
|
int ret = 0;
|
|
|
|
*data = NULL;
|
|
resp = aon_create_ivc_dbg_req(context, READ, 0);
|
|
if (IS_ERR(resp))
|
|
ret = PTR_ERR(resp);
|
|
else
|
|
*data = resp->data.tag_resp.tag;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aon_tag_show(struct seq_file *file, void *param)
|
|
{
|
|
char *data;
|
|
int ret;
|
|
|
|
mutex_lock(&aon_mutex);
|
|
ret = aon_get_fwtag(*(u32 *)file->private, &data);
|
|
if (ret >= 0)
|
|
seq_printf(file, "%s\n", data);
|
|
mutex_unlock(&aon_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int aon_tag_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, aon_tag_show, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations aon_tag_fops = {
|
|
.open = aon_tag_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release
|
|
};
|
|
|
|
static int __aon_do_ping(void)
|
|
{
|
|
struct aon_dbg_response *resp;
|
|
int challenge = 8;
|
|
int ret = 0;
|
|
|
|
resp = aon_create_ivc_dbg_req(AON_PING, READ, challenge);
|
|
if (IS_ERR(resp)) {
|
|
ret = PTR_ERR(resp);
|
|
goto exit;
|
|
}
|
|
|
|
ret = resp->data.ping_resp.reply;
|
|
if (ret != challenge * 2)
|
|
ret = -EINVAL;
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
static int aon_ping_show(void *data, u64 *val)
|
|
{
|
|
ktime_t tm;
|
|
int ret = 0;
|
|
|
|
mutex_lock(&aon_mutex);
|
|
tm = ktime_get();
|
|
ret = __aon_do_ping();
|
|
tm = ktime_sub(ktime_get(), tm);
|
|
*val = (ret < 0) ? tm : ret;
|
|
mutex_unlock(&aon_mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_ping_fops, aon_ping_show,
|
|
NULL, "%lld\n");
|
|
|
|
static int aon_mods_loops_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_loops();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_loops_store(void *data, u64 val)
|
|
{
|
|
set_mods_loops(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_loops_fops, aon_mods_loops_show,
|
|
aon_mods_loops_store, "%lld\n");
|
|
|
|
static int aon_mods_case_show(void *data, u64 *val)
|
|
{
|
|
*val = mods_case;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_case_store(void *data, u64 val)
|
|
{
|
|
struct aon_dbg_response *resp;
|
|
int ret = 0;
|
|
int i;
|
|
u64 adcc_data = 0U;
|
|
u64 ch_data = 0U;
|
|
|
|
if (val > MODS_ADCC_CONT) {
|
|
ret = -1;
|
|
dev_err(aondbg_dev.dev, "Invalid mods case\n");
|
|
goto out;
|
|
}
|
|
|
|
if (val > MODS_DMA_IO2MEM && val <= MODS_ADCC_CONT) {
|
|
if (!aondbg_dev.supports_adcc) {
|
|
ret = -1;
|
|
dev_err(aondbg_dev.dev, "no adcc on this platform\n");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
mutex_lock(&aon_mutex);
|
|
set_mods_result(MODS_DEFAULT_VAL);
|
|
resp = aon_create_ivc_dbg_req(*(u32 *)data, WRITE, val);
|
|
if (IS_ERR(resp)) {
|
|
ret = PTR_ERR(resp);
|
|
} else {
|
|
set_mods_result(resp->status);
|
|
if (val == MODS_ADCC_SINGLE || val == MODS_ADCC_CONT) {
|
|
adcc_data = 0U;
|
|
for (i = 0; i < ADCC_NCHANS; i++) {
|
|
ch_data = resp->data.adcc_resp.ch_data[i];
|
|
adcc_data |= (ch_data & 0x3FFU) << (i * 10);
|
|
}
|
|
set_mods_adcc_chans_data(adcc_data);
|
|
}
|
|
}
|
|
mutex_unlock(&aon_mutex);
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_case_fops, aon_mods_case_show,
|
|
aon_mods_case_store, "%lld\n");
|
|
|
|
static int aon_mods_result_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_result();
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_result_fops, aon_mods_result_show,
|
|
NULL, "%lld\n");
|
|
|
|
static int aon_mods_crc_show(void *data, u64 *val)
|
|
{
|
|
struct aon_dbg_response *resp;
|
|
int ret = 0;
|
|
|
|
mutex_lock(&aon_mutex);
|
|
resp = aon_create_ivc_dbg_req(*(u32 *)data, READ, 0);
|
|
if (IS_ERR(resp))
|
|
ret = PTR_ERR(resp);
|
|
else
|
|
*val = resp->data.crc_resp.crc;
|
|
mutex_unlock(&aon_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_crc_fops, aon_mods_crc_show,
|
|
NULL, "%llx\n");
|
|
|
|
static int aon_mods_dma_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_dma_chans();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_dma_store(void *data, u64 val)
|
|
{
|
|
set_mods_dma_chans(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_dma_fops, aon_mods_dma_show,
|
|
aon_mods_dma_store, "%lld\n");
|
|
|
|
static int aon_mods_adcc_chans_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_adcc_chans();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_adcc_chans_store(void *data, u64 val)
|
|
{
|
|
set_mods_adcc_chans(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_adcc_chans_fops, aon_mods_adcc_chans_show,
|
|
aon_mods_adcc_chans_store, "%lld\n");
|
|
|
|
static int aon_mods_adcc_smpl_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_adcc_smpl_dur();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_adcc_smpl_store(void *data, u64 val)
|
|
{
|
|
set_mods_adcc_smpl_dur(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_adcc_smpl_fops, aon_mods_adcc_smpl_show,
|
|
aon_mods_adcc_smpl_store, "%lld\n");
|
|
|
|
static int aon_mods_adcc_avg_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_adcc_avg_window();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_adcc_avg_store(void *data, u64 val)
|
|
{
|
|
set_mods_adcc_avg_window(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_adcc_avg_fops, aon_mods_adcc_avg_show,
|
|
aon_mods_adcc_avg_store, "%lld\n");
|
|
|
|
static int aon_mods_adcc_clk_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_adcc_clk_src();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_adcc_clk_store(void *data, u64 val)
|
|
{
|
|
set_mods_adcc_clk_src(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_adcc_clk_fops, aon_mods_adcc_clk_show,
|
|
aon_mods_adcc_clk_store, "%lld\n");
|
|
|
|
static int aon_mods_adcc_data_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_adcc_chans_data();
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_adcc_data_fops, aon_mods_adcc_data_show,
|
|
NULL, "%lld\n");
|
|
|
|
static int aon_mods_adcc_dac_show(void *data, u64 *val)
|
|
{
|
|
*val = get_mods_adcc_dac_lb_data();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_mods_adcc_dac_store(void *data, u64 val)
|
|
{
|
|
set_mods_adcc_dac_lb_data(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_mods_adcc_dac_fops, aon_mods_adcc_dac_show,
|
|
aon_mods_adcc_dac_store, "%lld\n");
|
|
|
|
static int aon_timeout_show(void *data, u64 *val)
|
|
{
|
|
*val = get_completion_timeout();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aon_timeout_store(void *data, u64 val)
|
|
{
|
|
set_completion_timeout(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(aon_timeout_fops, aon_timeout_show,
|
|
aon_timeout_store, "%lld\n");
|
|
|
|
static struct aon_dbgfs_node aon_nodes[] = {
|
|
{.name = "boot", .id = AON_BOOT, .pdr_id = AON_ROOT,
|
|
.mode = 0644, .fops = &aon_boot_fops, },
|
|
{.name = "loops", .pdr_id = AON_MODS,
|
|
.mode = 0644, .fops = &aon_mods_loops_fops, },
|
|
{.name = "result", .id = AON_MODS_RESULT, .pdr_id = AON_MODS,
|
|
.mode = 0444, .fops = &aon_mods_result_fops,},
|
|
{.name = "crc", .id = AON_MODS_CRC, .pdr_id = AON_MODS,
|
|
.mode = 0444, .fops = &aon_mods_crc_fops,},
|
|
{.name = "case", .id = AON_MODS_CASE, .pdr_id = AON_MODS,
|
|
.mode = 0644, .fops = &aon_mods_case_fops,},
|
|
{.name = "dma_channels", .pdr_id = AON_MODS,
|
|
.mode = 0644, .fops = &aon_mods_dma_fops,},
|
|
{.name = "adcc_chans", .pdr_id = AON_ADCC,
|
|
.mode = 0644, .fops = &aon_mods_adcc_chans_fops,},
|
|
{.name = "sampling_dur", .pdr_id = AON_ADCC,
|
|
.mode = 0644, .fops = &aon_mods_adcc_smpl_fops,},
|
|
{.name = "avg_window", .pdr_id = AON_ADCC,
|
|
.mode = 0644, .fops = &aon_mods_adcc_avg_fops,},
|
|
{.name = "clk_src", .pdr_id = AON_ADCC,
|
|
.mode = 0644, .fops = &aon_mods_adcc_clk_fops,},
|
|
{.name = "adcc_data", .pdr_id = AON_ADCC,
|
|
.mode = 0644, .fops = &aon_mods_adcc_data_fops,},
|
|
{.name = "dac", .pdr_id = AON_ADCC,
|
|
.mode = 0644, .fops = &aon_mods_adcc_dac_fops,},
|
|
{.name = "ping", .id = AON_PING, .pdr_id = AON_ROOT,
|
|
.mode = 0644, .fops = &aon_ping_fops,},
|
|
{.name = "tag", .id = AON_QUERY_TAG, .pdr_id = AON_ROOT,
|
|
.mode = 0644, .fops = &aon_tag_fops,},
|
|
{.name = "completion_timeout", .pdr_id = AON_ROOT,
|
|
.mode = 0644, .fops = &aon_timeout_fops,},
|
|
};
|
|
|
|
static void tegra_aondbg_recv_msg(struct mbox_client *cl, void *rx_msg)
|
|
{
|
|
struct tegra_aon_mbox_msg *msg;
|
|
struct aon_dbg_response *resp;
|
|
|
|
msg = (struct tegra_aon_mbox_msg *)rx_msg;
|
|
resp = (void *)msg->data;
|
|
if (resp->resp_type > AON_REQUEST_TYPE_MAX) {
|
|
dev_err(aondbg_dev.dev,
|
|
"Multiple request types in 1 response\n");
|
|
return;
|
|
}
|
|
memcpy(aon_nodes[resp->resp_type].data, msg->data,
|
|
IVC_DBG_CH_FRAME_SIZE);
|
|
complete(aon_nodes[resp->resp_type].wait_on);
|
|
}
|
|
|
|
static int aon_dbg_init(struct tegra_aondbg *aon)
|
|
{
|
|
struct dentry *d;
|
|
struct dentry *parent_dir;
|
|
struct dbgfs_dir *dbgdir;
|
|
int i;
|
|
|
|
d = debugfs_create_dir(aon_dbgfs_dirs[AON_ROOT].name, NULL);
|
|
if (IS_ERR_OR_NULL(d))
|
|
goto clean;
|
|
|
|
aon_dbgfs_dirs[AON_ROOT].dir = d;
|
|
aon->aon_root = d;
|
|
|
|
for (i = 1; i < ARRAY_SIZE(aon_dbgfs_dirs); i++) {
|
|
dbgdir = &aon_dbgfs_dirs[i];
|
|
d = debugfs_create_dir(dbgdir->name, dbgdir->parent->dir);
|
|
if (IS_ERR_OR_NULL(d))
|
|
goto clean;
|
|
|
|
dbgdir->dir = d;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(aon_nodes); i++) {
|
|
parent_dir = aon_dbgfs_dirs[aon_nodes[i].pdr_id].dir;
|
|
d = debugfs_create_file(aon_nodes[i].name,
|
|
aon_nodes[i].mode,
|
|
parent_dir,
|
|
&aon_nodes[i].id,
|
|
aon_nodes[i].fops);
|
|
if (IS_ERR_OR_NULL(d))
|
|
goto clean;
|
|
}
|
|
|
|
return 0;
|
|
|
|
clean:
|
|
debugfs_remove_recursive(aon->aon_root);
|
|
return PTR_ERR(d);
|
|
}
|
|
|
|
int tegra_aon_debugfs_create(struct tegra_aon *aon)
|
|
{
|
|
struct tegra_aondbg *aondbg = &aondbg_dev;
|
|
struct device *dev = aon->dev;
|
|
struct device_node *np = dev->of_node;
|
|
int count;
|
|
int ret = 0;
|
|
int i;
|
|
|
|
if (!debugfs_initialized()) {
|
|
ret = -ENODEV;
|
|
goto exit;
|
|
}
|
|
|
|
if (np == NULL) {
|
|
dev_err(dev, "tegra-aondbg: DT data required.\n");
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
|
|
if (count != 1) {
|
|
dev_err(dev, "incorrect mboxes property in '%pOF'\n", np);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (of_property_read_bool(np, NV("adcc")))
|
|
aondbg->supports_adcc = true;
|
|
else
|
|
aondbg->supports_adcc = false;
|
|
|
|
aondbg->dev = aon->dev;
|
|
aondbg->aon = aon;
|
|
aondbg->cl.dev = aon->dev;
|
|
aondbg->cl.tx_block = true;
|
|
aondbg->cl.tx_tout = TX_BLOCK_PERIOD;
|
|
aondbg->cl.knows_txdone = false;
|
|
aondbg->cl.rx_callback = tegra_aondbg_recv_msg;
|
|
aondbg->mbox = mbox_request_channel(&aondbg->cl, 0);
|
|
if (IS_ERR(aondbg->mbox)) {
|
|
ret = PTR_ERR(aondbg->mbox);
|
|
if (ret != -EPROBE_DEFER) {
|
|
dev_warn(dev,
|
|
"can't get mailbox channel (%d)\n", ret);
|
|
}
|
|
goto exit;
|
|
}
|
|
dev_dbg(dev, "aondbg->mbox = %p\n", aondbg->mbox);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(aon_nodes); i++) {
|
|
aon_nodes[i].wait_on = devm_kzalloc(aon->dev,
|
|
sizeof(struct completion),
|
|
GFP_KERNEL);
|
|
if (!aon_nodes[i].wait_on) {
|
|
dev_err(dev, "out of memory.\n");
|
|
ret = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
init_completion(aon_nodes[i].wait_on);
|
|
}
|
|
|
|
ret = aon_dbg_init(aondbg);
|
|
if (ret) {
|
|
dev_err(dev, "failed to create debugfs nodes.\n");
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
void tegra_aon_debugfs_remove(struct tegra_aon *aon)
|
|
{
|
|
struct tegra_aondbg *aondbg = &aondbg_dev;
|
|
|
|
mbox_free_channel(aondbg->mbox);
|
|
debugfs_remove_recursive(aondbg->aon_root);
|
|
}
|