Skip to content

Commit 1eefee9

Browse files
daviddaneydavem330
authored andcommitted
phy: mdio-octeon: Refactor into two files/modules
A follow-on patch uses PCI probing to find the Thunder MDIO hardware. In preparation for this, split out the common code into a new file mdio-cavium.c, which will be used by both the existing OCTEON driver, and the new Thunder PCI based driver. As part of the refactoring simplify the struct cavium_mdiobus by removing fields that are only ever used in the probe function and can just as well be local variables. Use readq/writeq in preference to readq_relaxed/writeq_relaxed as the relaxed form was an optimization for an early chip revision, and the MDIO drivers are not performance bottlenecks that need optimization in the first place. Signed-off-by: David Daney <david.daney@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 5fc7cf1 commit 1eefee9

File tree

5 files changed

+292
-268
lines changed

5 files changed

+292
-268
lines changed

drivers/net/phy/Kconfig

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,18 @@ config MDIO_GPIO
183183
To compile this driver as a module, choose M here: the module
184184
will be called mdio-gpio.
185185

186+
config MDIO_CAVIUM
187+
tristate
188+
186189
config MDIO_OCTEON
187-
tristate "Support for MDIO buses on Octeon and ThunderX SOCs"
190+
tristate "Support for MDIO buses on Octeon and some ThunderX SOCs"
188191
depends on 64BIT
189192
depends on HAS_IOMEM
193+
select MDIO_CAVIUM
190194
help
191-
192195
This module provides a driver for the Octeon and ThunderX MDIO
193-
busses. It is required by the Octeon and ThunderX ethernet device
194-
drivers.
196+
buses. It is required by the Octeon and ThunderX ethernet device
197+
drivers on some systems.
195198

196199
config MDIO_SUN4I
197200
tristate "Allwinner sun4i MDIO interface support"

drivers/net/phy/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ obj-$(CONFIG_DP83867_PHY) += dp83867.o
3131
obj-$(CONFIG_STE10XP) += ste10Xp.o
3232
obj-$(CONFIG_MICREL_PHY) += micrel.o
3333
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
34+
obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o
3435
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
3536
obj-$(CONFIG_AT803X_PHY) += at803x.o
3637
obj-$(CONFIG_AMD_PHY) += amd.o

drivers/net/phy/mdio-cavium.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* This file is subject to the terms and conditions of the GNU General Public
3+
* License. See the file "COPYING" in the main directory of this archive
4+
* for more details.
5+
*
6+
* Copyright (C) 2009-2016 Cavium, Inc.
7+
*/
8+
9+
#include <linux/delay.h>
10+
#include <linux/module.h>
11+
#include <linux/phy.h>
12+
#include <linux/io.h>
13+
14+
#include "mdio-cavium.h"
15+
16+
static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,
17+
enum cavium_mdiobus_mode m)
18+
{
19+
union cvmx_smix_clk smi_clk;
20+
21+
if (m == p->mode)
22+
return;
23+
24+
smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);
25+
smi_clk.s.mode = (m == C45) ? 1 : 0;
26+
smi_clk.s.preamble = 1;
27+
oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);
28+
p->mode = m;
29+
}
30+
31+
static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
32+
int phy_id, int regnum)
33+
{
34+
union cvmx_smix_cmd smi_cmd;
35+
union cvmx_smix_wr_dat smi_wr;
36+
int timeout = 1000;
37+
38+
cavium_mdiobus_set_mode(p, C45);
39+
40+
smi_wr.u64 = 0;
41+
smi_wr.s.dat = regnum & 0xffff;
42+
oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
43+
44+
regnum = (regnum >> 16) & 0x1f;
45+
46+
smi_cmd.u64 = 0;
47+
smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
48+
smi_cmd.s.phy_adr = phy_id;
49+
smi_cmd.s.reg_adr = regnum;
50+
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
51+
52+
do {
53+
/* Wait 1000 clocks so we don't saturate the RSL bus
54+
* doing reads.
55+
*/
56+
__delay(1000);
57+
smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
58+
} while (smi_wr.s.pending && --timeout);
59+
60+
if (timeout <= 0)
61+
return -EIO;
62+
return 0;
63+
}
64+
65+
int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
66+
{
67+
struct cavium_mdiobus *p = bus->priv;
68+
union cvmx_smix_cmd smi_cmd;
69+
union cvmx_smix_rd_dat smi_rd;
70+
unsigned int op = 1; /* MDIO_CLAUSE_22_READ */
71+
int timeout = 1000;
72+
73+
if (regnum & MII_ADDR_C45) {
74+
int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
75+
76+
if (r < 0)
77+
return r;
78+
79+
regnum = (regnum >> 16) & 0x1f;
80+
op = 3; /* MDIO_CLAUSE_45_READ */
81+
} else {
82+
cavium_mdiobus_set_mode(p, C22);
83+
}
84+
85+
smi_cmd.u64 = 0;
86+
smi_cmd.s.phy_op = op;
87+
smi_cmd.s.phy_adr = phy_id;
88+
smi_cmd.s.reg_adr = regnum;
89+
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
90+
91+
do {
92+
/* Wait 1000 clocks so we don't saturate the RSL bus
93+
* doing reads.
94+
*/
95+
__delay(1000);
96+
smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
97+
} while (smi_rd.s.pending && --timeout);
98+
99+
if (smi_rd.s.val)
100+
return smi_rd.s.dat;
101+
else
102+
return -EIO;
103+
}
104+
EXPORT_SYMBOL(cavium_mdiobus_read);
105+
106+
int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
107+
{
108+
struct cavium_mdiobus *p = bus->priv;
109+
union cvmx_smix_cmd smi_cmd;
110+
union cvmx_smix_wr_dat smi_wr;
111+
unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */
112+
int timeout = 1000;
113+
114+
if (regnum & MII_ADDR_C45) {
115+
int r = cavium_mdiobus_c45_addr(p, phy_id, regnum);
116+
117+
if (r < 0)
118+
return r;
119+
120+
regnum = (regnum >> 16) & 0x1f;
121+
op = 1; /* MDIO_CLAUSE_45_WRITE */
122+
} else {
123+
cavium_mdiobus_set_mode(p, C22);
124+
}
125+
126+
smi_wr.u64 = 0;
127+
smi_wr.s.dat = val;
128+
oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
129+
130+
smi_cmd.u64 = 0;
131+
smi_cmd.s.phy_op = op;
132+
smi_cmd.s.phy_adr = phy_id;
133+
smi_cmd.s.reg_adr = regnum;
134+
oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
135+
136+
do {
137+
/* Wait 1000 clocks so we don't saturate the RSL bus
138+
* doing reads.
139+
*/
140+
__delay(1000);
141+
smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
142+
} while (smi_wr.s.pending && --timeout);
143+
144+
if (timeout <= 0)
145+
return -EIO;
146+
147+
return 0;
148+
}
149+
EXPORT_SYMBOL(cavium_mdiobus_write);

drivers/net/phy/mdio-cavium.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* This file is subject to the terms and conditions of the GNU General Public
3+
* License. See the file "COPYING" in the main directory of this archive
4+
* for more details.
5+
*
6+
* Copyright (C) 2009-2016 Cavium, Inc.
7+
*/
8+
9+
enum cavium_mdiobus_mode {
10+
UNINIT = 0,
11+
C22,
12+
C45
13+
};
14+
15+
#define SMI_CMD 0x0
16+
#define SMI_WR_DAT 0x8
17+
#define SMI_RD_DAT 0x10
18+
#define SMI_CLK 0x18
19+
#define SMI_EN 0x20
20+
21+
#ifdef __BIG_ENDIAN_BITFIELD
22+
#define OCT_MDIO_BITFIELD_FIELD(field, more) \
23+
field; \
24+
more
25+
26+
#else
27+
#define OCT_MDIO_BITFIELD_FIELD(field, more) \
28+
more \
29+
field;
30+
31+
#endif
32+
33+
union cvmx_smix_clk {
34+
u64 u64;
35+
struct cvmx_smix_clk_s {
36+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_25_63:39,
37+
OCT_MDIO_BITFIELD_FIELD(u64 mode:1,
38+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_21_23:3,
39+
OCT_MDIO_BITFIELD_FIELD(u64 sample_hi:5,
40+
OCT_MDIO_BITFIELD_FIELD(u64 sample_mode:1,
41+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_14_14:1,
42+
OCT_MDIO_BITFIELD_FIELD(u64 clk_idle:1,
43+
OCT_MDIO_BITFIELD_FIELD(u64 preamble:1,
44+
OCT_MDIO_BITFIELD_FIELD(u64 sample:4,
45+
OCT_MDIO_BITFIELD_FIELD(u64 phase:8,
46+
;))))))))))
47+
} s;
48+
};
49+
50+
union cvmx_smix_cmd {
51+
u64 u64;
52+
struct cvmx_smix_cmd_s {
53+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
54+
OCT_MDIO_BITFIELD_FIELD(u64 phy_op:2,
55+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_13_15:3,
56+
OCT_MDIO_BITFIELD_FIELD(u64 phy_adr:5,
57+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_5_7:3,
58+
OCT_MDIO_BITFIELD_FIELD(u64 reg_adr:5,
59+
;))))))
60+
} s;
61+
};
62+
63+
union cvmx_smix_en {
64+
u64 u64;
65+
struct cvmx_smix_en_s {
66+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_1_63:63,
67+
OCT_MDIO_BITFIELD_FIELD(u64 en:1,
68+
;))
69+
} s;
70+
};
71+
72+
union cvmx_smix_rd_dat {
73+
u64 u64;
74+
struct cvmx_smix_rd_dat_s {
75+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
76+
OCT_MDIO_BITFIELD_FIELD(u64 pending:1,
77+
OCT_MDIO_BITFIELD_FIELD(u64 val:1,
78+
OCT_MDIO_BITFIELD_FIELD(u64 dat:16,
79+
;))))
80+
} s;
81+
};
82+
83+
union cvmx_smix_wr_dat {
84+
u64 u64;
85+
struct cvmx_smix_wr_dat_s {
86+
OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46,
87+
OCT_MDIO_BITFIELD_FIELD(u64 pending:1,
88+
OCT_MDIO_BITFIELD_FIELD(u64 val:1,
89+
OCT_MDIO_BITFIELD_FIELD(u64 dat:16,
90+
;))))
91+
} s;
92+
};
93+
94+
struct cavium_mdiobus {
95+
struct mii_bus *mii_bus;
96+
u64 register_base;
97+
enum cavium_mdiobus_mode mode;
98+
};
99+
100+
#ifdef CONFIG_CAVIUM_OCTEON_SOC
101+
102+
#include <asm/octeon/octeon.h>
103+
104+
static inline void oct_mdio_writeq(u64 val, u64 addr)
105+
{
106+
cvmx_write_csr(addr, val);
107+
}
108+
109+
static inline u64 oct_mdio_readq(u64 addr)
110+
{
111+
return cvmx_read_csr(addr);
112+
}
113+
#else
114+
#define oct_mdio_writeq(val, addr) writeq(val, (void *)addr)
115+
#define oct_mdio_readq(addr) readq((void *)addr)
116+
#endif
117+
118+
int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum);
119+
int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val);

0 commit comments

Comments
 (0)