• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2009-2016 Cavium, Inc.
4  */
5 
6 #include <linux/delay.h>
7 #include <linux/io.h>
8 #include <linux/module.h>
9 #include <linux/phy.h>
10 
11 #include "mdio-cavium.h"
12 
cavium_mdiobus_set_mode(struct cavium_mdiobus * p,enum cavium_mdiobus_mode m)13 static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p,
14 				    enum cavium_mdiobus_mode m)
15 {
16 	union cvmx_smix_clk smi_clk;
17 
18 	if (m == p->mode)
19 		return;
20 
21 	smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK);
22 	smi_clk.s.mode = (m == C45) ? 1 : 0;
23 	smi_clk.s.preamble = 1;
24 	oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK);
25 	p->mode = m;
26 }
27 
cavium_mdiobus_c45_addr(struct cavium_mdiobus * p,int phy_id,int devad,int regnum)28 static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p,
29 				   int phy_id, int devad, int regnum)
30 {
31 	union cvmx_smix_cmd smi_cmd;
32 	union cvmx_smix_wr_dat smi_wr;
33 	int timeout = 1000;
34 
35 	cavium_mdiobus_set_mode(p, C45);
36 
37 	smi_wr.u64 = 0;
38 	smi_wr.s.dat = regnum & 0xffff;
39 	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
40 
41 	smi_cmd.u64 = 0;
42 	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
43 	smi_cmd.s.phy_adr = phy_id;
44 	smi_cmd.s.reg_adr = devad;
45 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
46 
47 	do {
48 		/* Wait 1000 clocks so we don't saturate the RSL bus
49 		 * doing reads.
50 		 */
51 		__delay(1000);
52 		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
53 	} while (smi_wr.s.pending && --timeout);
54 
55 	if (timeout <= 0)
56 		return -EIO;
57 	return 0;
58 }
59 
cavium_mdiobus_read_c22(struct mii_bus * bus,int phy_id,int regnum)60 int cavium_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int regnum)
61 {
62 	struct cavium_mdiobus *p = bus->priv;
63 	union cvmx_smix_cmd smi_cmd;
64 	union cvmx_smix_rd_dat smi_rd;
65 	int timeout = 1000;
66 
67 	cavium_mdiobus_set_mode(p, C22);
68 
69 	smi_cmd.u64 = 0;
70 	smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
71 	smi_cmd.s.phy_adr = phy_id;
72 	smi_cmd.s.reg_adr = regnum;
73 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
74 
75 	do {
76 		/* Wait 1000 clocks so we don't saturate the RSL bus
77 		 * doing reads.
78 		 */
79 		__delay(1000);
80 		smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
81 	} while (smi_rd.s.pending && --timeout);
82 
83 	if (smi_rd.s.val)
84 		return smi_rd.s.dat;
85 	else
86 		return -EIO;
87 }
88 EXPORT_SYMBOL(cavium_mdiobus_read_c22);
89 
cavium_mdiobus_read_c45(struct mii_bus * bus,int phy_id,int devad,int regnum)90 int cavium_mdiobus_read_c45(struct mii_bus *bus, int phy_id, int devad,
91 			    int regnum)
92 {
93 	struct cavium_mdiobus *p = bus->priv;
94 	union cvmx_smix_cmd smi_cmd;
95 	union cvmx_smix_rd_dat smi_rd;
96 	int timeout = 1000;
97 	int r;
98 
99 	r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);
100 	if (r < 0)
101 		return r;
102 
103 	smi_cmd.u64 = 0;
104 	smi_cmd.s.phy_op = 3; /* MDIO_CLAUSE_45_READ */
105 	smi_cmd.s.phy_adr = phy_id;
106 	smi_cmd.s.reg_adr = regnum;
107 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
108 
109 	do {
110 		/* Wait 1000 clocks so we don't saturate the RSL bus
111 		 * doing reads.
112 		 */
113 		__delay(1000);
114 		smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT);
115 	} while (smi_rd.s.pending && --timeout);
116 
117 	if (smi_rd.s.val)
118 		return smi_rd.s.dat;
119 	else
120 		return -EIO;
121 }
122 EXPORT_SYMBOL(cavium_mdiobus_read_c45);
123 
cavium_mdiobus_write_c22(struct mii_bus * bus,int phy_id,int regnum,u16 val)124 int cavium_mdiobus_write_c22(struct mii_bus *bus, int phy_id, int regnum,
125 			     u16 val)
126 {
127 	struct cavium_mdiobus *p = bus->priv;
128 	union cvmx_smix_cmd smi_cmd;
129 	union cvmx_smix_wr_dat smi_wr;
130 	int timeout = 1000;
131 
132 	cavium_mdiobus_set_mode(p, C22);
133 
134 	smi_wr.u64 = 0;
135 	smi_wr.s.dat = val;
136 	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
137 
138 	smi_cmd.u64 = 0;
139 	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
140 	smi_cmd.s.phy_adr = phy_id;
141 	smi_cmd.s.reg_adr = regnum;
142 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
143 
144 	do {
145 		/* Wait 1000 clocks so we don't saturate the RSL bus
146 		 * doing reads.
147 		 */
148 		__delay(1000);
149 		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
150 	} while (smi_wr.s.pending && --timeout);
151 
152 	if (timeout <= 0)
153 		return -EIO;
154 
155 	return 0;
156 }
157 EXPORT_SYMBOL(cavium_mdiobus_write_c22);
158 
cavium_mdiobus_write_c45(struct mii_bus * bus,int phy_id,int devad,int regnum,u16 val)159 int cavium_mdiobus_write_c45(struct mii_bus *bus, int phy_id, int devad,
160 			     int regnum, u16 val)
161 {
162 	struct cavium_mdiobus *p = bus->priv;
163 	union cvmx_smix_cmd smi_cmd;
164 	union cvmx_smix_wr_dat smi_wr;
165 	int timeout = 1000;
166 	int r;
167 
168 	r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum);
169 	if (r < 0)
170 		return r;
171 
172 	smi_wr.u64 = 0;
173 	smi_wr.s.dat = val;
174 	oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT);
175 
176 	smi_cmd.u64 = 0;
177 	smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_45_WRITE */
178 	smi_cmd.s.phy_adr = phy_id;
179 	smi_cmd.s.reg_adr = devad;
180 	oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD);
181 
182 	do {
183 		/* Wait 1000 clocks so we don't saturate the RSL bus
184 		 * doing reads.
185 		 */
186 		__delay(1000);
187 		smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT);
188 	} while (smi_wr.s.pending && --timeout);
189 
190 	if (timeout <= 0)
191 		return -EIO;
192 
193 	return 0;
194 }
195 EXPORT_SYMBOL(cavium_mdiobus_write_c45);
196 
197 MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers");
198 MODULE_AUTHOR("David Daney");
199 MODULE_LICENSE("GPL v2");
200