ether.c 7.18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*
 * (C) Copyright 2003
 * Author : Hamid Ikdoumi (Atmel)
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <at91rm9200_net.h>
#include <net.h>

/* ----- Ethernet Buffer definitions ----- */

typedef struct {
	unsigned long addr, size;
} rbf_t;

#define RBF_ADDR      0xfffffffc
#define RBF_OWNER     (1<<0)
#define RBF_WRAP      (1<<1)
#define RBF_BROADCAST (1<<31)
#define RBF_MULTICAST (1<<30)
#define RBF_UNICAST   (1<<29)
#define RBF_EXTERNAL  (1<<28)
#define RBF_UNKOWN    (1<<27)
#define RBF_SIZE      0x07ff
#define RBF_LOCAL4    (1<<26)
#define RBF_LOCAL3    (1<<25)
#define RBF_LOCAL2    (1<<24)
#define RBF_LOCAL1    (1<<23)

/* Emac Buffers in last 512KBytes of SDRAM*/
/* Be careful, buffer size is limited to 512KBytes !!! */
#define RBF_FRAMEMAX 100
/*#define RBF_FRAMEMEM 0x200000 */
#define RBF_FRAMEMEM 0x21F80000
#define RBF_FRAMELEN 0x600

#define RBF_FRAMEBTD RBF_FRAMEMEM
#define RBF_FRAMEBUF (RBF_FRAMEMEM + RBF_FRAMEMAX*sizeof(rbf_t))


#ifdef CONFIG_DRIVER_ETHER

#if (CONFIG_COMMANDS & CFG_CMD_NET)

/* structure to interface the PHY */
wdenk's avatar
wdenk committed
63
AT91S_PhyOps PhyOps;
64 65 66 67 68

AT91PS_EMAC p_mac;

/*********** EMAC Phy layer Management functions *************************/
/*
wdenk's avatar
wdenk committed
69
 * Name:
70
 *	at91rm9200_EmacEnableMDIO
wdenk's avatar
wdenk committed
71
 * Description:
72
 *	Enables the MDIO bit in MAC control register
wdenk's avatar
wdenk committed
73
 * Arguments:
74
 *	p_mac - pointer to struct AT91S_EMAC
wdenk's avatar
wdenk committed
75
 * Return value:
76 77
 *	none
 */
wdenk's avatar
wdenk committed
78
void at91rm9200_EmacEnableMDIO (AT91PS_EMAC p_mac)
79 80 81 82 83 84
{
	/* Mac CTRL reg set for MDIO enable */
	p_mac->EMAC_CTL |= AT91C_EMAC_MPE;	/* Management port enable */
}

/*
wdenk's avatar
wdenk committed
85
 * Name:
86
 *	at91rm9200_EmacDisableMDIO
wdenk's avatar
wdenk committed
87
 * Description:
88
 *	Disables the MDIO bit in MAC control register
wdenk's avatar
wdenk committed
89
 * Arguments:
90
 *	p_mac - pointer to struct AT91S_EMAC
wdenk's avatar
wdenk committed
91
 * Return value:
92 93
 *	none
 */
wdenk's avatar
wdenk committed
94
void at91rm9200_EmacDisableMDIO (AT91PS_EMAC p_mac)
95 96 97 98 99 100 101
{
	/* Mac CTRL reg set for MDIO disable */
	p_mac->EMAC_CTL &= ~AT91C_EMAC_MPE;	/* Management port disable */
}


/*
wdenk's avatar
wdenk committed
102
 * Name:
103
 *	at91rm9200_EmacReadPhy
wdenk's avatar
wdenk committed
104
 * Description:
105
 *	Reads data from the PHY register
wdenk's avatar
wdenk committed
106
 * Arguments:
107 108
 *	dev - pointer to struct net_device
 *	RegisterAddress - unsigned char
wdenk's avatar
wdenk committed
109 110
 * 	pInput - pointer to value read from register
 * Return value:
111 112
 *	TRUE - if data read successfully
 */
wdenk's avatar
wdenk committed
113
UCHAR at91rm9200_EmacReadPhy (AT91PS_EMAC p_mac,
114 115 116 117
				     unsigned char RegisterAddress,
				     unsigned short *pInput)
{
	p_mac->EMAC_MAN = (AT91C_EMAC_HIGH & ~AT91C_EMAC_LOW) |
wdenk's avatar
wdenk committed
118 119 120
			  (AT91C_EMAC_RW_R) |
			  (RegisterAddress << 18) |
			  (AT91C_EMAC_CODE_802_3);
121 122 123 124 125 126 127 128 129 130

	udelay (10000);

	*pInput = (unsigned short) p_mac->EMAC_MAN;

	return TRUE;
}


/*
wdenk's avatar
wdenk committed
131
 * Name:
132
 *	at91rm9200_EmacWritePhy
wdenk's avatar
wdenk committed
133
 * Description:
134
 *	Writes data to the PHY register
wdenk's avatar
wdenk committed
135
 * Arguments:
136 137
 *	dev - pointer to struct net_device
 *	RegisterAddress - unsigned char
wdenk's avatar
wdenk committed
138 139
 * 	pOutput - pointer to value to be written in the register
 * Return value:
140 141
 *	TRUE - if data read successfully
 */
wdenk's avatar
wdenk committed
142
UCHAR at91rm9200_EmacWritePhy (AT91PS_EMAC p_mac,
wdenk's avatar
wdenk committed
143 144
				      unsigned char RegisterAddress,
				      unsigned short *pOutput)
145 146 147
{
	p_mac->EMAC_MAN = (AT91C_EMAC_HIGH & ~AT91C_EMAC_LOW) |
			AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_W |
wdenk's avatar
wdenk committed
148
			(RegisterAddress << 18) | *pOutput;
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

	udelay (10000);

	return TRUE;
}


rbf_t *rbfdt;
rbf_t *rbfp;

int eth_init (bd_t * bd)
{
	int ret;
	int i;

	p_mac = AT91C_BASE_EMAC;

166 167 168 169 170
	/* PIO Disable Register */
	*AT91C_PIOA_PDR = AT91C_PA16_EMDIO | AT91C_PA15_EMDC | AT91C_PA14_ERXER |
			  AT91C_PA13_ERX1 | AT91C_PA12_ERX0 | AT91C_PA11_ECRS_ECRSDV |
			  AT91C_PA10_ETX1 | AT91C_PA9_ETX0 | AT91C_PA8_ETXEN |
			  AT91C_PA7_ETXCK_EREFCK;
171

wdenk's avatar
wdenk committed
172 173 174 175 176
#ifdef CONFIG_AT91C_USE_RMII
	*AT91C_PIOB_PDR = AT91C_PB19_ERXCK;
	*AT91C_PIOB_BSR = AT91C_PB19_ERXCK;
#else
	*AT91C_PIOB_PDR = AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV |
177 178
			  AT91C_PB16_ERX3 | AT91C_PB15_ERX2 | AT91C_PB14_ETXER |
			  AT91C_PB13_ETX3 | AT91C_PB12_ETX2;
179

180
	/* Select B Register */
wdenk's avatar
wdenk committed
181
	*AT91C_PIOB_BSR = AT91C_PB19_ERXCK | AT91C_PB18_ECOL |
182 183
			  AT91C_PB17_ERXDV | AT91C_PB16_ERX3 | AT91C_PB15_ERX2 |
			  AT91C_PB14_ETXER | AT91C_PB13_ETX3 | AT91C_PB12_ETX2;
184
#endif
185 186 187 188 189 190 191 192 193 194 195 196 197 198

	*AT91C_PMC_PCER = 1 << AT91C_ID_EMAC;	/* Peripheral Clock Enable Register */

	p_mac->EMAC_CFG |= AT91C_EMAC_CSR;	/* Clear statistics */

	/* Init Ehternet buffers */
	rbfdt = (rbf_t *) RBF_FRAMEBTD;
	for (i = 0; i < RBF_FRAMEMAX; i++) {
		rbfdt[i].addr = RBF_FRAMEBUF + RBF_FRAMELEN * i;
		rbfdt[i].size = 0;
	}
	rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
	rbfp = &rbfdt[0];

199 200 201 202 203 204 205 206 207 208 209 210 211 212
	p_mac->EMAC_SA2L = (bd->bi_enetaddr[3] << 24) | (bd->bi_enetaddr[2] << 16)
			 | (bd->bi_enetaddr[1] <<  8) | (bd->bi_enetaddr[0]);
	p_mac->EMAC_SA2H = (bd->bi_enetaddr[5] <<  8) | (bd->bi_enetaddr[4]);

	p_mac->EMAC_RBQP = (long) (&rbfdt[0]);
	p_mac->EMAC_RSR &= ~(AT91C_EMAC_RSR_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);

	p_mac->EMAC_CFG = (p_mac->EMAC_CFG | AT91C_EMAC_CAF | AT91C_EMAC_NBC)
			& ~AT91C_EMAC_CLK;

#ifdef CONFIG_AT91C_USE_RMII
	p_mac->EMAC_CFG |= AT91C_EMAC_RMII;
#endif

wdenk's avatar
wdenk committed
213 214 215 216 217
#if (AT91C_MASTER_CLOCK > 40000000)
	/* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */
	p_mac->EMAC_CFG |= AT91C_EMAC_CLK_HCLK_64;
#endif

218 219
	p_mac->EMAC_CTL |= AT91C_EMAC_TE | AT91C_EMAC_RE;

wdenk's avatar
wdenk committed
220
	at91rm92000_GetPhyInterface (& PhyOps);
221

wdenk's avatar
wdenk committed
222
	if (!PhyOps.IsPhyConnected (p_mac))
223 224 225 226
		printf ("PHY not connected!!\n\r");

	/* MII management start from here */
	if (!(p_mac->EMAC_SR & AT91C_EMAC_LINK)) {
wdenk's avatar
wdenk committed
227
		if (!(ret = PhyOps.Init (p_mac))) {
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
			printf ("MAC: error during MII initialization\n");
			return 0;
		}
	} else {
		printf ("No link\n\r");
		return 0;
	}

	return 0;
}

int eth_send (volatile void *packet, int length)
{
	while (!(p_mac->EMAC_TSR & AT91C_EMAC_BNQ));
	p_mac->EMAC_TAR = (long) packet;
	p_mac->EMAC_TCR = length;
	while (p_mac->EMAC_TCR & 0x7ff);
	p_mac->EMAC_TSR |= AT91C_EMAC_COMP;
	return 0;
}

int eth_rx (void)
{
	int size;

	if (!(rbfp->addr & RBF_OWNER))
		return 0;

	size = rbfp->size & RBF_SIZE;
	NetReceive ((volatile uchar *) (rbfp->addr & RBF_ADDR), size);

	rbfp->addr &= ~RBF_OWNER;
	if (rbfp->addr & RBF_WRAP)
		rbfp = &rbfdt[0];
	else
		rbfp++;

	p_mac->EMAC_RSR |= AT91C_EMAC_REC;

	return size;
}

void eth_halt (void)
{
};
wdenk's avatar
wdenk committed
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291

#if (CONFIG_COMMANDS & CFG_CMD_MII)
int  miiphy_read(unsigned char addr, unsigned char reg, unsigned short * value)
{
	at91rm9200_EmacEnableMDIO (p_mac);
	at91rm9200_EmacReadPhy (p_mac, reg, value);
	at91rm9200_EmacDisableMDIO (p_mac);
	return 0;
}

int  miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
{
	at91rm9200_EmacEnableMDIO (p_mac);
	at91rm9200_EmacWritePhy (p_mac, reg, &value);
	at91rm9200_EmacDisableMDIO (p_mac);
	return 0;
}
#endif	/* CONFIG_COMMANDS & CFG_CMD_MII */

292
#endif	/* CONFIG_COMMANDS & CFG_CMD_NET */
wdenk's avatar
wdenk committed
293

294
#endif	/* CONFIG_DRIVER_ETHER */