diff options
author | David Daney <david.daney@cavium.com> | 2016-03-11 12:53:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-14 15:27:22 -0400 |
commit | 1eefee901fca0208b8a56f20cdc134e2b8638ae7 (patch) | |
tree | e8f32fb9b65e392349d1462c45d0f527c8c2f3d0 /drivers/net/phy | |
parent | 5fc7cf179449502ad4ad67845ded2df94b680de2 (diff) |
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>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 11 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio-cavium.c | 149 | ||||
-rw-r--r-- | drivers/net/phy/mdio-cavium.h | 119 | ||||
-rw-r--r-- | drivers/net/phy/mdio-octeon.c | 280 |
5 files changed, 292 insertions, 268 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f0a77020037a..40faec9f3b0b 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig | |||
@@ -183,15 +183,18 @@ config MDIO_GPIO | |||
183 | To compile this driver as a module, choose M here: the module | 183 | To compile this driver as a module, choose M here: the module |
184 | will be called mdio-gpio. | 184 | will be called mdio-gpio. |
185 | 185 | ||
186 | config MDIO_CAVIUM | ||
187 | tristate | ||
188 | |||
186 | config MDIO_OCTEON | 189 | 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" |
188 | depends on 64BIT | 191 | depends on 64BIT |
189 | depends on HAS_IOMEM | 192 | depends on HAS_IOMEM |
193 | select MDIO_CAVIUM | ||
190 | help | 194 | help |
191 | |||
192 | This module provides a driver for the Octeon and ThunderX MDIO | 195 | This module provides a driver for the Octeon and ThunderX MDIO |
193 | busses. It is required by the Octeon and ThunderX ethernet device | 196 | buses. It is required by the Octeon and ThunderX ethernet device |
194 | drivers. | 197 | drivers on some systems. |
195 | 198 | ||
196 | config MDIO_SUN4I | 199 | config MDIO_SUN4I |
197 | tristate "Allwinner sun4i MDIO interface support" | 200 | tristate "Allwinner sun4i MDIO interface support" |
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 680e88f9915a..041b3d977d31 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_DP83867_PHY) += dp83867.o | |||
31 | obj-$(CONFIG_STE10XP) += ste10Xp.o | 31 | obj-$(CONFIG_STE10XP) += ste10Xp.o |
32 | obj-$(CONFIG_MICREL_PHY) += micrel.o | 32 | obj-$(CONFIG_MICREL_PHY) += micrel.o |
33 | obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o | 33 | obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o |
34 | obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o | ||
34 | obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o | 35 | obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o |
35 | obj-$(CONFIG_AT803X_PHY) += at803x.o | 36 | obj-$(CONFIG_AT803X_PHY) += at803x.o |
36 | obj-$(CONFIG_AMD_PHY) += amd.o | 37 | obj-$(CONFIG_AMD_PHY) += amd.o |
diff --git a/drivers/net/phy/mdio-cavium.c b/drivers/net/phy/mdio-cavium.c new file mode 100644 index 000000000000..e796ee121eac --- /dev/null +++ b/drivers/net/phy/mdio-cavium.c | |||
@@ -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); | ||
diff --git a/drivers/net/phy/mdio-cavium.h b/drivers/net/phy/mdio-cavium.h new file mode 100644 index 000000000000..4bccd45d24e2 --- /dev/null +++ b/drivers/net/phy/mdio-cavium.h | |||
@@ -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); | ||
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index 47d4f2f263d1..ab6914f8bd50 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c | |||
@@ -3,272 +3,26 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 2009-2012 Cavium, Inc. | 6 | * Copyright (C) 2009-2015 Cavium, Inc. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
10 | #include <linux/of_address.h> | 10 | #include <linux/of_address.h> |
11 | #include <linux/of_mdio.h> | 11 | #include <linux/of_mdio.h> |
12 | #include <linux/delay.h> | ||
13 | #include <linux/module.h> | 12 | #include <linux/module.h> |
14 | #include <linux/gfp.h> | 13 | #include <linux/gfp.h> |
15 | #include <linux/phy.h> | 14 | #include <linux/phy.h> |
16 | #include <linux/io.h> | 15 | #include <linux/io.h> |
17 | 16 | ||
18 | #ifdef CONFIG_CAVIUM_OCTEON_SOC | 17 | #include "mdio-cavium.h" |
19 | #include <asm/octeon/octeon.h> | ||
20 | #endif | ||
21 | |||
22 | #define DRV_VERSION "1.1" | ||
23 | #define DRV_DESCRIPTION "Cavium Networks Octeon/ThunderX SMI/MDIO driver" | ||
24 | |||
25 | #define SMI_CMD 0x0 | ||
26 | #define SMI_WR_DAT 0x8 | ||
27 | #define SMI_RD_DAT 0x10 | ||
28 | #define SMI_CLK 0x18 | ||
29 | #define SMI_EN 0x20 | ||
30 | |||
31 | #ifdef __BIG_ENDIAN_BITFIELD | ||
32 | #define OCT_MDIO_BITFIELD_FIELD(field, more) \ | ||
33 | field; \ | ||
34 | more | ||
35 | |||
36 | #else | ||
37 | #define OCT_MDIO_BITFIELD_FIELD(field, more) \ | ||
38 | more \ | ||
39 | field; | ||
40 | |||
41 | #endif | ||
42 | |||
43 | union cvmx_smix_clk { | ||
44 | u64 u64; | ||
45 | struct cvmx_smix_clk_s { | ||
46 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_25_63:39, | ||
47 | OCT_MDIO_BITFIELD_FIELD(u64 mode:1, | ||
48 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_21_23:3, | ||
49 | OCT_MDIO_BITFIELD_FIELD(u64 sample_hi:5, | ||
50 | OCT_MDIO_BITFIELD_FIELD(u64 sample_mode:1, | ||
51 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_14_14:1, | ||
52 | OCT_MDIO_BITFIELD_FIELD(u64 clk_idle:1, | ||
53 | OCT_MDIO_BITFIELD_FIELD(u64 preamble:1, | ||
54 | OCT_MDIO_BITFIELD_FIELD(u64 sample:4, | ||
55 | OCT_MDIO_BITFIELD_FIELD(u64 phase:8, | ||
56 | ;)))))))))) | ||
57 | } s; | ||
58 | }; | ||
59 | |||
60 | union cvmx_smix_cmd { | ||
61 | u64 u64; | ||
62 | struct cvmx_smix_cmd_s { | ||
63 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, | ||
64 | OCT_MDIO_BITFIELD_FIELD(u64 phy_op:2, | ||
65 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_13_15:3, | ||
66 | OCT_MDIO_BITFIELD_FIELD(u64 phy_adr:5, | ||
67 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_5_7:3, | ||
68 | OCT_MDIO_BITFIELD_FIELD(u64 reg_adr:5, | ||
69 | ;)))))) | ||
70 | } s; | ||
71 | }; | ||
72 | |||
73 | union cvmx_smix_en { | ||
74 | u64 u64; | ||
75 | struct cvmx_smix_en_s { | ||
76 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_1_63:63, | ||
77 | OCT_MDIO_BITFIELD_FIELD(u64 en:1, | ||
78 | ;)) | ||
79 | } s; | ||
80 | }; | ||
81 | |||
82 | union cvmx_smix_rd_dat { | ||
83 | u64 u64; | ||
84 | struct cvmx_smix_rd_dat_s { | ||
85 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, | ||
86 | OCT_MDIO_BITFIELD_FIELD(u64 pending:1, | ||
87 | OCT_MDIO_BITFIELD_FIELD(u64 val:1, | ||
88 | OCT_MDIO_BITFIELD_FIELD(u64 dat:16, | ||
89 | ;)))) | ||
90 | } s; | ||
91 | }; | ||
92 | |||
93 | union cvmx_smix_wr_dat { | ||
94 | u64 u64; | ||
95 | struct cvmx_smix_wr_dat_s { | ||
96 | OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, | ||
97 | OCT_MDIO_BITFIELD_FIELD(u64 pending:1, | ||
98 | OCT_MDIO_BITFIELD_FIELD(u64 val:1, | ||
99 | OCT_MDIO_BITFIELD_FIELD(u64 dat:16, | ||
100 | ;)))) | ||
101 | } s; | ||
102 | }; | ||
103 | |||
104 | enum octeon_mdiobus_mode { | ||
105 | UNINIT = 0, | ||
106 | C22, | ||
107 | C45 | ||
108 | }; | ||
109 | |||
110 | struct octeon_mdiobus { | ||
111 | struct mii_bus *mii_bus; | ||
112 | u64 register_base; | ||
113 | resource_size_t mdio_phys; | ||
114 | resource_size_t regsize; | ||
115 | enum octeon_mdiobus_mode mode; | ||
116 | }; | ||
117 | |||
118 | #ifdef CONFIG_CAVIUM_OCTEON_SOC | ||
119 | static void oct_mdio_writeq(u64 val, u64 addr) | ||
120 | { | ||
121 | cvmx_write_csr(addr, val); | ||
122 | } | ||
123 | |||
124 | static u64 oct_mdio_readq(u64 addr) | ||
125 | { | ||
126 | return cvmx_read_csr(addr); | ||
127 | } | ||
128 | #else | ||
129 | #define oct_mdio_writeq(val, addr) writeq_relaxed(val, (void *)addr) | ||
130 | #define oct_mdio_readq(addr) readq_relaxed((void *)addr) | ||
131 | #endif | ||
132 | |||
133 | static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p, | ||
134 | enum octeon_mdiobus_mode m) | ||
135 | { | ||
136 | union cvmx_smix_clk smi_clk; | ||
137 | |||
138 | if (m == p->mode) | ||
139 | return; | ||
140 | |||
141 | smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK); | ||
142 | smi_clk.s.mode = (m == C45) ? 1 : 0; | ||
143 | smi_clk.s.preamble = 1; | ||
144 | oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK); | ||
145 | p->mode = m; | ||
146 | } | ||
147 | |||
148 | static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p, | ||
149 | int phy_id, int regnum) | ||
150 | { | ||
151 | union cvmx_smix_cmd smi_cmd; | ||
152 | union cvmx_smix_wr_dat smi_wr; | ||
153 | int timeout = 1000; | ||
154 | |||
155 | octeon_mdiobus_set_mode(p, C45); | ||
156 | |||
157 | smi_wr.u64 = 0; | ||
158 | smi_wr.s.dat = regnum & 0xffff; | ||
159 | oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); | ||
160 | |||
161 | regnum = (regnum >> 16) & 0x1f; | ||
162 | |||
163 | smi_cmd.u64 = 0; | ||
164 | smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ | ||
165 | smi_cmd.s.phy_adr = phy_id; | ||
166 | smi_cmd.s.reg_adr = regnum; | ||
167 | oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); | ||
168 | |||
169 | do { | ||
170 | /* Wait 1000 clocks so we don't saturate the RSL bus | ||
171 | * doing reads. | ||
172 | */ | ||
173 | __delay(1000); | ||
174 | smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); | ||
175 | } while (smi_wr.s.pending && --timeout); | ||
176 | |||
177 | if (timeout <= 0) | ||
178 | return -EIO; | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) | ||
183 | { | ||
184 | struct octeon_mdiobus *p = bus->priv; | ||
185 | union cvmx_smix_cmd smi_cmd; | ||
186 | union cvmx_smix_rd_dat smi_rd; | ||
187 | unsigned int op = 1; /* MDIO_CLAUSE_22_READ */ | ||
188 | int timeout = 1000; | ||
189 | |||
190 | if (regnum & MII_ADDR_C45) { | ||
191 | int r = octeon_mdiobus_c45_addr(p, phy_id, regnum); | ||
192 | if (r < 0) | ||
193 | return r; | ||
194 | |||
195 | regnum = (regnum >> 16) & 0x1f; | ||
196 | op = 3; /* MDIO_CLAUSE_45_READ */ | ||
197 | } else { | ||
198 | octeon_mdiobus_set_mode(p, C22); | ||
199 | } | ||
200 | |||
201 | |||
202 | smi_cmd.u64 = 0; | ||
203 | smi_cmd.s.phy_op = op; | ||
204 | smi_cmd.s.phy_adr = phy_id; | ||
205 | smi_cmd.s.reg_adr = regnum; | ||
206 | oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); | ||
207 | |||
208 | do { | ||
209 | /* Wait 1000 clocks so we don't saturate the RSL bus | ||
210 | * doing reads. | ||
211 | */ | ||
212 | __delay(1000); | ||
213 | smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT); | ||
214 | } while (smi_rd.s.pending && --timeout); | ||
215 | |||
216 | if (smi_rd.s.val) | ||
217 | return smi_rd.s.dat; | ||
218 | else | ||
219 | return -EIO; | ||
220 | } | ||
221 | |||
222 | static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, | ||
223 | int regnum, u16 val) | ||
224 | { | ||
225 | struct octeon_mdiobus *p = bus->priv; | ||
226 | union cvmx_smix_cmd smi_cmd; | ||
227 | union cvmx_smix_wr_dat smi_wr; | ||
228 | unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */ | ||
229 | int timeout = 1000; | ||
230 | |||
231 | |||
232 | if (regnum & MII_ADDR_C45) { | ||
233 | int r = octeon_mdiobus_c45_addr(p, phy_id, regnum); | ||
234 | if (r < 0) | ||
235 | return r; | ||
236 | |||
237 | regnum = (regnum >> 16) & 0x1f; | ||
238 | op = 1; /* MDIO_CLAUSE_45_WRITE */ | ||
239 | } else { | ||
240 | octeon_mdiobus_set_mode(p, C22); | ||
241 | } | ||
242 | |||
243 | smi_wr.u64 = 0; | ||
244 | smi_wr.s.dat = val; | ||
245 | oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); | ||
246 | |||
247 | smi_cmd.u64 = 0; | ||
248 | smi_cmd.s.phy_op = op; | ||
249 | smi_cmd.s.phy_adr = phy_id; | ||
250 | smi_cmd.s.reg_adr = regnum; | ||
251 | oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); | ||
252 | |||
253 | do { | ||
254 | /* Wait 1000 clocks so we don't saturate the RSL bus | ||
255 | * doing reads. | ||
256 | */ | ||
257 | __delay(1000); | ||
258 | smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); | ||
259 | } while (smi_wr.s.pending && --timeout); | ||
260 | |||
261 | if (timeout <= 0) | ||
262 | return -EIO; | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | 18 | ||
267 | static int octeon_mdiobus_probe(struct platform_device *pdev) | 19 | static int octeon_mdiobus_probe(struct platform_device *pdev) |
268 | { | 20 | { |
269 | struct octeon_mdiobus *bus; | 21 | struct cavium_mdiobus *bus; |
270 | struct mii_bus *mii_bus; | 22 | struct mii_bus *mii_bus; |
271 | struct resource *res_mem; | 23 | struct resource *res_mem; |
24 | resource_size_t mdio_phys; | ||
25 | resource_size_t regsize; | ||
272 | union cvmx_smix_en smi_en; | 26 | union cvmx_smix_en smi_en; |
273 | int err = -ENOENT; | 27 | int err = -ENOENT; |
274 | 28 | ||
@@ -284,17 +38,17 @@ static int octeon_mdiobus_probe(struct platform_device *pdev) | |||
284 | 38 | ||
285 | bus = mii_bus->priv; | 39 | bus = mii_bus->priv; |
286 | bus->mii_bus = mii_bus; | 40 | bus->mii_bus = mii_bus; |
287 | bus->mdio_phys = res_mem->start; | 41 | mdio_phys = res_mem->start; |
288 | bus->regsize = resource_size(res_mem); | 42 | regsize = resource_size(res_mem); |
289 | 43 | ||
290 | if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize, | 44 | if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize, |
291 | res_mem->name)) { | 45 | res_mem->name)) { |
292 | dev_err(&pdev->dev, "request_mem_region failed\n"); | 46 | dev_err(&pdev->dev, "request_mem_region failed\n"); |
293 | return -ENXIO; | 47 | return -ENXIO; |
294 | } | 48 | } |
295 | 49 | ||
296 | bus->register_base = | 50 | bus->register_base = |
297 | (u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize); | 51 | (u64)devm_ioremap(&pdev->dev, mdio_phys, regsize); |
298 | if (!bus->register_base) { | 52 | if (!bus->register_base) { |
299 | dev_err(&pdev->dev, "dev_ioremap failed\n"); | 53 | dev_err(&pdev->dev, "dev_ioremap failed\n"); |
300 | return -ENOMEM; | 54 | return -ENOMEM; |
@@ -304,13 +58,12 @@ static int octeon_mdiobus_probe(struct platform_device *pdev) | |||
304 | smi_en.s.en = 1; | 58 | smi_en.s.en = 1; |
305 | oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); | 59 | oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); |
306 | 60 | ||
307 | bus->mii_bus->priv = bus; | 61 | bus->mii_bus->name = KBUILD_MODNAME; |
308 | bus->mii_bus->name = "mdio-octeon"; | ||
309 | snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base); | 62 | snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base); |
310 | bus->mii_bus->parent = &pdev->dev; | 63 | bus->mii_bus->parent = &pdev->dev; |
311 | 64 | ||
312 | bus->mii_bus->read = octeon_mdiobus_read; | 65 | bus->mii_bus->read = cavium_mdiobus_read; |
313 | bus->mii_bus->write = octeon_mdiobus_write; | 66 | bus->mii_bus->write = cavium_mdiobus_write; |
314 | 67 | ||
315 | platform_set_drvdata(pdev, bus); | 68 | platform_set_drvdata(pdev, bus); |
316 | 69 | ||
@@ -318,7 +71,7 @@ static int octeon_mdiobus_probe(struct platform_device *pdev) | |||
318 | if (err) | 71 | if (err) |
319 | goto fail_register; | 72 | goto fail_register; |
320 | 73 | ||
321 | dev_info(&pdev->dev, "Version " DRV_VERSION "\n"); | 74 | dev_info(&pdev->dev, "Probed\n"); |
322 | 75 | ||
323 | return 0; | 76 | return 0; |
324 | fail_register: | 77 | fail_register: |
@@ -330,7 +83,7 @@ fail_register: | |||
330 | 83 | ||
331 | static int octeon_mdiobus_remove(struct platform_device *pdev) | 84 | static int octeon_mdiobus_remove(struct platform_device *pdev) |
332 | { | 85 | { |
333 | struct octeon_mdiobus *bus; | 86 | struct cavium_mdiobus *bus; |
334 | union cvmx_smix_en smi_en; | 87 | union cvmx_smix_en smi_en; |
335 | 88 | ||
336 | bus = platform_get_drvdata(pdev); | 89 | bus = platform_get_drvdata(pdev); |
@@ -352,7 +105,7 @@ MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); | |||
352 | 105 | ||
353 | static struct platform_driver octeon_mdiobus_driver = { | 106 | static struct platform_driver octeon_mdiobus_driver = { |
354 | .driver = { | 107 | .driver = { |
355 | .name = "mdio-octeon", | 108 | .name = KBUILD_MODNAME, |
356 | .of_match_table = octeon_mdiobus_match, | 109 | .of_match_table = octeon_mdiobus_match, |
357 | }, | 110 | }, |
358 | .probe = octeon_mdiobus_probe, | 111 | .probe = octeon_mdiobus_probe, |
@@ -367,7 +120,6 @@ EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency); | |||
367 | 120 | ||
368 | module_platform_driver(octeon_mdiobus_driver); | 121 | module_platform_driver(octeon_mdiobus_driver); |
369 | 122 | ||
370 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | 123 | MODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver"); |
371 | MODULE_VERSION(DRV_VERSION); | ||
372 | MODULE_AUTHOR("David Daney"); | 124 | MODULE_AUTHOR("David Daney"); |
373 | MODULE_LICENSE("GPL"); | 125 | MODULE_LICENSE("GPL"); |