This patch series introduces new subsystem called hardware timestamping
engine (HTE). It offers functionality such as timestamping through hardware
means in realtime. The HTE subsystem centralizes HTE provider and consumers
where providers can register themselves and the consumers can request
interested entity which could be lines, GPIO, signals or buses. The
HTE subsystem provides timestamp in nano seconds, having said that the provider
need to convert the timestamp if its not in that unit. There was upstream
discussion about the HTE at
https://lore.kernel.org/lkml/[email protected]/
To summarize upstream discussion:
- It was suggested by Linus and Kent to extend GPIOLIB and supporting
GPIO drivers to add HTE functionality and I agreed to experiment with it.
This patch series implements and extends GPIOLIB, GPIOLIB-CDEV and GPIO tegra
driver.
- Discussed possibility to add HTE provider as irqchip instead which
was argued against as HTE devices are not necessarily event emitting
devices. From RFC version 2 however, emulated threaded irq style
implementation.
- Discussed other possibility if HTE device can be added as posix clock
type like PTP clocks. That was argued against since HTE devices
are not necessarily tightly coupled with hardware clock.
Typical HTE provider does following:
- Register itself with HTE subsystem
- Provide request, release, enable, disable timestamp and
clock source info callbacks to HTE subsystem.
- Provide optional xlate callback to the subsystem which can translate
consumer provided logical ids into actual ids of the entity, where entity here
is the provider dependent and could be GPIO, in chip lines or signals, buses
etc...This converted id is used as communication token between HTE subsystem
and the provider.
- Push timestamps to the subsystem.
- Unregister itself on exit.
Typical HTE consumer does following:
- Initializes line attributes.
- Obtains HTE descriptor.
- Request interested entity it wishes to timestamp in realtime to the
subsystem.
- The subsystem does necessary communications with the provider to
complete the request, which includes translating logical id of the entity to
provider dependent physical/actual id and enabling hardware timestamping on
requested id.
- The request includes callbacks, it will be used to push timestamps.
Optionally, the consumer can provided threaded callback, if specified, the HTE
subsystem uses workqueue executing the secondary callback.
- Release entity and its resources.
HTE and GPIOLIB:
- For the HTE provider which can timestamp GPIO lines.
- For the userspace GPIO consumers, the GPIOLIB CDEV framework are extended as
a frontend to the HTE. The kernel space consumers request GPIO lines directly
to HTE subsystem.
- Tegra194 AON GPIO controller has HTE support known as GTE
(Generic Timestamping Engine). The tegra gpio driver is modified to accommodate
HTE functionality.
Changes in V2:
- Removed buffer management and related APIs from the HTE core.
- Removed timestamp retrieve APIs from the HTE core.
- Modified request API with two callbacks, second callback is invoked in thread
context and is optional, while first callback is mandatory and used to push
timestamp data to consumers.
- Replaced hte with hardware-timestamping in DT bindings as hte appeared too
short according to review comments.
Changes in V3:
- Corrected grammatical errors in HTE documentation and its bindings documents.
- Removed multi-plural words in the HTE DT bindings.
- Reflected changes done in DT bindings in the respective source codes.
- Separated previous patch 07 into two patches in this series as 07 and 08.
- Corrections in MAINTAINERS file.
Changes in V4:
- Removed hardware-timestamp-engine device tree property from gpio.txt.
- Added hte_req_ts_by_linedata_ns.
- Removed hte_req_ts_by_hte_name.
- Renamed devm_of_hte_request_ts to devm_of_hte_request_ts_ns.
- Corrected hte ts seqeunce counter handling in hte related code in
gpiolib-cdev code.
- Added line level detection in Tegra GPIO HTE provider.
- Corrected GPIO line level calculation in gpiolib-cdev.
Changes in V5:
- Minor changes in dt-bindings.
- Removed kernel thread in the HTE core.
Changes in V6:
- Changes in dt-bindings.
- Added APIs in HTE core.
- Merged tegra HTE test drivers.
There are patches pending to add HTE provider for another Nvidia Tegra chip
which will be pushed after this patch set.
Dipen Patel (10):
Documentation: Add HTE subsystem guide
drivers: Add hardware timestamp engine (HTE)
hte: Add tegra194 HTE kernel provider
dt-bindings: Add HTE bindings
gpiolib: Add HTE support
gpio: tegra186: Add HTE in gpio-tegra186 driver
gpiolib: cdev: Add hardware timestamp clock type
tools: gpio: Add new hardware clock type
hte: Add tegra HTE test driver
MAINTAINERS: Added HTE Subsystem
.../hte/hardware-timestamps-common.yaml | 29 +
.../devicetree/bindings/hte/hte-consumer.yaml | 39 +
.../bindings/hte/nvidia,tegra194-hte.yaml | 88 ++
Documentation/hte/hte.rst | 77 ++
Documentation/hte/index.rst | 22 +
Documentation/hte/tegra194-hte.rst | 47 +
Documentation/index.rst | 1 +
MAINTAINERS | 8 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/gpio/gpio-tegra186.c | 81 +-
drivers/gpio/gpiolib-cdev.c | 252 ++++-
drivers/gpio/gpiolib.c | 58 ++
drivers/gpio/gpiolib.h | 1 +
drivers/hte/Kconfig | 33 +
drivers/hte/Makefile | 3 +
drivers/hte/hte-tegra194-test.c | 239 +++++
drivers/hte/hte-tegra194.c | 730 ++++++++++++++
drivers/hte/hte.c | 948 ++++++++++++++++++
include/linux/gpio/consumer.h | 16 +-
include/linux/gpio/driver.h | 10 +
include/linux/hte.h | 272 +++++
include/uapi/linux/gpio.h | 3 +
tools/gpio/gpio-event-mon.c | 6 +-
24 files changed, 2929 insertions(+), 37 deletions(-)
create mode 100644 Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
create mode 100644 Documentation/devicetree/bindings/hte/hte-consumer.yaml
create mode 100644 Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
create mode 100644 Documentation/hte/hte.rst
create mode 100644 Documentation/hte/index.rst
create mode 100644 Documentation/hte/tegra194-hte.rst
create mode 100644 drivers/hte/Kconfig
create mode 100644 drivers/hte/Makefile
create mode 100644 drivers/hte/hte-tegra194-test.c
create mode 100644 drivers/hte/hte-tegra194.c
create mode 100644 drivers/hte/hte.c
create mode 100644 include/linux/hte.h
base-commit: c2528a0cdebd8ba7ef30e0655f8ea89f34c3a633
--
2.17.1
This patch adds new clock type for the GPIO controller which can
timestamp gpio lines in using hardware means. To expose such
functionalities to the userspace, code has been added where
during line create or set config API calls, it checks for new
clock type and if requested, calls HTE API. During line change
event, the HTE subsystem pushes timestamp data to userspace
through gpiolib-cdev.
Signed-off-by: Dipen Patel <[email protected]>
Acked-by: Linus Walleij <[email protected]>
Reported-by: kernel test robot <[email protected]>
Reported-by: Dan Carpenter <[email protected]>
---
Changes in v2:
- Added hte_dir and static structure hte_ts_desc.
- Added callbacks which get invoked by HTE when new data is available.
- Better use of hte_dir and seq from hte_ts_desc.
- Modified sw debounce function to accommodate hardware timestamping.
Changes in v4:
- Correced line level and event sequence counter handling.
- Added hte edge setup functionality.
Changes in v6:
- Added code to line init and get hte descriptor before making hte request.
drivers/gpio/gpiolib-cdev.c | 252 +++++++++++++++++++++++++++++++-----
include/uapi/linux/gpio.h | 3 +
2 files changed, 222 insertions(+), 33 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index ffa0256cad5a..2f224394e9e7 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -24,6 +24,7 @@
#include <linux/timekeeping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
+#include <linux/hte.h>
#include <uapi/linux/gpio.h>
#include "gpiolib.h"
@@ -464,6 +465,25 @@ struct line {
* stale value.
*/
unsigned int level;
+ /*
+ * -- hte specific fields --
+ */
+ struct hte_ts_desc hdesc;
+ /*
+ * HTE provider sets line level at the time of event. The valid
+ * value is 0 or 1 and negative value for an error.
+ */
+ int raw_level;
+ /*
+ * when sw_debounce is set on HTE enabled line, this is running
+ * counter of the discarded events.
+ */
+ u32 total_discard_seq;
+ /*
+ * when sw_debounce is set on HTE enabled line, this variable records
+ * last sequence number before debounce period expires.
+ */
+ u32 last_seqno;
};
/**
@@ -518,6 +538,7 @@ struct linereq {
GPIO_V2_LINE_DRIVE_FLAGS | \
GPIO_V2_LINE_EDGE_FLAGS | \
GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \
+ GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
GPIO_V2_LINE_BIAS_FLAGS)
static void linereq_put_event(struct linereq *lr,
@@ -542,10 +563,98 @@ static u64 line_event_timestamp(struct line *line)
{
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags))
return ktime_get_real_ns();
+ else if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))
+ return line->timestamp_ns;
return ktime_get_ns();
}
+static hte_return_t process_hw_ts_thread(void *p)
+{
+ struct line *line;
+ struct linereq *lr;
+ struct gpio_v2_line_event le;
+ int level;
+ u64 eflags;
+
+ if (!p)
+ return HTE_CB_HANDLED;
+
+ line = p;
+ lr = line->req;
+
+ memset(&le, 0, sizeof(le));
+
+ le.timestamp_ns = line->timestamp_ns;
+ eflags = READ_ONCE(line->eflags);
+
+ if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
+ if (line->raw_level >= 0) {
+ if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags))
+ level = !line->raw_level;
+ else
+ level = line->raw_level;
+ } else {
+ level = gpiod_get_value_cansleep(line->desc);
+ }
+
+ if (level)
+ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
+ else
+ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
+ } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
+ /* Emit low-to-high event */
+ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
+ } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
+ /* Emit high-to-low event */
+ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
+ } else {
+ return HTE_CB_HANDLED;
+ }
+ le.line_seqno = line->line_seqno;
+ le.seqno = (lr->num_lines == 1) ? le.line_seqno : line->req_seqno;
+ le.offset = gpio_chip_hwgpio(line->desc);
+
+ linereq_put_event(lr, &le);
+
+ return HTE_CB_HANDLED;
+}
+
+static hte_return_t process_hw_ts(struct hte_ts_data *ts, void *p)
+{
+ struct line *line;
+ struct linereq *lr;
+ int diff_seqno = 0;
+
+ if (!ts || !p)
+ return HTE_CB_HANDLED;
+
+ line = p;
+ line->timestamp_ns = ts->tsc;
+ line->raw_level = ts->raw_level;
+ lr = line->req;
+
+ if (READ_ONCE(line->sw_debounced)) {
+ line->total_discard_seq++;
+ line->last_seqno = ts->seq;
+ mod_delayed_work(system_wq, &line->work,
+ usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us)));
+ } else {
+ if (unlikely(ts->seq < line->line_seqno))
+ return HTE_CB_HANDLED;
+
+ diff_seqno = ts->seq - line->line_seqno;
+ line->line_seqno = ts->seq;
+ if (lr->num_lines != 1)
+ line->req_seqno = atomic_add_return(diff_seqno,
+ &lr->seqno);
+
+ return HTE_RUN_SECOND_CB;
+ }
+
+ return HTE_CB_HANDLED;
+}
+
static irqreturn_t edge_irq_thread(int irq, void *p)
{
struct line *line = p;
@@ -651,10 +760,16 @@ static void debounce_work_func(struct work_struct *work)
struct gpio_v2_line_event le;
struct line *line = container_of(work, struct line, work.work);
struct linereq *lr;
- int level;
+ int level, diff_seqno;
u64 eflags;
- level = gpiod_get_raw_value_cansleep(line->desc);
+ if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) {
+ level = line->raw_level;
+ if (level < 0)
+ level = gpiod_get_raw_value_cansleep(line->desc);
+ } else {
+ level = gpiod_get_raw_value_cansleep(line->desc);
+ }
if (level < 0) {
pr_debug_ratelimited("debouncer failed to read line value\n");
return;
@@ -685,10 +800,21 @@ static void debounce_work_func(struct work_struct *work)
lr = line->req;
le.timestamp_ns = line_event_timestamp(line);
le.offset = gpio_chip_hwgpio(line->desc);
- line->line_seqno++;
- le.line_seqno = line->line_seqno;
- le.seqno = (lr->num_lines == 1) ?
- le.line_seqno : atomic_inc_return(&lr->seqno);
+ if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) {
+ /* discard events except the last one */
+ line->total_discard_seq -= 1;
+ diff_seqno = line->last_seqno - line->total_discard_seq -
+ line->line_seqno;
+ line->line_seqno = line->last_seqno - line->total_discard_seq;
+ le.line_seqno = line->line_seqno;
+ le.seqno = (lr->num_lines == 1) ?
+ le.line_seqno : atomic_add_return(diff_seqno, &lr->seqno);
+ } else {
+ line->line_seqno++;
+ le.line_seqno = line->line_seqno;
+ le.seqno = (lr->num_lines == 1) ?
+ le.line_seqno : atomic_inc_return(&lr->seqno);
+ }
if (level)
/* Emit low-to-high event */
@@ -700,8 +826,34 @@ static void debounce_work_func(struct work_struct *work)
linereq_put_event(lr, &le);
}
+static int hte_edge_setup(struct line *line, u64 eflags)
+{
+ int ret;
+ unsigned long flags = 0;
+ struct hte_ts_desc *hdesc = &line->hdesc;
+
+ if (eflags & GPIO_V2_LINE_FLAG_EDGE_RISING)
+ flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
+ HTE_FALLING_EDGE_TS : HTE_RISING_EDGE_TS;
+ if (eflags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
+ flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
+ HTE_RISING_EDGE_TS : HTE_FALLING_EDGE_TS;
+
+ line->total_discard_seq = 0;
+
+ hte_init_line_attr(hdesc, desc_to_gpio(line->desc), flags,
+ NULL, line->desc);
+
+ ret = hte_ts_get(NULL, hdesc, 0);
+ if (ret)
+ return ret;
+
+ return hte_request_ts_ns(hdesc, process_hw_ts,
+ process_hw_ts_thread, line);
+}
+
static int debounce_setup(struct line *line,
- unsigned int debounce_period_us)
+ unsigned int debounce_period_us, bool hte_req)
{
unsigned long irqflags;
int ret, level, irq;
@@ -721,19 +873,27 @@ static int debounce_setup(struct line *line,
if (level < 0)
return level;
- irq = gpiod_to_irq(line->desc);
- if (irq < 0)
- return -ENXIO;
+ if (!hte_req) {
+ irq = gpiod_to_irq(line->desc);
+ if (irq < 0)
+ return -ENXIO;
- WRITE_ONCE(line->level, level);
- irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
- ret = request_irq(irq, debounce_irq_handler, irqflags,
- line->req->label, line);
- if (ret)
- return ret;
+ irqflags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+ ret = request_irq(irq, debounce_irq_handler, irqflags,
+ line->req->label, line);
+ if (ret)
+ return ret;
+ line->irq = irq;
+ } else {
+ ret = hte_edge_setup(line,
+ GPIO_V2_LINE_FLAG_EDGE_RISING |
+ GPIO_V2_LINE_FLAG_EDGE_FALLING);
+ if (ret)
+ return ret;
+ }
+ WRITE_ONCE(line->level, level);
WRITE_ONCE(line->sw_debounced, 1);
- line->irq = irq;
}
return 0;
}
@@ -766,13 +926,16 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc,
return 0;
}
-static void edge_detector_stop(struct line *line)
+static void edge_detector_stop(struct line *line, bool hte_en)
{
- if (line->irq) {
+ if (line->irq && !hte_en) {
free_irq(line->irq, line);
line->irq = 0;
}
+ if (hte_en)
+ hte_ts_put(&line->hdesc);
+
cancel_delayed_work_sync(&line->work);
WRITE_ONCE(line->sw_debounced, 0);
WRITE_ONCE(line->eflags, 0);
@@ -784,7 +947,7 @@ static void edge_detector_stop(struct line *line)
static int edge_detector_setup(struct line *line,
struct gpio_v2_line_config *lc,
unsigned int line_idx,
- u64 eflags)
+ u64 eflags, bool hte_req)
{
u32 debounce_period_us;
unsigned long irqflags = 0;
@@ -799,7 +962,7 @@ static int edge_detector_setup(struct line *line,
WRITE_ONCE(line->eflags, eflags);
if (gpio_v2_line_config_debounced(lc, line_idx)) {
debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx);
- ret = debounce_setup(line, debounce_period_us);
+ ret = debounce_setup(line, debounce_period_us, hte_req);
if (ret)
return ret;
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
@@ -809,6 +972,9 @@ static int edge_detector_setup(struct line *line,
if (!eflags || READ_ONCE(line->sw_debounced))
return 0;
+ if (hte_req)
+ return hte_edge_setup(line, eflags);
+
irq = gpiod_to_irq(line->desc);
if (irq < 0)
return -ENXIO;
@@ -834,13 +1000,18 @@ static int edge_detector_setup(struct line *line,
static int edge_detector_update(struct line *line,
struct gpio_v2_line_config *lc,
unsigned int line_idx,
- u64 eflags, bool polarity_change)
+ u64 flags, bool polarity_change,
+ bool prev_hte_flag)
{
+ u64 eflags = flags & GPIO_V2_LINE_EDGE_FLAGS;
unsigned int debounce_period_us =
- gpio_v2_line_config_debounce_period(lc, line_idx);
+ gpio_v2_line_config_debounce_period(lc, line_idx);
+ bool hte_change = (prev_hte_flag !=
+ ((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) != 0));
if ((READ_ONCE(line->eflags) == eflags) && !polarity_change &&
- (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us))
+ (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)
+ && !hte_change)
return 0;
/* sw debounced and still will be...*/
@@ -851,11 +1022,12 @@ static int edge_detector_update(struct line *line,
}
/* reconfiguring edge detection or sw debounce being disabled */
- if ((line->irq && !READ_ONCE(line->sw_debounced)) ||
+ if ((line->irq && !READ_ONCE(line->sw_debounced)) || prev_hte_flag ||
(!debounce_period_us && READ_ONCE(line->sw_debounced)))
- edge_detector_stop(line);
+ edge_detector_stop(line, prev_hte_flag);
- return edge_detector_setup(line, lc, line_idx, eflags);
+ return edge_detector_setup(line, lc, line_idx, eflags,
+ flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE);
}
static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc,
@@ -891,7 +1063,6 @@ static int gpio_v2_line_flags_validate(u64 flags)
/* Return an error if an unknown flag is set */
if (flags & ~GPIO_V2_LINE_VALID_FLAGS)
return -EINVAL;
-
/*
* Do not allow both INPUT and OUTPUT flags to be set as they are
* contradictory.
@@ -900,6 +1071,11 @@ static int gpio_v2_line_flags_validate(u64 flags)
(flags & GPIO_V2_LINE_FLAG_OUTPUT))
return -EINVAL;
+ /* Only allow one event clock source */
+ if ((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME) &&
+ (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
+ return -EINVAL;
+
/* Edge detection requires explicit input. */
if ((flags & GPIO_V2_LINE_EDGE_FLAGS) &&
!(flags & GPIO_V2_LINE_FLAG_INPUT))
@@ -992,6 +1168,8 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 flags,
assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp,
flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME);
+ assign_bit(FLAG_EVENT_CLOCK_HTE, flagsp,
+ flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE);
}
static long linereq_get_values(struct linereq *lr, void __user *ip)
@@ -1121,6 +1299,7 @@ static long linereq_set_config_unlocked(struct linereq *lr,
unsigned int i;
u64 flags;
bool polarity_change;
+ bool prev_hte_flag;
int ret;
for (i = 0; i < lr->num_lines; i++) {
@@ -1130,6 +1309,8 @@ static long linereq_set_config_unlocked(struct linereq *lr,
(!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) !=
((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0));
+ prev_hte_flag = !!test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags);
+
gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags);
/*
* Lines have to be requested explicitly for input
@@ -1138,7 +1319,7 @@ static long linereq_set_config_unlocked(struct linereq *lr,
if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
int val = gpio_v2_line_config_output_value(lc, i);
- edge_detector_stop(&lr->lines[i]);
+ edge_detector_stop(&lr->lines[i], prev_hte_flag);
ret = gpiod_direction_output(desc, val);
if (ret)
return ret;
@@ -1148,8 +1329,7 @@ static long linereq_set_config_unlocked(struct linereq *lr,
return ret;
ret = edge_detector_update(&lr->lines[i], lc, i,
- flags & GPIO_V2_LINE_EDGE_FLAGS,
- polarity_change);
+ flags, polarity_change, prev_hte_flag);
if (ret)
return ret;
}
@@ -1278,9 +1458,12 @@ static ssize_t linereq_read(struct file *file,
static void linereq_free(struct linereq *lr)
{
unsigned int i;
+ bool hte;
for (i = 0; i < lr->num_lines; i++) {
- edge_detector_stop(&lr->lines[i]);
+ hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
+ &lr->lines[i].desc->flags);
+ edge_detector_stop(&lr->lines[i], hte);
if (lr->lines[i].desc)
gpiod_free(lr->lines[i].desc);
}
@@ -1406,7 +1589,8 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
goto out_free_linereq;
ret = edge_detector_setup(&lr->lines[i], lc, i,
- flags & GPIO_V2_LINE_EDGE_FLAGS);
+ flags & GPIO_V2_LINE_EDGE_FLAGS,
+ flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE);
if (ret)
goto out_free_linereq;
}
@@ -1959,6 +2143,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags))
info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
+ else if (test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags))
+ info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE;
debounce_period_us = READ_ONCE(desc->debounce_period_us);
if (debounce_period_us) {
diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h
index eaaea3d8e6b4..cb9966d49a16 100644
--- a/include/uapi/linux/gpio.h
+++ b/include/uapi/linux/gpio.h
@@ -66,6 +66,8 @@ struct gpiochip_info {
* @GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN: line has pull-down bias enabled
* @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled
* @GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME: line events contain REALTIME timestamps
+ * @GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE: line events contain timestamps from
+ * hardware timestamp engine
*/
enum gpio_v2_line_flag {
GPIO_V2_LINE_FLAG_USED = _BITULL(0),
@@ -80,6 +82,7 @@ enum gpio_v2_line_flag {
GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN = _BITULL(9),
GPIO_V2_LINE_FLAG_BIAS_DISABLED = _BITULL(10),
GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME = _BITULL(11),
+ GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE = _BITULL(12),
};
/**
--
2.17.1
Introduces HTE devicetree binding details for the HTE subsystem. It
includes examples for the consumers, binding details for the providers
and specific binding details for the Tegra194 based HTE providers.
Signed-off-by: Dipen Patel <[email protected]>
Reviewed-by: Linus Walleij <[email protected]>
---
Changes in v2:
- Replace hte with hardware-timestamp for property names
- Renamed file
- Removed example from the common dt binding file.
Changes in v3:
- Addressed grammatical errors.
- Removed double plural from the respective properties.
- Added dual license.
- Prefixed "nvidia" in nvidia specific properties.
Changes in v4:
- Corrected make dt_binding_check error.
Changes in v5:
- Addressed review comments.
Changes in v6:
- Removed hardware prefix from the property as per review comments.
.../hte/hardware-timestamps-common.yaml | 29 ++++++
.../devicetree/bindings/hte/hte-consumer.yaml | 39 ++++++++
.../bindings/hte/nvidia,tegra194-hte.yaml | 88 +++++++++++++++++++
3 files changed, 156 insertions(+)
create mode 100644 Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
create mode 100644 Documentation/devicetree/bindings/hte/hte-consumer.yaml
create mode 100644 Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
diff --git a/Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml b/Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
new file mode 100644
index 000000000000..3e26de605f08
--- /dev/null
+++ b/Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hte/hardware-timestamps-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Hardware timestamp providers
+
+maintainers:
+ - Dipen Patel <[email protected]>
+
+description:
+ Some devices/SoCs have hardware time stamping engines which can use hardware
+ means to timestamp entity in realtime. The entity could be anything from
+ GPIOs, IRQs, Bus and so on. The hardware timestamp engine (HTE) present
+ itself as a provider with the bindings described in this document.
+
+properties:
+ $nodename:
+ pattern: "^timestamp(@.*|-[0-9a-f])?$"
+
+ "#timestamp-cells":
+ description:
+ Number of cells in a HTE specifier.
+
+required:
+ - "#timestamp-cells"
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/hte/hte-consumer.yaml b/Documentation/devicetree/bindings/hte/hte-consumer.yaml
new file mode 100644
index 000000000000..68d764ac040a
--- /dev/null
+++ b/Documentation/devicetree/bindings/hte/hte-consumer.yaml
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hte/hte-consumer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HTE Consumer Device Tree Bindings
+
+maintainers:
+ - Dipen Patel <[email protected]>
+
+select: true
+
+properties:
+ timestamps:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ The list of HTE provider phandle. The first cell must represent the
+ provider phandle followed by the line identifiers. The meaning of the
+ line identifier and exact number of arguments must be specified in the
+ HTE provider device tree binding document.
+
+ timestamp-names:
+ $ref: /schemas/types.yaml#/definitions/string-array
+ description:
+ An optional string property to label each line specifier present in the
+ timestamp property.
+
+dependencies:
+ timestamp-names: [ timestamps ]
+
+additionalProperties: true
+
+examples:
+ - |
+ hte_tegra_consumer {
+ timestamps = <&tegra_hte_aon 0x9>, <&tegra_hte_lic 0x19>;
+ timestamp-names = "hte-gpio", "hte-i2c";
+ };
diff --git a/Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml b/Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
new file mode 100644
index 000000000000..69e8402d95e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hte/nvidia,tegra194-hte.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra194 on chip generic hardware timestamping engine (HTE)
+
+maintainers:
+ - Dipen Patel <[email protected]>
+
+description:
+ Tegra SoC has two instances of generic hardware timestamping engines (GTE)
+ known as GTE GPIO and GTE IRQ, which can monitor subset of GPIO and on chip
+ IRQ lines for the state change respectively, upon detection it will record
+ timestamp (taken from system counter) in its internal hardware FIFO. It has
+ a bitmap array arranged in 32bit slices where each bit represent signal/line
+ to enable or disable for the hardware timestamping. The GTE GPIO monitors
+ GPIO lines from the AON (always on) GPIO controller.
+
+properties:
+ compatible:
+ enum:
+ - nvidia,tegra194-gte-aon
+ - nvidia,tegra194-gte-lic
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ nvidia,int-threshold:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ HTE device generates its interrupt based on this u32 FIFO threshold
+ value. The recommended value is 1.
+ minimum: 1
+ maximum: 256
+
+ nvidia,slices:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ HTE 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 depends on the HTE instance in the chip. The value 3 is for
+ GPIO GTE and 11 for IRQ GTE.
+ enum: [3, 11]
+
+ '#timestamp-cells':
+ description:
+ This represents number of line id arguments as specified by the
+ consumers. For the GTE IRQ, this is IRQ number as mentioned in the
+ SoC technical reference manual. For the GTE GPIO, its value is same as
+ mentioned in the nvidia GPIO device tree binding document.
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - nvidia,slices
+ - "#timestamp-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ tegra_hte_aon: timestamp@c1e0000 {
+ compatible = "nvidia,tegra194-gte-aon";
+ reg = <0xc1e0000 0x10000>;
+ interrupts = <0 13 0x4>;
+ nvidia,int-threshold = <1>;
+ nvidia,slices = <3>;
+ #timestamp-cells = <1>;
+ };
+
+ - |
+ tegra_hte_lic: timestamp@3aa0000 {
+ compatible = "nvidia,tegra194-gte-lic";
+ reg = <0x3aa0000 0x10000>;
+ interrupts = <0 11 0x4>;
+ nvidia,int-threshold = <1>;
+ nvidia,slices = <11>;
+ #timestamp-cells = <1>;
+ };
+
+...
--
2.17.1
Tegra194 device has multiple HTE instances also known as GTE
(Generic hardware Timestamping Engine) which can timestamp subset of
SoC lines/signals. This provider driver focuses on IRQ and GPIO lines
and exposes timestamping ability on those lines to the consumers
through HTE subsystem.
Also, with this patch, added:
- documentation about this provider and its capabilities at
Documentation/hte.
- Compilation support in Makefile and Kconfig
Signed-off-by: Dipen Patel <[email protected]>
Reported-by: kernel test robot <[email protected]>
---
Changes in v3:
- Addressed grammatical/spelling errors.
Changes in v4:
- Added gpio line level detection.
- Added edge setup for GPIO lines if requested.
- Added match_from_linedata callback to help hte_req_ts_by_linedata_ns
HTE API.
Changes in v6:
- Added xlate_plat support.
- Added secondary mapping of the GPIO lines to GTE namespace.
Documentation/hte/index.rst | 22 +
Documentation/hte/tegra194-hte.rst | 47 ++
Documentation/index.rst | 1 +
drivers/hte/Kconfig | 12 +
drivers/hte/Makefile | 1 +
drivers/hte/hte-tegra194.c | 730 +++++++++++++++++++++++++++++
6 files changed, 813 insertions(+)
create mode 100644 Documentation/hte/index.rst
create mode 100644 Documentation/hte/tegra194-hte.rst
create mode 100644 drivers/hte/hte-tegra194.c
diff --git a/Documentation/hte/index.rst b/Documentation/hte/index.rst
new file mode 100644
index 000000000000..9f43301c05dc
--- /dev/null
+++ b/Documentation/hte/index.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============================================
+The Linux Hardware Timestamping Engine (HTE)
+============================================
+
+The HTE Subsystem
+=================
+
+.. toctree::
+ :maxdepth: 1
+
+ hte
+
+HTE Tegra Provider
+==================
+
+.. toctree::
+ :maxdepth: 1
+
+ tegra194-hte
+
diff --git a/Documentation/hte/tegra194-hte.rst b/Documentation/hte/tegra194-hte.rst
new file mode 100644
index 000000000000..4037b1c8224a
--- /dev/null
+++ b/Documentation/hte/tegra194-hte.rst
@@ -0,0 +1,47 @@
+HTE Kernel provider driver
+==========================
+
+Description
+-----------
+The Nvidia tegra194 HTE provider driver implements two GTE
+(Generic Timestamping Engine) instances: 1) GPIO GTE and 2) LIC
+(Legacy Interrupt Controller) IRQ GTE. Both GTE instances get the
+timestamp from the system counter TSC which has 31.25MHz clock rate, and the
+driver converts clock tick rate to nanoseconds before storing it as timestamp
+value.
+
+GPIO GTE
+--------
+
+This GTE instance timestamps GPIO in real time. For that to happen GPIO
+needs to be configured as input. The always on (AON) GPIO controller instance
+supports timestamping GPIOs in real time and it has 39 GPIO lines. The GPIO GTE
+and AON GPIO controller are tightly coupled as it requires very specific bits
+to be set in GPIO config register before GPIO GTE can be used, for that GPIOLIB
+adds two optional APIs as below. The GPIO GTE code supports both kernel
+and userspace consumers. The kernel space consumers can directly talk to HTE
+subsystem while userspace consumers timestamp requests go through GPIOLIB CDEV
+framework to HTE subsystem.
+
+.. kernel-doc:: drivers/gpio/gpiolib.c
+ :functions: gpiod_enable_hw_timestamp_ns gpiod_disable_hw_timestamp_ns
+
+For userspace consumers, GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE flag must be
+specified during IOCTL calls. Refer to ``tools/gpio/gpio-event-mon.c``, which
+returns the timestamp in nanoseconds.
+
+LIC (Legacy Interrupt Controller) IRQ GTE
+-----------------------------------------
+
+This GTE instance timestamps LIC IRQ lines in real time. There are 352 IRQ
+lines which this instance can add timestamps to in real time. The hte
+devicetree binding described at ``Documentation/devicetree/bindings/hte/``
+provides an example of how a consumer can request an IRQ line. Since it is a
+one-to-one mapping with IRQ GTE provider, consumers can simply specify the IRQ
+number that they are interested in. There is no userspace consumer support for
+this GTE instance in the HTE framework.
+
+The provider source code of both IRQ and GPIO GTE instances is located at
+``drivers/hte/hte-tegra194.c``. The test driver
+``drivers/hte/hte-tegra194-test.c`` demonstrates HTE API usage for both IRQ
+and GPIO GTE.
diff --git a/Documentation/index.rst b/Documentation/index.rst
index ee639a500278..90eaf47e5214 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -140,6 +140,7 @@ needed).
mhi/index
tty/index
peci/index
+ hte/index
Architecture-agnostic documentation
-----------------------------------
diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig
index 478a80a2f384..3bd0fa367e84 100644
--- a/drivers/hte/Kconfig
+++ b/drivers/hte/Kconfig
@@ -12,3 +12,15 @@ menuconfig HTE
If unsure, say no.
+if HTE
+
+config HTE_TEGRA194
+ tristate "NVIDIA Tegra194 HTE Support"
+ depends on ARCH_TEGRA_194_SOC
+ help
+ Enable this option for integrated hardware timestamping engine also
+ known as generic timestamping engine (GTE) support on NVIDIA Tegra194
+ systems-on-chip. The driver supports 352 LIC IRQs and 39 AON GPIOs
+ lines for timestamping in realtime.
+
+endif
diff --git a/drivers/hte/Makefile b/drivers/hte/Makefile
index fc03bdf44427..3ae7c4029991 100644
--- a/drivers/hte/Makefile
+++ b/drivers/hte/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_HTE) += hte.o
+obj-$(CONFIG_HTE_TEGRA194) += hte-tegra194.o
diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c
new file mode 100644
index 000000000000..6765f07e5adb
--- /dev/null
+++ b/drivers/hte/hte-tegra194.c
@@ -0,0 +1,730 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021-2022 NVIDIA Corporation
+ *
+ * Author: Dipen Patel <[email protected]>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/hte.h>
+#include <linux/uaccess.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/consumer.h>
+
+#define HTE_SUSPEND 0
+
+/* HTE source clock TSC is 31.25MHz */
+#define HTE_TS_CLK_RATE_HZ 31250000ULL
+#define HTE_CLK_RATE_NS 32
+#define HTE_TS_NS_SHIFT __builtin_ctz(HTE_CLK_RATE_NS)
+
+#define NV_AON_SLICE_INVALID -1
+#define NV_LINES_IN_SLICE 32
+
+/* AON HTE line map For slice 1 */
+#define NV_AON_HTE_SLICE1_IRQ_GPIO_28 12
+#define NV_AON_HTE_SLICE1_IRQ_GPIO_29 13
+
+/* AON HTE line map For slice 2 */
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_0 0
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_1 1
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_2 2
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_3 3
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_4 4
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_5 5
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_6 6
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_7 7
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_8 8
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_9 9
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_10 10
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_11 11
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_12 12
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_13 13
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_14 14
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_15 15
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_16 16
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_17 17
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_18 18
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_19 19
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_20 20
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_21 21
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_22 22
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_23 23
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_24 24
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_25 25
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_26 26
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_27 27
+
+#define HTE_TECTRL 0x0
+#define HTE_TETSCH 0x4
+#define HTE_TETSCL 0x8
+#define HTE_TESRC 0xC
+#define HTE_TECCV 0x10
+#define HTE_TEPCV 0x14
+#define HTE_TECMD 0x1C
+#define HTE_TESTATUS 0x20
+#define HTE_SLICE0_TETEN 0x40
+#define HTE_SLICE1_TETEN 0x60
+
+#define HTE_SLICE_SIZE (HTE_SLICE1_TETEN - HTE_SLICE0_TETEN)
+
+#define HTE_TECTRL_ENABLE_ENABLE 0x1
+
+#define HTE_TECTRL_OCCU_SHIFT 0x8
+#define HTE_TECTRL_INTR_SHIFT 0x1
+#define HTE_TECTRL_INTR_ENABLE 0x1
+
+#define HTE_TESRC_SLICE_SHIFT 16
+#define HTE_TESRC_SLICE_DEFAULT_MASK 0xFF
+
+#define HTE_TECMD_CMD_POP 0x1
+
+#define HTE_TESTATUS_OCCUPANCY_SHIFT 8
+#define HTE_TESTATUS_OCCUPANCY_MASK 0xFF
+
+enum tegra_hte_type {
+ HTE_TEGRA_TYPE_GPIO = 1U << 0,
+ HTE_TEGRA_TYPE_LIC = 1U << 1,
+};
+
+struct hte_slices {
+ u32 r_val;
+ unsigned long flags;
+ /* to prevent lines mapped to same slice updating its register */
+ spinlock_t s_lock;
+};
+
+struct tegra_hte_line_mapped {
+ int slice;
+ u32 bit_index;
+};
+
+struct tegra_hte_line_data {
+ unsigned long flags;
+ void *data;
+};
+
+struct tegra_hte_data {
+ enum tegra_hte_type type;
+ u32 map_sz;
+ u32 sec_map_sz;
+ const struct tegra_hte_line_mapped *map;
+ const struct tegra_hte_line_mapped *sec_map;
+};
+
+struct tegra_hte_soc {
+ int hte_irq;
+ u32 itr_thrshld;
+ u32 conf_rval;
+ struct hte_slices *sl;
+ const struct tegra_hte_data *prov_data;
+ struct tegra_hte_line_data *line_data;
+ struct hte_chip *chip;
+ struct gpio_chip *c;
+ void __iomem *regs;
+};
+
+static const struct tegra_hte_line_mapped tegra194_aon_gpio_map[] = {
+ /* gpio, slice, bit_index */
+ /* AA port */
+ [0] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_11},
+ [1] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_10},
+ [2] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_9},
+ [3] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_8},
+ [4] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_7},
+ [5] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_6},
+ [6] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_5},
+ [7] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_4},
+ /* BB port */
+ [8] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_3},
+ [9] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_2},
+ [10] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_1},
+ [11] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_0},
+ /* CC port */
+ [12] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_22},
+ [13] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_21},
+ [14] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_20},
+ [15] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_19},
+ [16] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_18},
+ [17] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_17},
+ [18] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_16},
+ [19] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_15},
+ /* DD port */
+ [20] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_14},
+ [21] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_13},
+ [22] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_12},
+ /* EE port */
+ [23] = {1, NV_AON_HTE_SLICE1_IRQ_GPIO_29},
+ [24] = {1, NV_AON_HTE_SLICE1_IRQ_GPIO_28},
+ [25] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_27},
+ [26] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_26},
+ [27] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_25},
+ [28] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_24},
+ [29] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_23},
+};
+
+static const struct tegra_hte_line_mapped tegra194_aon_gpio_sec_map[] = {
+ /* gpio, slice, bit_index */
+ /* AA port */
+ [0] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_11},
+ [1] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_10},
+ [2] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_9},
+ [3] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_8},
+ [4] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_7},
+ [5] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_6},
+ [6] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_5},
+ [7] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_4},
+ /* BB port */
+ [8] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_3},
+ [9] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_2},
+ [10] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_1},
+ [11] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_0},
+ [12] = {NV_AON_SLICE_INVALID, 0},
+ [13] = {NV_AON_SLICE_INVALID, 0},
+ [14] = {NV_AON_SLICE_INVALID, 0},
+ [15] = {NV_AON_SLICE_INVALID, 0},
+ /* CC port */
+ [16] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_22},
+ [17] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_21},
+ [18] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_20},
+ [19] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_19},
+ [20] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_18},
+ [21] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_17},
+ [22] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_16},
+ [23] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_15},
+ /* DD port */
+ [24] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_14},
+ [25] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_13},
+ [26] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_12},
+ [27] = {NV_AON_SLICE_INVALID, 0},
+ [28] = {NV_AON_SLICE_INVALID, 0},
+ [29] = {NV_AON_SLICE_INVALID, 0},
+ [30] = {NV_AON_SLICE_INVALID, 0},
+ [31] = {NV_AON_SLICE_INVALID, 0},
+ /* EE port */
+ [32] = {1, NV_AON_HTE_SLICE1_IRQ_GPIO_29},
+ [33] = {1, NV_AON_HTE_SLICE1_IRQ_GPIO_28},
+ [34] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_27},
+ [35] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_26},
+ [36] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_25},
+ [37] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_24},
+ [38] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_23},
+ [39] = {NV_AON_SLICE_INVALID, 0},
+};
+
+static const struct tegra_hte_data aon_hte = {
+ .map_sz = ARRAY_SIZE(tegra194_aon_gpio_map),
+ .map = tegra194_aon_gpio_map,
+ .sec_map_sz = ARRAY_SIZE(tegra194_aon_gpio_sec_map),
+ .sec_map = tegra194_aon_gpio_sec_map,
+ .type = HTE_TEGRA_TYPE_GPIO,
+};
+
+static const struct tegra_hte_data lic_hte = {
+ .map_sz = 0,
+ .map = NULL,
+ .type = HTE_TEGRA_TYPE_LIC,
+};
+
+static inline u32 tegra_hte_readl(struct tegra_hte_soc *hte, u32 reg)
+{
+ return readl(hte->regs + reg);
+}
+
+static inline void tegra_hte_writel(struct tegra_hte_soc *hte, u32 reg,
+ u32 val)
+{
+ writel(val, hte->regs + reg);
+}
+
+static int tegra_hte_map_to_line_id(u32 eid,
+ const struct tegra_hte_line_mapped *m,
+ u32 map_sz, u32 *mapped)
+{
+
+ if (m) {
+ if (eid > map_sz)
+ return -EINVAL;
+ if (m[eid].slice == NV_AON_SLICE_INVALID)
+ return -EINVAL;
+
+ *mapped = (m[eid].slice << 5) + m[eid].bit_index;
+ } else {
+ *mapped = eid;
+ }
+
+ return 0;
+}
+
+static int tegra_hte_line_xlate(struct hte_chip *gc,
+ const struct of_phandle_args *args,
+ struct hte_ts_desc *desc, u32 *xlated_id)
+{
+ int ret = 0;
+ u32 line_id;
+ struct tegra_hte_soc *gs;
+ const struct tegra_hte_line_mapped *map = NULL;
+ u32 map_sz = 0;
+
+ if (!gc || !desc || !xlated_id)
+ return -EINVAL;
+
+ if (args) {
+ if (gc->of_hte_n_cells < 1)
+ return -EINVAL;
+
+ if (args->args_count != gc->of_hte_n_cells)
+ return -EINVAL;
+
+ desc->attr.line_id = args->args[0];
+ }
+
+ gs = gc->data;
+ if (!gs || !gs->prov_data)
+ return -EINVAL;
+
+ /*
+ *
+ * There are two paths GPIO consumers can take as follows:
+ * 1) The consumer (gpiolib-cdev for example) which uses GPIO global
+ * number which gets assigned run time.
+ * 2) The consumer passing GPIO from the DT which is assigned
+ * statically for example by using TEGRA194_AON_GPIO gpio DT binding.
+ *
+ * The code below addresses both the consumer use cases and maps into
+ * HTE/GTE namespace.
+ */
+ if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO && !args) {
+ line_id = desc->attr.line_id - gs->c->base;
+ map = gs->prov_data->map;
+ map_sz = gs->prov_data->map_sz;
+ } else if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO && args) {
+ line_id = desc->attr.line_id;
+ map = gs->prov_data->sec_map;
+ map_sz = gs->prov_data->sec_map_sz;
+ } else {
+ line_id = desc->attr.line_id;
+ }
+
+ ret = tegra_hte_map_to_line_id(line_id, map, map_sz, xlated_id);
+ if (ret < 0) {
+ dev_err(gc->dev, "line_id:%u mapping failed\n",
+ desc->attr.line_id);
+ return ret;
+ }
+
+ if (*xlated_id > gc->nlines)
+ return -EINVAL;
+
+ dev_dbg(gc->dev, "requested id:%u, xlated id:%u\n",
+ desc->attr.line_id, *xlated_id);
+
+ return 0;
+}
+
+static int tegra_hte_line_xlate_plat(struct hte_chip *gc,
+ struct hte_ts_desc *desc, u32 *xlated_id)
+{
+ return tegra_hte_line_xlate(gc, NULL, desc, xlated_id);
+}
+
+static int tegra_hte_en_dis_common(struct hte_chip *chip, u32 line_id, bool en)
+{
+ u32 slice, sl_bit_shift, line_bit, val, reg;
+ struct tegra_hte_soc *gs;
+
+ sl_bit_shift = __builtin_ctz(HTE_SLICE_SIZE);
+
+ if (!chip)
+ return -EINVAL;
+
+ gs = chip->data;
+
+ if (line_id > chip->nlines) {
+ dev_err(chip->dev,
+ "line id: %u is not supported by this controller\n",
+ line_id);
+ return -EINVAL;
+ }
+
+ slice = line_id >> sl_bit_shift;
+ line_bit = line_id & (HTE_SLICE_SIZE - 1);
+ reg = (slice << sl_bit_shift) + HTE_SLICE0_TETEN;
+
+ spin_lock(&gs->sl[slice].s_lock);
+
+ if (test_bit(HTE_SUSPEND, &gs->sl[slice].flags)) {
+ spin_unlock(&gs->sl[slice].s_lock);
+ dev_dbg(chip->dev, "device suspended");
+ return -EBUSY;
+ }
+
+ val = tegra_hte_readl(gs, reg);
+ if (en)
+ val = val | (1 << line_bit);
+ else
+ val = val & (~(1 << line_bit));
+ tegra_hte_writel(gs, reg, val);
+
+ spin_unlock(&gs->sl[slice].s_lock);
+
+ dev_dbg(chip->dev, "line: %u, slice %u, line_bit %u, reg:0x%x\n",
+ line_id, slice, line_bit, reg);
+
+ return 0;
+}
+
+static int tegra_hte_enable(struct hte_chip *chip, u32 line_id)
+{
+ if (!chip)
+ return -EINVAL;
+
+ return tegra_hte_en_dis_common(chip, line_id, true);
+}
+
+static int tegra_hte_disable(struct hte_chip *chip, u32 line_id)
+{
+ if (!chip)
+ return -EINVAL;
+
+ return tegra_hte_en_dis_common(chip, line_id, false);
+}
+
+static int tegra_hte_request(struct hte_chip *chip, struct hte_ts_desc *desc,
+ u32 line_id)
+{
+ int ret;
+ struct tegra_hte_soc *gs;
+ struct hte_line_attr *attr;
+
+ if (!chip || !chip->data || !desc)
+ return -EINVAL;
+
+ gs = chip->data;
+ attr = &desc->attr;
+
+ if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO) {
+ if (!attr->line_data)
+ return -EINVAL;
+
+ ret = gpiod_enable_hw_timestamp_ns(attr->line_data,
+ attr->edge_flags);
+ if (ret)
+ return ret;
+
+ gs->line_data[line_id].data = attr->line_data;
+ gs->line_data[line_id].flags = attr->edge_flags;
+ }
+
+ return tegra_hte_en_dis_common(chip, line_id, true);
+}
+
+static int tegra_hte_release(struct hte_chip *chip, struct hte_ts_desc *desc,
+ u32 line_id)
+{
+ struct tegra_hte_soc *gs;
+ struct hte_line_attr *attr;
+ int ret;
+
+ if (!chip || !chip->data || !desc)
+ return -EINVAL;
+
+ gs = chip->data;
+ attr = &desc->attr;
+
+ if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO) {
+ ret = gpiod_disable_hw_timestamp_ns(attr->line_data,
+ gs->line_data[line_id].flags);
+ if (ret)
+ return ret;
+
+ gs->line_data[line_id].data = NULL;
+ gs->line_data[line_id].flags = 0;
+ }
+
+ return tegra_hte_en_dis_common(chip, line_id, false);
+}
+
+static int tegra_hte_clk_src_info(struct hte_chip *chip,
+ struct hte_clk_info *ci)
+{
+ (void)chip;
+
+ if (!ci)
+ return -EINVAL;
+
+ ci->hz = HTE_TS_CLK_RATE_HZ;
+ ci->type = CLOCK_MONOTONIC;
+
+ return 0;
+}
+
+static int tegra_hte_get_level(struct tegra_hte_soc *gs, u32 line_id)
+{
+ struct gpio_desc *desc;
+
+ if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO) {
+ desc = gs->line_data[line_id].data;
+ if (desc)
+ return gpiod_get_raw_value(desc);
+ }
+
+ return -1;
+}
+
+static void tegra_hte_read_fifo(struct tegra_hte_soc *gs)
+{
+ u32 tsh, tsl, src, pv, cv, acv, slice, bit_index, line_id;
+ u64 tsc;
+ struct hte_ts_data el;
+
+ while ((tegra_hte_readl(gs, HTE_TESTATUS) >>
+ HTE_TESTATUS_OCCUPANCY_SHIFT) &
+ HTE_TESTATUS_OCCUPANCY_MASK) {
+ tsh = tegra_hte_readl(gs, HTE_TETSCH);
+ tsl = tegra_hte_readl(gs, HTE_TETSCL);
+ tsc = (((u64)tsh << 32) | tsl);
+
+ src = tegra_hte_readl(gs, HTE_TESRC);
+ slice = (src >> HTE_TESRC_SLICE_SHIFT) &
+ HTE_TESRC_SLICE_DEFAULT_MASK;
+
+ pv = tegra_hte_readl(gs, HTE_TEPCV);
+ cv = tegra_hte_readl(gs, HTE_TECCV);
+ acv = pv ^ cv;
+ while (acv) {
+ bit_index = __builtin_ctz(acv);
+ line_id = bit_index + (slice << 5);
+ el.tsc = tsc << HTE_TS_NS_SHIFT;
+ el.raw_level = tegra_hte_get_level(gs, line_id);
+ hte_push_ts_ns(gs->chip, line_id, &el);
+ acv &= ~BIT(bit_index);
+ }
+ tegra_hte_writel(gs, HTE_TECMD, HTE_TECMD_CMD_POP);
+ }
+}
+
+static irqreturn_t tegra_hte_isr(int irq, void *dev_id)
+{
+ struct tegra_hte_soc *gs = dev_id;
+ (void)irq;
+
+ tegra_hte_read_fifo(gs);
+
+ return IRQ_HANDLED;
+}
+
+static bool tegra_hte_match_from_linedata(const struct hte_chip *chip,
+ const struct hte_ts_desc *hdesc)
+{
+ struct tegra_hte_soc *hte_dev = chip->data;
+
+ if (!hte_dev || (hte_dev->prov_data->type != HTE_TEGRA_TYPE_GPIO))
+ return false;
+
+ return hte_dev->c == gpiod_to_chip(hdesc->attr.line_data);
+}
+
+static const struct of_device_id tegra_hte_of_match[] = {
+ { .compatible = "nvidia,tegra194-gte-lic", .data = &lic_hte},
+ { .compatible = "nvidia,tegra194-gte-aon", .data = &aon_hte},
+ { }
+};
+MODULE_DEVICE_TABLE(of, tegra_hte_of_match);
+
+static const struct hte_ops g_ops = {
+ .request = tegra_hte_request,
+ .release = tegra_hte_release,
+ .enable = tegra_hte_enable,
+ .disable = tegra_hte_disable,
+ .get_clk_src_info = tegra_hte_clk_src_info,
+};
+
+static void tegra_gte_disable(void *data)
+{
+ struct platform_device *pdev = data;
+ struct tegra_hte_soc *gs = dev_get_drvdata(&pdev->dev);
+
+ tegra_hte_writel(gs, HTE_TECTRL, 0);
+}
+
+static int tegra_get_gpiochip_from_name(struct gpio_chip *chip, void *data)
+{
+ return !strcmp(chip->label, data);
+}
+
+static int tegra_hte_probe(struct platform_device *pdev)
+{
+ int ret;
+ u32 i, slices, val = 0;
+ u32 nlines;
+ struct device *dev;
+ struct tegra_hte_soc *hte_dev;
+ struct hte_chip *gc;
+
+ dev = &pdev->dev;
+
+ ret = of_property_read_u32(dev->of_node, "nvidia,slices", &slices);
+ if (ret != 0) {
+ dev_err(dev, "Could not read slices\n");
+ return -EINVAL;
+ }
+ nlines = slices << 5;
+
+ hte_dev = devm_kzalloc(dev, sizeof(*hte_dev), GFP_KERNEL);
+ if (!hte_dev)
+ return -ENOMEM;
+
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, hte_dev);
+ hte_dev->prov_data = of_device_get_match_data(&pdev->dev);
+
+ hte_dev->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(hte_dev->regs))
+ return PTR_ERR(hte_dev->regs);
+
+ ret = of_property_read_u32(dev->of_node, "nvidia,int-threshold",
+ &hte_dev->itr_thrshld);
+ if (ret != 0)
+ hte_dev->itr_thrshld = 1;
+
+ hte_dev->sl = devm_kcalloc(dev, slices, sizeof(*hte_dev->sl),
+ GFP_KERNEL);
+ if (!hte_dev->sl)
+ return -ENOMEM;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "failed to get irq\n");
+ return ret;
+ }
+ hte_dev->hte_irq = ret;
+ ret = devm_request_irq(dev, hte_dev->hte_irq, tegra_hte_isr, 0,
+ dev_name(dev), hte_dev);
+ if (ret < 0) {
+ dev_err(dev, "request irq failed.\n");
+ return ret;
+ }
+
+ gc->nlines = nlines;
+ gc->ops = &g_ops;
+ gc->dev = dev;
+ gc->data = hte_dev;
+ gc->xlate_of = tegra_hte_line_xlate;
+ gc->xlate_plat = tegra_hte_line_xlate_plat;
+ gc->of_hte_n_cells = 1;
+
+ if (hte_dev->prov_data &&
+ hte_dev->prov_data->type == HTE_TEGRA_TYPE_GPIO) {
+ hte_dev->line_data = devm_kcalloc(dev, nlines,
+ sizeof(*hte_dev->line_data),
+ GFP_KERNEL);
+ if (!hte_dev->line_data)
+ return -ENOMEM;
+
+ gc->match_from_linedata = tegra_hte_match_from_linedata;
+
+ hte_dev->c = gpiochip_find("tegra194-gpio-aon",
+ tegra_get_gpiochip_from_name);
+ if (!hte_dev->c)
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "wait for gpio controller\n");
+ }
+
+ hte_dev->chip = gc;
+
+ ret = devm_hte_register_chip(hte_dev->chip);
+ if (ret) {
+ dev_err(gc->dev, "hte chip register failed");
+ return ret;
+ }
+
+ for (i = 0; i < slices; i++) {
+ hte_dev->sl[i].flags = 0;
+ spin_lock_init(&hte_dev->sl[i].s_lock);
+ }
+
+ val = HTE_TECTRL_ENABLE_ENABLE |
+ (HTE_TECTRL_INTR_ENABLE << HTE_TECTRL_INTR_SHIFT) |
+ (hte_dev->itr_thrshld << HTE_TECTRL_OCCU_SHIFT);
+ tegra_hte_writel(hte_dev, HTE_TECTRL, val);
+
+ ret = devm_add_action_or_reset(&pdev->dev, tegra_gte_disable, pdev);
+ if (ret)
+ return ret;
+
+ dev_dbg(gc->dev, "lines: %d, slices:%d", gc->nlines, slices);
+
+ return 0;
+}
+
+static int __maybe_unused tegra_hte_resume_early(struct device *dev)
+{
+ u32 i;
+ struct tegra_hte_soc *gs = dev_get_drvdata(dev);
+ u32 slices = gs->chip->nlines / NV_LINES_IN_SLICE;
+ u32 sl_bit_shift = __builtin_ctz(HTE_SLICE_SIZE);
+
+ tegra_hte_writel(gs, HTE_TECTRL, gs->conf_rval);
+
+ for (i = 0; i < slices; i++) {
+ spin_lock(&gs->sl[i].s_lock);
+ tegra_hte_writel(gs,
+ ((i << sl_bit_shift) + HTE_SLICE0_TETEN),
+ gs->sl[i].r_val);
+ clear_bit(HTE_SUSPEND, &gs->sl[i].flags);
+ spin_unlock(&gs->sl[i].s_lock);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused tegra_hte_suspend_late(struct device *dev)
+{
+ u32 i;
+ struct tegra_hte_soc *gs = dev_get_drvdata(dev);
+ u32 slices = gs->chip->nlines / NV_LINES_IN_SLICE;
+ u32 sl_bit_shift = __builtin_ctz(HTE_SLICE_SIZE);
+
+ gs->conf_rval = tegra_hte_readl(gs, HTE_TECTRL);
+ for (i = 0; i < slices; i++) {
+ spin_lock(&gs->sl[i].s_lock);
+ gs->sl[i].r_val = tegra_hte_readl(gs,
+ ((i << sl_bit_shift) + HTE_SLICE0_TETEN));
+ set_bit(HTE_SUSPEND, &gs->sl[i].flags);
+ spin_unlock(&gs->sl[i].s_lock);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops tegra_hte_pm = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra_hte_suspend_late,
+ tegra_hte_resume_early)
+};
+
+static struct platform_driver tegra_hte_driver = {
+ .probe = tegra_hte_probe,
+ .driver = {
+ .name = "tegra_hte",
+ .pm = &tegra_hte_pm,
+ .of_match_table = tegra_hte_of_match,
+ },
+};
+
+module_platform_driver(tegra_hte_driver);
+
+MODULE_AUTHOR("Dipen Patel <[email protected]>");
+MODULE_DESCRIPTION("NVIDIA Tegra HTE (Hardware Timestamping Engine) driver");
+MODULE_LICENSE("GPL v2");
--
2.17.1
On Fri, Apr 22, 2022 at 01:52:15PM -0700, Dipen Patel wrote:
> Introduces HTE devicetree binding details for the HTE subsystem. It
> includes examples for the consumers, binding details for the providers
> and specific binding details for the Tegra194 based HTE providers.
>
> Signed-off-by: Dipen Patel <[email protected]>
> Reviewed-by: Linus Walleij <[email protected]>
> ---
> Changes in v2:
> - Replace hte with hardware-timestamp for property names
> - Renamed file
> - Removed example from the common dt binding file.
>
> Changes in v3:
> - Addressed grammatical errors.
> - Removed double plural from the respective properties.
> - Added dual license.
> - Prefixed "nvidia" in nvidia specific properties.
>
> Changes in v4:
> - Corrected make dt_binding_check error.
>
> Changes in v5:
> - Addressed review comments.
>
> Changes in v6:
> - Removed hardware prefix from the property as per review comments.
>
> .../hte/hardware-timestamps-common.yaml | 29 ++++++
> .../devicetree/bindings/hte/hte-consumer.yaml | 39 ++++++++
> .../bindings/hte/nvidia,tegra194-hte.yaml | 88 +++++++++++++++++++
> 3 files changed, 156 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
> create mode 100644 Documentation/devicetree/bindings/hte/hte-consumer.yaml
> create mode 100644 Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
'hte' is not obvious what it is, so 'timestamp' for the directory name.
>
> diff --git a/Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml b/Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
> new file mode 100644
> index 000000000000..3e26de605f08
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hte/hardware-timestamps-common.yaml
> @@ -0,0 +1,29 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hte/hardware-timestamps-common.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Hardware timestamp providers
> +
> +maintainers:
> + - Dipen Patel <[email protected]>
> +
> +description:
> + Some devices/SoCs have hardware time stamping engines which can use hardware
> + means to timestamp entity in realtime. The entity could be anything from
> + GPIOs, IRQs, Bus and so on. The hardware timestamp engine (HTE) present
Define HTE at the 1st use, not the 2nd.
> + itself as a provider with the bindings described in this document.
> +
> +properties:
> + $nodename:
> + pattern: "^timestamp(@.*|-[0-9a-f])?$"
> +
> + "#timestamp-cells":
> + description:
> + Number of cells in a HTE specifier.
> +
> +required:
> + - "#timestamp-cells"
> +
> +additionalProperties: true
> diff --git a/Documentation/devicetree/bindings/hte/hte-consumer.yaml b/Documentation/devicetree/bindings/hte/hte-consumer.yaml
> new file mode 100644
> index 000000000000..68d764ac040a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hte/hte-consumer.yaml
> @@ -0,0 +1,39 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hte/hte-consumer.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HTE Consumer Device Tree Bindings
> +
> +maintainers:
> + - Dipen Patel <[email protected]>
> +
> +select: true
> +
> +properties:
> + timestamps:
> + $ref: /schemas/types.yaml#/definitions/phandle-array
> + description:
> + The list of HTE provider phandle. The first cell must represent the
> + provider phandle followed by the line identifiers. The meaning of the
> + line identifier and exact number of arguments must be specified in the
> + HTE provider device tree binding document.
> +
> + timestamp-names:
> + $ref: /schemas/types.yaml#/definitions/string-array
> + description:
> + An optional string property to label each line specifier present in the
> + timestamp property.
> +
> +dependencies:
> + timestamp-names: [ timestamps ]
> +
> +additionalProperties: true
> +
> +examples:
> + - |
> + hte_tegra_consumer {
> + timestamps = <&tegra_hte_aon 0x9>, <&tegra_hte_lic 0x19>;
> + timestamp-names = "hte-gpio", "hte-i2c";
> + };
> diff --git a/Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml b/Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
> new file mode 100644
> index 000000000000..69e8402d95e5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hte/nvidia,tegra194-hte.yaml
> @@ -0,0 +1,88 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hte/nvidia,tegra194-hte.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Tegra194 on chip generic hardware timestamping engine (HTE)
> +
> +maintainers:
> + - Dipen Patel <[email protected]>
> +
> +description:
> + Tegra SoC has two instances of generic hardware timestamping engines (GTE)
> + known as GTE GPIO and GTE IRQ, which can monitor subset of GPIO and on chip
> + IRQ lines for the state change respectively, upon detection it will record
> + timestamp (taken from system counter) in its internal hardware FIFO. It has
> + a bitmap array arranged in 32bit slices where each bit represent signal/line
> + to enable or disable for the hardware timestamping. The GTE GPIO monitors
> + GPIO lines from the AON (always on) GPIO controller.
> +
> +properties:
> + compatible:
> + enum:
> + - nvidia,tegra194-gte-aon
> + - nvidia,tegra194-gte-lic
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + nvidia,int-threshold:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description:
> + HTE device generates its interrupt based on this u32 FIFO threshold
> + value. The recommended value is 1.
> + minimum: 1
> + maximum: 256
> +
> + nvidia,slices:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description:
> + HTE 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 depends on the HTE instance in the chip. The value 3 is for
> + GPIO GTE and 11 for IRQ GTE.
> + enum: [3, 11]
> +
> + '#timestamp-cells':
> + description:
> + This represents number of line id arguments as specified by the
> + consumers. For the GTE IRQ, this is IRQ number as mentioned in the
> + SoC technical reference manual. For the GTE GPIO, its value is same as
> + mentioned in the nvidia GPIO device tree binding document.
> + const: 1
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - nvidia,slices
> + - "#timestamp-cells"
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + tegra_hte_aon: timestamp@c1e0000 {
> + compatible = "nvidia,tegra194-gte-aon";
> + reg = <0xc1e0000 0x10000>;
> + interrupts = <0 13 0x4>;
> + nvidia,int-threshold = <1>;
> + nvidia,slices = <3>;
> + #timestamp-cells = <1>;
> + };
> +
> + - |
> + tegra_hte_lic: timestamp@3aa0000 {
> + compatible = "nvidia,tegra194-gte-lic";
> + reg = <0x3aa0000 0x10000>;
> + interrupts = <0 11 0x4>;
> + nvidia,int-threshold = <1>;
> + nvidia,slices = <11>;
> + #timestamp-cells = <1>;
> + };
> +
> +...
> --
> 2.17.1
>
>