diff options
author | Greg Ungerer <gerg@snapgear.com> | 2005-11-06 23:09:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 11:00:47 -0500 |
commit | 562d2f8ce4e463e1427ddfab5e84440323856f43 (patch) | |
tree | df5807fb8521eb4f7a70820cb3293f1c19ef8764 /drivers/net/fec.c | |
parent | 7a77d918ad8fb152312525b70780f6e0052b3ee3 (diff) |
[PATCH] m68knommu: FEC ethernet support for the ColdFire 5208
Add support for the new 5208 ColdFire (Matt Waddel / Mike Lavender)
Patch originally from Matt Waddel (from code originally written by
Mike Lavender).
I also re-ordered the init code to avoid interrupt lockups on
some platforms (at least the 5275, but others have reported it on
the 5235 as well).
Signed-off-by: Greg Ungerer <gerg@uclinux.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/net/fec.c')
-rw-r--r-- | drivers/net/fec.c | 240 |
1 files changed, 218 insertions, 22 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 85504fb900da..bd6983d1afba 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
@@ -18,8 +18,8 @@ | |||
18 | * Much better multiple PHY support by Magnus Damm. | 18 | * Much better multiple PHY support by Magnus Damm. |
19 | * Copyright (c) 2000 Ericsson Radio Systems AB. | 19 | * Copyright (c) 2000 Ericsson Radio Systems AB. |
20 | * | 20 | * |
21 | * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282. | 21 | * Support for FEC controller of ColdFire processors. |
22 | * Copyright (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) | 22 | * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) |
23 | * | 23 | * |
24 | * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) | 24 | * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) |
25 | * Copyright (c) 2004-2005 Macq Electronique SA. | 25 | * Copyright (c) 2004-2005 Macq Electronique SA. |
@@ -50,7 +50,8 @@ | |||
50 | #include <asm/pgtable.h> | 50 | #include <asm/pgtable.h> |
51 | 51 | ||
52 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ | 52 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ |
53 | defined(CONFIG_M5272) || defined(CONFIG_M528x) | 53 | defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ |
54 | defined(CONFIG_M520x) | ||
54 | #include <asm/coldfire.h> | 55 | #include <asm/coldfire.h> |
55 | #include <asm/mcfsim.h> | 56 | #include <asm/mcfsim.h> |
56 | #include "fec.h" | 57 | #include "fec.h" |
@@ -77,6 +78,8 @@ static unsigned int fec_hw[] = { | |||
77 | (MCF_MBAR + 0x1800), | 78 | (MCF_MBAR + 0x1800), |
78 | #elif defined(CONFIG_M523x) || defined(CONFIG_M528x) | 79 | #elif defined(CONFIG_M523x) || defined(CONFIG_M528x) |
79 | (MCF_MBAR + 0x1000), | 80 | (MCF_MBAR + 0x1000), |
81 | #elif defined(CONFIG_M520x) | ||
82 | (MCF_MBAR+0x30000), | ||
80 | #else | 83 | #else |
81 | &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), | 84 | &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), |
82 | #endif | 85 | #endif |
@@ -139,6 +142,10 @@ typedef struct { | |||
139 | #define TX_RING_SIZE 16 /* Must be power of two */ | 142 | #define TX_RING_SIZE 16 /* Must be power of two */ |
140 | #define TX_RING_MOD_MASK 15 /* for this to work */ | 143 | #define TX_RING_MOD_MASK 15 /* for this to work */ |
141 | 144 | ||
145 | #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) | ||
146 | #error "FEC: descriptor ring size contants too large" | ||
147 | #endif | ||
148 | |||
142 | /* Interrupt events/masks. | 149 | /* Interrupt events/masks. |
143 | */ | 150 | */ |
144 | #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ | 151 | #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ |
@@ -164,7 +171,8 @@ typedef struct { | |||
164 | * size bits. Other FEC hardware does not, so we need to take that into | 171 | * size bits. Other FEC hardware does not, so we need to take that into |
165 | * account when setting it. | 172 | * account when setting it. |
166 | */ | 173 | */ |
167 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) | 174 | #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ |
175 | defined(CONFIG_M520x) | ||
168 | #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) | 176 | #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) |
169 | #else | 177 | #else |
170 | #define OPT_FRAME_SIZE 0 | 178 | #define OPT_FRAME_SIZE 0 |
@@ -1137,6 +1145,65 @@ static phy_info_t const phy_info_ks8721bl = { | |||
1137 | }; | 1145 | }; |
1138 | 1146 | ||
1139 | /* ------------------------------------------------------------------------- */ | 1147 | /* ------------------------------------------------------------------------- */ |
1148 | /* register definitions for the DP83848 */ | ||
1149 | |||
1150 | #define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ | ||
1151 | |||
1152 | static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) | ||
1153 | { | ||
1154 | struct fec_enet_private *fep = dev->priv; | ||
1155 | volatile uint *s = &(fep->phy_status); | ||
1156 | |||
1157 | *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); | ||
1158 | |||
1159 | /* Link up */ | ||
1160 | if (mii_reg & 0x0001) { | ||
1161 | fep->link = 1; | ||
1162 | *s |= PHY_STAT_LINK; | ||
1163 | } else | ||
1164 | fep->link = 0; | ||
1165 | /* Status of link */ | ||
1166 | if (mii_reg & 0x0010) /* Autonegotioation complete */ | ||
1167 | *s |= PHY_STAT_ANC; | ||
1168 | if (mii_reg & 0x0002) { /* 10MBps? */ | ||
1169 | if (mii_reg & 0x0004) /* Full Duplex? */ | ||
1170 | *s |= PHY_STAT_10FDX; | ||
1171 | else | ||
1172 | *s |= PHY_STAT_10HDX; | ||
1173 | } else { /* 100 Mbps? */ | ||
1174 | if (mii_reg & 0x0004) /* Full Duplex? */ | ||
1175 | *s |= PHY_STAT_100FDX; | ||
1176 | else | ||
1177 | *s |= PHY_STAT_100HDX; | ||
1178 | } | ||
1179 | if (mii_reg & 0x0008) | ||
1180 | *s |= PHY_STAT_FAULT; | ||
1181 | } | ||
1182 | |||
1183 | static phy_info_t phy_info_dp83848= { | ||
1184 | 0x020005c9, | ||
1185 | "DP83848", | ||
1186 | |||
1187 | (const phy_cmd_t []) { /* config */ | ||
1188 | { mk_mii_read(MII_REG_CR), mii_parse_cr }, | ||
1189 | { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, | ||
1190 | { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, | ||
1191 | { mk_mii_end, } | ||
1192 | }, | ||
1193 | (const phy_cmd_t []) { /* startup - enable interrupts */ | ||
1194 | { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ | ||
1195 | { mk_mii_read(MII_REG_SR), mii_parse_sr }, | ||
1196 | { mk_mii_end, } | ||
1197 | }, | ||
1198 | (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ | ||
1199 | { mk_mii_end, } | ||
1200 | }, | ||
1201 | (const phy_cmd_t []) { /* shutdown */ | ||
1202 | { mk_mii_end, } | ||
1203 | }, | ||
1204 | }; | ||
1205 | |||
1206 | /* ------------------------------------------------------------------------- */ | ||
1140 | 1207 | ||
1141 | static phy_info_t const * const phy_info[] = { | 1208 | static phy_info_t const * const phy_info[] = { |
1142 | &phy_info_lxt970, | 1209 | &phy_info_lxt970, |
@@ -1144,6 +1211,7 @@ static phy_info_t const * const phy_info[] = { | |||
1144 | &phy_info_qs6612, | 1211 | &phy_info_qs6612, |
1145 | &phy_info_am79c874, | 1212 | &phy_info_am79c874, |
1146 | &phy_info_ks8721bl, | 1213 | &phy_info_ks8721bl, |
1214 | &phy_info_dp83848, | ||
1147 | NULL | 1215 | NULL |
1148 | }; | 1216 | }; |
1149 | 1217 | ||
@@ -1422,6 +1490,134 @@ static void __inline__ fec_uncache(unsigned long addr) | |||
1422 | 1490 | ||
1423 | /* ------------------------------------------------------------------------- */ | 1491 | /* ------------------------------------------------------------------------- */ |
1424 | 1492 | ||
1493 | #elif defined(CONFIG_M520x) | ||
1494 | |||
1495 | /* | ||
1496 | * Code specific to Coldfire 520x | ||
1497 | */ | ||
1498 | static void __inline__ fec_request_intrs(struct net_device *dev) | ||
1499 | { | ||
1500 | struct fec_enet_private *fep; | ||
1501 | int b; | ||
1502 | static const struct idesc { | ||
1503 | char *name; | ||
1504 | unsigned short irq; | ||
1505 | } *idp, id[] = { | ||
1506 | { "fec(TXF)", 23 }, | ||
1507 | { "fec(TXB)", 24 }, | ||
1508 | { "fec(TXFIFO)", 25 }, | ||
1509 | { "fec(TXCR)", 26 }, | ||
1510 | { "fec(RXF)", 27 }, | ||
1511 | { "fec(RXB)", 28 }, | ||
1512 | { "fec(MII)", 29 }, | ||
1513 | { "fec(LC)", 30 }, | ||
1514 | { "fec(HBERR)", 31 }, | ||
1515 | { "fec(GRA)", 32 }, | ||
1516 | { "fec(EBERR)", 33 }, | ||
1517 | { "fec(BABT)", 34 }, | ||
1518 | { "fec(BABR)", 35 }, | ||
1519 | { NULL }, | ||
1520 | }; | ||
1521 | |||
1522 | fep = netdev_priv(dev); | ||
1523 | b = 64 + 13; | ||
1524 | |||
1525 | /* Setup interrupt handlers. */ | ||
1526 | for (idp = id; idp->name; idp++) { | ||
1527 | if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) | ||
1528 | printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); | ||
1529 | } | ||
1530 | |||
1531 | /* Unmask interrupts at ColdFire interrupt controller */ | ||
1532 | { | ||
1533 | volatile unsigned char *icrp; | ||
1534 | volatile unsigned long *imrp; | ||
1535 | |||
1536 | icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 + | ||
1537 | MCFINTC_ICR0); | ||
1538 | for (b = 36; (b < 49); b++) | ||
1539 | icrp[b] = 0x04; | ||
1540 | imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + | ||
1541 | MCFINTC_IMRH); | ||
1542 | *imrp &= ~0x0001FFF0; | ||
1543 | } | ||
1544 | *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0; | ||
1545 | *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f; | ||
1546 | } | ||
1547 | |||
1548 | static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) | ||
1549 | { | ||
1550 | volatile fec_t *fecp; | ||
1551 | |||
1552 | fecp = fep->hwp; | ||
1553 | fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; | ||
1554 | fecp->fec_x_cntrl = 0x00; | ||
1555 | |||
1556 | /* | ||
1557 | * Set MII speed to 2.5 MHz | ||
1558 | * See 5282 manual section 17.5.4.7: MSCR | ||
1559 | */ | ||
1560 | fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; | ||
1561 | fecp->fec_mii_speed = fep->phy_speed; | ||
1562 | |||
1563 | fec_restart(dev, 0); | ||
1564 | } | ||
1565 | |||
1566 | static void __inline__ fec_get_mac(struct net_device *dev) | ||
1567 | { | ||
1568 | struct fec_enet_private *fep = netdev_priv(dev); | ||
1569 | volatile fec_t *fecp; | ||
1570 | unsigned char *iap, tmpaddr[ETH_ALEN]; | ||
1571 | |||
1572 | fecp = fep->hwp; | ||
1573 | |||
1574 | if (FEC_FLASHMAC) { | ||
1575 | /* | ||
1576 | * Get MAC address from FLASH. | ||
1577 | * If it is all 1's or 0's, use the default. | ||
1578 | */ | ||
1579 | iap = FEC_FLASHMAC; | ||
1580 | if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && | ||
1581 | (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) | ||
1582 | iap = fec_mac_default; | ||
1583 | if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && | ||
1584 | (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) | ||
1585 | iap = fec_mac_default; | ||
1586 | } else { | ||
1587 | *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; | ||
1588 | *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); | ||
1589 | iap = &tmpaddr[0]; | ||
1590 | } | ||
1591 | |||
1592 | memcpy(dev->dev_addr, iap, ETH_ALEN); | ||
1593 | |||
1594 | /* Adjust MAC if using default MAC address */ | ||
1595 | if (iap == fec_mac_default) | ||
1596 | dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; | ||
1597 | } | ||
1598 | |||
1599 | static void __inline__ fec_enable_phy_intr(void) | ||
1600 | { | ||
1601 | } | ||
1602 | |||
1603 | static void __inline__ fec_disable_phy_intr(void) | ||
1604 | { | ||
1605 | } | ||
1606 | |||
1607 | static void __inline__ fec_phy_ack_intr(void) | ||
1608 | { | ||
1609 | } | ||
1610 | |||
1611 | static void __inline__ fec_localhw_setup(void) | ||
1612 | { | ||
1613 | } | ||
1614 | |||
1615 | static void __inline__ fec_uncache(unsigned long addr) | ||
1616 | { | ||
1617 | } | ||
1618 | |||
1619 | /* ------------------------------------------------------------------------- */ | ||
1620 | |||
1425 | #else | 1621 | #else |
1426 | 1622 | ||
1427 | /* | 1623 | /* |
@@ -1952,6 +2148,14 @@ int __init fec_enet_init(struct net_device *dev) | |||
1952 | if (index >= FEC_MAX_PORTS) | 2148 | if (index >= FEC_MAX_PORTS) |
1953 | return -ENXIO; | 2149 | return -ENXIO; |
1954 | 2150 | ||
2151 | /* Allocate memory for buffer descriptors. | ||
2152 | */ | ||
2153 | mem_addr = __get_free_page(GFP_KERNEL); | ||
2154 | if (mem_addr == 0) { | ||
2155 | printk("FEC: allocate descriptor memory failed?\n"); | ||
2156 | return -ENOMEM; | ||
2157 | } | ||
2158 | |||
1955 | /* Create an Ethernet device instance. | 2159 | /* Create an Ethernet device instance. |
1956 | */ | 2160 | */ |
1957 | fecp = (volatile fec_t *) fec_hw[index]; | 2161 | fecp = (volatile fec_t *) fec_hw[index]; |
@@ -1964,16 +2168,6 @@ int __init fec_enet_init(struct net_device *dev) | |||
1964 | fecp->fec_ecntrl = 1; | 2168 | fecp->fec_ecntrl = 1; |
1965 | udelay(10); | 2169 | udelay(10); |
1966 | 2170 | ||
1967 | /* Clear and enable interrupts */ | ||
1968 | fecp->fec_ievent = 0xffc00000; | ||
1969 | fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | | ||
1970 | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); | ||
1971 | fecp->fec_hash_table_high = 0; | ||
1972 | fecp->fec_hash_table_low = 0; | ||
1973 | fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; | ||
1974 | fecp->fec_ecntrl = 2; | ||
1975 | fecp->fec_r_des_active = 0x01000000; | ||
1976 | |||
1977 | /* Set the Ethernet address. If using multiple Enets on the 8xx, | 2171 | /* Set the Ethernet address. If using multiple Enets on the 8xx, |
1978 | * this needs some work to get unique addresses. | 2172 | * this needs some work to get unique addresses. |
1979 | * | 2173 | * |
@@ -1982,14 +2176,6 @@ int __init fec_enet_init(struct net_device *dev) | |||
1982 | */ | 2176 | */ |
1983 | fec_get_mac(dev); | 2177 | fec_get_mac(dev); |
1984 | 2178 | ||
1985 | /* Allocate memory for buffer descriptors. | ||
1986 | */ | ||
1987 | if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { | ||
1988 | printk("FEC init error. Need more space.\n"); | ||
1989 | printk("FEC initialization failed.\n"); | ||
1990 | return 1; | ||
1991 | } | ||
1992 | mem_addr = __get_free_page(GFP_KERNEL); | ||
1993 | cbd_base = (cbd_t *)mem_addr; | 2179 | cbd_base = (cbd_t *)mem_addr; |
1994 | /* XXX: missing check for allocation failure */ | 2180 | /* XXX: missing check for allocation failure */ |
1995 | 2181 | ||
@@ -2067,6 +2253,16 @@ int __init fec_enet_init(struct net_device *dev) | |||
2067 | */ | 2253 | */ |
2068 | fec_request_intrs(dev); | 2254 | fec_request_intrs(dev); |
2069 | 2255 | ||
2256 | /* Clear and enable interrupts */ | ||
2257 | fecp->fec_ievent = 0xffc00000; | ||
2258 | fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | | ||
2259 | FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); | ||
2260 | fecp->fec_hash_table_high = 0; | ||
2261 | fecp->fec_hash_table_low = 0; | ||
2262 | fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; | ||
2263 | fecp->fec_ecntrl = 2; | ||
2264 | fecp->fec_r_des_active = 0x01000000; | ||
2265 | |||
2070 | dev->base_addr = (unsigned long)fecp; | 2266 | dev->base_addr = (unsigned long)fecp; |
2071 | 2267 | ||
2072 | /* The FEC Ethernet specific entries in the device structure. */ | 2268 | /* The FEC Ethernet specific entries in the device structure. */ |