Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy-zynqmp: Postpone getting clock rate until actually needed

At probe time the driver would display the following error and abort:
xilinx-psgtr fd400000.phy: Invalid rate 0 for reference clock 0

At probe time, the associated GTR driver (e.g. SATA or PCIe) hasn't
initialized the clock yet, so clk_get_rate() likely returns 0 if the clock
is programmable. So this driver only works if the clock is fixed.

The PHY driver doesn't need to know the clock frequency at probe yet, so
wait until the associated driver initializes the lane before requesting the
clock rate setting.

In addition to allowing the driver to be used with programmable clocks,
this also reduces the driver's runtime memory footprint by removing an
array of pointers from struct xpsgtr_phy.

Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
Acked-by: Michal Simek <michal.simek@amd.com>
Link: https://lore.kernel.org/r/20250428063648.22034-1-mike.looijmans@topic.nl
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Mike Looijmans and committed by
Vinod Koul
065d5885 1b1e9499

+37 -33
+37 -33
drivers/phy/xilinx/phy-zynqmp.c
··· 222 222 * @siou: siou base address 223 223 * @gtr_mutex: mutex for locking 224 224 * @phys: PHY lanes 225 - * @refclk_sscs: spread spectrum settings for the reference clocks 226 225 * @clk: reference clocks 227 226 * @tx_term_fix: fix for GT issue 228 227 * @saved_icm_cfg0: stored value of ICM CFG0 register ··· 234 235 void __iomem *siou; 235 236 struct mutex gtr_mutex; /* mutex for locking */ 236 237 struct xpsgtr_phy phys[NUM_LANES]; 237 - const struct xpsgtr_ssc *refclk_sscs[NUM_LANES]; 238 238 struct clk *clk[NUM_LANES]; 239 239 bool tx_term_fix; 240 240 unsigned int saved_icm_cfg0; ··· 396 398 return ret; 397 399 } 398 400 401 + /* Get the spread spectrum (SSC) settings for the reference clock rate */ 402 + static const struct xpsgtr_ssc *xpsgtr_find_sscs(struct xpsgtr_phy *gtr_phy) 403 + { 404 + unsigned long rate; 405 + struct clk *clk; 406 + unsigned int i; 407 + 408 + clk = gtr_phy->dev->clk[gtr_phy->refclk]; 409 + rate = clk_get_rate(clk); 410 + 411 + for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) { 412 + /* Allow an error of 100 ppm */ 413 + unsigned long error = ssc_lookup[i].refclk_rate / 10000; 414 + 415 + if (abs(rate - ssc_lookup[i].refclk_rate) < error) 416 + return &ssc_lookup[i]; 417 + } 418 + 419 + dev_err(gtr_phy->dev->dev, "Invalid rate %lu for reference clock %u\n", 420 + rate, gtr_phy->refclk); 421 + 422 + return NULL; 423 + } 424 + 399 425 /* Configure PLL and spread-sprectrum clock. */ 400 - static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy) 426 + static int xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy) 401 427 { 402 428 const struct xpsgtr_ssc *ssc; 403 429 u32 step_size; 404 430 405 - ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk]; 431 + ssc = xpsgtr_find_sscs(gtr_phy); 432 + if (!ssc) 433 + return -EINVAL; 434 + 406 435 step_size = ssc->step_size; 407 436 408 437 xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane), ··· 471 446 xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB, 472 447 STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) | 473 448 FORCE_STEP_SIZE | FORCE_STEPS); 449 + 450 + return 0; 474 451 } 475 452 476 453 /* Configure the lane protocol. */ ··· 685 658 * Configure the PLL, the lane protocol, and perform protocol-specific 686 659 * initialization. 687 660 */ 688 - xpsgtr_configure_pll(gtr_phy); 661 + ret = xpsgtr_configure_pll(gtr_phy); 662 + if (ret) 663 + goto out; 664 + 689 665 xpsgtr_lane_set_protocol(gtr_phy); 690 666 691 667 switch (gtr_phy->protocol) { ··· 853 823 } 854 824 855 825 refclk = args->args[3]; 856 - if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) || 857 - !gtr_dev->refclk_sscs[refclk]) { 826 + if (refclk >= ARRAY_SIZE(gtr_dev->clk)) { 858 827 dev_err(dev, "Invalid reference clock number %u\n", refclk); 859 828 return ERR_PTR(-EINVAL); 860 829 } ··· 957 928 { 958 929 unsigned int refclk; 959 930 960 - for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { 961 - unsigned long rate; 962 - unsigned int i; 931 + for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->clk); ++refclk) { 963 932 struct clk *clk; 964 933 char name[8]; 965 934 ··· 973 946 continue; 974 947 975 948 gtr_dev->clk[refclk] = clk; 976 - 977 - /* 978 - * Get the spread spectrum (SSC) settings for the reference 979 - * clock rate. 980 - */ 981 - rate = clk_get_rate(clk); 982 - 983 - for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) { 984 - /* Allow an error of 100 ppm */ 985 - unsigned long error = ssc_lookup[i].refclk_rate / 10000; 986 - 987 - if (abs(rate - ssc_lookup[i].refclk_rate) < error) { 988 - gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i]; 989 - break; 990 - } 991 - } 992 - 993 - if (i == ARRAY_SIZE(ssc_lookup)) { 994 - dev_err(gtr_dev->dev, 995 - "Invalid rate %lu for reference clock %u\n", 996 - rate, refclk); 997 - return -EINVAL; 998 - } 999 949 } 1000 950 1001 951 return 0;