Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion Documentation/driver-api/dpll.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,47 @@ in order to configure active input of a MUX-type pin, the user needs to
request desired pin state of the child pin on the parent pin,
as described in the ``MUX-type pins`` chapter.

Phase offset measurement and adjustment
========================================

Device may provide ability to measure and adjust a signal phase difference
between a pin and its parent dpll device, configurable on pin-dpll tuple.

=============================== ======================================
``DPLL_A_PIN_ID`` configured pin id
``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase adjustment
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase adjustment
``DPLL_A_PIN_PARENT_DEVICE`` nested attribute for requesting
configuration on given parent dpll
device
``DPLL_A_PIN_PARENT_ID`` parent dpll device id
``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
between a pin and parent dpll device
``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
adjustment on parent dpll device
=============================== ======================================

If pin-dpll phase offset measurement is supported, it shall be provided
with ``DPLL_A_PIN_PHASE_OFFSET`` attribute.

If pin-dpll phase adjustment is supported, minimal and maximal values
that are configurable shall be provide to the user on ``DPLL_CMD_PIN_GET``
respond with ``DPLL_A_PIN_PHASE_ADJUST_MIN`` and
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attributes. Configured phase adjust value
is provided with ``DPLL_A_PIN_PHASE_ADJUST`` attribute for each parent
dpll device, and can be requested with the same attribute.

All phase related values are provided in pico seconds, which represents
time differnece between signals phase. The negative value means that
phase of signal on pin is earlier in time than dpll's signal. Positive
value means that phase of signal on pin is later in time than signal of
a dpll.

Phase adjust (also min and max) values are integers, but measured phase
offset values are fractional with 3-digit decimal places and shell be
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
modulo divided to get fractional part.

Configuration commands group
============================

Expand Down Expand Up @@ -263,15 +304,23 @@ according to attribute purpose.
frequencies
``DPLL_A_PIN_ANY_FREQUENCY_MIN`` attr minimum value of frequency
``DPLL_A_PIN_ANY_FREQUENCY_MAX`` attr maximum value of frequency
``DPLL_A_PIN_PHASE_ADJUST_MIN`` attr minimum value of phase
adjustment
``DPLL_A_PIN_PHASE_ADJUST_MAX`` attr maximum value of phase
adjustment
``DPLL_A_PIN_PARENT_DEVICE`` nested attr for each parent device
the pin is connected with
``DPLL_A_PIN_PARENT_ID`` attr parent dpll device id
``DPLL_A_PIN_PRIO`` attr priority of pin on the
dpll device
``DPLL_A_PIN_STATE`` attr state of pin on the parent
dpll device
``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the
``DPLL_A_PIN_DIRECTION`` attr direction of a pin on the
parent dpll device
``DPLL_A_PIN_PHASE_OFFSET`` attr measured phase difference
between a pin and parent dpll
``DPLL_A_PIN_PHASE_ADJUST`` attr configured value of phase
adjustment on parent device
``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
the pin is connected with
``DPLL_A_PIN_PARENT_ID`` attr parent pin id
Expand All @@ -292,6 +341,8 @@ according to attribute purpose.
the dpll device
``DPLL_A_PIN_STATE`` attr requested state of pin on
the dpll device
``DPLL_A_PIN_PHASE_ADJUST`` attr requested value of phase
adjustment on parent device
``DPLL_A_PIN_PARENT_PIN`` nested attr for each parent pin
configuration request
``DPLL_A_PIN_PARENT_ID`` attr parent pin id
Expand Down
34 changes: 33 additions & 1 deletion Documentation/netlink/specs/dpll.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)

name: dpll

version: 2
doc: DPLL subsystem.

definitions:
Expand Down Expand Up @@ -164,6 +164,18 @@ definitions:
-
name: state-can-change
doc: pin state can be changed
-
type: const
name: phase-offset-divider
value: 1000
doc: |
phase offset divider allows userspace to calculate a value of
measured signal phase difference between a pin and dpll device
as a fractional value with three digit decimal precision.
Value of (DPLL_A_PHASE_OFFSET / DPLL_PHASE_OFFSET_DIVIDER) is an
integer part of a measured phase offest value.
Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a
fractional part of a measured phase offest value.

attribute-sets:
-
Expand Down Expand Up @@ -272,6 +284,18 @@ attribute-sets:
type: nest
multi-attr: true
nested-attributes: pin-parent-pin
-
name: phase-adjust-min
type: s32
-
name: phase-adjust-max
type: s32
-
name: phase-offset
type: s64
-
name: phase-adjust
type: s32
-
name: pin-parent-device
subset-of: pin
Expand All @@ -288,6 +312,12 @@ attribute-sets:
-
name: state
type: u32
-
name: phase-offset
type: s64
-
name: phase-adjust
type: s32
-
name: pin-parent-pin
subset-of: pin
Expand Down Expand Up @@ -439,6 +469,8 @@ operations:
- capabilities
- parent-device
- parent-pin
- phase-adjust-min
- phase-adjust-max

dump:
pre: dpll-lock-dumpit
Expand Down
94 changes: 93 additions & 1 deletion drivers/dpll/dpll_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,52 @@ dpll_msg_add_pin_direction(struct sk_buff *msg, struct dpll_pin *pin,
return 0;
}

static int
dpll_msg_add_pin_phase_adjust(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
struct dpll_device *dpll = ref->dpll;
s32 phase_adjust;
int ret;

if (!ops->phase_adjust_get)
return 0;
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
dpll_priv(dpll), &phase_adjust, extack);
if (ret)
return ret;
if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST, phase_adjust))
return -EMSGSIZE;

return 0;
}

static int
dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref,
struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
struct dpll_device *dpll = ref->dpll;
s64 phase_offset;
int ret;

if (!ops->phase_offset_get)
return 0;
ret = ops->phase_offset_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), &phase_offset,
extack);
if (ret)
return ret;
if (nla_put_64bit(msg, DPLL_A_PIN_PHASE_OFFSET, sizeof(phase_offset),
&phase_offset, DPLL_A_PIN_PAD))
return -EMSGSIZE;

return 0;
}

static int
dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
Expand Down Expand Up @@ -330,6 +376,12 @@ dpll_msg_add_pin_dplls(struct sk_buff *msg, struct dpll_pin *pin,
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_direction(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
ret = dpll_msg_add_phase_offset(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack);
if (ret)
goto nest_cancel;
nla_nest_end(msg, attr);
Expand Down Expand Up @@ -376,6 +428,12 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
return -EMSGSIZE;
if (nla_put_u32(msg, DPLL_A_PIN_CAPABILITIES, prop->capabilities))
return -EMSGSIZE;
if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MIN,
prop->phase_range.min))
return -EMSGSIZE;
if (nla_put_s32(msg, DPLL_A_PIN_PHASE_ADJUST_MAX,
prop->phase_range.max))
return -EMSGSIZE;
ret = dpll_msg_add_pin_freq(msg, pin, ref, extack);
if (ret)
return ret;
Expand Down Expand Up @@ -416,7 +474,7 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg,
if (nla_put_u32(msg, DPLL_A_TYPE, dpll->type))
return -EMSGSIZE;

return ret;
return 0;
}

static int
Expand Down Expand Up @@ -705,6 +763,33 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,
return 0;
}

static int
dpll_pin_phase_adj_set(struct dpll_pin *pin, struct dpll_device *dpll,
s32 phase_adj, struct netlink_ext_ack *extack)
{
const struct dpll_pin_ops *ops;
struct dpll_pin_ref *ref;
int ret;

if (phase_adj > pin->prop->phase_range.max ||
phase_adj < pin->prop->phase_range.min) {
NL_SET_ERR_MSG(extack, "phase adjust value not supported");
return -EINVAL;
}
ref = xa_load(&pin->dpll_refs, dpll->id);
ASSERT_NOT_NULL(ref);
ops = dpll_pin_ops(ref);
if (!ops->phase_adjust_set)
return -EOPNOTSUPP;
ret = ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
dpll_priv(dpll), phase_adj, extack);
if (ret)
return ret;
__dpll_pin_change_ntf(pin);

return 0;
}

static int
dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
struct netlink_ext_ack *extack)
Expand All @@ -715,6 +800,7 @@ dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
struct dpll_pin_ref *ref;
struct dpll_device *dpll;
u32 pdpll_idx, prio;
s32 phase_adj;
int ret;

nla_parse_nested(tb, DPLL_A_PIN_MAX, parent_nest,
Expand Down Expand Up @@ -752,6 +838,12 @@ dpll_pin_parent_device_set(struct dpll_pin *pin, struct nlattr *parent_nest,
if (ret)
return ret;
}
if (tb[DPLL_A_PIN_PHASE_ADJUST]) {
phase_adj = nla_get_s32(tb[DPLL_A_PIN_PHASE_ADJUST]);
ret = dpll_pin_phase_adj_set(pin, dpll, phase_adj, extack);
if (ret)
return ret;
}
return 0;
}

Expand Down
4 changes: 3 additions & 1 deletion drivers/dpll/dpll_nl.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
#include <uapi/linux/dpll.h>

/* Common nested types */
const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1] = {
const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1] = {
[DPLL_A_PIN_PARENT_ID] = { .type = NLA_U32, },
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
[DPLL_A_PIN_PRIO] = { .type = NLA_U32, },
[DPLL_A_PIN_STATE] = NLA_POLICY_RANGE(NLA_U32, 1, 3),
[DPLL_A_PIN_PHASE_OFFSET] = { .type = NLA_S64, },
[DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, },
};

const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1] = {
Expand Down
2 changes: 1 addition & 1 deletion drivers/dpll/dpll_nl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include <uapi/linux/dpll.h>

/* Common nested types */
extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_STATE + 1];
extern const struct nla_policy dpll_pin_parent_device_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1];
extern const struct nla_policy dpll_pin_parent_pin_nl_policy[DPLL_A_PIN_STATE + 1];

int dpll_lock_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
Expand Down
Loading