Skip to content

Commit b7d907d

Browse files
ivecerakuba-moo
authored andcommitted
dpll: zl3073x: Fetch invariants during probe
Several configuration parameters will remain constant at runtime, so we can load them during probe to avoid excessive reads from the hardware. Read the following parameters from the device during probe and store them for later use: * enablement status and frequencies of the synthesizers and their associated DPLL channels * enablement status and type (single-ended or differential) of input pins * associated synthesizers, signal format, and enablement status of outputs Signed-off-by: Ivan Vecera <ivecera@redhat.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Link: https://patch.msgid.link/20250704182202.1641943-7-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 2df8e64 commit b7d907d

File tree

3 files changed

+600
-0
lines changed

3 files changed

+600
-0
lines changed

drivers/dpll/zl3073x/core.c

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
#include <linux/dev_printk.h>
77
#include <linux/device.h>
88
#include <linux/export.h>
9+
#include <linux/math64.h>
910
#include <linux/module.h>
1011
#include <linux/netlink.h>
1112
#include <linux/regmap.h>
1213
#include <linux/sprintf.h>
14+
#include <linux/string_choices.h>
1315
#include <linux/unaligned.h>
1416
#include <net/devlink.h>
1517

@@ -383,6 +385,248 @@ int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask)
383385
ZL_POLL_SLEEP_US, ZL_POLL_TIMEOUT_US);
384386
}
385387

388+
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
389+
unsigned int mask_reg, u16 mask_val)
390+
{
391+
int rc;
392+
393+
/* Set mask for the operation */
394+
rc = zl3073x_write_u16(zldev, mask_reg, mask_val);
395+
if (rc)
396+
return rc;
397+
398+
/* Trigger the operation */
399+
rc = zl3073x_write_u8(zldev, op_reg, op_val);
400+
if (rc)
401+
return rc;
402+
403+
/* Wait for the operation to actually finish */
404+
return zl3073x_poll_zero_u8(zldev, op_reg, op_val);
405+
}
406+
407+
/**
408+
* zl3073x_ref_state_fetch - get input reference state
409+
* @zldev: pointer to zl3073x_dev structure
410+
* @index: input reference index to fetch state for
411+
*
412+
* Function fetches information for the given input reference that are
413+
* invariant and stores them for later use.
414+
*
415+
* Return: 0 on success, <0 on error
416+
*/
417+
static int
418+
zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index)
419+
{
420+
struct zl3073x_ref *input = &zldev->ref[index];
421+
u8 ref_config;
422+
int rc;
423+
424+
/* If the input is differential then the configuration for N-pin
425+
* reference is ignored and P-pin config is used for both.
426+
*/
427+
if (zl3073x_is_n_pin(index) &&
428+
zl3073x_ref_is_diff(zldev, index - 1)) {
429+
input->enabled = zl3073x_ref_is_enabled(zldev, index - 1);
430+
input->diff = true;
431+
432+
return 0;
433+
}
434+
435+
guard(mutex)(&zldev->multiop_lock);
436+
437+
/* Read reference configuration */
438+
rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD,
439+
ZL_REG_REF_MB_MASK, BIT(index));
440+
if (rc)
441+
return rc;
442+
443+
/* Read ref_config register */
444+
rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref_config);
445+
if (rc)
446+
return rc;
447+
448+
input->enabled = FIELD_GET(ZL_REF_CONFIG_ENABLE, ref_config);
449+
input->diff = FIELD_GET(ZL_REF_CONFIG_DIFF_EN, ref_config);
450+
451+
dev_dbg(zldev->dev, "REF%u is %s and configured as %s\n", index,
452+
str_enabled_disabled(input->enabled),
453+
input->diff ? "differential" : "single-ended");
454+
455+
return rc;
456+
}
457+
458+
/**
459+
* zl3073x_out_state_fetch - get output state
460+
* @zldev: pointer to zl3073x_dev structure
461+
* @index: output index to fetch state for
462+
*
463+
* Function fetches information for the given output (not output pin)
464+
* that are invariant and stores them for later use.
465+
*
466+
* Return: 0 on success, <0 on error
467+
*/
468+
static int
469+
zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
470+
{
471+
struct zl3073x_out *out = &zldev->out[index];
472+
u8 output_ctrl, output_mode;
473+
int rc;
474+
475+
/* Read output configuration */
476+
rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &output_ctrl);
477+
if (rc)
478+
return rc;
479+
480+
/* Store info about output enablement and synthesizer the output
481+
* is connected to.
482+
*/
483+
out->enabled = FIELD_GET(ZL_OUTPUT_CTRL_EN, output_ctrl);
484+
out->synth = FIELD_GET(ZL_OUTPUT_CTRL_SYNTH_SEL, output_ctrl);
485+
486+
dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
487+
str_enabled_disabled(out->enabled), out->synth);
488+
489+
guard(mutex)(&zldev->multiop_lock);
490+
491+
/* Read output configuration */
492+
rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
493+
ZL_REG_OUTPUT_MB_MASK, BIT(index));
494+
if (rc)
495+
return rc;
496+
497+
/* Read output_mode */
498+
rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode);
499+
if (rc)
500+
return rc;
501+
502+
/* Extract and store output signal format */
503+
out->signal_format = FIELD_GET(ZL_OUTPUT_MODE_SIGNAL_FORMAT,
504+
output_mode);
505+
506+
dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
507+
out->signal_format);
508+
509+
return rc;
510+
}
511+
512+
/**
513+
* zl3073x_synth_state_fetch - get synth state
514+
* @zldev: pointer to zl3073x_dev structure
515+
* @index: synth index to fetch state for
516+
*
517+
* Function fetches information for the given synthesizer that are
518+
* invariant and stores them for later use.
519+
*
520+
* Return: 0 on success, <0 on error
521+
*/
522+
static int
523+
zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 index)
524+
{
525+
struct zl3073x_synth *synth = &zldev->synth[index];
526+
u16 base, m, n;
527+
u8 synth_ctrl;
528+
u32 mult;
529+
int rc;
530+
531+
/* Read synth control register */
532+
rc = zl3073x_read_u8(zldev, ZL_REG_SYNTH_CTRL(index), &synth_ctrl);
533+
if (rc)
534+
return rc;
535+
536+
/* Store info about synth enablement and DPLL channel the synth is
537+
* driven by.
538+
*/
539+
synth->enabled = FIELD_GET(ZL_SYNTH_CTRL_EN, synth_ctrl);
540+
synth->dpll = FIELD_GET(ZL_SYNTH_CTRL_DPLL_SEL, synth_ctrl);
541+
542+
dev_dbg(zldev->dev, "SYNTH%u is %s and driven by DPLL%u\n", index,
543+
str_enabled_disabled(synth->enabled), synth->dpll);
544+
545+
guard(mutex)(&zldev->multiop_lock);
546+
547+
/* Read synth configuration */
548+
rc = zl3073x_mb_op(zldev, ZL_REG_SYNTH_MB_SEM, ZL_SYNTH_MB_SEM_RD,
549+
ZL_REG_SYNTH_MB_MASK, BIT(index));
550+
if (rc)
551+
return rc;
552+
553+
/* The output frequency is determined by the following formula:
554+
* base * multiplier * numerator / denominator
555+
*
556+
* Read registers with these values
557+
*/
558+
rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_BASE, &base);
559+
if (rc)
560+
return rc;
561+
562+
rc = zl3073x_read_u32(zldev, ZL_REG_SYNTH_FREQ_MULT, &mult);
563+
if (rc)
564+
return rc;
565+
566+
rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_M, &m);
567+
if (rc)
568+
return rc;
569+
570+
rc = zl3073x_read_u16(zldev, ZL_REG_SYNTH_FREQ_N, &n);
571+
if (rc)
572+
return rc;
573+
574+
/* Check denominator for zero to avoid div by 0 */
575+
if (!n) {
576+
dev_err(zldev->dev,
577+
"Zero divisor for SYNTH%u retrieved from device\n",
578+
index);
579+
return -EINVAL;
580+
}
581+
582+
/* Compute and store synth frequency */
583+
zldev->synth[index].freq = div_u64(mul_u32_u32(base * m, mult), n);
584+
585+
dev_dbg(zldev->dev, "SYNTH%u frequency: %u Hz\n", index,
586+
zldev->synth[index].freq);
587+
588+
return rc;
589+
}
590+
591+
static int
592+
zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
593+
{
594+
int rc;
595+
u8 i;
596+
597+
for (i = 0; i < ZL3073X_NUM_REFS; i++) {
598+
rc = zl3073x_ref_state_fetch(zldev, i);
599+
if (rc) {
600+
dev_err(zldev->dev,
601+
"Failed to fetch input state: %pe\n",
602+
ERR_PTR(rc));
603+
return rc;
604+
}
605+
}
606+
607+
for (i = 0; i < ZL3073X_NUM_SYNTHS; i++) {
608+
rc = zl3073x_synth_state_fetch(zldev, i);
609+
if (rc) {
610+
dev_err(zldev->dev,
611+
"Failed to fetch synth state: %pe\n",
612+
ERR_PTR(rc));
613+
return rc;
614+
}
615+
}
616+
617+
for (i = 0; i < ZL3073X_NUM_OUTS; i++) {
618+
rc = zl3073x_out_state_fetch(zldev, i);
619+
if (rc) {
620+
dev_err(zldev->dev,
621+
"Failed to fetch output state: %pe\n",
622+
ERR_PTR(rc));
623+
return rc;
624+
}
625+
}
626+
627+
return rc;
628+
}
629+
386630
/**
387631
* zl3073x_dev_probe - initialize zl3073x device
388632
* @zldev: pointer to zl3073x device
@@ -450,6 +694,11 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
450694
return dev_err_probe(zldev->dev, rc,
451695
"Failed to initialize mutex\n");
452696

697+
/* Fetch device state */
698+
rc = zl3073x_dev_state_fetch(zldev);
699+
if (rc)
700+
return rc;
701+
453702
/* Register the devlink instance and parameters */
454703
rc = zl3073x_devlink_register(zldev);
455704
if (rc)

0 commit comments

Comments
 (0)