diff options
| author | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-16 13:44:25 +0000 | 
|---|---|---|
| committer | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-16 13:44:25 +0000 | 
| commit | a3a71d430b762ca48c6030c92d268a86b9f9137d (patch) | |
| tree | 5937de88cb9dca7bfebc4dc3dce3cf904bf65357 /package/boot/uboot-ar71xx/files/drivers | |
| parent | 05a3ece84affbb56ac43d1bf67b15d06bb354ca0 (diff) | |
[boot] move boot related packages to their own folder
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33781 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/boot/uboot-ar71xx/files/drivers')
5 files changed, 2348 insertions, 0 deletions
| diff --git a/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c new file mode 100644 index 000000000..b3324c019 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.c @@ -0,0 +1,809 @@ +/* + *  Atheros AR71xx built-in ethernet mac driver + * + *  Copyright (C) 2010 Michael Kurz <michi.kurz@googlemail.com> + *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> + *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + *  Based on Atheros' AG7100 driver + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + */ +  +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> + +#include <asm/ar71xx.h> + +#include "ag71xx.h" + +#ifdef AG71XX_DEBUG +#define DBG(fmt,args...)		printf(fmt ,##args) +#else +#define DBG(fmt,args...) +#endif + + +static struct ag71xx agtable[] = { +	{ +		.mac_base = KSEG1ADDR(AR71XX_GE0_BASE), +		.mii_ctrl = KSEG1ADDR(AR71XX_MII_BASE + MII_REG_MII0_CTRL), +		.mii_if = CONFIG_AG71XX_MII0_IIF, +	} , { +		.mac_base = KSEG1ADDR(AR71XX_GE1_BASE), +		.mii_ctrl = KSEG1ADDR(AR71XX_MII_BASE + MII_REG_MII1_CTRL), +		.mii_if = CONFIG_AG71XX_MII1_IIF, +	} +}; + +static int ag71xx_ring_alloc(struct ag71xx_ring *ring, unsigned int size) +{ +	int err; +	int i; +	int rsize; + +	ring->desc_size = sizeof(struct ag71xx_desc); +	if (ring->desc_size % (CONFIG_SYS_CACHELINE_SIZE)) { +		rsize = roundup(ring->desc_size, CONFIG_SYS_CACHELINE_SIZE); +		DBG("ag71xx: ring %p, desc size %u rounded to %u\n", +			ring, ring->desc_size, +			rsize); +		ring->desc_size = rsize; +	} + +	ring->descs_cpu = (u8 *) malloc((size * ring->desc_size) +		+ CONFIG_SYS_CACHELINE_SIZE - 1); +	if (!ring->descs_cpu) { +		err = -1; +		goto err; +	} +	ring->descs_cpu = (u8 *) UNCACHED_SDRAM((((u32) ring->descs_cpu +  +		CONFIG_SYS_CACHELINE_SIZE - 1) & ~(CONFIG_SYS_CACHELINE_SIZE - 1))); +    ring->descs_dma = (u8 *) virt_to_phys(ring->descs_cpu); + +	ring->size = size; + +	ring->buf = malloc(size * sizeof(*ring->buf)); +	if (!ring->buf) { +		err = -1; +		goto err; +	} +    memset(ring->buf, 0, size * sizeof(*ring->buf)); + +	for (i = 0; i < size; i++) { +		ring->buf[i].desc = +			(struct ag71xx_desc *)&ring->descs_cpu[i * ring->desc_size]; +		DBG("ag71xx: ring %p, desc %d at %p\n", +			ring, i, ring->buf[i].desc); +	} + +	flush_cache( (u32) ring->buf, size * sizeof(*ring->buf)); +	 +	return 0; + + err: +	return err; +} + +static void ag71xx_ring_tx_init(struct ag71xx *ag) +{ +	struct ag71xx_ring *ring = &ag->tx_ring; +	int i; + +	for (i = 0; i < AG71XX_TX_RING_SIZE; i++) { +		ring->buf[i].desc->next = (u32) virt_to_phys((ring->descs_dma + +			ring->desc_size * ((i + 1) % AG71XX_TX_RING_SIZE))); + +		ring->buf[i].desc->ctrl = DESC_EMPTY; +		ring->buf[i].skb = NULL; +	} + +	ring->curr = 0; +} + +static void ag71xx_ring_rx_clean(struct ag71xx *ag) +{ +	struct ag71xx_ring *ring = &ag->rx_ring; +	int i; + +	if (!ring->buf) +		return; + +	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { +	    ring->buf[i].desc->data = (u32) virt_to_phys(NetRxPackets[i]); +	    flush_cache((u32) NetRxPackets[i], PKTSIZE_ALIGN); +        ring->buf[i].desc->ctrl = DESC_EMPTY; +    } + +	ring->curr = 0; +} + +static int ag71xx_ring_rx_init(struct ag71xx *ag) +{ +	struct ag71xx_ring *ring = &ag->rx_ring; +	unsigned int i; + +	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { +		ring->buf[i].desc->next = (u32) virt_to_phys((ring->descs_dma + +			ring->desc_size * ((i + 1) % AG71XX_RX_RING_SIZE))); + +		DBG("ag71xx: RX desc at %p, next is %08x\n", +			ring->buf[i].desc, +			ring->buf[i].desc->next); +	} + +	for (i = 0; i < AG71XX_RX_RING_SIZE; i++) { +		ring->buf[i].desc->data = (u32) virt_to_phys(NetRxPackets[i]); +		ring->buf[i].desc->ctrl = DESC_EMPTY; +	} + +	ring->curr = 0; + +	return 0; +} + +static int ag71xx_rings_init(struct ag71xx *ag) +{ +	int ret; + +	ret = ag71xx_ring_alloc(&ag->tx_ring, AG71XX_TX_RING_SIZE); +	if (ret) +		return ret; + +	ag71xx_ring_tx_init(ag); + +	ret = ag71xx_ring_alloc(&ag->rx_ring, AG71XX_RX_RING_SIZE); +	if (ret) +		return ret; + +	ret = ag71xx_ring_rx_init(ag); +	return ret; +} + +static void ar71xx_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift) +{ +	uint32_t base = KSEG1ADDR(AR71XX_PLL_BASE); +	u32 t; + +	t = readl(base + cfg_reg); +	t &= ~(3 << shift); +	t |=  (2 << shift); +	writel(t, base + cfg_reg); +	udelay(100); + +	writel(pll_val, base + pll_reg); + +	t |= (3 << shift); +	writel(t, base + cfg_reg); +	udelay(100); + +	t &= ~(3 << shift); +	writel(t, base + cfg_reg); +	udelay(100); + +	debug("ar71xx: pll_reg %#x: %#x\n", (unsigned int)(base + pll_reg), +       readl(base + pll_reg)); +} + +static void ar91xx_set_pll_ge0(int speed) +{ +	//u32 val = ar71xx_get_eth_pll(0, speed); +	u32 pll_val; + +	switch (speed) { +	case SPEED_10: +		pll_val = 0x00441099; +		break; +	case SPEED_100: +		pll_val = 0x13000a44; +		break; +	case SPEED_1000: +		pll_val = 0x1a000000; +		break; +	default: +		BUG(); +	} + +	ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH0_INT_CLOCK, +			 pll_val, AR91XX_ETH0_PLL_SHIFT); +} + +static void ar91xx_set_pll_ge1(int speed) +{ +	//u32 val = ar71xx_get_eth_pll(1, speed); +    u32 pll_val; + +	switch (speed) { +	case SPEED_10: +		pll_val = 0x00441099; +		break; +	case SPEED_100: +		pll_val = 0x13000a44; +		break; +	case SPEED_1000: +		pll_val = 0x1a000000; +		break; +	default: +		BUG(); +	} + +	ar71xx_set_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH1_INT_CLOCK, +			 pll_val, AR91XX_ETH1_PLL_SHIFT); +} + +static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac) +{ +	u32 t; + +	t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16) +	  | (((u32) mac[3]) << 8) | ((u32) mac[2]); + +	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t); + +	t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16); +	ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t); +} + +static void ag71xx_dma_reset(struct ag71xx *ag) +{ +	u32 val; +	int i; + +	DBG("%s: txdesc reg: 0x%08x rxdesc reg: 0x%08x\n", +			ag->dev->name, +			ag71xx_rr(ag, AG71XX_REG_TX_DESC), +			ag71xx_rr(ag, AG71XX_REG_RX_DESC)); +	 +	/* stop RX and TX */ +	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); +	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); + +	/* clear descriptor addresses */ +	ag71xx_wr(ag, AG71XX_REG_TX_DESC, 0); +	ag71xx_wr(ag, AG71XX_REG_RX_DESC, 0); + +	/* clear pending RX/TX interrupts */ +	for (i = 0; i < 256; i++) { +		ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR); +		ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); +	} + +	/* clear pending errors */ +	ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF); +	ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR); + +	val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS); +	if (val) +		printf("%s: unable to clear DMA Rx status: %08x\n", +			ag->dev->name, val); + +	val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS); + +	/* mask out reserved bits */ +	val &= ~0xff000000; + +	if (val) +		printf("%s: unable to clear DMA Tx status: %08x\n", +			ag->dev->name, val); +} + +static void ag71xx_halt(struct eth_device *dev) +{ +    struct ag71xx *ag = (struct ag71xx *) dev->priv; + +    /* stop RX engine */ +	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0); + +	ag71xx_dma_reset(ag); +} + +#define MAX_WAIT        1000 + +static int ag71xx_send(struct eth_device *dev, volatile void *packet, +                       int length) +{ +    struct ag71xx *ag = (struct ag71xx *) dev->priv; +	struct ag71xx_ring *ring = &ag->tx_ring; +	struct ag71xx_desc *desc; +	int i; + +	i = ring->curr % AG71XX_TX_RING_SIZE; +	desc = ring->buf[i].desc; + +	if (!ag71xx_desc_empty(desc)) { +		printf("%s: tx buffer full\n", ag->dev->name); +		return 1; +	} + +	flush_cache((u32) packet, length); +    desc->data = (u32) virt_to_phys(packet); +    desc->ctrl = (length & DESC_PKTLEN_M); +	 +	DBG("%s: sending %#08x length %#08x\n", +		ag->dev->name, desc->data, desc->ctrl); +	 +	ring->curr++; +	if (ring->curr >= AG71XX_TX_RING_SIZE){ +		ring->curr = 0; +	} +	 +	/* enable TX engine */ +	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE); + +    for (i = 0; i < MAX_WAIT; i++) +    { +        if (ag71xx_desc_empty(desc)) +            break; +        udelay(10); +    } +    if (i == MAX_WAIT) { +        printf("%s: tx timed out!\n", ag->dev->name); +		return -1; +	} +	 +	/* disable TX engine */ +	ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0); +	desc->data = 0; +	desc->ctrl = DESC_EMPTY; +	 +	return 0; +} + +static int ag71xx_recv(struct eth_device *dev) +{ +    struct ag71xx *ag = (struct ag71xx *) dev->priv; +	struct ag71xx_ring *ring = &ag->rx_ring; + +    for (;;) { +		unsigned int i = ring->curr % AG71XX_RX_RING_SIZE; +		struct ag71xx_desc *desc = ring->buf[i].desc; +		int pktlen; +		 +		if (ag71xx_desc_empty(desc)) +			break; + +		DBG("%s: rx packets, curr=%u\n", dev->name, ring->curr); + +        pktlen = ag71xx_desc_pktlen(desc); +		pktlen -= ETH_FCS_LEN; + + +		NetReceive(NetRxPackets[i] , pktlen); +		flush_cache( (u32) NetRxPackets[i], PKTSIZE_ALIGN); + +        ring->buf[i].desc->ctrl = DESC_EMPTY; +		ring->curr++; +		if (ring->curr >= AG71XX_RX_RING_SIZE){ +			ring->curr = 0; +		} + +    } + +	if ((ag71xx_rr(ag, AG71XX_REG_RX_CTRL) & RX_CTRL_RXE) == 0) { +		/* start RX engine */ +		ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); +	} +	 +	return 0; +} + +#ifdef AG71XX_DEBUG +static char *ag71xx_speed_str(struct ag71xx *ag) +{ +	switch (ag->speed) { +	case SPEED_1000: +		return "1000"; +	case SPEED_100: +		return "100"; +	case SPEED_10: +		return "10"; +	} + +	return "?"; +} +#endif + +void ag71xx_link_adjust(struct ag71xx *ag) +{ +	u32 cfg2; +	u32 ifctl; +	u32 fifo5; +	u32 mii_speed; + +	if (!ag->link) { +		DBG("%s: link down\n", ag->dev->name); +		return; +	} + +	cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2); +	cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX); +	cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0; + +	ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL); +	ifctl &= ~(MAC_IFCTL_SPEED); + +	fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5); +	fifo5 &= ~FIFO_CFG5_BM; + +	switch (ag->speed) { +	case SPEED_1000: +		mii_speed =  MII_CTRL_SPEED_1000; +		cfg2 |= MAC_CFG2_IF_1000; +		fifo5 |= FIFO_CFG5_BM; +		break; +	case SPEED_100: +		mii_speed = MII_CTRL_SPEED_100; +		cfg2 |= MAC_CFG2_IF_10_100; +		ifctl |= MAC_IFCTL_SPEED; +		break; +	case SPEED_10: +		mii_speed = MII_CTRL_SPEED_10; +		cfg2 |= MAC_CFG2_IF_10_100; +		break; +	default: +		BUG(); +		return; +	} + +    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff); + +    if (ag->macNum == 0) +        ar91xx_set_pll_ge0(ag->speed); +    else +        ar91xx_set_pll_ge1(ag->speed); + +	ag71xx_mii_ctrl_set_speed(ag, mii_speed); + +	ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2); +	ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5); +	ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl); + +    DBG("%s: link up (%sMbps/%s duplex)\n", +        ag->dev->name, +        ag71xx_speed_str(ag), +        (1 == ag->duplex) ? "Full" : "Half"); + +	DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n", +		ag->dev->name, +		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0), +		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1), +		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2)); + +	DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n", +		ag->dev->name, +		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3), +		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4), +		ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5)); + +	DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x, mii_ctrl=%#x\n", +		ag->dev->name, +		ag71xx_rr(ag, AG71XX_REG_MAC_CFG2), +		ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL), +		ag71xx_mii_ctrl_rr(ag)); +} + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int ag71xx_getMiiSpeed(struct ag71xx *ag)  +{ +    uint16_t phyreg, cap; + +    if (miiphy_read(ag->phyname, ag->phyid, +                    PHY_BMSR, &phyreg)) { +        puts("PHY_BMSR read failed, assuming no link\n"); +        return -1; +    } + +    if ((phyreg & PHY_BMSR_LS) == 0) { +        return -1; +    } + +    if (miiphy_read(ag->phyname, ag->phyid, +                PHY_1000BTSR, &phyreg)) +        return -1; + +    if (phyreg & PHY_1000BTSR_1000FD) { +        ag->speed = SPEED_1000; +        ag->duplex = 1; +    } else if (phyreg & PHY_1000BTSR_1000HD) { +        ag->speed = SPEED_1000; +        ag->duplex = 0; +    } else { +        if (miiphy_read(ag->phyname, ag->phyid, +                PHY_ANAR, &cap)) +            return -1; + +        if (miiphy_read(ag->phyname, ag->phyid, +                PHY_ANLPAR, &phyreg)) +            return -1; + +        cap &= phyreg; +        if (cap & PHY_ANLPAR_TXFD) { +            ag->speed = SPEED_100; +            ag->duplex = 1; +        } else if (cap & PHY_ANLPAR_TX) { +            ag->speed = SPEED_100; +            ag->duplex = 0; +        } else if (cap & PHY_ANLPAR_10FD) { +            ag->speed = SPEED_10; +            ag->duplex = 1; +        } else { +            ag->speed = SPEED_10; +            ag->duplex = 0; +        } +    } +	 +	ag->link = 1; +	 +	return 0; +} +#endif + +static int ag71xx_hw_start(struct eth_device *dev, bd_t * bd) +{ +	struct ag71xx *ag = (struct ag71xx *) dev->priv; + +	ag71xx_dma_reset(ag); + +    ag71xx_ring_rx_clean(ag); +	ag71xx_ring_tx_init(ag); +	 +	ag71xx_wr(ag, AG71XX_REG_TX_DESC,  +				(u32) virt_to_phys(ag->tx_ring.descs_dma)); +	ag71xx_wr(ag, AG71XX_REG_RX_DESC, +				(u32) virt_to_phys(ag->rx_ring.descs_dma)); + +	ag71xx_hw_set_macaddr(ag, ag->dev->enetaddr); + +    if (ag->phyfixed) { +        ag->link = 1; +        ag->duplex = 1; +        ag->speed = SPEED_1000; +    } else { + +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) +		if (ag71xx_getMiiSpeed(ag)) +			return -1; +#else +		/* only fixed, without mii */ +		return -1; +#endif + +    } +    ag71xx_link_adjust(ag); +	 +	DBG("%s: txdesc reg: %#08x rxdesc reg: %#08x\n", +		ag->dev->name, +		ag71xx_rr(ag, AG71XX_REG_TX_DESC), +		ag71xx_rr(ag, AG71XX_REG_RX_DESC)); +	 +	/* start RX engine */ +	ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE); +	 +	return 0; +} + +#define FIFO_CFG0_INIT	(FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT) + +#define FIFO_CFG4_INIT	(FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \ +			 FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \ +			 FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \ +			 FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \ +			 FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \ +			 FIFO_CFG4_VT) + +#define FIFO_CFG5_INIT	(FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \ +			 FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \ +			 FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \ +			 FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \ +			 FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \ +			 FIFO_CFG5_17 | FIFO_CFG5_SF) + +static int ag71xx_hw_init(struct ag71xx *ag) +{ +    int ret = 0; +	uint32_t reg; +	uint32_t mask, mii_type; + +    if (ag->macNum == 0) { +        mask = (RESET_MODULE_GE0_MAC | RESET_MODULE_GE0_PHY); +        mii_type = 0x13; +    } else { +        mask = (RESET_MODULE_GE1_MAC | RESET_MODULE_GE1_PHY); +        mii_type = 0x11; +    } + +    // mac soft reset +    ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR); +    udelay(20); +	 +	// device stop +	reg = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE); +	ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, reg | mask); +	udelay(100 * 1000); +	 +    // device start +    reg = ar71xx_reset_rr(AR91XX_RESET_REG_RESET_MODULE); +    ar71xx_reset_wr(AR91XX_RESET_REG_RESET_MODULE, reg & ~mask); +    udelay(100 * 1000); + +    /* setup MAC configuration registers */ +    ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, (MAC_CFG1_RXE | MAC_CFG1_TXE)); + +    ag71xx_sb(ag, AG71XX_REG_MAC_CFG2, +          MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK); + +    /* setup FIFO configuration register 0 */ +    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT); + +    /* setup MII interface type */ +    ag71xx_mii_ctrl_set_if(ag, ag->mii_if); + +    /* setup mdio clock divisor */ +    ag71xx_wr(ag, AG71XX_REG_MII_CFG, MII_CFG_CLK_DIV_20); +	 +	/* setup FIFO configuration registers */ +	ag71xx_sb(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT); +    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000); +    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff); +    ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT); + +    ag71xx_dma_reset(ag); + +    ret = ag71xx_rings_init(ag); +    if (ret) +        return -1; + +	ag71xx_wr(ag, AG71XX_REG_TX_DESC,  +				(u32) virt_to_phys(ag->tx_ring.descs_dma)); +	ag71xx_wr(ag, AG71XX_REG_RX_DESC, +				(u32) virt_to_phys(ag->rx_ring.descs_dma)); +		 +	ag71xx_hw_set_macaddr(ag, ag->dev->enetaddr); +	 +    return 0; +} + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#define AG71XX_MDIO_RETRY	1000 +#define AG71XX_MDIO_DELAY	5 + +static inline struct ag71xx *ag71xx_name2mac(char *devname) +{ +    if (strcmp(devname, agtable[0].dev->name) == 0) +        return &agtable[0]; +    else if (strcmp(devname, agtable[1].dev->name) == 0) +        return &agtable[1]; +    else +        return NULL; +} + +static inline void ag71xx_mdio_wr(struct ag71xx *ag, unsigned reg, +				  u32 value) +{ +	uint32_t r; + +	r = ag->mac_base + reg; +	writel(value, r); + +	/* flush write */ +	(void) readl(r); +} + +static inline u32 ag71xx_mdio_rr(struct ag71xx *ag, unsigned reg) +{ +	return readl(ag->mac_base + reg); +} + +static int ag71xx_mdio_read(char *devname, unsigned char addr, +                            unsigned char reg, unsigned short *val) +{ +	struct ag71xx *ag = ag71xx_name2mac(devname); +	uint16_t regData; +	int i; + +	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE); +	ag71xx_mdio_wr(ag, AG71XX_REG_MII_ADDR, +			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff)); +	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_READ); + +	i = AG71XX_MDIO_RETRY; +	while (ag71xx_mdio_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) { +		if (i-- == 0) { +			printf("%s: mii_read timed out\n", +				ag->dev->name); +			return -1; +		} +		udelay(AG71XX_MDIO_DELAY); +	} + +	regData = (uint16_t) ag71xx_mdio_rr(ag, AG71XX_REG_MII_STATUS) & 0xffff; +	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CMD, MII_CMD_WRITE); + +	DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, regData); + +    if (val) +        *val = regData; + +	return 0; +} + +static int ag71xx_mdio_write(char *devname, unsigned char addr, +                            unsigned char reg, unsigned short val) +{ +	struct ag71xx *ag = ag71xx_name2mac(devname); +	int i; + +    if (ag == NULL) +        return 1; + +	DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val); + +	ag71xx_mdio_wr(ag, AG71XX_REG_MII_ADDR, +			((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff)); +	ag71xx_mdio_wr(ag, AG71XX_REG_MII_CTRL, val); + +	i = AG71XX_MDIO_RETRY; +	while (ag71xx_mdio_rr(ag, AG71XX_REG_MII_IND) & MII_IND_BUSY) { +		if (i-- == 0) { +			printf("%s: mii_write timed out\n", +				ag->dev->name); +			break; +		} +		udelay(AG71XX_MDIO_DELAY); +	} + +	return 0; +} +#endif + +int ag71xx_register(bd_t * bis, char *phyname[], uint16_t phyid[], uint16_t phyfixed[]) +{ +    int i, num = 0; +    u8 used_ports[MAX_AG71XX_DEVS] = CONFIG_AG71XX_PORTS; + +	for (i = 0; i < MAX_AG71XX_DEVS; i++) { +		/*skip if port is configured not to use */ +		if (used_ports[i] == 0) +			continue; + +		agtable[i].dev = malloc(sizeof(struct eth_device)); +		if (agtable[i].dev == NULL) { +			puts("malloc failed\n"); +			return 0; +        } +		memset(agtable[i].dev, 0, sizeof(struct eth_device)); +		sprintf(agtable[i].dev->name, "eth%d", i); + +		agtable[i].dev->iobase = 0; +		agtable[i].dev->init = ag71xx_hw_start; +		agtable[i].dev->halt = ag71xx_halt; +		agtable[i].dev->send = ag71xx_send; +		agtable[i].dev->recv = ag71xx_recv; +		agtable[i].dev->priv = (void *) (&agtable[i]); +		agtable[i].macNum = i; +		eth_register(agtable[i].dev); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + +        if ((phyname == NULL) || (phyid == NULL) || (phyfixed == NULL)) +            return -1; + +        agtable[i].phyname = strdup(phyname[i]); +        agtable[i].phyid = phyid[i]; +        agtable[i].phyfixed = phyfixed[i]; + +        miiphy_register(agtable[i].dev->name, ag71xx_mdio_read, +			ag71xx_mdio_write); +#endif + +		if (ag71xx_hw_init(&agtable[i])) +			continue; + +        num++; +	} + +    return num; +} diff --git a/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h new file mode 100644 index 000000000..edce42974 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/ag71xx.h @@ -0,0 +1,374 @@ +/* + *  Atheros AR71xx built-in ethernet mac driver + * + *  Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> + *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + *  Based on Atheros' AG7100 driver + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + */ + +#ifndef __AG71XX_H +#define __AG71XX_H + +#include <linux/types.h> +#include <linux/bitops.h> + +#include <asm/ar71xx.h> + +// controller has 2 ports +#define MAX_AG71XX_DEVS 2 + +#define ETH_FCS_LEN	4 + +#define SPEED_10        10 +#define SPEED_100       100 +#define SPEED_1000      1000 + + +#define AG71XX_INT_ERR	(AG71XX_INT_RX_BE | AG71XX_INT_TX_BE) +#define AG71XX_INT_TX	(AG71XX_INT_TX_PS) +#define AG71XX_INT_RX	(AG71XX_INT_RX_PR | AG71XX_INT_RX_OF) + +#define AG71XX_INT_POLL	(AG71XX_INT_RX | AG71XX_INT_TX) +#define AG71XX_INT_INIT	(AG71XX_INT_ERR | AG71XX_INT_POLL) + +#define AG71XX_TX_FIFO_LEN	2048 +#define AG71XX_TX_MTU_LEN	1536 +#define AG71XX_RX_PKT_RESERVE	64 +#define AG71XX_RX_PKT_SIZE	\ +	(AG71XX_RX_PKT_RESERVE + ETH_HLEN + ETH_FRAME_LEN + ETH_FCS_LEN) + +#ifndef CONFIG_SYS_RX_ETH_BUFFER +#define AG71XX_TX_RING_SIZE	4 +#define AG71XX_RX_RING_SIZE	4 +#else +#define AG71XX_TX_RING_SIZE	CONFIG_SYS_RX_ETH_BUFFER +#define AG71XX_RX_RING_SIZE	CONFIG_SYS_RX_ETH_BUFFER +#endif + +#define AG71XX_TX_THRES_STOP	(AG71XX_TX_RING_SIZE - 4) +#define AG71XX_TX_THRES_WAKEUP	\ +		(AG71XX_TX_RING_SIZE - (AG71XX_TX_RING_SIZE / 4)) + + + + +struct ag71xx_desc { +	u32	data; +	u32	ctrl; +#define DESC_EMPTY	BIT(31) +#define DESC_MORE	BIT(24) +#define DESC_PKTLEN_M	0xfff +	u32	next; +	u32	pad; +} __attribute__((aligned(4))); + +struct ag71xx_buf { +	struct sk_buff		*skb; +	struct ag71xx_desc 	*desc; +	dma_addr_t		dma_addr; +	u32			pad; +}; + +struct ag71xx_ring { +	struct ag71xx_buf	*buf; +	u8			*descs_cpu; +	u8		    *descs_dma; +	unsigned int		desc_size; +	unsigned int		curr; +	unsigned int		size; +}; + +struct ag71xx { +	uint32_t		    mac_base; +	uint32_t		    mii_ctrl; + +	struct eth_device	*dev; + +	struct ag71xx_ring	rx_ring; +	struct ag71xx_ring	tx_ring; + +    char               *phyname; +    u16                 phyid; +    u16                 phyfixed; +	uint32_t	    	link; +	uint32_t	    	speed; +	int32_t			    duplex; +    uint32_t            macNum; +    uint32_t            mii_if; +}; + +void ag71xx_link_adjust(struct ag71xx *ag); + +int ag71xx_phy_connect(struct ag71xx *ag); +void ag71xx_phy_disconnect(struct ag71xx *ag); +void ag71xx_phy_start(struct ag71xx *ag); +void ag71xx_phy_stop(struct ag71xx *ag); + +static inline int ag71xx_desc_empty(struct ag71xx_desc *desc) +{ +	return ((desc->ctrl & DESC_EMPTY) != 0); +} + +static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc) +{ +	return (desc->ctrl & DESC_PKTLEN_M); +} + +/* Register offsets */ +#define AG71XX_REG_MAC_CFG1	0x0000 +#define AG71XX_REG_MAC_CFG2	0x0004 +#define AG71XX_REG_MAC_IPG	0x0008 +#define AG71XX_REG_MAC_HDX	0x000c +#define AG71XX_REG_MAC_MFL	0x0010 +#define AG71XX_REG_MII_CFG	0x0020 +#define AG71XX_REG_MII_CMD	0x0024 +#define AG71XX_REG_MII_ADDR	0x0028 +#define AG71XX_REG_MII_CTRL	0x002c +#define AG71XX_REG_MII_STATUS	0x0030 +#define AG71XX_REG_MII_IND	0x0034 +#define AG71XX_REG_MAC_IFCTL	0x0038 +#define AG71XX_REG_MAC_ADDR1	0x0040 +#define AG71XX_REG_MAC_ADDR2	0x0044 +#define AG71XX_REG_FIFO_CFG0	0x0048 +#define AG71XX_REG_FIFO_CFG1	0x004c +#define AG71XX_REG_FIFO_CFG2	0x0050 +#define AG71XX_REG_FIFO_CFG3	0x0054 +#define AG71XX_REG_FIFO_CFG4	0x0058 +#define AG71XX_REG_FIFO_CFG5	0x005c +#define AG71XX_REG_FIFO_RAM0	0x0060 +#define AG71XX_REG_FIFO_RAM1	0x0064 +#define AG71XX_REG_FIFO_RAM2	0x0068 +#define AG71XX_REG_FIFO_RAM3	0x006c +#define AG71XX_REG_FIFO_RAM4	0x0070 +#define AG71XX_REG_FIFO_RAM5	0x0074 +#define AG71XX_REG_FIFO_RAM6	0x0078 +#define AG71XX_REG_FIFO_RAM7	0x007c + +#define AG71XX_REG_TX_CTRL	0x0180 +#define AG71XX_REG_TX_DESC	0x0184 +#define AG71XX_REG_TX_STATUS	0x0188 +#define AG71XX_REG_RX_CTRL	0x018c +#define AG71XX_REG_RX_DESC	0x0190 +#define AG71XX_REG_RX_STATUS	0x0194 +#define AG71XX_REG_INT_ENABLE	0x0198 +#define AG71XX_REG_INT_STATUS	0x019c + +#define MAC_CFG1_TXE		BIT(0)	/* Tx Enable */ +#define MAC_CFG1_STX		BIT(1)	/* Synchronize Tx Enable */ +#define MAC_CFG1_RXE		BIT(2)	/* Rx Enable */ +#define MAC_CFG1_SRX		BIT(3)	/* Synchronize Rx Enable */ +#define MAC_CFG1_TFC		BIT(4)	/* Tx Flow Control Enable */ +#define MAC_CFG1_RFC		BIT(5)	/* Rx Flow Control Enable */ +#define MAC_CFG1_LB		BIT(8)	/* Loopback mode */ +#define MAC_CFG1_SR		BIT(31)	/* Soft Reset */ + +#define MAC_CFG2_FDX		BIT(0) +#define MAC_CFG2_CRC_EN		BIT(1) +#define MAC_CFG2_PAD_CRC_EN	BIT(2) +#define MAC_CFG2_LEN_CHECK	BIT(4) +#define MAC_CFG2_HUGE_FRAME_EN	BIT(5) +#define MAC_CFG2_IF_1000	BIT(9) +#define MAC_CFG2_IF_10_100	BIT(8) + +#define FIFO_CFG0_WTM		BIT(0)	/* Watermark Module */ +#define FIFO_CFG0_RXS		BIT(1)	/* Rx System Module */ +#define FIFO_CFG0_RXF		BIT(2)	/* Rx Fabric Module */ +#define FIFO_CFG0_TXS		BIT(3)	/* Tx System Module */ +#define FIFO_CFG0_TXF		BIT(4)	/* Tx Fabric Module */ +#define FIFO_CFG0_ALL	(FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \ +			| FIFO_CFG0_TXS | FIFO_CFG0_TXF) + +#define FIFO_CFG0_ENABLE_SHIFT	8 + +#define FIFO_CFG4_DE		BIT(0)	/* Drop Event */ +#define FIFO_CFG4_DV		BIT(1)	/* RX_DV Event */ +#define FIFO_CFG4_FC		BIT(2)	/* False Carrier */ +#define FIFO_CFG4_CE		BIT(3)	/* Code Error */ +#define FIFO_CFG4_CR		BIT(4)	/* CRC error */ +#define FIFO_CFG4_LM		BIT(5)	/* Length Mismatch */ +#define FIFO_CFG4_LO		BIT(6)	/* Length out of range */ +#define FIFO_CFG4_OK		BIT(7)	/* Packet is OK */ +#define FIFO_CFG4_MC		BIT(8)	/* Multicast Packet */ +#define FIFO_CFG4_BC		BIT(9)	/* Broadcast Packet */ +#define FIFO_CFG4_DR		BIT(10)	/* Dribble */ +#define FIFO_CFG4_LE		BIT(11)	/* Long Event */ +#define FIFO_CFG4_CF		BIT(12)	/* Control Frame */ +#define FIFO_CFG4_PF		BIT(13)	/* Pause Frame */ +#define FIFO_CFG4_UO		BIT(14)	/* Unsupported Opcode */ +#define FIFO_CFG4_VT		BIT(15)	/* VLAN tag detected */ +#define FIFO_CFG4_FT		BIT(16)	/* Frame Truncated */ +#define FIFO_CFG4_UC		BIT(17)	/* Unicast Packet */ + +#define FIFO_CFG5_DE		BIT(0)	/* Drop Event */ +#define FIFO_CFG5_DV		BIT(1)	/* RX_DV Event */ +#define FIFO_CFG5_FC		BIT(2)	/* False Carrier */ +#define FIFO_CFG5_CE		BIT(3)	/* Code Error */ +#define FIFO_CFG5_LM		BIT(4)	/* Length Mismatch */ +#define FIFO_CFG5_LO		BIT(5)	/* Length Out of Range */ +#define FIFO_CFG5_OK		BIT(6)	/* Packet is OK */ +#define FIFO_CFG5_MC		BIT(7)	/* Multicast Packet */ +#define FIFO_CFG5_BC		BIT(8)	/* Broadcast Packet */ +#define FIFO_CFG5_DR		BIT(9)	/* Dribble */ +#define FIFO_CFG5_CF		BIT(10)	/* Control Frame */ +#define FIFO_CFG5_PF		BIT(11)	/* Pause Frame */ +#define FIFO_CFG5_UO		BIT(12)	/* Unsupported Opcode */ +#define FIFO_CFG5_VT		BIT(13)	/* VLAN tag detected */ +#define FIFO_CFG5_LE		BIT(14)	/* Long Event */ +#define FIFO_CFG5_FT		BIT(15)	/* Frame Truncated */ +#define FIFO_CFG5_16		BIT(16)	/* unknown */ +#define FIFO_CFG5_17		BIT(17)	/* unknown */ +#define FIFO_CFG5_SF		BIT(18)	/* Short Frame */ +#define FIFO_CFG5_BM		BIT(19)	/* Byte Mode */ + +#define AG71XX_INT_TX_PS	BIT(0) +#define AG71XX_INT_TX_UR	BIT(1) +#define AG71XX_INT_TX_BE	BIT(3) +#define AG71XX_INT_RX_PR	BIT(4) +#define AG71XX_INT_RX_OF	BIT(6) +#define AG71XX_INT_RX_BE	BIT(7) + +#define MAC_IFCTL_SPEED		BIT(16) + +#define MII_CFG_CLK_DIV_4	0 +#define MII_CFG_CLK_DIV_6	2 +#define MII_CFG_CLK_DIV_8	3 +#define MII_CFG_CLK_DIV_10	4 +#define MII_CFG_CLK_DIV_14	5 +#define MII_CFG_CLK_DIV_20	6 +#define MII_CFG_CLK_DIV_28	7 +#define MII_CFG_RESET		BIT(31) + +#define MII_CMD_WRITE		0x0 +#define MII_CMD_READ		0x1 +#define MII_ADDR_SHIFT		8 +#define MII_IND_BUSY		BIT(0) +#define MII_IND_INVALID		BIT(2) + +#define TX_CTRL_TXE		BIT(0)	/* Tx Enable */ + +#define TX_STATUS_PS		BIT(0)	/* Packet Sent */ +#define TX_STATUS_UR		BIT(1)	/* Tx Underrun */ +#define TX_STATUS_BE		BIT(3)	/* Bus Error */ + +#define RX_CTRL_RXE		BIT(0)	/* Rx Enable */ + +#define RX_STATUS_PR		BIT(0)	/* Packet Received */ +#define RX_STATUS_OF		BIT(2)	/* Rx Overflow */ +#define RX_STATUS_BE		BIT(3)	/* Bus Error */ + +#define MII_CTRL_IF_MASK	3 +#define MII_CTRL_SPEED_SHIFT	4 +#define MII_CTRL_SPEED_MASK	3 +#define MII_CTRL_SPEED_10	0 +#define MII_CTRL_SPEED_100	1 +#define MII_CTRL_SPEED_1000	2 + +static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value) +{ +	__raw_writel(value, ag->mac_base + reg); +	/* flush write */ +	(void) __raw_readl(ag->mac_base + reg); +} + +static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg) +{ +	return __raw_readl(ag->mac_base + reg); +} + +static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask) +{ +	uint32_t r; + +	r = ag->mac_base + reg; +	__raw_writel(__raw_readl(r) | mask, r); +	/* flush write */ +	(void)__raw_readl(r); +} + +static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask) +{ +	uint32_t r; + +	r = ag->mac_base + reg; +	__raw_writel(__raw_readl(r) & ~mask, r); +	/* flush write */ +	(void) __raw_readl(r); +} + +static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints) +{ +	ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints); +} + +static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints) +{ +	ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints); +} + +static inline void ag71xx_mii_ctrl_wr(struct ag71xx *ag, u32 value) +{ +	__raw_writel(value, ag->mii_ctrl); + +	/* flush write */ +	__raw_readl(ag->mii_ctrl); +} + +static inline u32 ag71xx_mii_ctrl_rr(struct ag71xx *ag) +{ +	return __raw_readl(ag->mii_ctrl); +} + +static void inline ag71xx_mii_ctrl_set_if(struct ag71xx *ag, +					  unsigned int mii_if) +{ +	u32 t; + +	t = ag71xx_mii_ctrl_rr(ag); +	t &= ~(MII_CTRL_IF_MASK); +	t |= (mii_if & MII_CTRL_IF_MASK); +	ag71xx_mii_ctrl_wr(ag, t); +} + +static void inline ag71xx_mii_ctrl_set_speed(struct ag71xx *ag, +					     unsigned int speed) +{ +	u32 t; + +	t = ag71xx_mii_ctrl_rr(ag); +	t &= ~(MII_CTRL_SPEED_MASK << MII_CTRL_SPEED_SHIFT); +	t |= (speed & MII_CTRL_SPEED_MASK) << MII_CTRL_SPEED_SHIFT; +	ag71xx_mii_ctrl_wr(ag, t); +} + +#ifdef CONFIG_AG71XX_AR8216_SUPPORT +void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb); +int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb, +				int pktlen); +static inline int ag71xx_has_ar8216(struct ag71xx *ag) +{ +	return ag71xx_get_pdata(ag)->has_ar8216; +} +#else +static inline void ag71xx_add_ar8216_header(struct ag71xx *ag, +					   struct sk_buff *skb) +{ +} + +static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag, +					      struct sk_buff *skb, +					      int pktlen) +{ +	return 0; +} +static inline int ag71xx_has_ar8216(struct ag71xx *ag) +{ +	return 0; +} +#endif + +#endif /* _AG71XX_H */ diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h new file mode 100644 index 000000000..f0567dd64 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366.h @@ -0,0 +1,188 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.com>. + * + * 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 + */ + +#ifndef RTL8366_MII_H +#define RTL8366_MII_H + +#define	MII_CONTROL_REG		    0 +#define	MII_STATUS_REG	    	1 +#define	MII_PHY_ID0		        2 +#define	MII_PHY_ID1		        3 +#define	MII_LOCAL_CAP	    	4 +#define	MII_REMOTE_CAP		    5 +#define	MII_EXT_AUTONEG		    6 +#define	MII_LOCAL_NEXT_PAGE	    7 +#define	MII_REMOTE_NEXT_PAGE	8 +#define	MII_GIGA_CONTROL	    9 +#define	MII_GIGA_STATUS		    10 +#define	MII_EXT_STATUS_REG	    15 + +/* Control register */ +#define	MII_CONTROL_1000MBPS	6 +#define	MII_CONTROL_COLL_TEST	7 +#define	MII_CONTROL_FULLDUPLEX	8 +#define	MII_CONTROL_RENEG	    9 +#define	MII_CONTROL_ISOLATE	    10 +#define	MII_CONTROL_POWERDOWN	11 +#define	MII_CONTROL_AUTONEG	    12 +#define	MII_CONTROL_100MBPS	    13 +#define	MII_CONTROL_LOOPBACK	14 +#define	MII_CONTROL_RESET	    15 + +/* Status/Extended status register */ +/* Basic status */ +#define	MII_STATUS_CAPABILITY	0 +#define	MII_STATUS_JABBER	    1 +#define	MII_STATUS_LINK_UP	    2 +#define	MII_STATUS_AUTONEG_ABLE	3 +#define	MII_STATUS_REMOTE_FAULT	4 +#define	MII_STATUS_AUTONEG_DONE	5 +#define	MII_STATUS_NO_PREAMBLE	6 +#define	MII_STATUS_RESERVED	    7 +#define	MII_STATUS_EXTENDED	    8 +#define	MII_STATUS_100_T2_HALF	9 +#define	MII_STATUS_100_T2_FULL	10 +#define	MII_STATUS_10_TX_HALF	11 +#define	MII_STATUS_10_TX_FULL	12 +#define	MII_STATUS_100_TX_HALF	13 +#define	MII_STATUS_100_TX_FULL	14 +#define	MII_STATUS_100_T4	    15 + +#define	MII_GIGA_CONTROL_HALF	8 +#define	MII_GIGA_CONTROL_FULL	9 +#define	MII_GIGA_STATUS_HALF	10 +#define	MII_GIGA_STATUS_FULL	11 + +/* Extended status */ +#define	MII_STATUS_1000_T_HALF	12 +#define	MII_STATUS_1000_T_FULL	13 +#define	MII_STATUS_1000_X_HALF	14 +#define	MII_STATUS_1000_X_FULL	15 + +/* Local/Remmote capability register */ +#define	MII_CAP_10BASE_TX	    5 +#define	MII_CAP_10BASE_TX_FULL	6 +#define	MII_CAP_100BASE_TX	    7 +#define	MII_CAP_100BASE_TX_FULL	8 +#define	MII_CAP_100BASE_T4	    9 +#define	MII_CAP_SYMM_PAUSE	    10 +#define	MII_CAP_ASYMM_PAUSE	    11 +#define	MII_CAP_RESERVED	    12 +#define	MII_CAP_REMOTE_FAULT	13 +#define	MII_CAP_ACKNOWLEDGE	    14 +#define	MII_CAP_NEXT_PAGE	    15 +#define	MII_CAP_IEEE_802_3	    0x0001 + +#define	MII_LINK_MODE_MASK	    0x1f + +#define REALTEK_RTL8366_CHIP_ID0    0x001C +#define REALTEK_RTL8366_CHIP_ID1    0xC940 +#define REALTEK_RTL8366_CHIP_ID1_MP 0xC960 + +#define REALTEK_MIN_PORT_ID     0 +#define REALTEK_MAX_PORT_ID     5 +#define REALTEK_MIN_PHY_ID      REALTEK_MIN_PORT_ID +#define REALTEK_MAX_PHY_ID      4 +#define REALTEK_CPU_PORT_ID     REALTEK_MAX_PORT_ID +#define REALTEK_PHY_PORT_MASK   ((1<<(REALTEK_MAX_PHY_ID+1)) - (1<<REALTEK_MIN_PHY_ID)) +#define REALTEK_CPU_PORT_MASK   (1<<REALTEK_CPU_PORT_ID) +#define REALTEK_ALL_PORT_MASK   (REALTEK_PHY_PORT_MASK | REALTEK_CPU_PORT_MASK) + +/* port ability */ +#define RTL8366S_PORT_ABILITY_BASE			0x0011 + +/* port vlan control register */ +#define RTL8366S_PORT_VLAN_CTRL_BASE			0x0058 + +/* port linking status */ +#define RTL8366S_PORT_LINK_STATUS_BASE			0x0060 +#define RTL8366S_PORT_STATUS_SPEED_BIT			0 +#define RTL8366S_PORT_STATUS_SPEED_MSK			0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_BIT			2 +#define RTL8366S_PORT_STATUS_DUPLEX_MSK			0x0004 +#define RTL8366S_PORT_STATUS_LINK_BIT			4 +#define RTL8366S_PORT_STATUS_LINK_MSK			0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_BIT		5 +#define RTL8366S_PORT_STATUS_TXPAUSE_MSK		0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_BIT		6 +#define RTL8366S_PORT_STATUS_RXPAUSE_MSK		0x0040 +#define RTL8366S_PORT_STATUS_AN_BIT			7 +#define RTL8366S_PORT_STATUS_AN_MSK			0x0080 + +/* internal control */ +#define RTL8366S_RESET_CONTROL_REG			0x0100 +#define RTL8366S_RESET_QUEUE_BIT			2 + +#define RTL8366S_CHIP_ID_REG				0x0105 + +/* MAC control */ +#define RTL8366S_MAC_FORCE_CTRL0_REG			0x0F04 +#define RTL8366S_MAC_FORCE_CTRL1_REG			0x0F05 + + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG			0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG			0x8029 + +#define RTL8366S_PHY_CTRL_READ				1 +#define RTL8366S_PHY_CTRL_WRITE				0 + +#define RTL8366S_PHY_REG_MASK				0x1F +#define RTL8366S_PHY_PAGE_OFFSET			5 +#define RTL8366S_PHY_PAGE_MASK				(0x7<<5) +#define RTL8366S_PHY_NO_OFFSET				9 +#define RTL8366S_PHY_NO_MASK				(0x1F<<9) + +#define RTL8366S_PHY_NO_MAX				4 +#define RTL8366S_PHY_PAGE_MAX				7 +#define RTL8366S_PHY_ADDR_MAX				31 + +/* cpu port control reg */ +#define RTL8366S_CPU_CTRL_REG				0x004F +#define RTL8366S_CPU_DRP_BIT				14 +#define RTL8366S_CPU_DRP_MSK				0x4000 +#define RTL8366S_CPU_INSTAG_BIT				15 +#define RTL8366S_CPU_INSTAG_MSK				0x8000 + +/* LED registers*/ +#define RTL8366S_LED_BLINK_REG				0x420 +#define RTL8366S_LED_BLINKRATE_BIT			0 +#define RTL8366S_LED_BLINKRATE_MSK			0x0007 +#define RTL8366S_LED_INDICATED_CONF_REG			0x421 +#define RTL8366S_LED_0_1_FORCE_REG			0x422 +#define RTL8366S_LED_2_3_FORCE_REG			0x423 +#define RTL8366S_LEDCONF_LEDFORCE			0x1F +#define RTL8366S_LED_GROUP_MAX				4 + +#define RTL8366S_GREEN_FEATURE_REG			0x000A +#define RTL8366S_GREEN_FEATURE_TX_BIT			3 +#define RTL8366S_GREEN_FEATURE_TX_MSK			0x0008 +#define RTL8366S_GREEN_FEATURE_RX_BIT			4 +#define RTL8366S_GREEN_FEATURE_RX_MSK			0x0010 + +#define	RTL8366S_MODEL_ID_REG	0x5C +#define	RTL8366S_REV_ID_REG	0x5D +#define	RTL8366S_MODEL_8366SR	0x6027 +#define	RTL8366S_MODEL_8366RB	0x5937 + +#endif diff --git a/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c new file mode 100644 index 000000000..e3c531654 --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/net/phy/rtl8366_mii.c @@ -0,0 +1,786 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.com>. + * + * 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 <common.h> +#include <net.h> +#include <netdev.h> +#include <miiphy.h> +#include MII_GPIOINCLUDE + +#include "rtl8366.h" + +#ifdef DEBUG_RTL8366 +	#define DBG(fmt,args...)	printf (fmt ,##args) +#else +	#define DBG(fmt,args...) +#endif + + +//------------------------------------------------------------------- +// Soft SMI functions +//------------------------------------------------------------------- + +#define DELAY 2 + +static void smi_init(void) +{ +    MII_SDAINPUT; +    MII_SCKINPUT; + +	MII_SETSDA(1); +	MII_SETSCK(1); + +    udelay(20); +} + +static void smi_start(void) +{ +/* + * rtl8366 chip needs a extra clock with + * SDA high before start condition + */ + +    /* set gpio pins output */ +    MII_SDAOUTPUT; +    MII_SCKOUTPUT; +    udelay(DELAY); + +    /* set initial state: SCK:0, SDA:1 */ +    MII_SETSCK(0); +    MII_SETSDA(1); +    udelay(DELAY); + +    /* toggle clock */ +    MII_SETSCK(1); +    udelay(DELAY); +    MII_SETSCK(0); +    udelay(DELAY); + +    /* start condition */ +    MII_SETSCK(1); +    udelay(DELAY); +    MII_SETSDA(0); +    udelay(DELAY); +    MII_SETSCK(0); +    udelay(DELAY); +    MII_SETSDA(1); +} + +static void smi_stop(void) +{ +/* + * rtl8366 chip needs a extra clock with + * SDA high after stop condition + */ + +    /* stop condition */ +	udelay(DELAY); +    MII_SETSDA(0); +    MII_SETSCK(1); +    udelay(DELAY); +    MII_SETSDA(1); +    udelay(DELAY); +    MII_SETSCK(1); +    udelay(DELAY); +    MII_SETSCK(0); +    udelay(DELAY); + +    /* toggle clock */ +    MII_SETSCK(1); +    udelay(DELAY); +    MII_SETSCK(0); +    udelay(DELAY); +    MII_SETSCK(1); + +    /* set gpio pins input */ +    MII_SDAINPUT; +    MII_SCKINPUT; +} + +static void smi_writeBits(uint32_t data, uint8_t length) +{ +    uint8_t test; + +    for( ; length > 0; length--) { +        udelay(DELAY); + +        /* output data */ +        test = (((data & (1 << (length - 1))) != 0) ? 1 : 0); +        MII_SETSDA(test); +        udelay(DELAY); + +        /* toogle clock */ +        MII_SETSCK(1); +        udelay(DELAY); +        MII_SETSCK(0); +    } +} + +static uint32_t smi_readBits(uint8_t length) +{ +    uint32_t ret; + +    MII_SDAINPUT; + +    for(ret = 0 ; length > 0; length--) { +        udelay(DELAY); + +        ret <<= 1; + +        /* toogle clock */ +        MII_SETSCK(1); +        udelay(DELAY); +        ret |= MII_GETSDA; +        MII_SETSCK(0); +    } + +    MII_SDAOUTPUT; + +    return ret; +} + +static int smi_waitAck(void) +{ +    uint32_t retry = 0; + +	while (smi_readBits(1)) { +		if (retry++ == 5) +			return -1; +	} + +	return 0; + +} + +static int smi_read(uint32_t reg, uint32_t *data) +{ +    uint32_t rawData; + +    /* send start condition */ +    smi_start(); +    /* send CTRL1 code: 0b1010*/ +    smi_writeBits(0x0a, 4); +    /* send CTRL2 code: 0b100 */ +    smi_writeBits(0x04, 3); +    /* send READ command */ +    smi_writeBits(0x01, 1); + +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; + +    /* send address low */ +    smi_writeBits(reg & 0xFF, 8); +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; +    /* send address high */ +    smi_writeBits((reg & 0xFF00) >> 8, 8); +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; + +    /* read data low */ +    rawData = (smi_readBits(8) & 0xFF); +    /* send ACK */ +    smi_writeBits(0, 1); +    /* read data high */ +    rawData |= (smi_readBits(8) & 0xFF) << 8; +    /* send NACK */ +    smi_writeBits(1, 1); + +    /* send stop condition */ +    smi_stop(); + +    if (data) +        *data = rawData; + +    return 0; +} + +static int smi_write(uint32_t reg, uint32_t data) +{ +    /* send start condition */ +    smi_start(); +    /* send CTRL1 code: 0b1010*/ +    smi_writeBits(0x0a, 4); +    /* send CTRL2 code: 0b100 */ +    smi_writeBits(0x04, 3); +    /* send WRITE command */ +    smi_writeBits(0x00, 1); + +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; + +    /* send address low */ +    smi_writeBits(reg & 0xFF, 8); +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; +    /* send address high */ +    smi_writeBits((reg & 0xFF00) >> 8, 8); +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; + +    /* send data low */ +    smi_writeBits(data & 0xFF, 8); +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; +    /* send data high */ +    smi_writeBits((data & 0xFF00) >> 8, 8); +    /* wait for ACK */ +    if (smi_waitAck()) +        return -1; + +    /* send stop condition */ +    smi_stop(); + +    return 0; +} + + +//------------------------------------------------------------------- +// Switch register read / write functions +//------------------------------------------------------------------- +static int rtl8366_readRegister(uint32_t reg, uint16_t *data) +{ +    uint32_t regData; + +    DBG("rtl8366: read register=%#04x, data=", reg); + +    if (smi_read(reg, ®Data)) { +        printf("\nrtl8366 smi read failed!\n"); +        return -1; +    } + +    if (data) +        *data = regData; + +    DBG("%#04x\n", regData); + +    return 0; +} + +static int rtl8366_writeRegister(uint32_t reg, uint16_t data) +{ +    DBG("rtl8366: write register=%#04x, data=%#04x\n", reg, data); + +    if (smi_write(reg, data)) { +        printf("rtl8366 smi write failed!\n"); +        return -1; +    } + +    return 0; +} + +static int rtl8366_setRegisterBit(uint32_t reg, uint32_t bitNum, uint32_t value) +{ +    uint16_t regData; + +    if (bitNum >= 16) +        return -1; + +    if (rtl8366_readRegister(reg, ®Data)) +        return -1; + +    if (value) +        regData |= (1 << bitNum); +    else +        regData &= ~(1 << bitNum); + +    if (rtl8366_writeRegister(reg, regData)) +        return -1; + +    return 0; +} + +//------------------------------------------------------------------- +// MII PHY read / write functions +//------------------------------------------------------------------- +static int rtl8366_getPhyReg(uint32_t phyNum, uint32_t reg, uint16_t *data) +{ +    uint16_t phyAddr, regData; + +    if (phyNum > RTL8366S_PHY_NO_MAX) { +		printf("rtl8366s: invalid phy number!\n"); +		return -1; +	} + +    if (phyNum > RTL8366S_PHY_ADDR_MAX) { +		printf("rtl8366s: invalid phy register number!\n"); +		return -1; +	} + +	if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, +                           RTL8366S_PHY_CTRL_READ)) +        return -1; + +    phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) +                     | (reg & RTL8366S_PHY_REG_MASK); +    if (rtl8366_writeRegister(phyAddr, 0)) +        return -1; + +    if (rtl8366_readRegister(RTL8366S_PHY_ACCESS_DATA_REG, ®Data)) +        return -1; + +    if (data) +        *data = regData; + +    return 0; +} + +static int rtl8366_setPhyReg(uint32_t phyNum, uint32_t reg, uint16_t data) +{ +    uint16_t phyAddr; + +    if (phyNum > RTL8366S_PHY_NO_MAX) { +		printf("rtl8366s: invalid phy number!\n"); +		return -1; +	} + +    if (phyNum > RTL8366S_PHY_ADDR_MAX) { +		printf("rtl8366s: invalid phy register number!\n"); +		return -1; +	} + +	if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, +                           RTL8366S_PHY_CTRL_WRITE)) +        return -1; + +    phyAddr = 0x8000 | (1 << (phyNum + RTL8366S_PHY_NO_OFFSET)) +                     | (reg & RTL8366S_PHY_REG_MASK); +    if (rtl8366_writeRegister(phyAddr, data)) +        return -1; + +    return 0; +} + +static int rtl8366_miiread(char *devname, uchar phy_adr, uchar reg, ushort *data) +{ +    uint16_t regData; + +    DBG("rtl8366_miiread: devname=%s, addr=%#02x, reg=%#02x\n", +          devname, phy_adr, reg); + +    if (strcmp(devname, RTL8366_DEVNAME) != 0) +        return -1; + +    if (rtl8366_getPhyReg(phy_adr, reg, ®Data)) { +        printf("rtl8366_miiread: write failed!\n"); +        return -1; +    } + +    if (data) +        *data = regData; + +    return 0; +} + +static int rtl8366_miiwrite(char *devname, uchar phy_adr, uchar reg, ushort data) +{ +    DBG("rtl8366_miiwrite: devname=%s, addr=%#02x, reg=%#02x, data=%#04x\n", +          devname, phy_adr, reg, data); + +    if (strcmp(devname, RTL8366_DEVNAME) != 0) +        return -1; + +    if (rtl8366_setPhyReg(phy_adr, reg, data)) { +        printf("rtl8366_miiwrite: write failed!\n"); +        return -1; +    } + +    return 0; +} + +int rtl8366_mii_register(bd_t *bis) +{ +    miiphy_register(strdup(RTL8366_DEVNAME), rtl8366_miiread, +			rtl8366_miiwrite); + +    return 0; +} + + +//------------------------------------------------------------------- +// Switch management functions +//------------------------------------------------------------------- + +int rtl8366s_setGreenFeature(uint32_t tx, uint32_t rx) +{ +    if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, +                               RTL8366S_GREEN_FEATURE_TX_BIT, tx)) +        return -1; + +    if (rtl8366_setRegisterBit(RTL8366S_GREEN_FEATURE_REG, +                               RTL8366S_GREEN_FEATURE_RX_BIT, rx)) +        return -1; + +    return 0; +} + +int rtl8366s_setPowerSaving(uint32_t phyNum, uint32_t enabled) +{ +    uint16_t regData; + +    if (phyNum > RTL8366S_PHY_NO_MAX) +        return -1; + +    if (rtl8366_getPhyReg(phyNum, 12, ®Data)) +        return -1; + +    if (enabled) +        regData |= (1 << 12); +    else +        regData &= ~(1 << 12); + +    if (rtl8366_setPhyReg(phyNum, 12, regData)) +        return -1; + +    return 0; +} + +int rtl8366s_setGreenEthernet(uint32_t greenFeature, uint32_t powerSaving) +{ +    uint32_t phyNum, i; +    uint16_t regData; + +	const uint16_t greenSettings[][2] = +	{ +		{0xBE5B,0x3500}, +		{0xBE5C,0xB975}, +		{0xBE5D,0xB9B9}, +		{0xBE77,0xA500}, +		{0xBE78,0x5A78}, +		{0xBE79,0x6478} +	}; + +    if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) +        return -1; + +	switch (regData) +	{ +		case 0x0000: +			for (i = 0; i < 6; i++) { +				if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) +					return -1; +				if (rtl8366_writeRegister(greenSettings[i][0], greenSettings[i][1])) +					return -1; +			} +			break; + +		case RTL8366S_MODEL_8366SR: +			if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, RTL8366S_PHY_CTRL_WRITE)) +				return -1; +			if (rtl8366_writeRegister(greenSettings[0][0], greenSettings[0][1])) +				return -1; +			break; + +		default: +			printf("rtl8366s_initChip: unsupported chip found!\n"); +			return -1; +	} + +    if (rtl8366s_setGreenFeature(greenFeature, powerSaving)) +        return -1; + +    for (phyNum = 0; phyNum <= RTL8366S_PHY_NO_MAX; phyNum++) { +        if (rtl8366s_setPowerSaving(phyNum, powerSaving)) +            return -1; +    } + +    return 0; +} + +int rtl8366s_setCPUPortMask(uint8_t port, uint32_t enabled) +{ +	if(port >= 6){ +		printf("rtl8366s_setCPUPortMask: invalid port number\n"); +		return -1; +	} + +	return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, port, enabled); +} + +int rtl8366s_setCPUDisableInsTag(uint32_t enable) +{ +	return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, +		RTL8366S_CPU_INSTAG_BIT, enable); +} + +int rtl8366s_setCPUDropUnda(uint32_t enable) +{ +	return rtl8366_setRegisterBit(RTL8366S_CPU_CTRL_REG, +		RTL8366S_CPU_DRP_BIT, enable); +} + +int rtl8366s_setCPUPort(uint8_t port, uint32_t noTag, uint32_t dropUnda) +{ +	uint32_t i; + +	if(port >= 6){ +		printf("rtl8366s_setCPUPort: invalid port number\n"); +		return -1; +	} + +	/* reset register */ +	for(i = 0; i < 6; i++) +	{ +		if(rtl8366s_setCPUPortMask(i, 0)){ +			printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); +			return -1; +		} +	} + +	if(rtl8366s_setCPUPortMask(port, 1)){ +		printf("rtl8366s_setCPUPort: rtl8366s_setCPUPortMask failed\n"); +		return -1; +	} + +	if(rtl8366s_setCPUDisableInsTag(noTag)){ +		printf("rtl8366s_setCPUPort: rtl8366s_setCPUDisableInsTag fail\n"); +		return -1; +	} + +	if(rtl8366s_setCPUDropUnda(dropUnda)){ +		printf("rtl8366s_setCPUPort: rtl8366s_setCPUDropUnda fail\n"); +		return -1; +	} + +	return 0; +} + +int rtl8366s_setLedConfig(uint32_t ledNum, uint8_t config) +{ +    uint16_t regData; + +	if(ledNum >= RTL8366S_LED_GROUP_MAX) { +		DBG("rtl8366s_setLedConfig: invalid led group\n"); +		return -1; +	} + +    if(config > RTL8366S_LEDCONF_LEDFORCE) { +		DBG("rtl8366s_setLedConfig: invalid led config\n"); +		return -1; +	} + +	if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { +        printf("rtl8366s_setLedConfig: failed to get led register!\n"); +        return -1; +	} + +	regData &= ~(0xF << (ledNum * 4)); +	regData |= config << (ledNum * 4); + +	if (rtl8366_writeRegister(RTL8366S_LED_INDICATED_CONF_REG, regData)) { +        printf("rtl8366s_setLedConfig: failed to set led register!\n"); +        return -1; +	} + +	return 0; +} + +int rtl8366s_getLedConfig(uint32_t ledNum, uint8_t *config) +{ +    uint16_t regData; + +	if(ledNum >= RTL8366S_LED_GROUP_MAX) { +		DBG("rtl8366s_getLedConfig: invalid led group\n"); +		return -1; +	} + +    if (rtl8366_readRegister(RTL8366S_LED_INDICATED_CONF_REG, ®Data)) { +        printf("rtl8366s_getLedConfig: failed to get led register!\n"); +        return -1; +	} + +	if (config) +        *config = (regData >> (ledNum * 4)) & 0xF; + +    return 0; +} + +int rtl8366s_setLedForceValue(uint32_t group0, uint32_t group1, +                              uint32_t group2, uint32_t group3) +{ +    uint16_t regData; + +    regData = (group0 & 0x3F) | ((group1 & 0x3F) << 6); +	if (rtl8366_writeRegister(RTL8366S_LED_0_1_FORCE_REG, regData)) { +        printf("rtl8366s_setLedForceValue: failed to set led register!\n"); +        return -1; +	} + +    regData = (group2 & 0x3F) | ((group3 & 0x3F) << 6); +	if (rtl8366_writeRegister(RTL8366S_LED_2_3_FORCE_REG, regData)) { +        printf("rtl8366s_setLedForceValue: failed to set led register!\n"); +        return -1; +	} + +	return 0; +} + +int rtl8366s_initChip(void) +{ +    uint32_t ledGroup, i = 0; +    uint16_t regData; +    uint8_t ledData[RTL8366S_LED_GROUP_MAX]; +	const uint16_t (*chipData)[2]; + +	const uint16_t chipB[][2] = +	{ +		{0x0000,	0x0038},{0x8100,	0x1B37},{0xBE2E,	0x7B9F},{0xBE2B,	0xA4C8}, +		{0xBE74,	0xAD14},{0xBE2C,	0xDC00},{0xBE69,	0xD20F},{0xBE3B,	0xB414}, +		{0xBE24,	0x0000},{0xBE23,	0x00A1},{0xBE22,	0x0008},{0xBE21,	0x0120}, +		{0xBE20,	0x1000},{0xBE24,	0x0800},{0xBE24,	0x0000},{0xBE24,	0xF000}, +		{0xBE23,	0xDF01},{0xBE22,	0xDF20},{0xBE21,	0x101A},{0xBE20,	0xA0FF}, +		{0xBE24,	0xF800},{0xBE24,	0xF000},{0x0242,	0x02BF},{0x0245,	0x02BF}, +		{0x0248,	0x02BF},{0x024B,	0x02BF},{0x024E,	0x02BF},{0x0251,	0x02BF}, +		{0x0230,	0x0A32},{0x0233,	0x0A32},{0x0236,	0x0A32},{0x0239,	0x0A32}, +		{0x023C,	0x0A32},{0x023F,	0x0A32},{0x0254,	0x0A3F},{0x0255,	0x0064}, +		{0x0256,	0x0A3F},{0x0257,	0x0064},{0x0258,	0x0A3F},{0x0259,	0x0064}, +		{0x025A,	0x0A3F},{0x025B,	0x0064},{0x025C,	0x0A3F},{0x025D,	0x0064}, +		{0x025E,	0x0A3F},{0x025F,	0x0064},{0x0260,	0x0178},{0x0261,	0x01F4}, +		{0x0262,	0x0320},{0x0263,	0x0014},{0x021D,	0x9249},{0x021E,	0x0000}, +		{0x0100,	0x0004},{0xBE4A,	0xA0B4},{0xBE40,	0x9C00},{0xBE41,	0x501D}, +		{0xBE48,	0x3602},{0xBE47,	0x8051},{0xBE4C,	0x6465},{0x8000,	0x1F00}, +		{0x8001,	0x000C},{0x8008,	0x0000},{0x8007,	0x0000},{0x800C,	0x00A5}, +		{0x8101,	0x02BC},{0xBE53,	0x0005},{0x8E45,	0xAFE8},{0x8013,	0x0005}, +		{0xBE4B,	0x6700},{0x800B,	0x7000},{0xBE09,	0x0E00}, +		{0xFFFF, 0xABCD} +	}; + +    const uint16_t chipDefault[][2] = +    { +        {0x0242, 0x02BF},{0x0245, 0x02BF},{0x0248, 0x02BF},{0x024B, 0x02BF}, +		{0x024E, 0x02BF},{0x0251, 0x02BF}, +		{0x0254, 0x0A3F},{0x0256, 0x0A3F},{0x0258, 0x0A3F},{0x025A, 0x0A3F}, +		{0x025C, 0x0A3F},{0x025E, 0x0A3F}, +		{0x0263, 0x007C},{0x0100, 0x0004}, +		{0xBE5B, 0x3500},{0x800E, 0x200F},{0xBE1D, 0x0F00},{0x8001, 0x5011}, +		{0x800A, 0xA2F4},{0x800B, 0x17A3},{0xBE4B, 0x17A3},{0xBE41, 0x5011}, +		{0xBE17, 0x2100},{0x8000, 0x8304},{0xBE40, 0x8304},{0xBE4A, 0xA2F4}, +		{0x800C, 0xA8D5},{0x8014, 0x5500},{0x8015, 0x0004},{0xBE4C, 0xA8D5}, +		{0xBE59, 0x0008},{0xBE09, 0x0E00},{0xBE36, 0x1036},{0xBE37, 0x1036}, +		{0x800D, 0x00FF},{0xBE4D, 0x00FF}, +		{0xFFFF, 0xABCD} +    }; + +	DBG("rtl8366s_initChip\n"); + +    /* save current led config and set to led force */ +    for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { +        if (rtl8366s_getLedConfig(ledGroup, &ledData[ledGroup])) +            return -1; + +        if (rtl8366s_setLedConfig(ledGroup, RTL8366S_LEDCONF_LEDFORCE)) +            return -1; +    } + +    if (rtl8366s_setLedForceValue(0,0,0,0)) +        return -1; + +    if (rtl8366_readRegister(RTL8366S_MODEL_ID_REG, ®Data)) +        return -1; + +	switch (regData) +	{ +		case 0x0000: +			chipData = chipB; +			break; + +		case RTL8366S_MODEL_8366SR: +			chipData = chipDefault; +			break; + +		default: +			printf("rtl8366s_initChip: unsupported chip found!\n"); +			return -1; +	} + +    DBG("rtl8366s_initChip: found %x chip\n", regData); + +    while ((chipData[i][0] != 0xFFFF) && (chipData[i][1] != 0xABCD)) { + +        /* phy settings*/ +        if ((chipData[i][0] & 0xBE00) == 0xBE00) { +            if (rtl8366_writeRegister(RTL8366S_PHY_ACCESS_CTRL_REG, +                                      RTL8366S_PHY_CTRL_WRITE)) +                return -1; +        } + +        if (rtl8366_writeRegister(chipData[i][0], chipData[i][1])) +            return -1; + +        i++; +    } + +    /* chip needs some time */ +    udelay(100 * 1000); + +    /* restore led config */ +    for (ledGroup = 0; ledGroup < RTL8366S_LED_GROUP_MAX; ledGroup++) { +        if (rtl8366s_setLedConfig(ledGroup, ledData[ledGroup])) +            return -1; +    } + +    return 0; +} + +int rtl8366s_initialize(void) +{ +	uint16_t regData; + +    DBG("rtl8366s_initialize: start setup\n"); + +    smi_init(); + +	rtl8366_readRegister(RTL8366S_CHIP_ID_REG, ®Data); +	DBG("Realtek 8366SR switch ID %#04x\n", regData); + +	if (regData != 0x8366) { +		printf("rtl8366s_initialize: found unsupported switch\n"); +		return -1; +	} + +    if (rtl8366s_initChip()) { +        printf("rtl8366s_initialize: init chip failed\n"); +        return -1; +    } + +	if (rtl8366s_setGreenEthernet(1, 1)) { +       printf("rtl8366s_initialize: set green ethernet failed\n"); +       return -1; +   } + +   	/* Set port 5 noTag and don't dropUnda */ +	if (rtl8366s_setCPUPort(5, 1, 0)) { +		printf("rtl8366s_initialize: set CPU port failed\n"); +		return -1; +	} + +    return 0; +} diff --git a/package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c b/package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c new file mode 100644 index 000000000..bbe27b16e --- /dev/null +++ b/package/boot/uboot-ar71xx/files/drivers/spi/ar71xx_spi.c @@ -0,0 +1,191 @@ +/* + * (C) Copyright 2010 + * Michael Kurz <michi.kurz@googlemail.com> + * + * 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 <common.h> +#include <malloc.h> +#include <spi.h> + +#include <asm/addrspace.h> +#include <asm/types.h> +#include <asm/ar71xx.h> + +/*----------------------------------------------------------------------- + * Definitions + */ + +#ifdef DEBUG_SPI +#define PRINTD(fmt,args...)	printf (fmt ,##args) +#else +#define PRINTD(fmt,args...) +#endif + +struct ar71xx_spi_slave { +	struct spi_slave slave; +	unsigned int mode; +}; + +static inline struct ar71xx_spi_slave *to_ar71xx_spi(struct spi_slave *slave) +{ +	return container_of(slave, struct ar71xx_spi_slave, slave); +} + +/*=====================================================================*/ +/*                         Public Functions                            */ +/*=====================================================================*/ + +/*----------------------------------------------------------------------- + * Initialization + */ +  +void spi_init() +{ +	PRINTD("ar71xx_spi: spi_init"); + +	// Init SPI Hardware, disable remap, set clock +	__raw_writel(0x43, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_CTRL)); +	 +	PRINTD(" ---> out\n"); +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +		unsigned int max_hz, unsigned int mode) +{ +	struct ar71xx_spi_slave *ss; + +	PRINTD("ar71xx_spi: spi_setup_slave"); +	 +	if ((bus != 0) || (cs > 2)) +		return NULL; + +	ss = malloc(sizeof(struct ar71xx_spi_slave)); +	if (!ss) +		return NULL; + +	ss->slave.bus = bus; +	ss->slave.cs = cs; +	ss->mode = mode; + +	/* TODO: Use max_hz to limit the SCK rate */ + +	PRINTD(" ---> out\n"); +	 +	return &ss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	struct ar71xx_spi_slave *ss = to_ar71xx_spi(slave); + +	free(ss); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + +	return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, +		void *din, unsigned long flags) +{ +	struct ar71xx_spi_slave *ss = to_ar71xx_spi(slave); +	uint8_t *rx = din; +	const uint8_t *tx = dout; +	uint8_t curbyte, curbitlen, restbits; +	uint32_t bytes = bitlen / 8; +	uint32_t out; +	uint32_t in; +	 +	PRINTD("ar71xx_spi: spi_xfer: slave:%p bitlen:%08x dout:%p din:%p flags:%08x\n", slave, bitlen, dout, din, flags); +	 +	if (flags & SPI_XFER_BEGIN) { +		__raw_writel(SPI_FS_GPIO, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_FS)); +		__raw_writel(SPI_IOC_CS_ALL, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC)); +	} +	 +	restbits = (bitlen % 8); +	if (restbits != 0) +		bytes++; + +	// enable chip select +	out = SPI_IOC_CS_ALL & ~(SPI_IOC_CS(slave->cs)); + +	while (bytes--) { +		 +		curbyte = 0; +		if (tx) { +			curbyte = *tx++; +		} +		 +		if (restbits != 0) { +			curbitlen = restbits; +			curbyte <<= 8 - restbits; +		} else { +			curbitlen = 8; +		} +		 +		PRINTD("ar71xx_spi: sending: data:%02x length:%d\n", curbyte, curbitlen); +		 +		/* clock starts at inactive polarity */ +		for (curbyte <<= (8 - curbitlen); curbitlen; curbitlen--) { + +			if (curbyte & (1 << 7)) +				out |= SPI_IOC_DO; +			else +				out &= ~(SPI_IOC_DO); + +			/* setup MSB (to slave) on trailing edge */ +			__raw_writel(out, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC)); + +			__raw_writel(out | SPI_IOC_CLK, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC)); + +			curbyte <<= 1; +		} +		 +		in = __raw_readl(KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_RDS)); +		PRINTD("ar71xx_spi: received:%02x\n", in); +		 +		if (rx) { +			if (restbits == 0) { +				*rx++ = in; +			} else { +				*rx++ = (in << (8 - restbits)); +			} +		} +	} +	 +	if (flags & SPI_XFER_END) { +		__raw_writel(SPI_IOC_CS(slave->cs), KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC)); +		__raw_writel(SPI_IOC_CS_ALL, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_IOC)); +		__raw_writel(0, KSEG1ADDR(AR71XX_SPI_BASE + SPI_REG_FS)); +	} + +	PRINTD(" ---> out\n"); +	 +	return 0; +} | 
