📄 ag7100.c
字号:
#include <config.h>#include <common.h>#include <malloc.h>#include <net.h>#include <command.h>#include <asm/io.h>#include <asm/addrspace.h>#include <asm/types.h>#include "ar7100_soc.h"#include "ag7100.h"#include "ag7100_phy.h"#if (CONFIG_COMMANDS & CFG_CMD_MII)#include <miiphy.h>#endifint ag7100_miiphy_read(char *devname, unsigned char phaddr, unsigned char reg, unsigned short *value);int ag7100_miiphy_write(char *devname, unsigned char phaddr, unsigned char reg, unsigned short data);ag7100_mac_t mac;static intag7100_send(struct eth_device *dev, volatile void *packet, int length){ int i; ag7100_desc_t *f = mac.fifo_tx[mac.next_tx];#if defined(CFG_ATHRS26_PHY) && defined(CFG_ATHRHDR_EN) uint8_t *pkt_buf; pkt_buf = (uint8_t *) packet; if ((pkt_buf[1] & 0xf) != 0x5) { length = length + ATHRHDR_LEN; pkt_buf = (uint8_t *) packet - ATHRHDR_LEN; pkt_buf[0] = 0x10; /* broadcast = 0; from_cpu = 0; reserved = 1; port_num = 0 */ pkt_buf[1] = 0x80; /* reserved = 0b10; priority = 0; type = 0 (normal) */ } f->pkt_size = length; f->pkt_start_addr = virt_to_phys(pkt_buf);#else f->pkt_size = length; f->pkt_start_addr = virt_to_phys(packet);#endif ag7100_tx_give_to_dma(f); flush_cache((u32) packet, length); ag7100_reg_wr(AG7100_DMA_TX_DESC, virt_to_phys(f)); ag7100_reg_wr(AG7100_DMA_TX_CTRL, AG7100_TXE); for (i = 0; i < MAX_WAIT; i++) { udelay(10); if (!ag7100_tx_owned_by_dma(f)) break; } if (i == MAX_WAIT) printf("Tx Timed out\n"); f->pkt_start_addr = 0; f->pkt_size = 0; if (++mac.next_tx >= NO_OF_TX_FIFOS) mac.next_tx = 0; return (0);}static int ag7100_recv(struct eth_device *dev){ int length; ag7100_desc_t *f; for (;;) { f = mac.fifo_rx[mac.next_rx]; if (ag7100_rx_owned_by_dma(f)) break; length = f->pkt_size; NetReceive(NetRxPackets[mac.next_rx] , length - 4); flush_cache((u32) NetRxPackets[mac.next_rx] , PKTSIZE_ALIGN); ag7100_rx_give_to_dma(f); if (++mac.next_rx >= NO_OF_RX_FIFOS) mac.next_rx = 0; } if (!(ag7100_reg_rd(AG7100_DMA_RX_CTRL))) { ag7100_reg_wr(AG7100_DMA_RX_DESC, virt_to_phys(f)); ag7100_reg_wr(AG7100_DMA_RX_CTRL, 1); } return (0);}static void ag7100_hw_start(){ u32 mii_ctrl_val, isXGMII = CFG_GMII;#ifdef CFG_MII0_RGMII mii_ctrl_val = 0x12;#else#ifdef CFG_MII0_MII mii_ctrl_val = 0x11;#else#ifdef CFG_MII0_RMII mii_ctrl_val = 0x13;#endif#endif#endif ag7100_reg_wr(AG7100_MAC_CFG1, (AG7100_MAC_CFG1_RX_EN | AG7100_MAC_CFG1_TX_EN)); ag7100_reg_rmw_set(AG7100_MAC_CFG2, (AG7100_MAC_CFG2_PAD_CRC_EN | AG7100_MAC_CFG2_LEN_CHECK));#if 1 ag7100_set_mac_if(isXGMII);#endif //ag7100_reg_wr(AG7100_MAC_CFG2, 0x7135); ag7100_reg_wr(AG7100_MAC_FIFO_CFG_0, 0x1f00);#if 0 ag7100_reg_wr(AR7100_MII0_CTRL, ag7100_get_mii_if());#else ar7100_reg_wr(AR7100_MII0_CTRL, mii_ctrl_val);#endif //ag7100_reg_wr(AG7100_MAC_IFCTL, 0x10000); //ag7100_reg_wr(AG7100_MAC_CFG1, 0x005); ag7100_reg_wr(AG7100_MAC_MII_MGMT_CFG, AG7100_MGMT_CFG_CLK_DIV_20); ag7100_reg_rmw_set(AG7100_MAC_FIFO_CFG_4, 0x3ffff); ag7100_reg_rmw_clear(AG7100_MAC_FIFO_CFG_5, (1 << 19));#ifdef AR9100 ag7100_reg_wr(AG7100_MAC_FIFO_CFG_3, 0x780008);#else ag7100_reg_wr(AG7100_MAC_FIFO_CFG_3, 0x400fff);#endif ag7100_reg_wr(AG7100_MAC_FIFO_CFG_1, 0xfff0000); ag7100_reg_wr(AG7100_MAC_FIFO_CFG_2, 0x1fff);}static void ag7100_set_mac_from_link(int speed, int fdx){ int is1000 = (speed == _1000BASET); int is100 = (speed == _100BASET); mac.speed = speed; mac.duplex = fdx; ag7100_set_mii_ctrl_speed(speed); ag7100_set_mac_if(is1000); ag7100_set_mac_duplex(fdx); if (!is1000) ag7100_set_mac_speed(is100); /* * XXX program PLL */ mac.link = 1;}static int ag7100_check_link(){ u32 link, duplex, speed, fdx, i;/* #if !defined(CFG_ATHRS26_PHY) && !defined(CFG_ATHRHDR_EN) */#if 0 if (!(link = miiphy_link("eth0", CFG_PHY_ADDR))) { mac.link = 0; printf("link down\n"); return 0; } duplex = miiphy_duplex("eth0", CFG_PHY_ADDR); speed = miiphy_speed("eth0", CFG_PHY_ADDR);#else duplex = FULL; speed = _100BASET; printf("set link to 100M full by lqm.\n");#endif if (speed == _1000BASET) { i = *(volatile int *) 0xb8050004; i = i | (0x6 << 19); *(volatile int *) 0xb8050004 = i; udelay(100); *(volatile int *) 0xb8050014 = 0x1a000000; i = *(volatile int *) 0xb8050004; i = i & (~(0x3b << 19)); *(volatile int *) 0xb8050004 = i; udelay(100); i = *(volatile int *) 0xb8050004; i = i | (0x3 << 20); *(volatile int *) 0xb8050004 = i; udelay(100); i = *(volatile int *) 0xb8050004; i = i & (~(0x3 << 20)); *(volatile int *) 0xb8050004 = i; udelay(100); ar7100_reg_wr(AR7100_MII0_CTRL, 0x22); ag7100_reg_rmw_clear(AG7100_MAC_CFG2, 0xffff); ag7100_reg_rmw_set(AG7100_MAC_CFG2, 0x7215); ag7100_reg_wr(AG7100_MAC_FIFO_CFG_3, 0x780fff); miiphy_write("eth0", CFG_PHY_ADDR, 0x1f, 0x1); miiphy_write("eth0", CFG_PHY_ADDR, 0x1c, 0x3000); miiphy_write("eth0", CFG_PHY_ADDR, 0x1f, 0x0); } else if (speed == _100BASET) { i = *(volatile int *) 0xb8050004; i = i | (0x3 << 20); *(volatile int *) 0xb8050004 = i; udelay(100); *(volatile int *) 0xb8050014 = 0x13000a44; *(volatile int *) 0xb805001c = 0x00000909; udelay(100); i = *(volatile int *) 0xb8050004; i = i & (~(0x1 << 20)); *(volatile int *) 0xb8050004 = i; udelay(100); i = *(volatile int *) 0xb8050004; i = i | (0x3 << 20); *(volatile int *) 0xb8050004 = i; udelay(100); i = *(volatile int *) 0xb8050004; i = i & (~(0x3 << 20)); *(volatile int *) 0xb8050004 = i; udelay(100); ag7100_reg_rmw_clear(AG7100_MAC_CFG2, 0xffff); ag7100_reg_rmw_set(AG7100_MAC_CFG2, 0x7115); } if (mac.link && (duplex == mac.duplex) && (speed == mac.speed)) return 1; mac.duplex = duplex; mac.speed = speed; mac.link = 1; fdx = (duplex == FULL) ? 1 : 0; printf("dup %d speed %d\n", fdx, speed); ag7100_set_mac_duplex(fdx); if (speed == _100BASET) ag7100_set_mac_speed(1); else if (speed == _10BASET) ag7100_set_mac_speed(0); return 1;}/* * For every command we re-setup the ring and start with clean h/w rx state */static int ag7100_clean_rx(struct eth_device *dev, bd_t * bd){ int i; ag7100_desc_t *fr; if (!ag7100_check_link()) return 0; mac.next_rx = 0; for (i = 0; i < NO_OF_RX_FIFOS; i++) { fr = mac.fifo_rx[i]; fr->pkt_start_addr = virt_to_phys(NetRxPackets[i]); flush_cache((u32) NetRxPackets[i], PKTSIZE_ALIGN); ag7100_rx_give_to_dma(fr); } ag7100_reg_wr(AG7100_DMA_RX_DESC, virt_to_phys(mac.fifo_rx[0])); ag7100_reg_wr(AG7100_DMA_RX_CTRL, AG7100_RXE); /* rx start */ udelay(1000 * 1000); return 1;}static int ag7100_alloc_fifo(int ndesc, ag7100_desc_t ** fifo){ int i; u32 size; uchar *p = NULL; size = sizeof(ag7100_desc_t) * ndesc; size += CFG_CACHELINE_SIZE - 1; if ((p = malloc(size)) == NULL) { printf("Cant allocate fifos\n"); return -1; } p = (uchar *) (((u32) p + CFG_CACHELINE_SIZE - 1) & ~(CFG_CACHELINE_SIZE - 1)); p = UNCACHED_SDRAM(p); for (i = 0; i < ndesc; i++) fifo[i] = (ag7100_desc_t *) p + i; return 0;}static int ag7100_setup_fifos(){ int i; if (ag7100_alloc_fifo(NO_OF_TX_FIFOS, mac.fifo_tx)) return 1; for (i = 0; i < NO_OF_TX_FIFOS; i++) { mac.fifo_tx[i]->next_desc = (i == NO_OF_TX_FIFOS - 1) ? virt_to_phys(mac.fifo_tx[0]) : virt_to_phys(mac.fifo_tx[i + 1]); ag7100_tx_own(mac.fifo_tx[i]); } if (ag7100_alloc_fifo(NO_OF_RX_FIFOS, mac.fifo_rx)) return 1; for (i = 0; i < NO_OF_RX_FIFOS; i++) { mac.fifo_rx[i]->next_desc = (i == NO_OF_RX_FIFOS - 1) ? virt_to_phys(mac.fifo_rx[0]) : virt_to_phys(mac.fifo_rx[i + 1]); } return (1);}static void ag7100_halt(struct eth_device *dev){ ag7100_reg_wr(AG7100_DMA_RX_CTRL, 0); while (ag7100_reg_rd(AG7100_DMA_RX_CTRL));}unsigned char *ag7100_mac_addr_loc(void){ extern flash_info_t flash_info[]; /* MAC address is store in the 2nd 4k of last sector */ return ((unsigned char *) (KSEG1ADDR(AR7100_SPI_BASE) + (4 * 1024) + flash_info[0].size - (64 * 1024) /* sector_size */ ));}static void ag7100_get_ethaddr(struct eth_device *dev){#if 0 int x, temp; char *s, *e, buf[64]; temp = getenv_r("ethaddr", buf, sizeof(buf)); s = (temp > 0) ? buf : NULL; for (x = 0; x < 6; ++x) { dev->enetaddr[x] = s ? simple_strtoul(s, &e, 16) : 0; if (s) s = (*e) ? e + 1 : e; }#else unsigned char *eeprom; unsigned char *mac = dev->enetaddr; eeprom = ag7100_mac_addr_loc(); if (strcmp(dev->name, "eth0") == 0) { memcpy(mac, eeprom, 6); } else if (strcmp(dev->name, "eth1") == 0) { eeprom += 6; memcpy(mac, eeprom, 6); } else { printf("%s: unknown ethernet device %s\n", __func__, dev->name); return; } /* Use fixed address if the above address is invalid */ if (mac[0] == 0xff && mac[5] == 0xff) { mac[0] = 0x00; mac[1] = 0x03; mac[2] = 0x7f; mac[3] = 0x09; mac[4] = 0x0b; mac[5] = 0xad; printf("No valid address in Flash. Using fixed address\n"); } else { printf("Fetching MAC Address from 0x%p\n", __func__, eeprom); }#endif}#ifdef CONFIG_AR9100_MDIO_DEBUGintag7100_dump_vsc_regs(){ unsigned i; unsigned short v; char *fmt[] = {"\t", "\n"}; printf("IEEE & Standard registers\n"); for (i = 0; i < 0x20; i++) { v = 0; ag7100_miiphy_read("eth0", 0, i, &v); printf("0x%02x: 0x%04x%s", i, v, fmt[i & 1]); } printf("Extended registers\n"); /* Enable extended register set access */ ag7100_miiphy_write("eth0", 0, 0x1f, 0x1); for (i = 16; i <= 30; i++) { v = 0; ag7100_miiphy_read("eth0", 0, i, &v); printf("0x%02x: 0x%04x%s", i, v, fmt[i & 1]); } ag7100_miiphy_write("eth0", 0, 0x1f, 0x0); printf("\n");}#endifint ag7100_enet_initialize(bd_t * bis){ struct eth_device *dev; u32 mask, mac_h, mac_l; int i; u32 pll_value; printf("ag7100_enet_initialize...\n"); /* Workaround to bring the TX_EN to low */ i = *(volatile int *) 0xb806001c ; *(volatile int *) 0xb806001c = (i | 0x3300); udelay(10 * 1000); i = *(volatile int *) 0xb806001c ; *(volatile int *) 0xb806001c = (i & 0xffffccff); udelay(10 * 1000); *(volatile int *) 0xb8070000 = 0x13; *(volatile int *) 0xb8070004 = 0x11; udelay(10 * 1000); *(volatile int *) 0xb9000000 = 0x0; *(volatile int *) 0xba000000 = 0x0; i = *(volatile int *) 0xb806001c ; *(volatile int *) 0xb806001c = (i | 0x3300); udelay(10 * 1000); if ((dev = (struct eth_device *) malloc(sizeof *dev)) == NULL) { puts("malloc failed\n"); return 0; } memset(&mac, 0, sizeof(mac)); memset(dev, 0, sizeof *dev); sprintf(dev->name, "eth0"); ag7100_get_ethaddr(dev); dev->iobase = 0; dev->priv = 0; dev->init = ag7100_clean_rx; dev->halt = ag7100_halt; dev->send = ag7100_send; dev->recv = ag7100_recv; eth_register(dev);#if defined(CFG_ATHRS26_PHY) && defined(CFG_ATHRHDR_EN) athrs26_reg_dev(dev);#endif#if (CONFIG_COMMANDS & CFG_CMD_MII) miiphy_register(dev->name, ag7100_miiphy_read, ag7100_miiphy_write);#endif mask = (AR7100_RESET_GE0_MAC | AR7100_RESET_GE0_PHY | AR7100_RESET_GE1_MAC | AR7100_RESET_GE1_PHY); ar7100_reg_rmw_set(AR7100_RESET, mask); udelay(1000 * 100); ar7100_reg_rmw_clear(AR7100_RESET, mask); udelay(1000 * 100); udelay(10 * 1000); ag7100_hw_start(); ag7100_setup_fifos();#if defined(CFG_ATHRS26_PHY) && defined(CFG_SWITCH_FREQ) pll_value = ar7100_reg_rd(AR7100_CPU_PLL_CONFIG); mask = pll_value & ~(PLL_CONFIG_PLL_FB_MASK | PLL_CONFIG_REF_DIV_MASK); mask = mask | (0x64 << PLL_CONFIG_PLL_FB_SHIFT) | (0x5 << PLL_CONFIG_REF_DIV_SHIFT) | (1 << PLL_CONFIG_AHB_DIV_SHIFT); ar7100_reg_wr_nf(AR7100_CPU_PLL_CONFIG, mask); udelay(100 * 1000);#endif ag7100_phy_setup(0); udelay(100 * 1000);#if defined(CFG_ATHRS26_PHY) && defined(CFG_SWITCH_FREQ) ar7100_reg_wr_nf(AR7100_CPU_PLL_CONFIG, pll_value); udelay(100 * 1000);#endif { unsigned char *mac = dev->enetaddr; printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); } mac_l = (dev->enetaddr[4] << 8) | (dev->enetaddr[5]); mac_h = (dev->enetaddr[0] << 24) | (dev->enetaddr[1] << 16) | (dev->enetaddr[2] << 8) | (dev->enetaddr[3] << 0); ag7100_reg_wr(AG7100_GE_MAC_ADDR1, mac_l); ag7100_reg_wr(AG7100_GE_MAC_ADDR2, mac_h);#if defined(CFG_ATHRS26_PHY) && defined(CFG_ATHRHDR_EN) /* if using header for register configuration, we have to */ /* configure s26 register after frame transmission is enabled */ athrs26_reg_init();#endif printf("eth0 up\n");#ifdef CONFIG_AR9100_MDIO_DEBUG ag7100_dump_vsc_regs();#endif return 1;}#if (CONFIG_COMMANDS & CFG_CMD_MII)int ag7100_miiphy_read(char *devname, unsigned char phaddr, unsigned char reg, unsigned short *value){ uint16_t addr = (phaddr << AG7100_ADDR_SHIFT) | reg; volatile int rddata; ag7100_reg_wr(AG7100_MII_MGMT_CMD, 0x0); ag7100_reg_wr(AG7100_MII_MGMT_ADDRESS, addr); ag7100_reg_wr(AG7100_MII_MGMT_CMD, AG7100_MGMT_CMD_READ); rddata = ag7100_reg_rd(AG7100_MII_MGMT_IND) & 0x1; while (rddata) { rddata = ag7100_reg_rd(AG7100_MII_MGMT_IND) & 0x1; } *value = ag7100_reg_rd(AG7100_MII_MGMT_STATUS); ag7100_reg_wr(AG7100_MII_MGMT_CMD, 0x0); return 0;}int ag7100_miiphy_write(char *devname, unsigned char phaddr, unsigned char reg, unsigned short data){ uint16_t addr = (phaddr << AG7100_ADDR_SHIFT) | reg; volatile int rddata; ag7100_reg_wr(AG7100_MII_MGMT_ADDRESS, addr); ag7100_reg_wr(AG7100_MII_MGMT_CTRL, data); rddata = ag7100_reg_rd(AG7100_MII_MGMT_IND) & 0x1; while (rddata) { rddata = ag7100_reg_rd(AG7100_MII_MGMT_IND) & 0x1; } return 0;}#endif /* CONFIG_COMMANDS & CFG_CMD_MII */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -