aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/mdio-octeon.c
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2013-04-03 05:25:32 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-07 17:12:01 -0400
commit775ae9b264c391c96f6ed7bb6f063876afddcea5 (patch)
tree4ba54e49721e2617c146ccee2197297e8a194d4b /drivers/net/phy/mdio-octeon.c
parentfc52eea4c5f160d1b42fa1852fece38e5a0fc991 (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.c94
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
30enum octeon_mdiobus_mode {
31 UNINIT = 0,
32 C22,
33 C45
34};
35
30struct octeon_mdiobus { 36struct 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
45static 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
60static 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
38static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) 94static 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);