Skip to content

Commit cda1fba

Browse files
kubalewskikuba-moo
authored andcommitted
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 <[email protected]> Signed-off-by: Arkadiusz Kubalewski <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 2c16392 commit cda1fba

File tree

6 files changed

+196
-2
lines changed

6 files changed

+196
-2
lines changed

Documentation/driver-api/dpll.rst

+21
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,27 @@ offset values are fractional with 3-digit decimal places and shell be
214214
divided with ``DPLL_PIN_PHASE_OFFSET_DIVIDER`` to get integer part and
215215
modulo divided to get fractional part.
216216

217+
Embedded SYNC
218+
=============
219+
220+
Device may provide ability to use Embedded SYNC feature. It allows
221+
to embed additional SYNC signal into the base frequency of a pin - a one
222+
special pulse of base frequency signal every time SYNC signal pulse
223+
happens. The user can configure the frequency of Embedded SYNC.
224+
The Embedded SYNC capability is always related to a given base frequency
225+
and HW capabilities. The user is provided a range of Embedded SYNC
226+
frequencies supported, depending on current base frequency configured for
227+
the pin.
228+
229+
========================================= =================================
230+
``DPLL_A_PIN_ESYNC_FREQUENCY`` current Embedded SYNC frequency
231+
``DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED`` nest available Embedded SYNC
232+
frequency ranges
233+
``DPLL_A_PIN_FREQUENCY_MIN`` attr minimum value of frequency
234+
``DPLL_A_PIN_FREQUENCY_MAX`` attr maximum value of frequency
235+
``DPLL_A_PIN_ESYNC_PULSE`` pulse type of Embedded SYNC
236+
========================================= =================================
237+
217238
Configuration commands group
218239
============================
219240

Documentation/netlink/specs/dpll.yaml

+24
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,26 @@ attribute-sets:
345345
Value is in PPM (parts per million).
346346
This may be implemented for example for pin of type
347347
PIN_TYPE_SYNCE_ETH_PORT.
348+
-
349+
name: esync-frequency
350+
type: u64
351+
doc: |
352+
Frequency of Embedded SYNC signal. If provided, the pin is configured
353+
with a SYNC signal embedded into its base clock frequency.
354+
-
355+
name: esync-frequency-supported
356+
type: nest
357+
multi-attr: true
358+
nested-attributes: frequency-range
359+
doc: |
360+
If provided a pin is capable of embedding a SYNC signal (within given
361+
range) into its base frequency signal.
362+
-
363+
name: esync-pulse
364+
type: u32
365+
doc: |
366+
A ratio of high to low state of a SYNC signal pulse embedded
367+
into base clock frequency. Value is in percents.
348368
-
349369
name: pin-parent-device
350370
subset-of: pin
@@ -510,6 +530,9 @@ operations:
510530
- phase-adjust-max
511531
- phase-adjust
512532
- fractional-frequency-offset
533+
- esync-frequency
534+
- esync-frequency-supported
535+
- esync-pulse
513536

514537
dump:
515538
request:
@@ -536,6 +559,7 @@ operations:
536559
- parent-device
537560
- parent-pin
538561
- phase-adjust
562+
- esync-frequency
539563
-
540564
name: pin-create-ntf
541565
doc: Notification about pin appearing

drivers/dpll/dpll_netlink.c

+130
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,51 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
342342
return 0;
343343
}
344344

345+
static int
346+
dpll_msg_add_pin_esync(struct sk_buff *msg, struct dpll_pin *pin,
347+
struct dpll_pin_ref *ref, struct netlink_ext_ack *extack)
348+
{
349+
const struct dpll_pin_ops *ops = dpll_pin_ops(ref);
350+
struct dpll_device *dpll = ref->dpll;
351+
struct dpll_pin_esync esync;
352+
struct nlattr *nest;
353+
int ret, i;
354+
355+
if (!ops->esync_get)
356+
return 0;
357+
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
358+
dpll_priv(dpll), &esync, extack);
359+
if (ret == -EOPNOTSUPP)
360+
return 0;
361+
else if (ret)
362+
return ret;
363+
if (nla_put_64bit(msg, DPLL_A_PIN_ESYNC_FREQUENCY, sizeof(esync.freq),
364+
&esync.freq, DPLL_A_PIN_PAD))
365+
return -EMSGSIZE;
366+
if (nla_put_u32(msg, DPLL_A_PIN_ESYNC_PULSE, esync.pulse))
367+
return -EMSGSIZE;
368+
for (i = 0; i < esync.range_num; i++) {
369+
nest = nla_nest_start(msg,
370+
DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED);
371+
if (!nest)
372+
return -EMSGSIZE;
373+
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN,
374+
sizeof(esync.range[i].min),
375+
&esync.range[i].min, DPLL_A_PIN_PAD))
376+
goto nest_cancel;
377+
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX,
378+
sizeof(esync.range[i].max),
379+
&esync.range[i].max, DPLL_A_PIN_PAD))
380+
goto nest_cancel;
381+
nla_nest_end(msg, nest);
382+
}
383+
return 0;
384+
385+
nest_cancel:
386+
nla_nest_cancel(msg, nest);
387+
return -EMSGSIZE;
388+
}
389+
345390
static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
346391
{
347392
int fs;
@@ -481,6 +526,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
481526
if (ret)
482527
return ret;
483528
ret = dpll_msg_add_ffo(msg, pin, ref, extack);
529+
if (ret)
530+
return ret;
531+
ret = dpll_msg_add_pin_esync(msg, pin, ref, extack);
484532
if (ret)
485533
return ret;
486534
if (xa_empty(&pin->parent_refs))
@@ -738,6 +786,83 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
738786
return ret;
739787
}
740788

789+
static int
790+
dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
791+
struct netlink_ext_ack *extack)
792+
{
793+
struct dpll_pin_ref *ref, *failed;
794+
const struct dpll_pin_ops *ops;
795+
struct dpll_pin_esync esync;
796+
u64 freq = nla_get_u64(a);
797+
struct dpll_device *dpll;
798+
bool supported = false;
799+
unsigned long i;
800+
int ret;
801+
802+
xa_for_each(&pin->dpll_refs, i, ref) {
803+
ops = dpll_pin_ops(ref);
804+
if (!ops->esync_set || !ops->esync_get) {
805+
NL_SET_ERR_MSG(extack,
806+
"embedded sync feature is not supported by this device");
807+
return -EOPNOTSUPP;
808+
}
809+
}
810+
ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
811+
ops = dpll_pin_ops(ref);
812+
dpll = ref->dpll;
813+
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
814+
dpll_priv(dpll), &esync, extack);
815+
if (ret) {
816+
NL_SET_ERR_MSG(extack, "unable to get current embedded sync frequency value");
817+
return ret;
818+
}
819+
if (freq == esync.freq)
820+
return 0;
821+
for (i = 0; i < esync.range_num; i++)
822+
if (freq <= esync.range[i].max && freq >= esync.range[i].min)
823+
supported = true;
824+
if (!supported) {
825+
NL_SET_ERR_MSG_ATTR(extack, a,
826+
"requested embedded sync frequency value is not supported by this device");
827+
return -EINVAL;
828+
}
829+
830+
xa_for_each(&pin->dpll_refs, i, ref) {
831+
void *pin_dpll_priv;
832+
833+
ops = dpll_pin_ops(ref);
834+
dpll = ref->dpll;
835+
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
836+
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
837+
freq, extack);
838+
if (ret) {
839+
failed = ref;
840+
NL_SET_ERR_MSG_FMT(extack,
841+
"embedded sync frequency set failed for dpll_id: %u",
842+
dpll->id);
843+
goto rollback;
844+
}
845+
}
846+
__dpll_pin_change_ntf(pin);
847+
848+
return 0;
849+
850+
rollback:
851+
xa_for_each(&pin->dpll_refs, i, ref) {
852+
void *pin_dpll_priv;
853+
854+
if (ref == failed)
855+
break;
856+
ops = dpll_pin_ops(ref);
857+
dpll = ref->dpll;
858+
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
859+
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
860+
esync.freq, extack))
861+
NL_SET_ERR_MSG(extack, "set embedded sync frequency rollback failed");
862+
}
863+
return ret;
864+
}
865+
741866
static int
742867
dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
743868
enum dpll_pin_state state,
@@ -1039,6 +1164,11 @@ dpll_pin_set_from_nlattr(struct dpll_pin *pin, struct genl_info *info)
10391164
if (ret)
10401165
return ret;
10411166
break;
1167+
case DPLL_A_PIN_ESYNC_FREQUENCY:
1168+
ret = dpll_pin_esync_set(pin, a, info->extack);
1169+
if (ret)
1170+
return ret;
1171+
break;
10421172
}
10431173
}
10441174

drivers/dpll/dpll_nl.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ static const struct nla_policy dpll_pin_get_dump_nl_policy[DPLL_A_PIN_ID + 1] =
6262
};
6363

6464
/* DPLL_CMD_PIN_SET - do */
65-
static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_PHASE_ADJUST + 1] = {
65+
static const struct nla_policy dpll_pin_set_nl_policy[DPLL_A_PIN_ESYNC_FREQUENCY + 1] = {
6666
[DPLL_A_PIN_ID] = { .type = NLA_U32, },
6767
[DPLL_A_PIN_FREQUENCY] = { .type = NLA_U64, },
6868
[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 +
7171
[DPLL_A_PIN_PARENT_DEVICE] = NLA_POLICY_NESTED(dpll_pin_parent_device_nl_policy),
7272
[DPLL_A_PIN_PARENT_PIN] = NLA_POLICY_NESTED(dpll_pin_parent_pin_nl_policy),
7373
[DPLL_A_PIN_PHASE_ADJUST] = { .type = NLA_S32, },
74+
[DPLL_A_PIN_ESYNC_FREQUENCY] = { .type = NLA_U64, },
7475
};
7576

7677
/* Ops table for dpll */
@@ -138,7 +139,7 @@ static const struct genl_split_ops dpll_nl_ops[] = {
138139
.doit = dpll_nl_pin_set_doit,
139140
.post_doit = dpll_pin_post_doit,
140141
.policy = dpll_pin_set_nl_policy,
141-
.maxattr = DPLL_A_PIN_PHASE_ADJUST,
142+
.maxattr = DPLL_A_PIN_ESYNC_FREQUENCY,
142143
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
143144
},
144145
};

include/linux/dpll.h

+15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
struct dpll_device;
1717
struct dpll_pin;
18+
struct dpll_pin_esync;
1819

1920
struct dpll_device_ops {
2021
int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv,
@@ -83,6 +84,13 @@ struct dpll_pin_ops {
8384
int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv,
8485
const struct dpll_device *dpll, void *dpll_priv,
8586
s64 *ffo, struct netlink_ext_ack *extack);
87+
int (*esync_set)(const struct dpll_pin *pin, void *pin_priv,
88+
const struct dpll_device *dpll, void *dpll_priv,
89+
u64 freq, struct netlink_ext_ack *extack);
90+
int (*esync_get)(const struct dpll_pin *pin, void *pin_priv,
91+
const struct dpll_device *dpll, void *dpll_priv,
92+
struct dpll_pin_esync *esync,
93+
struct netlink_ext_ack *extack);
8694
};
8795

8896
struct dpll_pin_frequency {
@@ -111,6 +119,13 @@ struct dpll_pin_phase_adjust_range {
111119
s32 max;
112120
};
113121

122+
struct dpll_pin_esync {
123+
u64 freq;
124+
const struct dpll_pin_frequency *range;
125+
u8 range_num;
126+
u8 pulse;
127+
};
128+
114129
struct dpll_pin_properties {
115130
const char *board_label;
116131
const char *panel_label;

include/uapi/linux/dpll.h

+3
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ enum dpll_a_pin {
210210
DPLL_A_PIN_PHASE_ADJUST,
211211
DPLL_A_PIN_PHASE_OFFSET,
212212
DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET,
213+
DPLL_A_PIN_ESYNC_FREQUENCY,
214+
DPLL_A_PIN_ESYNC_FREQUENCY_SUPPORTED,
215+
DPLL_A_PIN_ESYNC_PULSE,
213216

214217
__DPLL_A_PIN_MAX,
215218
DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)

0 commit comments

Comments
 (0)