diff options
author | David Daney <david.daney@cavium.com> | 2013-04-03 05:25:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-07 17:12:01 -0400 |
commit | 775ae9b264c391c96f6ed7bb6f063876afddcea5 (patch) | |
tree | 4ba54e49721e2617c146ccee2197297e8a194d4b /drivers/net/phy/mdio-octeon.c | |
parent | fc52eea4c5f160d1b42fa1852fece38e5a0fc991 (diff) |
netdev/phy: Implement ieee802.3 clause 45 in mdio-octeon.c
The Octeon SMI/MDIO interfaces can do clause 45 communications, so
implement this in the driver.
Also fix some comment formatting to make it consistent and to comply
with the netdev style.
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/mdio-octeon.c')
-rw-r--r-- | drivers/net/phy/mdio-octeon.c | 94 |
1 files changed, 87 insertions, 7 deletions
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index c2c878d496ad..b51fa1f469b0 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c | |||
@@ -3,7 +3,7 @@ | |||
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,2011 Cavium, Inc. | 6 | * Copyright (C) 2009-2012 Cavium, Inc. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
@@ -27,30 +27,98 @@ | |||
27 | #define SMI_CLK 0x18 | 27 | #define SMI_CLK 0x18 |
28 | #define SMI_EN 0x20 | 28 | #define SMI_EN 0x20 |
29 | 29 | ||
30 | enum octeon_mdiobus_mode { | ||
31 | UNINIT = 0, | ||
32 | C22, | ||
33 | C45 | ||
34 | }; | ||
35 | |||
30 | struct octeon_mdiobus { | 36 | struct octeon_mdiobus { |
31 | struct mii_bus *mii_bus; | 37 | struct mii_bus *mii_bus; |
32 | u64 register_base; | 38 | u64 register_base; |
33 | resource_size_t mdio_phys; | 39 | resource_size_t mdio_phys; |
34 | resource_size_t regsize; | 40 | resource_size_t regsize; |
41 | enum octeon_mdiobus_mode mode; | ||
35 | int phy_irq[PHY_MAX_ADDR]; | 42 | int phy_irq[PHY_MAX_ADDR]; |
36 | }; | 43 | }; |
37 | 44 | ||
45 | static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p, | ||
46 | enum octeon_mdiobus_mode m) | ||
47 | { | ||
48 | union cvmx_smix_clk smi_clk; | ||
49 | |||
50 | if (m == p->mode) | ||
51 | return; | ||
52 | |||
53 | smi_clk.u64 = cvmx_read_csr(p->register_base + SMI_CLK); | ||
54 | smi_clk.s.mode = (m == C45) ? 1 : 0; | ||
55 | smi_clk.s.preamble = 1; | ||
56 | cvmx_write_csr(p->register_base + SMI_CLK, smi_clk.u64); | ||
57 | p->mode = m; | ||
58 | } | ||
59 | |||
60 | static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p, | ||
61 | int phy_id, int regnum) | ||
62 | { | ||
63 | union cvmx_smix_cmd smi_cmd; | ||
64 | union cvmx_smix_wr_dat smi_wr; | ||
65 | int timeout = 1000; | ||
66 | |||
67 | octeon_mdiobus_set_mode(p, C45); | ||
68 | |||
69 | smi_wr.u64 = 0; | ||
70 | smi_wr.s.dat = regnum & 0xffff; | ||
71 | cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); | ||
72 | |||
73 | regnum = (regnum >> 16) & 0x1f; | ||
74 | |||
75 | smi_cmd.u64 = 0; | ||
76 | smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ | ||
77 | smi_cmd.s.phy_adr = phy_id; | ||
78 | smi_cmd.s.reg_adr = regnum; | ||
79 | cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); | ||
80 | |||
81 | do { | ||
82 | /* Wait 1000 clocks so we don't saturate the RSL bus | ||
83 | * doing reads. | ||
84 | */ | ||
85 | __delay(1000); | ||
86 | smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT); | ||
87 | } while (smi_wr.s.pending && --timeout); | ||
88 | |||
89 | if (timeout <= 0) | ||
90 | return -EIO; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
38 | static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) | 94 | static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) |
39 | { | 95 | { |
40 | struct octeon_mdiobus *p = bus->priv; | 96 | struct octeon_mdiobus *p = bus->priv; |
41 | union cvmx_smix_cmd smi_cmd; | 97 | union cvmx_smix_cmd smi_cmd; |
42 | union cvmx_smix_rd_dat smi_rd; | 98 | union cvmx_smix_rd_dat smi_rd; |
99 | unsigned int op = 1; /* MDIO_CLAUSE_22_READ */ | ||
43 | int timeout = 1000; | 100 | int timeout = 1000; |
44 | 101 | ||
102 | if (regnum & MII_ADDR_C45) { | ||
103 | int r = octeon_mdiobus_c45_addr(p, phy_id, regnum); | ||
104 | if (r < 0) | ||
105 | return r; | ||
106 | |||
107 | regnum = (regnum >> 16) & 0x1f; | ||
108 | op = 3; /* MDIO_CLAUSE_45_READ */ | ||
109 | } else { | ||
110 | octeon_mdiobus_set_mode(p, C22); | ||
111 | } | ||
112 | |||
113 | |||
45 | smi_cmd.u64 = 0; | 114 | smi_cmd.u64 = 0; |
46 | smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */ | 115 | smi_cmd.s.phy_op = op; |
47 | smi_cmd.s.phy_adr = phy_id; | 116 | smi_cmd.s.phy_adr = phy_id; |
48 | smi_cmd.s.reg_adr = regnum; | 117 | smi_cmd.s.reg_adr = regnum; |
49 | cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); | 118 | cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); |
50 | 119 | ||
51 | do { | 120 | do { |
52 | /* | 121 | /* Wait 1000 clocks so we don't saturate the RSL bus |
53 | * Wait 1000 clocks so we don't saturate the RSL bus | ||
54 | * doing reads. | 122 | * doing reads. |
55 | */ | 123 | */ |
56 | __delay(1000); | 124 | __delay(1000); |
@@ -69,21 +137,33 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, | |||
69 | struct octeon_mdiobus *p = bus->priv; | 137 | struct octeon_mdiobus *p = bus->priv; |
70 | union cvmx_smix_cmd smi_cmd; | 138 | union cvmx_smix_cmd smi_cmd; |
71 | union cvmx_smix_wr_dat smi_wr; | 139 | union cvmx_smix_wr_dat smi_wr; |
140 | unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */ | ||
72 | int timeout = 1000; | 141 | int timeout = 1000; |
73 | 142 | ||
143 | |||
144 | if (regnum & MII_ADDR_C45) { | ||
145 | int r = octeon_mdiobus_c45_addr(p, phy_id, regnum); | ||
146 | if (r < 0) | ||
147 | return r; | ||
148 | |||
149 | regnum = (regnum >> 16) & 0x1f; | ||
150 | op = 1; /* MDIO_CLAUSE_45_WRITE */ | ||
151 | } else { | ||
152 | octeon_mdiobus_set_mode(p, C22); | ||
153 | } | ||
154 | |||
74 | smi_wr.u64 = 0; | 155 | smi_wr.u64 = 0; |
75 | smi_wr.s.dat = val; | 156 | smi_wr.s.dat = val; |
76 | cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); | 157 | cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); |
77 | 158 | ||
78 | smi_cmd.u64 = 0; | 159 | smi_cmd.u64 = 0; |
79 | smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */ | 160 | smi_cmd.s.phy_op = op; |
80 | smi_cmd.s.phy_adr = phy_id; | 161 | smi_cmd.s.phy_adr = phy_id; |
81 | smi_cmd.s.reg_adr = regnum; | 162 | smi_cmd.s.reg_adr = regnum; |
82 | cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); | 163 | cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); |
83 | 164 | ||
84 | do { | 165 | do { |
85 | /* | 166 | /* Wait 1000 clocks so we don't saturate the RSL bus |
86 | * Wait 1000 clocks so we don't saturate the RSL bus | ||
87 | * doing reads. | 167 | * doing reads. |
88 | */ | 168 | */ |
89 | __delay(1000); | 169 | __delay(1000); |