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

mlxbf_gige: compute MDIO period based on i1clk

This patch adds logic to compute the MDIO period based on
the i1clk, and thereafter write the MDIO period into the YU
MDIO config register. The i1clk resource from the ACPI table
is used to provide addressing to YU bootrecord PLL registers.
The values in these registers are used to compute MDIO period.
If the i1clk resource is not present in the ACPI table, then
the current default hardcorded value of 430Mhz is used.
The i1clk clock value of 430MHz is only accurate for boards
with BF2 mid bin and main bin SoCs. The BF2 high bin SoCs
have i1clk = 500MHz, but can support a slower MDIO period.

Fixes: f92e1869d74e ("Add Mellanox BlueField Gigabit Ethernet driver")
Reviewed-by: Asmaa Mnebhi <asmaa@nvidia.com>
Signed-off-by: David Thompson <davthompson@nvidia.com>
Link: https://lore.kernel.org/r/20220826155916.12491-1-davthompson@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

David Thompson and committed by
Jakub Kicinski
3a1a274e c0955bf9

+113 -21
+3 -1
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
··· 75 75 struct net_device *netdev; 76 76 struct platform_device *pdev; 77 77 void __iomem *mdio_io; 78 + void __iomem *clk_io; 78 79 struct mii_bus *mdiobus; 79 80 spinlock_t lock; /* for packet processing indices */ 80 81 u16 rx_q_entries; ··· 138 137 MLXBF_GIGE_RES_MDIO9, 139 138 MLXBF_GIGE_RES_GPIO0, 140 139 MLXBF_GIGE_RES_LLU, 141 - MLXBF_GIGE_RES_PLU 140 + MLXBF_GIGE_RES_PLU, 141 + MLXBF_GIGE_RES_CLK 142 142 }; 143 143 144 144 /* Version of register data returned by mlxbf_gige_get_regs() */
+108 -20
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
··· 22 22 #include <linux/property.h> 23 23 24 24 #include "mlxbf_gige.h" 25 + #include "mlxbf_gige_regs.h" 25 26 26 27 #define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 27 28 #define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 29 + 30 + #define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL 31 + #define MLXBF_GIGE_MDIO_COREPLL_CONST 16384ULL 32 + #define MLXBF_GIGE_MDC_CLK_NS 400 33 + #define MLXBF_GIGE_MDIO_PLL_I1CLK_REG1 0x4 34 + #define MLXBF_GIGE_MDIO_PLL_I1CLK_REG2 0x8 35 + #define MLXBF_GIGE_MDIO_CORE_F_SHIFT 0 36 + #define MLXBF_GIGE_MDIO_CORE_F_MASK GENMASK(25, 0) 37 + #define MLXBF_GIGE_MDIO_CORE_R_SHIFT 26 38 + #define MLXBF_GIGE_MDIO_CORE_R_MASK GENMASK(31, 26) 39 + #define MLXBF_GIGE_MDIO_CORE_OD_SHIFT 0 40 + #define MLXBF_GIGE_MDIO_CORE_OD_MASK GENMASK(3, 0) 28 41 29 42 /* Support clause 22 */ 30 43 #define MLXBF_GIGE_MDIO_CL22_ST1 0x1 ··· 63 50 #define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) 64 51 #define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) 65 52 66 - /* Formula for encoding the MDIO period. The encoded value is 67 - * passed to the MDIO config register. 68 - * 69 - * mdc_clk = 2*(val + 1)*i1clk 70 - * 71 - * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) 72 - * 73 - * val = (((400 * 430 / 1000) / 2) - 1) 74 - */ 75 - #define MLXBF_GIGE_I1CLK_MHZ 430 76 - #define MLXBF_GIGE_MDC_CLK_NS 400 77 - 78 - #define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) 79 - 80 53 #define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ 81 54 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ 82 55 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ 83 - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ 84 - MLXBF_GIGE_MDIO_PERIOD) | \ 85 56 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ 86 57 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) 58 + 59 + #define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30 60 + #define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c 61 + 62 + static struct resource corepll_params[] = { 63 + [MLXBF_GIGE_VERSION_BF2] = { 64 + .start = MLXBF_GIGE_BF2_COREPLL_ADDR, 65 + .end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1, 66 + .name = "COREPLL_RES" 67 + }, 68 + }; 69 + 70 + /* Returns core clock i1clk in Hz */ 71 + static u64 calculate_i1clk(struct mlxbf_gige *priv) 72 + { 73 + u8 core_od, core_r; 74 + u64 freq_output; 75 + u32 reg1, reg2; 76 + u32 core_f; 77 + 78 + reg1 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG1); 79 + reg2 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG2); 80 + 81 + core_f = (reg1 & MLXBF_GIGE_MDIO_CORE_F_MASK) >> 82 + MLXBF_GIGE_MDIO_CORE_F_SHIFT; 83 + core_r = (reg1 & MLXBF_GIGE_MDIO_CORE_R_MASK) >> 84 + MLXBF_GIGE_MDIO_CORE_R_SHIFT; 85 + core_od = (reg2 & MLXBF_GIGE_MDIO_CORE_OD_MASK) >> 86 + MLXBF_GIGE_MDIO_CORE_OD_SHIFT; 87 + 88 + /* Compute PLL output frequency as follow: 89 + * 90 + * CORE_F / 16384 91 + * freq_output = freq_reference * ---------------------------- 92 + * (CORE_R + 1) * (CORE_OD + 1) 93 + */ 94 + freq_output = div_u64((MLXBF_GIGE_MDIO_FREQ_REFERENCE * core_f), 95 + MLXBF_GIGE_MDIO_COREPLL_CONST); 96 + freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1)); 97 + 98 + return freq_output; 99 + } 100 + 101 + /* Formula for encoding the MDIO period. The encoded value is 102 + * passed to the MDIO config register. 103 + * 104 + * mdc_clk = 2*(val + 1)*(core clock in sec) 105 + * 106 + * i1clk is in Hz: 107 + * 400 ns = 2*(val + 1)*(1/i1clk) 108 + * 109 + * val = (((400/10^9) / (1/i1clk) / 2) - 1) 110 + * val = (400/2 * i1clk)/10^9 - 1 111 + */ 112 + static u8 mdio_period_map(struct mlxbf_gige *priv) 113 + { 114 + u8 mdio_period; 115 + u64 i1clk; 116 + 117 + i1clk = calculate_i1clk(priv); 118 + 119 + mdio_period = div_u64((MLXBF_GIGE_MDC_CLK_NS >> 1) * i1clk, 1000000000) - 1; 120 + 121 + return mdio_period; 122 + } 87 123 88 124 static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, 89 125 int phy_reg, u32 opcode) ··· 186 124 int phy_reg, u16 val) 187 125 { 188 126 struct mlxbf_gige *priv = bus->priv; 127 + u32 temp; 189 128 u32 cmd; 190 129 int ret; 191 - u32 temp; 192 130 193 131 if (phy_reg & MII_ADDR_C45) 194 132 return -EOPNOTSUPP; ··· 206 144 return ret; 207 145 } 208 146 147 + static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv) 148 + { 149 + u8 mdio_period; 150 + u32 val; 151 + 152 + mdio_period = mdio_period_map(priv); 153 + 154 + val = MLXBF_GIGE_MDIO_CFG_VAL; 155 + val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period); 156 + writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); 157 + } 158 + 209 159 int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) 210 160 { 211 161 struct device *dev = &pdev->dev; 162 + struct resource *res; 212 163 int ret; 213 164 214 165 priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9); 215 166 if (IS_ERR(priv->mdio_io)) 216 167 return PTR_ERR(priv->mdio_io); 217 168 218 - /* Configure mdio parameters */ 219 - writel(MLXBF_GIGE_MDIO_CFG_VAL, 220 - priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); 169 + /* clk resource shared with other drivers so cannot use 170 + * devm_platform_ioremap_resource 171 + */ 172 + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK); 173 + if (!res) { 174 + /* For backward compatibility with older ACPI tables, also keep 175 + * CLK resource internal to the driver. 176 + */ 177 + res = &corepll_params[MLXBF_GIGE_VERSION_BF2]; 178 + } 179 + 180 + priv->clk_io = devm_ioremap(dev, res->start, resource_size(res)); 181 + if (IS_ERR(priv->clk_io)) 182 + return PTR_ERR(priv->clk_io); 183 + 184 + mlxbf_gige_mdio_cfg(priv); 221 185 222 186 priv->mdiobus = devm_mdiobus_alloc(dev); 223 187 if (!priv->mdiobus) {
+2
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
··· 8 8 #ifndef __MLXBF_GIGE_REGS_H__ 9 9 #define __MLXBF_GIGE_REGS_H__ 10 10 11 + #define MLXBF_GIGE_VERSION 0x0000 12 + #define MLXBF_GIGE_VERSION_BF2 0x0 11 13 #define MLXBF_GIGE_STATUS 0x0010 12 14 #define MLXBF_GIGE_STATUS_READY BIT(0) 13 15 #define MLXBF_GIGE_INT_STATUS 0x0028