Skip to content
/ linux Public

Commit 3a1a274

Browse files
dthompsokuba-moo
authored andcommitted
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: f92e186 ("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>
1 parent c0955bf commit 3a1a274

File tree

3 files changed

+110
-18
lines changed

3 files changed

+110
-18
lines changed

drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct mlxbf_gige {
7575
struct net_device *netdev;
7676
struct platform_device *pdev;
7777
void __iomem *mdio_io;
78+
void __iomem *clk_io;
7879
struct mii_bus *mdiobus;
7980
spinlock_t lock; /* for packet processing indices */
8081
u16 rx_q_entries;
@@ -137,7 +138,8 @@ enum mlxbf_gige_res {
137138
MLXBF_GIGE_RES_MDIO9,
138139
MLXBF_GIGE_RES_GPIO0,
139140
MLXBF_GIGE_RES_LLU,
140-
MLXBF_GIGE_RES_PLU
141+
MLXBF_GIGE_RES_PLU,
142+
MLXBF_GIGE_RES_CLK
141143
};
142144

143145
/* Version of register data returned by mlxbf_gige_get_regs() */

drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,23 @@
2222
#include <linux/property.h>
2323

2424
#include "mlxbf_gige.h"
25+
#include "mlxbf_gige_regs.h"
2526

2627
#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0
2728
#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4
2829

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)
41+
2942
/* Support clause 22 */
3043
#define MLXBF_GIGE_MDIO_CL22_ST1 0x1
3144
#define MLXBF_GIGE_MDIO_CL22_WRITE 0x1
@@ -50,27 +63,76 @@
5063
#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16)
5164
#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24)
5265

66+
#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
67+
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
68+
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
69+
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
70+
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
71+
72+
#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30
73+
#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c
74+
75+
static struct resource corepll_params[] = {
76+
[MLXBF_GIGE_VERSION_BF2] = {
77+
.start = MLXBF_GIGE_BF2_COREPLL_ADDR,
78+
.end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1,
79+
.name = "COREPLL_RES"
80+
},
81+
};
82+
83+
/* Returns core clock i1clk in Hz */
84+
static u64 calculate_i1clk(struct mlxbf_gige *priv)
85+
{
86+
u8 core_od, core_r;
87+
u64 freq_output;
88+
u32 reg1, reg2;
89+
u32 core_f;
90+
91+
reg1 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG1);
92+
reg2 = readl(priv->clk_io + MLXBF_GIGE_MDIO_PLL_I1CLK_REG2);
93+
94+
core_f = (reg1 & MLXBF_GIGE_MDIO_CORE_F_MASK) >>
95+
MLXBF_GIGE_MDIO_CORE_F_SHIFT;
96+
core_r = (reg1 & MLXBF_GIGE_MDIO_CORE_R_MASK) >>
97+
MLXBF_GIGE_MDIO_CORE_R_SHIFT;
98+
core_od = (reg2 & MLXBF_GIGE_MDIO_CORE_OD_MASK) >>
99+
MLXBF_GIGE_MDIO_CORE_OD_SHIFT;
100+
101+
/* Compute PLL output frequency as follow:
102+
*
103+
* CORE_F / 16384
104+
* freq_output = freq_reference * ----------------------------
105+
* (CORE_R + 1) * (CORE_OD + 1)
106+
*/
107+
freq_output = div_u64((MLXBF_GIGE_MDIO_FREQ_REFERENCE * core_f),
108+
MLXBF_GIGE_MDIO_COREPLL_CONST);
109+
freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1));
110+
111+
return freq_output;
112+
}
113+
53114
/* Formula for encoding the MDIO period. The encoded value is
54115
* passed to the MDIO config register.
55116
*
56-
* mdc_clk = 2*(val + 1)*i1clk
117+
* mdc_clk = 2*(val + 1)*(core clock in sec)
57118
*
58-
* 400 ns = 2*(val + 1)*(((1/430)*1000) ns)
119+
* i1clk is in Hz:
120+
* 400 ns = 2*(val + 1)*(1/i1clk)
59121
*
60-
* val = (((400 * 430 / 1000) / 2) - 1)
122+
* val = (((400/10^9) / (1/i1clk) / 2) - 1)
123+
* val = (400/2 * i1clk)/10^9 - 1
61124
*/
62-
#define MLXBF_GIGE_I1CLK_MHZ 430
63-
#define MLXBF_GIGE_MDC_CLK_NS 400
125+
static u8 mdio_period_map(struct mlxbf_gige *priv)
126+
{
127+
u8 mdio_period;
128+
u64 i1clk;
64129

65-
#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1)
130+
i1clk = calculate_i1clk(priv);
66131

67-
#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
68-
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
69-
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
70-
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \
71-
MLXBF_GIGE_MDIO_PERIOD) | \
72-
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
73-
FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
132+
mdio_period = div_u64((MLXBF_GIGE_MDC_CLK_NS >> 1) * i1clk, 1000000000) - 1;
133+
134+
return mdio_period;
135+
}
74136

75137
static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
76138
int phy_reg, u32 opcode)
@@ -124,9 +186,9 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
124186
int phy_reg, u16 val)
125187
{
126188
struct mlxbf_gige *priv = bus->priv;
189+
u32 temp;
127190
u32 cmd;
128191
int ret;
129-
u32 temp;
130192

131193
if (phy_reg & MII_ADDR_C45)
132194
return -EOPNOTSUPP;
@@ -144,18 +206,44 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
144206
return ret;
145207
}
146208

209+
static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv)
210+
{
211+
u8 mdio_period;
212+
u32 val;
213+
214+
mdio_period = mdio_period_map(priv);
215+
216+
val = MLXBF_GIGE_MDIO_CFG_VAL;
217+
val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period);
218+
writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
219+
}
220+
147221
int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
148222
{
149223
struct device *dev = &pdev->dev;
224+
struct resource *res;
150225
int ret;
151226

152227
priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9);
153228
if (IS_ERR(priv->mdio_io))
154229
return PTR_ERR(priv->mdio_io);
155230

156-
/* Configure mdio parameters */
157-
writel(MLXBF_GIGE_MDIO_CFG_VAL,
158-
priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
231+
/* clk resource shared with other drivers so cannot use
232+
* devm_platform_ioremap_resource
233+
*/
234+
res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK);
235+
if (!res) {
236+
/* For backward compatibility with older ACPI tables, also keep
237+
* CLK resource internal to the driver.
238+
*/
239+
res = &corepll_params[MLXBF_GIGE_VERSION_BF2];
240+
}
241+
242+
priv->clk_io = devm_ioremap(dev, res->start, resource_size(res));
243+
if (IS_ERR(priv->clk_io))
244+
return PTR_ERR(priv->clk_io);
245+
246+
mlxbf_gige_mdio_cfg(priv);
159247

160248
priv->mdiobus = devm_mdiobus_alloc(dev);
161249
if (!priv->mdiobus) {

drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#ifndef __MLXBF_GIGE_REGS_H__
99
#define __MLXBF_GIGE_REGS_H__
1010

11+
#define MLXBF_GIGE_VERSION 0x0000
12+
#define MLXBF_GIGE_VERSION_BF2 0x0
1113
#define MLXBF_GIGE_STATUS 0x0010
1214
#define MLXBF_GIGE_STATUS_READY BIT(0)
1315
#define MLXBF_GIGE_INT_STATUS 0x0028

0 commit comments

Comments
 (0)