mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
dpll: add Embedded SYNC feature for a pin
Implement and document new pin attributes for providing Embedded SYNC capabilities to the DPLL subsystem users through a netlink pin-get do/dump messages. Allow the user to set Embedded SYNC frequency with pin-set do netlink message. Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Link: https://patch.msgid.link/20240822222513.255179-2-arkadiusz.kubalewski@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
2c163922de
commit
cda1fba15c
@ -214,6 +214,27 @@ offset values are fractional with 3-digit decimal places and shell be
|
|||||||
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
|
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
|
||||||
modulo divided to get fractional part.
|
modulo divided to get fractional part.
|
||||||
|
|
||||||
|
Embedded SYNC
|
||||||
|
=============
|
||||||
|
|
||||||
|
Device may provide ability to use Embedded SYNC feature. It allows
|
||||||
|
to embed additional SYNC signal into the base frequency of a pin - a one
|
||||||
|
special pulse of base frequency signal every time SYNC signal pulse
|
||||||
|
happens. The user can configure the frequency of Embedded SYNC.
|
||||||
|
The Embedded SYNC capability is always related to a given base frequency
|
||||||
|
and HW capabilities. The user is provided a range of Embedded SYNC
|
||||||
|
frequencies supported, depending on current base frequency configured for
|
||||||
|
the pin.
|
||||||
|
|
||||||
|
========================================= =================================
|
||||||
|
``DPLL_A_PIN_ESYNC_FREQUENCY`` current Embedded SYNC frequency
|
||||||
|
``DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED`` nest available Embedded SYNC
|
||||||
|
frequency ranges
|
||||||
|
``DPLL_A_PIN_FREQUENCY_MIN`` attr minimum value of frequency
|
||||||
|
``DPLL_A_PIN_FREQUENCY_MAX`` attr maximum value of frequency
|
||||||
|
``DPLL_A_PIN_ESYNC_PULSE`` pulse type of Embedded SYNC
|
||||||
|
========================================= =================================
|
||||||
|
|
||||||
Configuration commands group
|
Configuration commands group
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
@ -345,6 +345,26 @@ attribute-sets:
|
|||||||
Value is in PPM (parts per million).
|
Value is in PPM (parts per million).
|
||||||
This may be implemented for example for pin of type
|
This may be implemented for example for pin of type
|
||||||
PIN_TYPE_SYNCE_ETH_PORT.
|
PIN_TYPE_SYNCE_ETH_PORT.
|
||||||
|
-
|
||||||
|
name: esync-frequency
|
||||||
|
type: u64
|
||||||
|
doc: |
|
||||||
|
Frequency of Embedded SYNC signal. If provided, the pin is configured
|
||||||
|
with a SYNC signal embedded into its base clock frequency.
|
||||||
|
-
|
||||||
|
name: esync-frequency-supported
|
||||||
|
type: nest
|
||||||
|
multi-attr: true
|
||||||
|
nested-attributes: frequency-range
|
||||||
|
doc: |
|
||||||
|
If provided a pin is capable of embedding a SYNC signal (within given
|
||||||
|
range) into its base frequency signal.
|
||||||
|
-
|
||||||
|
name: esync-pulse
|
||||||
|
type: u32
|
||||||
|
doc: |
|
||||||
|
A ratio of high to low state of a SYNC signal pulse embedded
|
||||||
|
into base clock frequency. Value is in percents.
|
||||||
-
|
-
|
||||||
name: pin-parent-device
|
name: pin-parent-device
|
||||||
subset-of: pin
|
subset-of: pin
|
||||||
@ -510,6 +530,9 @@ operations:
|
|||||||
- phase-adjust-max
|
- phase-adjust-max
|
||||||
- phase-adjust
|
- phase-adjust
|
||||||
- fractional-frequency-offset
|
- fractional-frequency-offset
|
||||||
|
- esync-frequency
|
||||||
|
- esync-frequency-supported
|
||||||
|
- esync-pulse
|
||||||
|
|
||||||
dump:
|
dump:
|
||||||
request:
|
request:
|
||||||
@ -536,6 +559,7 @@ operations:
|
|||||||
- parent-device
|
- parent-device
|
||||||
- parent-pin
|
- parent-pin
|
||||||
- phase-adjust
|
- phase-adjust
|
||||||
|
- esync-frequency
|
||||||
-
|
-
|
||||||
name: pin-create-ntf
|
name: pin-create-ntf
|
||||||
doc: Notification about pin appearing
|
doc: Notification about pin appearing
|
||||||
|
@ -342,6 +342,51 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dpll_msg_add_pin_esync(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;
|
||||||
|
struct dpll_pin_esync esync;
|
||||||
|
struct nlattr *nest;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
if (!ops->esync_get)
|
||||||
|
return 0;
|
||||||
|
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||||
|
dpll_priv(dpll), &esync, extack);
|
||||||
|
if (ret == -EOPNOTSUPP)
|
||||||
|
return 0;
|
||||||
|
else if (ret)
|
||||||
|
return ret;
|
||||||
|
if (nla_put_64bit(msg, DPLL_A_PIN_ESYNC_FREQUENCY, sizeof(esync.freq),
|
||||||
|
&esync.freq, DPLL_A_PIN_PAD))
|
||||||
|
return -EMSGSIZE;
|
||||||
|
if (nla_put_u32(msg, DPLL_A_PIN_ESYNC_PULSE, esync.pulse))
|
||||||
|
return -EMSGSIZE;
|
||||||
|
for (i = 0; i < esync.range_num; i++) {
|
||||||
|
nest = nla_nest_start(msg,
|
||||||
|
DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED);
|
||||||
|
if (!nest)
|
||||||
|
return -EMSGSIZE;
|
||||||
|
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN,
|
||||||
|
sizeof(esync.range[i].min),
|
||||||
|
&esync.range[i].min, DPLL_A_PIN_PAD))
|
||||||
|
goto nest_cancel;
|
||||||
|
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX,
|
||||||
|
sizeof(esync.range[i].max),
|
||||||
|
&esync.range[i].max, DPLL_A_PIN_PAD))
|
||||||
|
goto nest_cancel;
|
||||||
|
nla_nest_end(msg, nest);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nest_cancel:
|
||||||
|
nla_nest_cancel(msg, nest);
|
||||||
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
|
static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
|
||||||
{
|
{
|
||||||
int fs;
|
int fs;
|
||||||
@ -481,6 +526,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = dpll_msg_add_ffo(msg, pin, ref, extack);
|
ret = dpll_msg_add_ffo(msg, pin, ref, extack);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = dpll_msg_add_pin_esync(msg, pin, ref, extack);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (xa_empty(&pin->parent_refs))
|
if (xa_empty(&pin->parent_refs))
|
||||||
@ -738,6 +786,83 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
struct dpll_pin_ref *ref, *failed;
|
||||||
|
const struct dpll_pin_ops *ops;
|
||||||
|
struct dpll_pin_esync esync;
|
||||||
|
u64 freq = nla_get_u64(a);
|
||||||
|
struct dpll_device *dpll;
|
||||||
|
bool supported = false;
|
||||||
|
unsigned long i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||||
|
ops = dpll_pin_ops(ref);
|
||||||
|
if (!ops->esync_set || !ops->esync_get) {
|
||||||
|
NL_SET_ERR_MSG(extack,
|
||||||
|
"embedded sync feature is not supported by this device");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
|
||||||
|
ops = dpll_pin_ops(ref);
|
||||||
|
dpll = ref->dpll;
|
||||||
|
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
|
||||||
|
dpll_priv(dpll), &esync, extack);
|
||||||
|
if (ret) {
|
||||||
|
NL_SET_ERR_MSG(extack, "unable to get current embedded sync frequency value");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (freq == esync.freq)
|
||||||
|
return 0;
|
||||||
|
for (i = 0; i < esync.range_num; i++)
|
||||||
|
if (freq <= esync.range[i].max && freq >= esync.range[i].min)
|
||||||
|
supported = true;
|
||||||
|
if (!supported) {
|
||||||
|
NL_SET_ERR_MSG_ATTR(extack, a,
|
||||||
|
"requested embedded sync frequency value is not supported by this device");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||||
|
void *pin_dpll_priv;
|
||||||
|
|
||||||
|
ops = dpll_pin_ops(ref);
|
||||||
|
dpll = ref->dpll;
|
||||||
|
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||||
|
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
|
||||||
|
freq, extack);
|
||||||
|
if (ret) {
|
||||||
|
failed = ref;
|
||||||
|
NL_SET_ERR_MSG_FMT(extack,
|
||||||
|
"embedded sync frequency set failed for dpll_id: %u",
|
||||||
|
dpll->id);
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__dpll_pin_change_ntf(pin);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rollback:
|
||||||
|
xa_for_each(&pin->dpll_refs, i, ref) {
|
||||||
|
void *pin_dpll_priv;
|
||||||
|
|
||||||
|
if (ref == failed)
|
||||||
|
break;
|
||||||
|
ops = dpll_pin_ops(ref);
|
||||||
|
dpll = ref->dpll;
|
||||||
|
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||||
|
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
|
||||||
|
esync.freq, extack))
|
||||||
|
NL_SET_ERR_MSG(extack, "set embedded sync frequency rollback failed");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
|
dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
|
||||||
enum dpll_pin_state state,
|
enum dpll_pin_state state,
|
||||||
@ -1039,6 +1164,11 @@ dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
break;
|
||||||
|
case DPLL_A_PIN_ESYNC_FREQUENCY:
|
||||||
|
ret = dpll_pin_esync_set(pin, a, info->extack);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* DPLL_CMD_PIN_SET - do */
|
/* DPLL_CMD_PIN_SET - do */
|
||||||
static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1] = {
|
static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_ESYNC_FREQUENCY + 1] = {
|
||||||
[DPLL_A_PIN_ID] = { .type = NLA_U32, },
|
[DPLL_A_PIN_ID] = { .type = NLA_U32, },
|
||||||
[DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, },
|
[DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, },
|
||||||
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
|
[DPLL_A_PIN_DIRECTION] = NLA_POLICY_RANGE(NLA_U32, 1, 2),
|
||||||
@ -71,6 +71,7 @@ static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST +
|
|||||||
[DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy),
|
[DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy),
|
||||||
[DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy),
|
[DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy),
|
||||||
[DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, },
|
[DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, },
|
||||||
|
[DPLL_A_PIN_ESYNC_FREQUENCY] = { .type = NLA_U64, },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Ops table for dpll */
|
/* Ops table for dpll */
|
||||||
@ -138,7 +139,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
|
|||||||
.doit = dpll_nl_pin_set_doit,
|
.doit = dpll_nl_pin_set_doit,
|
||||||
.post_doit = dpll_pin_post_doit,
|
.post_doit = dpll_pin_post_doit,
|
||||||
.policy = dpll_pin_set_nl_policy,
|
.policy = dpll_pin_set_nl_policy,
|
||||||
.maxattr = DPLL_A_PIN_PHASE_ADJUST,
|
.maxattr = DPLL_A_PIN_ESYNC_FREQUENCY,
|
||||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
struct dpll_device;
|
struct dpll_device;
|
||||||
struct dpll_pin;
|
struct dpll_pin;
|
||||||
|
struct dpll_pin_esync;
|
||||||
|
|
||||||
struct dpll_device_ops {
|
struct dpll_device_ops {
|
||||||
int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv,
|
int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv,
|
||||||
@ -83,6 +84,13 @@ struct dpll_pin_ops {
|
|||||||
int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
|
int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
|
||||||
const struct dpll_device *dpll, void *dpll_priv,
|
const struct dpll_device *dpll, void *dpll_priv,
|
||||||
s64 *ffo, struct netlink_ext_ack *extack);
|
s64 *ffo, struct netlink_ext_ack *extack);
|
||||||
|
int (*esync_set)(const struct dpll_pin *pin, void *pin_priv,
|
||||||
|
const struct dpll_device *dpll, void *dpll_priv,
|
||||||
|
u64 freq, struct netlink_ext_ack *extack);
|
||||||
|
int (*esync_get)(const struct dpll_pin *pin, void *pin_priv,
|
||||||
|
const struct dpll_device *dpll, void *dpll_priv,
|
||||||
|
struct dpll_pin_esync *esync,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dpll_pin_frequency {
|
struct dpll_pin_frequency {
|
||||||
@ -111,6 +119,13 @@ struct dpll_pin_phase_adjust_range {
|
|||||||
s32 max;
|
s32 max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dpll_pin_esync {
|
||||||
|
u64 freq;
|
||||||
|
const struct dpll_pin_frequency *range;
|
||||||
|
u8 range_num;
|
||||||
|
u8 pulse;
|
||||||
|
};
|
||||||
|
|
||||||
struct dpll_pin_properties {
|
struct dpll_pin_properties {
|
||||||
const char *board_label;
|
const char *board_label;
|
||||||
const char *panel_label;
|
const char *panel_label;
|
||||||
|
@ -210,6 +210,9 @@ enum dpll_a_pin {
|
|||||||
DPLL_A_PIN_PHASE_ADJUST,
|
DPLL_A_PIN_PHASE_ADJUST,
|
||||||
DPLL_A_PIN_PHASE_OFFSET,
|
DPLL_A_PIN_PHASE_OFFSET,
|
||||||
DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
|
DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
|
||||||
|
DPLL_A_PIN_ESYNC_FREQUENCY,
|
||||||
|
DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED,
|
||||||
|
DPLL_A_PIN_ESYNC_PULSE,
|
||||||
|
|
||||||
__DPLL_A_PIN_MAX,
|
__DPLL_A_PIN_MAX,
|
||||||
DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)
|
DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user