static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
{
	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
		| ((phy_addr & 0x1f) << 23) | (address << 18));

	/* Wait until IDLE bit in Network Status register is cleared */
	at91_phy_wait();

	*value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
}
Пример #2
0
static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
{
	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
		| ((phy_addr & 0x1f) << 23) | (address << 18));

	
	at91_phy_wait();

	*value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
}
Пример #3
0
static int at91_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val)
{
	int ret;

	enable_mdi();
	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
		| ((addr & 0x1f) << 23) | (reg << 18) | (val & AT91_EMAC_DATA));

	/* Wait until IDLE bit in Network Status register is cleared */
	ret = at91_phy_wait();

	disable_mdi();

	return ret;
}
Пример #4
0
/*
 * Access the PHY to determine the current link speed and mode, and update the
 * MAC accordingly.
 * If no link or auto-negotiation is busy, then no changes are made.
 */
static void update_linkspeed(struct net_device *dev, int silent)
{
	struct at91_private *lp = netdev_priv(dev);
	unsigned int bmsr, bmcr, lpa, mac_cfg;
	unsigned int speed, duplex;

	if (!mii_link_ok(&lp->mii)) {		/* no link */
		netif_carrier_off(dev);
		if (!silent)
			printk(KERN_INFO "%s: Link down.\n", dev->name);
		return;
	}

	/* Link up, or auto-negotiation still in progress */
	read_phy(lp->phy_address, MII_BMSR, &bmsr);
	read_phy(lp->phy_address, MII_BMCR, &bmcr);
	if (bmcr & BMCR_ANENABLE) {				/* AutoNegotiation is enabled */
		if (!(bmsr & BMSR_ANEGCOMPLETE))
			return;			/* Do nothing - another interrupt generated when negotiation complete */

		read_phy(lp->phy_address, MII_LPA, &lpa);
		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
		else speed = SPEED_10;
		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
		else duplex = DUPLEX_HALF;
	} else {
		speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
		duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
	}

	/* Update the MAC */
	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
	if (speed == SPEED_100) {
		if (duplex == DUPLEX_FULL)		/* 100 Full Duplex */
			mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
		else					/* 100 Half Duplex */
			mac_cfg |= AT91_EMAC_SPD;
	} else {
		if (duplex == DUPLEX_FULL)		/* 10 Full Duplex */
			mac_cfg |= AT91_EMAC_FD;
		else {}					/* 10 Half Duplex */
	}
	at91_emac_write(AT91_EMAC_CFG, mac_cfg);

	if (!silent)
		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
	netif_carrier_on(dev);
}
Пример #5
0
static void update_linkspeed(struct net_device *dev, int silent)
{
	struct at91_private *lp = netdev_priv(dev);
	unsigned int bmsr, bmcr, lpa, mac_cfg;
	unsigned int speed, duplex;

	if (!mii_link_ok(&lp->mii)) {		
		netif_carrier_off(dev);
		if (!silent)
			printk(KERN_INFO "%s: Link down.\n", dev->name);
		return;
	}

	
	read_phy(lp->phy_address, MII_BMSR, &bmsr);
	read_phy(lp->phy_address, MII_BMCR, &bmcr);
	if (bmcr & BMCR_ANENABLE) {				
		if (!(bmsr & BMSR_ANEGCOMPLETE))
			return;			

		read_phy(lp->phy_address, MII_LPA, &lpa);
		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
		else speed = SPEED_10;
		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
		else duplex = DUPLEX_HALF;
	} else {
		speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
		duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
	}

	
	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
	if (speed == SPEED_100) {
		if (duplex == DUPLEX_FULL)		
			mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
		else					
			mac_cfg |= AT91_EMAC_SPD;
	} else {
		if (duplex == DUPLEX_FULL)		
			mac_cfg |= AT91_EMAC_FD;
		else {}					
	}
	at91_emac_write(AT91_EMAC_CFG, mac_cfg);

	if (!silent)
		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
	netif_carrier_on(dev);
}
Пример #6
0
static void update_linkspeed(struct eth_device *edev)
{
	unsigned int mac_cfg;

	/* Update the MAC */
	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
	if (edev->phydev->speed == SPEED_100) {
		if (edev->phydev->duplex)
			mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
		else					/* 100 Half Duplex */
			mac_cfg |= AT91_EMAC_SPD;
	} else {
		if (edev->phydev->duplex)
			mac_cfg |= AT91_EMAC_FD;
		else {}					/* 10 Half Duplex */
	}
	at91_emac_write(AT91_EMAC_CFG, mac_cfg);
}
Пример #7
0
static int at91_ether_mii_read(struct mii_bus *dev, int addr, int reg)
{
	int value;

	enable_mdi();

	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
		| ((addr & 0x1f) << 23) | (reg << 18));

	/* Wait until IDLE bit in Network Status register is cleared */
	value = at91_phy_wait();
	if (value < 0)
		goto out;

	value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;

out:
	disable_mdi();

	return value;
}
Пример #8
0
static int at91_ether_rx(struct eth_device *edev)
{
	struct ether_device *etdev = to_ether(edev);
	int size;
	struct rbf_t *rbfp = etdev->rbfp;

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

	size = rbfp->size & RBF_SIZE;

	net_receive(edev, (unsigned char *)(rbfp->addr & RBF_ADDR), size);

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

	at91_emac_write(AT91_EMAC_RSR,
		at91_emac_read(AT91_EMAC_RSR) | AT91_EMAC_RSR_REC);

	return size;
}
Пример #9
0
static int at91_ether_probe(struct device_d *dev)
{
	unsigned int mac_cfg;
	struct ether_device *ether_dev;
	struct eth_device *edev;
	struct mii_bus *miibus;
	unsigned long ether_hz;
	struct clk *pclk;
	struct macb_platform_data *pdata;

	if (!dev->platform_data) {
		printf("at91_ether: no platform_data\n");
		return -ENODEV;
	}

	pdata = dev->platform_data;

	ether_dev = xzalloc(sizeof(struct ether_device));

	edev = &ether_dev->netdev;
	miibus = &ether_dev->miibus;
	edev->priv = ether_dev;

	edev->init = at91_ether_init;
	edev->open = at91_ether_open;
	edev->send = at91_ether_send;
	edev->recv = at91_ether_rx;
	edev->halt = at91_ether_halt;
	edev->get_ethaddr = at91_ether_get_ethaddr;
	edev->set_ethaddr = at91_ether_set_ethaddr;
	ether_dev->rbf_framebuf = dma_alloc_coherent(MAX_RX_DESCR * MAX_RBUFF_SZ);
	ether_dev->rbfdt = dma_alloc_coherent(sizeof(struct rbf_t) * MAX_RX_DESCR);

	ether_dev->phy_addr = pdata->phy_addr;
	miibus->read = at91_ether_mii_read;
	miibus->write = at91_ether_mii_write;

	/* Sanitize the clocks */
	mac_cfg = at91_emac_read(AT91_EMAC_CFG);

	pclk = clk_get(dev, "ether_clk");
	clk_enable(pclk);
	ether_hz = clk_get_rate(pclk);
	if (ether_hz > 40000000) {
		/* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */
		mac_cfg |= AT91_EMAC_CLK_DIV64;
	} else {
		mac_cfg &= ~AT91_EMAC_CLK;
	}

	mac_cfg |= AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG;

	if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) {
		ether_dev->interface = PHY_INTERFACE_MODE_RGMII;
		mac_cfg |= AT91_EMAC_RMII;
	} else {
		ether_dev->interface = PHY_INTERFACE_MODE_MII;
	}

	at91_emac_write(AT91_EMAC_CFG, mac_cfg);

	mdiobus_register(miibus);
	eth_register(edev);

	return 0;
}