mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
drivers: Add GTE support
The CL adds GTE driver support in OOT. The driver is copied from nvidia directory in dev-main with below changes. - Added removable module support This driver as module is needed as per the oot development requirement. Bug 3583612 Change-Id: I2772078fb96e1b172e45befe643b4c7c569866d9 Signed-off-by: Dipen Patel <dipenp@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2706260 Reviewed-by: Bitan Biswas <bbiswas@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
c9217a1b82
commit
e7c8a70f65
78
Documentation/devicetree/bindings/tegra_gte/tegra-gte.yaml
Normal file
78
Documentation/devicetree/bindings/tegra_gte/tegra-gte.yaml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/tegra_gte/tegra-gte.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: NVIDIA Tegra T194 GTE (Generic hardware Timestamping Engine) bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Dipen Patel <dipenp@nvidia.com>
|
||||||
|
|
||||||
|
description: |+
|
||||||
|
GTE is a hardware block which monitors various events for the state change and
|
||||||
|
timestamps them using TSC counter. Tegra implements LIC GTE and AON GTE
|
||||||
|
instances. LIC GTE is used only to monitor LIC IRQ lines and AON GTE is used
|
||||||
|
to monitor Always On domain GPIO lines.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nvidia,tegra194-gte-lic
|
||||||
|
- nvidia,tegra194-gte-aon
|
||||||
|
- nvidia,tegra234-gte-aon
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
description: physical base address.
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
description:
|
||||||
|
interrupt number
|
||||||
|
|
||||||
|
nvidia,int-threshold:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
GTE device generates its interrupt based on this u32 FIFO threshold
|
||||||
|
value. The recommended value is 1.
|
||||||
|
minimum: 1
|
||||||
|
maximum: 256
|
||||||
|
|
||||||
|
nvidia,num-slices:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
GTE lines are arranged in 32 bit slice where each bit represents different
|
||||||
|
line/signal that it can enable/configure for the timestamp. It is u32
|
||||||
|
property and the value depends on the GTE instance in the chip. Tegra194
|
||||||
|
LIC instance uses 11 slices while Tegra234 instance uses 17 slices to
|
||||||
|
represent interrupts line from LIC. The AON-GPIO GTE instances for both
|
||||||
|
Tegra194 and Tegra234 use 3 slices for the GPIO.
|
||||||
|
enum: [3, 11, 17]
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- nvidia,num-slices
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
gte@3aa0000 {
|
||||||
|
interrupts = <0x00 0x0b 0x04>;
|
||||||
|
compatible = "nvidia,tegra194-gte-lic";
|
||||||
|
nvidia,int-threshold = <0x01>;
|
||||||
|
status = "okay";
|
||||||
|
nvidia,num-slices = <0x11>;
|
||||||
|
reg = <0x3aa0000 0x10000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
gte@c1e0000 {
|
||||||
|
interrupts = <0x00 0x0d 0x04>;
|
||||||
|
compatible = "nvidia,tegra234-gte-aon";
|
||||||
|
nvidia,int-threshold = <0x01>;
|
||||||
|
status = "okay";
|
||||||
|
nvidia,num-slices = <0x03>;
|
||||||
|
reg = <0xc1e0000 0x10000>;
|
||||||
|
};
|
||||||
7
Documentation/ioctl/ioctl-number.txt
Normal file
7
Documentation/ioctl/ioctl-number.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Ioctl Numbers
|
||||||
|
21 February 2020
|
||||||
|
Dipen Patel
|
||||||
|
|
||||||
|
Code Seq#(hex) Include File Comments
|
||||||
|
========================================================
|
||||||
|
0xB5 00 linux/tegra-gte-ioctl.h
|
||||||
@@ -32,4 +32,6 @@ obj-m += watchdog/
|
|||||||
obj-m += video/tegra/
|
obj-m += video/tegra/
|
||||||
obj-m += virt/tegra/
|
obj-m += virt/tegra/
|
||||||
obj-m += media/
|
obj-m += media/
|
||||||
|
obj-m += staging/platform/tegra/gte/
|
||||||
|
obj-m += staging/platform/tegra/gte_test/
|
||||||
|
|
||||||
|
|||||||
1
drivers/staging/platform/tegra/gte/Makefile
Normal file
1
drivers/staging/platform/tegra/gte/Makefile
Normal file
@@ -0,0 +1 @@
|
|||||||
|
obj-m += tegra194_gte.o
|
||||||
1363
drivers/staging/platform/tegra/gte/tegra194_gte.c
Normal file
1363
drivers/staging/platform/tegra/gte/tegra194_gte.c
Normal file
File diff suppressed because it is too large
Load Diff
1
drivers/staging/platform/tegra/gte_test/Makefile
Normal file
1
drivers/staging/platform/tegra/gte_test/Makefile
Normal file
@@ -0,0 +1 @@
|
|||||||
|
obj-m += tegra194_gte_test.o
|
||||||
355
drivers/staging/platform/tegra/gte_test/tegra194_gte_test.c
Normal file
355
drivers/staging/platform/tegra/gte_test/tegra194_gte_test.c
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES.All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/tegra-gte.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sample GTE test driver demonstrating GTE API usage.
|
||||||
|
*
|
||||||
|
* Sample drivers monitors LIC IRQ provided by lic_irq module parameter and
|
||||||
|
* GPIO provided by gpio_in parameter.
|
||||||
|
*
|
||||||
|
* Note: gpio_out and gpio_in need to be shorted externally using some wire
|
||||||
|
* in order for this test driver to work for the GPIO monitoring.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This represents global ID of the GPIO since global ID or logical
|
||||||
|
* partitioning of the GPIOs across various GPIO controller happens
|
||||||
|
* at the run time, user has to provide this parameter in order to
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* gpio_in will be used in GTE to monitor the event and will be configured
|
||||||
|
* as input.
|
||||||
|
*/
|
||||||
|
static int gpio_in = -EINVAL;
|
||||||
|
module_param(gpio_in, int, 0660);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same comment as gpio_in but will be used as output and to toggle gpio_in
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
static int gpio_out = -EINVAL;
|
||||||
|
module_param(gpio_out, int, 0660);
|
||||||
|
|
||||||
|
/* IRQ number to monitor */
|
||||||
|
static int lic_irq = -EINVAL;
|
||||||
|
module_param(lic_irq, int, 0660);
|
||||||
|
|
||||||
|
static struct tegra_gte_test {
|
||||||
|
struct tegra_gte_ev_desc *data_lic;
|
||||||
|
struct tegra_gte_ev_desc *data_gpio;
|
||||||
|
int gpio_in_irq;
|
||||||
|
struct timer_list timer;
|
||||||
|
struct kobject *kobj;
|
||||||
|
} gte;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sysfs attribute to register/unregister GTE gpio event for 1 and 0 values
|
||||||
|
*/
|
||||||
|
static ssize_t store_gpio_en_dis(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int ret = count;
|
||||||
|
unsigned long val = 0;
|
||||||
|
struct device_node *np;
|
||||||
|
np = of_find_compatible_node(NULL, NULL, "nvidia,tegra194-gte-aon");
|
||||||
|
|
||||||
|
if (!np) {
|
||||||
|
np = of_find_compatible_node(NULL, NULL, "nvidia,tegra234-gte-aon");
|
||||||
|
if (!np) {
|
||||||
|
pr_err("Could not locate aon gte node\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == 1) {
|
||||||
|
if (gte.data_gpio) {
|
||||||
|
pr_info("gpio_in is already registered\n");
|
||||||
|
ret = -EEXIST;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
gte.data_gpio = tegra_gte_register_event(np, gpio_in);
|
||||||
|
if (IS_ERR(gte.data_gpio)) {
|
||||||
|
pr_err("Could not register gpio\n");
|
||||||
|
ret = PTR_ERR(gte.data_gpio);
|
||||||
|
gte.data_gpio = NULL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else if (val == 0) {
|
||||||
|
if (!gte.data_gpio) {
|
||||||
|
pr_info("gpio_in is not registered\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ret = tegra_gte_unregister_event(gte.data_gpio);
|
||||||
|
if (ret == -EBUSY) {
|
||||||
|
/* User should retry */
|
||||||
|
pr_err("failed to unregister gpio in\n");
|
||||||
|
goto error;
|
||||||
|
} else { /* For anything else set data to null */
|
||||||
|
gte.data_gpio = NULL;
|
||||||
|
if (ret == 0)
|
||||||
|
ret = count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
of_node_put(np);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sysfs attribute to register/unregister GTE LIC IRQ event for 1 and 0 values
|
||||||
|
*/
|
||||||
|
static ssize_t store_lic_irq_en_dis(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int ret = count;
|
||||||
|
unsigned long val = 0;
|
||||||
|
struct device_node *np;
|
||||||
|
np = of_find_compatible_node(NULL, NULL, "nvidia,tegra194-gte-lic");
|
||||||
|
|
||||||
|
if (!np) {
|
||||||
|
pr_err("Could not locate lic gte node\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == 1) {
|
||||||
|
if (gte.data_lic) {
|
||||||
|
pr_info("lic_irq is already registered\n");
|
||||||
|
ret = -EEXIST;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
gte.data_lic = tegra_gte_register_event(np, lic_irq);
|
||||||
|
if (IS_ERR(gte.data_lic)) {
|
||||||
|
pr_err("Could not register lic irq\n");
|
||||||
|
ret = PTR_ERR(gte.data_lic);
|
||||||
|
gte.data_lic = NULL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else if (val == 0) {
|
||||||
|
if (!gte.data_lic) {
|
||||||
|
pr_info("lic_irq is not registered\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ret = tegra_gte_unregister_event(gte.data_lic);
|
||||||
|
if (ret == -EBUSY) {
|
||||||
|
/* User should retry */
|
||||||
|
pr_err("failed to unregister lic irq\n");
|
||||||
|
goto error;
|
||||||
|
} else { /* For anything else set data to null */
|
||||||
|
gte.data_lic = NULL;
|
||||||
|
if (ret == 0)
|
||||||
|
ret = count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
of_node_put(np);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shows LIC event timestamp information */
|
||||||
|
static ssize_t show_lic_irq_ts(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct tegra_gte_ev_detail hts;
|
||||||
|
|
||||||
|
if (tegra_gte_retrieve_event((gte.data_lic), &hts) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pr_debug("Retrieved lic event ts_raw: %llu, ts_ns %llu\n",
|
||||||
|
hts.ts_raw, hts.ts_ns);
|
||||||
|
return scnprintf(buf, PAGE_SIZE, "ts_raw: %llu, ts_ns: %llu\n",
|
||||||
|
hts.ts_raw, hts.ts_ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct kobj_attribute gpio_en_dis_attr =
|
||||||
|
__ATTR(gpio_en_dis, 0220, NULL, store_gpio_en_dis);
|
||||||
|
struct kobj_attribute lic_irq_en_dis_attr =
|
||||||
|
__ATTR(lic_irq_en_dis, 0220, NULL, store_lic_irq_en_dis);
|
||||||
|
struct kobj_attribute lic_irq_ts_attr =
|
||||||
|
__ATTR(lic_irq_ts, 0440, show_lic_irq_ts, NULL);
|
||||||
|
|
||||||
|
static struct attribute *attrs[] = {
|
||||||
|
&gpio_en_dis_attr.attr,
|
||||||
|
&lic_irq_en_dis_attr.attr,
|
||||||
|
&lic_irq_ts_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group tegra_gte_test_attr_group = {
|
||||||
|
.attrs = attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tegra_gte_test_sysfs_create(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Creates object under /sys/kernel/ */
|
||||||
|
gte.kobj = kobject_create_and_add("tegra_gte_test", kernel_kobj);
|
||||||
|
if (!gte.kobj)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = sysfs_create_group(gte.kobj, &tegra_gte_test_attr_group);
|
||||||
|
if (ret)
|
||||||
|
kobject_put(gte.kobj);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
|
||||||
|
static void gpio_timer_cb(unsigned long data)
|
||||||
|
#else
|
||||||
|
static void gpio_timer_cb(struct timer_list *t)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
gpio_set_value(gpio_out, !gpio_get_value(gpio_out));
|
||||||
|
mod_timer(>e.timer, jiffies + msecs_to_jiffies(5000));
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t tegra_gte_test_gpio_isr(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct tegra_gte_ev_detail hts;
|
||||||
|
struct tegra_gte_test *gte = data;
|
||||||
|
|
||||||
|
if (tegra_gte_retrieve_event((gte->data_gpio), &hts) != 0) {
|
||||||
|
pr_info("No timestamp available\n");
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("GPIO HW Timestamp: raw %llu, ns %llu\n",
|
||||||
|
hts.ts_raw, hts.ts_ns);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init tegra_gte_test_init(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (gpio_out == -EINVAL || gpio_in == -EINVAL || lic_irq == EINVAL) {
|
||||||
|
pr_err("Invalid gpio_out, gpio_in and irq\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gte.data_lic = NULL;
|
||||||
|
gte.data_gpio = NULL;
|
||||||
|
|
||||||
|
ret = gpio_request(gpio_out, "gte_test_gpio_out");
|
||||||
|
if (ret) {
|
||||||
|
pr_err("failed request gpio out\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_direction_output(gpio_out, 0);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("failed to set pin direction\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_gpio_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_request(gpio_in, "gte_test_gpio_in");
|
||||||
|
if (ret) {
|
||||||
|
pr_err("failed to request gpio in\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_gpio_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpio_direction_input(gpio_in);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("failed to set pin direction\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_gpio_in;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IRQ setup */
|
||||||
|
ret = gpio_to_irq(gpio_in);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("failed to map GPIO to IRQ: %d\n", ret);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_gpio_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
gte.gpio_in_irq = ret;
|
||||||
|
|
||||||
|
ret = request_irq(ret, tegra_gte_test_gpio_isr,
|
||||||
|
IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
|
||||||
|
"tegra_gte_test_isr", >e);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("failed to acquire IRQ\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_gpio_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tegra_gte_test_sysfs_create();
|
||||||
|
if (ret != 0) {
|
||||||
|
pr_err("sysfs creation failed\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
|
||||||
|
setup_timer(>e.timer, gpio_timer_cb, 0);
|
||||||
|
#else
|
||||||
|
timer_setup(>e.timer, gpio_timer_cb, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mod_timer(>e.timer, jiffies + msecs_to_jiffies(5000));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_irq:
|
||||||
|
free_irq(gte.gpio_in_irq, >e);
|
||||||
|
free_gpio_in:
|
||||||
|
gpio_free(gpio_in);
|
||||||
|
free_gpio_out:
|
||||||
|
gpio_free(gpio_out);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit tegra_gte_test_exit(void)
|
||||||
|
{
|
||||||
|
free_irq(gte.gpio_in_irq, >e);
|
||||||
|
gpio_free(gpio_in);
|
||||||
|
gpio_free(gpio_out);
|
||||||
|
tegra_gte_unregister_event(gte.data_gpio);
|
||||||
|
tegra_gte_unregister_event(gte.data_lic);
|
||||||
|
kobject_put(gte.kobj);
|
||||||
|
del_timer(>e.timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(tegra_gte_test_init);
|
||||||
|
module_exit(tegra_gte_test_exit);
|
||||||
|
MODULE_AUTHOR("Dipen Patel <dipenp@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NVIDIA Tegra GTE driver test");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
* Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES.All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LINUX_TEGRA_GTE_ENGINE_H
|
#ifndef _TEGRA_GTE_H
|
||||||
#define _LINUX_TEGRA_GTE_ENGINE_H
|
#define _TEGRA_GTE_H
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
|
||||||
@@ -21,7 +22,6 @@ struct tegra_gte_ev_detail {
|
|||||||
int dir; /* direction of the event */
|
int dir; /* direction of the event */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_TEGRA_HTS_GTE
|
|
||||||
/*
|
/*
|
||||||
* GTE event registration function
|
* GTE event registration function
|
||||||
*
|
*
|
||||||
@@ -74,23 +74,4 @@ int tegra_gte_unregister_event(struct tegra_gte_ev_desc *desc);
|
|||||||
int tegra_gte_retrieve_event(const struct tegra_gte_ev_desc *desc,
|
int tegra_gte_retrieve_event(const struct tegra_gte_ev_desc *desc,
|
||||||
struct tegra_gte_ev_detail *hts);
|
struct tegra_gte_ev_detail *hts);
|
||||||
|
|
||||||
#else /* ! CONFIG_TEGRA_HTS_GTE */
|
|
||||||
static inline struct tegra_gte_ev_desc *tegra_gte_register_event(
|
|
||||||
struct device_node *np, u32 ev_id)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int tegra_gte_unregister_event(struct tegra_gte_ev_desc *desc)
|
|
||||||
{
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int tegra_gte_retrieve_event(const struct tegra_gte_ev_desc *desc,
|
|
||||||
struct tegra_gte_ev_detail *hts)
|
|
||||||
{
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* ! CONFIG_TEGRA_HTS_GTE */
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
54
include/uapi/linux/tegra-gte-ioctl.h
Normal file
54
include/uapi/linux/tegra-gte-ioctl.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES.All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TEGRA_GTE_IOCTL_H
|
||||||
|
#define _TEGRA_GTE_IOCTL_H
|
||||||
|
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPIO event types
|
||||||
|
*/
|
||||||
|
#define TEGRA_GTE_EVENT_RISING_EDGE 0x1
|
||||||
|
#define TEGRA_GTE_EVENT_FALLING_EDGE 0x2
|
||||||
|
#define TEGRA_GTE_EVENT_REQ_BOTH_EDGES (TEGRA_GTE_EVENT_RISING_EDGE | \
|
||||||
|
TEGRA_GTE_EVENT_FALLING_EDGE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a GPIO event request
|
||||||
|
* @global_gpio_pin: global gpio pin number to monitor event
|
||||||
|
* @eventflags: desired flags for the desired GPIO event line, such as
|
||||||
|
* EVENT_RISING_EDGE or EVENT_FALLING_EDGE
|
||||||
|
* @fd: if successful this field will contain a valid anonymous file handle
|
||||||
|
* after a HTS_CREATE_GPIO_EVENT_IOCTL operation, zero or negative value
|
||||||
|
* means error
|
||||||
|
*/
|
||||||
|
struct tegra_gte_hts_event_req {
|
||||||
|
__u32 global_gpio_pin;
|
||||||
|
__u32 eventflags;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hts_event_data - event data
|
||||||
|
* @timestamp: hardware timestamp in nanosecond
|
||||||
|
* @dir: direction of the event
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct tegra_gte_hts_event_data {
|
||||||
|
__u64 timestamp;
|
||||||
|
int dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event request IOCTL command
|
||||||
|
*/
|
||||||
|
#define TEGRA_GTE_HTS_CREATE_GPIO_EV_IOCTL \
|
||||||
|
_IOWR(0xB5, 0x0, \
|
||||||
|
struct tegra_gte_hts_event_req)
|
||||||
|
|
||||||
|
#endif
|
||||||
162
tools/tegra-gte/tegra_gte_mon.c
Normal file
162
tools/tegra-gte/tegra_gte_mon.c
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES.All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tegra_gte_mon - monitor GPIO line events from userspace and hardware
|
||||||
|
* timestamp.
|
||||||
|
*
|
||||||
|
* Example Usage:
|
||||||
|
* tegra_gte_mon -d <device> -g <global gpio pin> -r -f
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <linux/tegra-gte-ioctl.h>
|
||||||
|
|
||||||
|
int monitor_device(const char *device_name,
|
||||||
|
unsigned int gnum,
|
||||||
|
unsigned int eventflags,
|
||||||
|
unsigned int loops)
|
||||||
|
{
|
||||||
|
struct tegra_gte_hts_event_req req = {0};
|
||||||
|
struct tegra_gte_hts_event_data event;
|
||||||
|
char *chrdev_name;
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
ret = asprintf(&chrdev_name, "/dev/%s", device_name);
|
||||||
|
if (ret < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fd = open(chrdev_name, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
ret = -errno;
|
||||||
|
perror("Error: ");
|
||||||
|
goto exit_close_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.global_gpio_pin = gnum;
|
||||||
|
req.eventflags = eventflags;
|
||||||
|
|
||||||
|
ret = ioctl(fd, TEGRA_GTE_HTS_CREATE_GPIO_EV_IOCTL, &req);
|
||||||
|
if (ret == -1) {
|
||||||
|
ret = -errno;
|
||||||
|
fprintf(stderr, "Failed to issue GET EVENT "
|
||||||
|
"IOCTL (%d)\n",
|
||||||
|
ret);
|
||||||
|
goto exit_close_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "Monitoring line %d on %s\n", gnum, device_name);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
ret = read(req.fd, &event, sizeof(event));
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno == -EAGAIN) {
|
||||||
|
fprintf(stderr, "nothing available\n");
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
ret = -errno;
|
||||||
|
fprintf(stderr, "Failed to read event (%d)\n",
|
||||||
|
ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != sizeof(event)) {
|
||||||
|
fprintf(stderr, "Reading event failed\n");
|
||||||
|
ret = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "HW timestamp GPIO EVENT %" PRIu64 "\n",
|
||||||
|
event.timestamp);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
if (i == loops)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_close_error:
|
||||||
|
if (close(fd) == -1)
|
||||||
|
perror("Failed to close GPIO character device file");
|
||||||
|
free(chrdev_name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_usage(char *bin_name)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s [options]...\n"
|
||||||
|
"Listen to events on GPIO lines, 0->1 1->0\n"
|
||||||
|
" -d <name> Listen using named HW ts engine device\n"
|
||||||
|
" -g <n> GPIO global id\n"
|
||||||
|
" -r Listen for rising edges\n"
|
||||||
|
" -f Listen for falling edges\n"
|
||||||
|
" [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
|
||||||
|
" -h This helptext\n"
|
||||||
|
"\n"
|
||||||
|
"Example:\n"
|
||||||
|
"%s -d gtechip0 -g 257 -r -f\n"
|
||||||
|
"(means GPIO 257 rising and falling edge monitoring)\n",
|
||||||
|
bin_name, bin_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
const char *device_name = NULL;
|
||||||
|
unsigned int gnum = -1;
|
||||||
|
unsigned int loops = 0;
|
||||||
|
unsigned int eventflags = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "c:g:d:rfh")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'c':
|
||||||
|
loops = strtoul(optarg, NULL, 10);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
device_name = optarg;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
gnum = strtoul(optarg, NULL, 10);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
eventflags |= TEGRA_GTE_EVENT_RISING_EDGE;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
eventflags |= TEGRA_GTE_EVENT_FALLING_EDGE;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_name || gnum == -1) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eventflags) {
|
||||||
|
printf("No flags specified, listening on both rising and "
|
||||||
|
"falling edges\n");
|
||||||
|
eventflags = TEGRA_GTE_EVENT_REQ_BOTH_EDGES;
|
||||||
|
}
|
||||||
|
return monitor_device(device_name, gnum, eventflags, loops);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user