Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
net
ethernet
xilinx
xilinx_axienet_mdio.c
Go to the documentation of this file.
1
/*
2
* MDIO bus driver for the Xilinx Axi Ethernet device
3
*
4
* Copyright (c) 2009 Secret Lab Technologies, Ltd.
5
* Copyright (c) 2010 - 2011 Michal Simek <
[email protected]
>
6
* Copyright (c) 2010 - 2011 PetaLogix
7
* Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved.
8
*/
9
10
#include <
linux/of_address.h
>
11
#include <
linux/of_mdio.h
>
12
#include <
linux/jiffies.h
>
13
14
#include "
xilinx_axienet.h
"
15
16
#define MAX_MDIO_FREQ 2500000
/* 2.5 MHz */
17
#define DEFAULT_CLOCK_DIVISOR XAE_MDIO_DIV_DFT
18
19
/* Wait till MDIO interface is ready to accept a new transaction.*/
20
int
axienet_mdio_wait_until_ready
(
struct
axienet_local
*
lp
)
21
{
22
long
end
=
jiffies
+ 2;
23
while
(!(axienet_ior(lp,
XAE_MDIO_MCR_OFFSET
) &
24
XAE_MDIO_MCR_READY_MASK
)) {
25
if
(end -
jiffies
<= 0) {
26
WARN_ON
(1);
27
return
-
ETIMEDOUT
;
28
}
29
udelay
(1);
30
}
31
return
0;
32
}
33
46
static
int
axienet_mdio_read(
struct
mii_bus
*
bus
,
int
phy_id
,
int
reg
)
47
{
48
u32
rc
;
49
int
ret
;
50
struct
axienet_local
*
lp
= bus->
priv
;
51
52
ret =
axienet_mdio_wait_until_ready
(lp);
53
if
(ret < 0)
54
return
ret
;
55
56
axienet_iow(lp,
XAE_MDIO_MCR_OFFSET
,
57
(((phy_id <<
XAE_MDIO_MCR_PHYAD_SHIFT
) &
58
XAE_MDIO_MCR_PHYAD_MASK
) |
59
((reg <<
XAE_MDIO_MCR_REGAD_SHIFT
) &
60
XAE_MDIO_MCR_REGAD_MASK
) |
61
XAE_MDIO_MCR_INITIATE_MASK
|
62
XAE_MDIO_MCR_OP_READ_MASK
));
63
64
ret =
axienet_mdio_wait_until_ready
(lp);
65
if
(ret < 0)
66
return
ret
;
67
68
rc = axienet_ior(lp,
XAE_MDIO_MRD_OFFSET
) & 0x0000FFFF;
69
70
dev_dbg
(lp->
dev
,
"axienet_mdio_read(phy_id=%i, reg=%x) == %x\n"
,
71
phy_id, reg, rc);
72
73
return
rc
;
74
}
75
89
static
int
axienet_mdio_write(
struct
mii_bus
*bus,
int
phy_id,
int
reg,
90
u16
val
)
91
{
92
int
ret
;
93
struct
axienet_local
*lp = bus->
priv
;
94
95
dev_dbg
(lp->
dev
,
"axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n"
,
96
phy_id, reg, val);
97
98
ret =
axienet_mdio_wait_until_ready
(lp);
99
if
(ret < 0)
100
return
ret
;
101
102
axienet_iow(lp,
XAE_MDIO_MWD_OFFSET
, (
u32
) val);
103
axienet_iow(lp,
XAE_MDIO_MCR_OFFSET
,
104
(((phy_id <<
XAE_MDIO_MCR_PHYAD_SHIFT
) &
105
XAE_MDIO_MCR_PHYAD_MASK) |
106
((reg <<
XAE_MDIO_MCR_REGAD_SHIFT
) &
107
XAE_MDIO_MCR_REGAD_MASK
) |
108
XAE_MDIO_MCR_INITIATE_MASK
|
109
XAE_MDIO_MCR_OP_WRITE_MASK
));
110
111
ret =
axienet_mdio_wait_until_ready
(lp);
112
if
(ret < 0)
113
return
ret
;
114
return
0;
115
}
116
128
int
axienet_mdio_setup
(
struct
axienet_local
*lp,
struct
device_node
*np)
129
{
130
int
ret
;
131
u32
clk_div
, host_clock;
132
u32
*property_p;
133
struct
mii_bus
*
bus
;
134
struct
resource
res;
135
struct
device_node
*np1;
136
137
/* clk_div can be calculated by deriving it from the equation:
138
* fMDIO = fHOST / ((1 + clk_div) * 2)
139
*
140
* Where fMDIO <= 2500000, so we get:
141
* fHOST / ((1 + clk_div) * 2) <= 2500000
142
*
143
* Then we get:
144
* 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST)
145
*
146
* Then we get:
147
* 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST)
148
*
149
* Then we get:
150
* 1 / (1 + clk_div) <= (5000000 / fHOST)
151
*
152
* So:
153
* (1 + clk_div) >= (fHOST / 5000000)
154
*
155
* And finally:
156
* clk_div >= (fHOST / 5000000) - 1
157
*
158
* fHOST can be read from the flattened device tree as property
159
* "clock-frequency" from the CPU
160
*/
161
162
np1 =
of_find_node_by_name
(
NULL
,
"cpu"
);
163
if
(!np1) {
164
printk
(
KERN_WARNING
"%s(): Could not find CPU device node."
,
165
__func__);
166
printk
(
KERN_WARNING
"Setting MDIO clock divisor to "
167
"default %d\n"
,
DEFAULT_CLOCK_DIVISOR
);
168
clk_div =
DEFAULT_CLOCK_DIVISOR
;
169
goto
issue;
170
}
171
property_p = (
u32
*)
of_get_property
(np1,
"clock-frequency"
,
NULL
);
172
if
(!property_p) {
173
printk
(
KERN_WARNING
"%s(): Could not find CPU property: "
174
"clock-frequency."
, __func__);
175
printk
(
KERN_WARNING
"Setting MDIO clock divisor to "
176
"default %d\n"
,
DEFAULT_CLOCK_DIVISOR
);
177
clk_div =
DEFAULT_CLOCK_DIVISOR
;
178
goto
issue;
179
}
180
181
host_clock =
be32_to_cpup
(property_p);
182
clk_div = (host_clock / (
MAX_MDIO_FREQ
* 2)) - 1;
183
/* If there is any remainder from the division of
184
* fHOST / (MAX_MDIO_FREQ * 2), then we need to add
185
* 1 to the clock divisor or we will surely be above 2.5 MHz */
186
if
(host_clock % (
MAX_MDIO_FREQ
* 2))
187
clk_div++;
188
189
printk
(
KERN_DEBUG
"%s(): Setting MDIO clock divisor to %u based "
190
"on %u Hz host clock.\n"
, __func__, clk_div, host_clock);
191
192
of_node_put(np1);
193
issue:
194
axienet_iow(lp,
XAE_MDIO_MC_OFFSET
,
195
(((
u32
) clk_div) |
XAE_MDIO_MC_MDIOEN_MASK
));
196
197
ret =
axienet_mdio_wait_until_ready
(lp);
198
if
(ret < 0)
199
return
ret
;
200
201
bus = mdiobus_alloc();
202
if
(!bus)
203
return
-
ENOMEM
;
204
205
np1 =
of_get_parent
(lp->
phy_node
);
206
of_address_to_resource
(np1, 0, &res);
207
snprintf
(bus->
id
,
MII_BUS_ID_SIZE
,
"%.8llx"
,
208
(
unsigned
long
long
) res.
start
);
209
210
bus->
priv
= lp;
211
bus->
name
=
"Xilinx Axi Ethernet MDIO"
;
212
bus->
read
= axienet_mdio_read;
213
bus->
write
= axienet_mdio_write;
214
bus->
parent
= lp->
dev
;
215
bus->
irq
= lp->
mdio_irqs
;
/* preallocated IRQ table */
216
lp->
mii_bus
=
bus
;
217
218
ret =
of_mdiobus_register
(bus, np1);
219
if
(ret) {
220
mdiobus_free
(bus);
221
return
ret
;
222
}
223
return
0;
224
}
225
232
void
axienet_mdio_teardown
(
struct
axienet_local
*lp)
233
{
234
mdiobus_unregister
(lp->
mii_bus
);
235
kfree
(lp->
mii_bus
->irq);
236
mdiobus_free
(lp->
mii_bus
);
237
lp->
mii_bus
=
NULL
;
238
}
Generated on Thu Jan 10 2013 14:06:13 for Linux Kernel by
1.8.2