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 <monstr@monstr.eu>
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