2 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
4 * Copyright (c) 2003 Intracom S.A.
5 * by Pantelis Antoniou <panto@intracom.gr>
7 * 2005 (c) MontaVista Software, Inc.
8 * Vitaly Bordug <vbordug@ru.mvista.com>
10 * This file is licensed under the terms of the GNU General Public License
11 * version 2. This program is licensed "as is" without any warranty of any
12 * kind, whether express or implied.
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/string.h>
21 #include <linux/ptrace.h>
22 #include <linux/errno.h>
23 #include <linux/ioport.h>
24 #include <linux/slab.h>
25 #include <linux/interrupt.h>
26 #include <linux/pci.h>
27 #include <linux/init.h>
28 #include <linux/delay.h>
29 #include <linux/netdevice.h>
30 #include <linux/etherdevice.h>
31 #include <linux/skbuff.h>
32 #include <linux/spinlock.h>
33 #include <linux/mii.h>
34 #include <linux/ethtool.h>
35 #include <linux/bitops.h>
37 #include <asm/pgtable.h>
39 #include <asm/uaccess.h>
44 static int bitbang_prep_bit(u8
**dirp
, u8
**datp
, u8
*mskp
, int port
, int bit
)
46 immap_t
*im
= (immap_t
*)fs_enet_immap
;
47 void *dir
, *dat
, *ppar
;
53 dir
= &im
->im_ioport
.iop_padir
;
54 dat
= &im
->im_ioport
.iop_padat
;
55 ppar
= &im
->im_ioport
.iop_papar
;
59 dir
= &im
->im_cpm
.cp_pbdir
;
60 dat
= &im
->im_cpm
.cp_pbdat
;
61 ppar
= &im
->im_cpm
.cp_pbpar
;
65 dir
= &im
->im_ioport
.iop_pcdir
;
66 dat
= &im
->im_ioport
.iop_pcdat
;
67 ppar
= &im
->im_ioport
.iop_pcpar
;
71 dir
= &im
->im_ioport
.iop_pddir
;
72 dat
= &im
->im_ioport
.iop_pddat
;
73 ppar
= &im
->im_ioport
.iop_pdpar
;
77 dir
= &im
->im_cpm
.cp_pedir
;
78 dat
= &im
->im_cpm
.cp_pedat
;
79 ppar
= &im
->im_cpm
.cp_pepar
;
83 printk(KERN_ERR DRV_MODULE_NAME
84 "Illegal port value %d!\n", port
);
89 dir
= (char *)dir
+ adv
;
90 dat
= (char *)dat
+ adv
;
91 ppar
= (char *)ppar
+ adv
;
93 msk
= 1 << (7 - (bit
& 7));
94 if ((in_8(ppar
) & msk
) != 0) {
95 printk(KERN_ERR DRV_MODULE_NAME
96 "pin %d on port %d is not general purpose!\n", bit
, port
);
109 static int bitbang_prep_bit(u8
**dirp
, u8
**datp
, u8
*mskp
, int port
, int bit
)
111 iop_cpm2_t
*io
= &((cpm2_map_t
*)fs_enet_immap
)->im_ioport
;
112 void *dir
, *dat
, *ppar
;
118 dir
= &io
->iop_pdira
;
119 dat
= &io
->iop_pdata
;
120 ppar
= &io
->iop_ppara
;
124 dir
= &io
->iop_pdirb
;
125 dat
= &io
->iop_pdatb
;
126 ppar
= &io
->iop_pparb
;
130 dir
= &io
->iop_pdirc
;
131 dat
= &io
->iop_pdatc
;
132 ppar
= &io
->iop_pparc
;
136 dir
= &io
->iop_pdird
;
137 dat
= &io
->iop_pdatd
;
138 ppar
= &io
->iop_ppard
;
142 printk(KERN_ERR DRV_MODULE_NAME
143 "Illegal port value %d!\n", port
);
148 dir
= (char *)dir
+ adv
;
149 dat
= (char *)dat
+ adv
;
150 ppar
= (char *)ppar
+ adv
;
152 msk
= 1 << (7 - (bit
& 7));
153 if ((in_8(ppar
) & msk
) != 0) {
154 printk(KERN_ERR DRV_MODULE_NAME
155 "pin %d on port %d is not general purpose!\n", bit
, port
);
167 static inline void bb_set(u8
*p
, u8 m
)
169 out_8(p
, in_8(p
) | m
);
172 static inline void bb_clr(u8
*p
, u8 m
)
174 out_8(p
, in_8(p
) & ~m
);
177 static inline int bb_read(u8
*p
, u8 m
)
179 return (in_8(p
) & m
) != 0;
182 static inline void mdio_active(struct fs_enet_mii_bus
*bus
)
184 bb_set(bus
->bitbang
.mdio_dir
, bus
->bitbang
.mdio_msk
);
187 static inline void mdio_tristate(struct fs_enet_mii_bus
*bus
)
189 bb_clr(bus
->bitbang
.mdio_dir
, bus
->bitbang
.mdio_msk
);
192 static inline int mdio_read(struct fs_enet_mii_bus
*bus
)
194 return bb_read(bus
->bitbang
.mdio_dat
, bus
->bitbang
.mdio_msk
);
197 static inline void mdio(struct fs_enet_mii_bus
*bus
, int what
)
200 bb_set(bus
->bitbang
.mdio_dat
, bus
->bitbang
.mdio_msk
);
202 bb_clr(bus
->bitbang
.mdio_dat
, bus
->bitbang
.mdio_msk
);
205 static inline void mdc(struct fs_enet_mii_bus
*bus
, int what
)
208 bb_set(bus
->bitbang
.mdc_dat
, bus
->bitbang
.mdc_msk
);
210 bb_clr(bus
->bitbang
.mdc_dat
, bus
->bitbang
.mdc_msk
);
213 static inline void mii_delay(struct fs_enet_mii_bus
*bus
)
215 udelay(bus
->bus_info
->i
.bitbang
.delay
);
218 /* Utility to send the preamble, address, and register (common to read and write). */
219 static void bitbang_pre(struct fs_enet_mii_bus
*bus
, int read
, u8 addr
, u8 reg
)
224 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
225 * The IEEE spec says this is a PHY optional requirement. The AMD
226 * 79C874 requires one after power up and one after a MII communications
227 * error. This means that we are doing more preambles than we need,
228 * but it is safer and will be much more robust.
233 for (j
= 0; j
< 32; j
++) {
240 /* send the start bit (01) and the read opcode (10) or write (10) */
262 /* send the PHY address */
263 for (j
= 0; j
< 5; j
++) {
265 mdio(bus
, (addr
& 0x10) != 0);
272 /* send the register address */
273 for (j
= 0; j
< 5; j
++) {
275 mdio(bus
, (reg
& 0x10) != 0);
283 static int mii_read(struct fs_enet_mii_bus
*bus
, int phy_id
, int location
)
287 u8 addr
= phy_id
& 0xff;
288 u8 reg
= location
& 0xff;
290 bitbang_pre(bus
, 1, addr
, reg
);
292 /* tri-state our MDIO I/O pin so we can read */
299 /* check the turnaround bit: the PHY should be driving it to zero */
300 if (mdio_read(bus
) != 0) {
301 /* PHY didn't drive TA low */
302 for (j
= 0; j
< 32; j
++) {
315 /* read 16 bits of register data, MSB first */
317 for (j
= 0; j
< 16; j
++) {
321 rdreg
|= mdio_read(bus
);
338 static void mii_write(struct fs_enet_mii_bus
*bus
, int phy_id
, int location
, int val
)
341 u8 addr
= phy_id
& 0xff;
342 u8 reg
= location
& 0xff;
343 u16 value
= val
& 0xffff;
345 bitbang_pre(bus
, 0, addr
, reg
);
347 /* send the turnaround (10) */
359 /* write 16 bits of register data, MSB first */
360 for (j
= 0; j
< 16; j
++) {
362 mdio(bus
, (value
& 0x8000) != 0);
370 * Tri-state the MDIO line.
379 int fs_mii_bitbang_init(struct fs_enet_mii_bus
*bus
)
381 const struct fs_mii_bus_info
*bi
= bus
->bus_info
;
384 r
= bitbang_prep_bit(&bus
->bitbang
.mdio_dir
,
385 &bus
->bitbang
.mdio_dat
,
386 &bus
->bitbang
.mdio_msk
,
387 bi
->i
.bitbang
.mdio_port
,
388 bi
->i
.bitbang
.mdio_bit
);
392 r
= bitbang_prep_bit(&bus
->bitbang
.mdc_dir
,
393 &bus
->bitbang
.mdc_dat
,
394 &bus
->bitbang
.mdc_msk
,
395 bi
->i
.bitbang
.mdc_port
,
396 bi
->i
.bitbang
.mdc_bit
);
400 bus
->mii_read
= mii_read
;
401 bus
->mii_write
= mii_write
;