#include #include "steth.h" #define AN_RETRY 6 static int running; static int an_clock; static int an_happy; static int ready; static uint8_t __attribute__ ((aligned (4))) eth_buf[ETH_BUF_LEN]; static uint8_t sa[ETHARP_HWADDR_LEN] = { 0xc0, 0xf1, 0xee, 0xc0, 0xff, 0xdd }; extern uint32_t TxBD; extern uint32_t RxBD; #define FOO(a) \ do { static uint32_t w; \ uint32_t v=a; \ if (v!=w) {\ printf (" " #a": %08x (%08x +%08x -%08x)\r\n", \ (unsigned) v,(unsigned) (v^w),(unsigned) ((v^w) &v),(unsigned) ((v^w)&w)); \ }\ w=v; \ } while (0) static void mac_stat (void) { //uint32_t d, s; printf ("Net:\r\n"); FOO (ETH_MACCR); FOO (ETH_MACFFR); FOO (ETH_MACFCR); FOO (ETH_MACDBGR); FOO (ETH_MACSR); FOO (ETH_DMAOMR); FOO (ETH_DMASR); FOO (ETH_DMAIER); FOO (ETH_DMACHTDR); FOO (ETH_DMACHRDR); FOO (ETH_DMAOMR); FOO (ETH_DMATDLAR); FOO (ETH_DMARDLAR); FOO (ETH_DMABMR); #if 0 s = d = RxBD; if (running) do { printf (" %08" PRIx32 ": %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\r\n", d, ETH_DES0 (d), ETH_DES1 (d), ETH_DES2 (d), ETH_DES3 (d)); d = ETH_DES3 (d); } while (d != s); #endif } #define PHY_REGS 0x20 static void phy_stat_reg (unsigned i) { static uint16_t last_phy[PHY_REGS]; uint16_t cur = eth_smi_read (PHY, i); if (cur == last_phy[i]) return; printf (" phy:%02x %4x (was %4x +%4x -%4x)\r\n", i, (unsigned) cur, (unsigned) last_phy[i], (unsigned) ((last_phy[i] ^ cur) & cur), (unsigned) ((last_phy[i] ^ cur) & last_phy[i])); last_phy[i] = cur; } static void phy_stat (void) { unsigned i; for (i = 0; i < PHY_REGS; ++i) phy_stat_reg (i); } static bool phy_link_an_done (uint8_t phy) { return eth_smi_read (phy, PHY_REG_BSR) & PHY_REG_BSR_ANDONE; } static err_t steth_tx (struct netif *netif, struct pbuf *p) { if (p->next) return ERR_IF; while (!eth_tx (p->payload, p->len)); return ERR_OK; } static err_t steth_rx (void) { struct pbuf *p; uint32_t len; p = pbuf_alloc (PBUF_RAW, MTU, PBUF_POOL); if (!p) return ERR_MEM; len = 0; if (!eth_rx (p->payload, &len, MTU)) { pbuf_free (p); return ERR_IF; } pbuf_realloc (p, len); return if0.input (p, &if0); } static void steth_nis (void) { if (eth_irq_ack_pending (ETH_DMASR_RS)) steth_rx(); } void eth_isr (void) { if (eth_irq_ack_pending (ETH_DMASR_NIS)) steth_nis(); } void steth_isr (void) { if (eth_irq_ack_pending (ETH_DMASR_NIS)) steth_nis(); } err_t steth_lwip_init (struct netif *netif) { LWIP_ASSERT ("netif != NULL", (netif != NULL)); #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif->hostname = "lwip"; #endif /* LWIP_NETIF_HOSTNAME */ netif->name[0] = 's'; netif->name[1] = 't'; /* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; netif->linkoutput = steth_tx; /* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* set MAC hardware address */ memcpy (netif->hwaddr, sa, ETHARP_HWADDR_LEN); /* maximum transfer unit */ netif->mtu = 1500; /* device capabilities */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; return ERR_OK; } static void my_eth_init (uint8_t phy, enum eth_clk clock) { ETH_MACMIIAR = clock; ETH_MACCR = ETH_MACCR_CSTF | ETH_MACCR_FES | ETH_MACCR_DM | ETH_MACCR_APCS | ETH_MACCR_RD; ETH_MACFFR = ETH_MACFFR_RA | ETH_MACFFR_PM; ETH_MACHTHR = 0; /* pass all frames */ ETH_MACHTLR = 0; ETH_MACFCR = (0x100 << ETH_MACFCR_PT_SHIFT); ETH_MACVLANTR = 0; ETH_DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_DFRF | ETH_DMAOMR_TSF | ETH_DMAOMR_FEF | ETH_DMAOMR_OSF; ETH_DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_FB | (32 << ETH_DMABMR_RDP_SHIFT) | (32 << ETH_DMABMR_PBL_SHIFT) | ETH_DMABMR_PM_2_1 | ETH_DMABMR_USP; } static void phy_set_ignore_address (void) { unsigned i; i = 0; while (eth_smi_read (PHY0, 0) == 0xffff) { delay_us (1000); i++; if (i > 10) break; } eth_smi_write (PHY, 0x11, 0x8); i = 0; while (eth_smi_read (PHY1, 0) == 0xffff) { delay_us (1000); i++; if (i > 10) break; } eth_smi_write (PHY1, 0x11, 0x8); } static void eth_reset (void) { unsigned i; printf ("Eth_reset()\r\n"); rcc_periph_reset_hold (RST_ETHMAC); delay_us (1000); #ifndef SYSCFG_PMC_MII_RMII_SEL #define SYSCFG_PMC_MII_RMII_SEL (1UL << 23) #endif SYSCFG_PMC |= SYSCFG_PMC_MII_RMII_SEL; delay_us (1000); rcc_periph_reset_release (RST_ETHMAC); #ifdef NRST #if 0 delay_us (1000); CLEAR (NRST); delay_us (1); SET (NRST); delay_us (1000); #endif #endif TRACE; ETH_DMABMR |= ETH_DMABMR_SR; i = 0; while (ETH_DMABMR & ETH_DMABMR_SR) { delay_us (1000); i++; if (i > 1000) { printf ("No 50MHz clock to ethernet MAC\n"); return; } } /*MDC = HCLK / 102 (0b100) => 1.6MHz */ TRACE; my_eth_init (PHY, ETH_CLK_150_168MHZ); //phy_set_ignore_address(); TRACE; phy_stat(); eth_set_mac (sa); eth_enable_checksum_offload(); eth_desc_init (eth_buf, TX_BUFS, RX_BUFS, FRAME_SZ, FRAME_SZ, 1); eth_irq_enable (ETH_DMAIER_NISE); eth_irq_enable (ETH_DMAIER_RIE); eth_irq_enable (ETH_DMASR_TS); } static void eth_start_an (void) { printf ("starting autonegociation\r\n"); eth_smi_write (PHY, PHY_REG_ANTX, 0x1e1); phy_autoneg_enable (PHY); } void steth_init (void) { rcc_periph_reset_hold (RST_ETHMAC); delay_ms (1); #ifndef SYSCFG_PMC_MII_RMII_SEL #define SYSCFG_PMC_MII_RMII_SEL (1UL << 23) #endif SYSCFG_PMC |= SYSCFG_PMC_MII_RMII_SEL; delay_ms (1); rcc_periph_reset_release (RST_ETHMAC); #ifdef NRST MAP_OUTPUT_PP (NRST); #endif MAP_OUTPUT_PP (RXD0); MAP_OUTPUT_PP (RXD1); MAP_OUTPUT_PP (CRS_DV); MAP_AF_100 (REF_CLK, GPIO_AF11); SET (RXD0); SET (RXD1); SET (CRS_DV); #ifdef NRST delay_ms (1); CLEAR (NRST); delay_ms (1); SET (NRST); delay_ms (1); #endif MAP_AF_100 (MDIO, GPIO_AF11); MAP_AF_100 (CRS_DV, GPIO_AF11); #ifdef RXER MAP_AF_100 (RXER, GPIO_AF11); #endif MAP_AF_100 (TXEN, GPIO_AF11); MAP_AF_100 (TXD0, GPIO_AF11); MAP_AF_100 (TXD1, GPIO_AF11); MAP_AF_100 (MDC, GPIO_AF11); MAP_AF_100 (RXD0, GPIO_AF11); MAP_AF_100 (RXD1, GPIO_AF11); /* The switch to RMII has be done with steth under reset, with no clock */ eth_reset(); phy_stat(); mac_stat(); #if 0 eth_smi_write (PHY, PHY_REG_BCR, 0x2100); printf ("Waiting for link\r\n"); while (!phy_link_isup (phy)) { phy_stat(); delay_ms (1000); } #endif eth_start_an(); nvic_enable_irq (NVIC_ETH_IRQ); ready++; } #if 0 static void eth_stop (void) { ETH_MACCR &= (ETH_MACCR_TE & ETH_MACCR_RE); ETH_DMAOMR &= ~ (ETH_DMAOMR_FTF | ETH_DMAOMR_ST | ETH_DMAOMR_SR); } #endif void steth_slow_tick (void) { phy_stat(); #if 0 mac_stat(); #endif if (!ready) return; an_happy = phy_link_an_done (PHY); if ((!phy_link_isup (PHY) || !an_happy) && running) { printf ("stopping nic\r\n"); eth_reset(); running = 0; } if (!phy_link_isup (PHY) && an_happy) { eth_start_an(); an_clock = 0; } if (!an_happy) { an_clock++; if (an_clock > AN_RETRY) { eth_start_an(); an_clock = 0; } } else an_clock = 0; if (phy_link_isup (PHY) && an_happy && !running) { printf ("autonegociation done\r\n"); printf ("phy link status %x\r\n", phy_link_status (PHY)); switch (phy_link_status (PHY)) { case LINK_HD_10M: TRACE; case LINK_HD_100M: TRACE; ETH_MACCR &= ~ETH_MACCR_DM; ETH_MACCR |= ETH_MACCR_ROD; break; default: ; } ETH_MACCR &= ~ETH_MACCR_RD; eth_start(); printf ("starting nic\r\n"); running++; } }