Fork of Smoothie to port to mbed non-LPC targets.
Fork of Smoothie by
Diff: libs/Network/Drivers/LPC17XX_Ethernet.cpp
- Revision:
- 3:f151d08d335c
- Parent:
- 2:1df0b61d3b5a
--- a/libs/Network/Drivers/LPC17XX_Ethernet.cpp Fri Feb 28 18:52:52 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,508 +0,0 @@ -#if 1 -#include "LPC17XX_Ethernet.h" - -#include "Kernel.h" - -#include <cstring> -#include <cstdio> - -#include "lpc17xx_clkpwr.h" - -#include <mri.h> - -// #include "netcore.h" - -static const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 }; - -/*--------------------------- write_PHY -------------------------------------*/ -/*********************************************************************//** -* @brief Write value to PHY device -* @param[in] PhyReg: PHY Register address -* @param[in] Value: Value to write -* @return 0 - if success -* 1 - if fail -***********************************************************************/ -static int32_t write_PHY (uint32_t PhyReg, uint16_t Value) -{ - /* Write a data 'Value' to PHY register 'PhyReg'. */ - uint32_t tout; - - LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; - LPC_EMAC->MWTD = Value; - - /* Wait until operation completed */ - tout = 0; - for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) { - if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { - return (0); - } - } - printf("write PHY %lu %04X failed!\n", PhyReg, Value); - // Time out! - return (-1); -} - - -/*--------------------------- read_PHY --------------------------------------*/ -/*********************************************************************//** -* @brief Read value from PHY device -* @param[in] PhyReg: PHY Register address -* @return 0 - if success -* 1 - if fail -***********************************************************************/ -static int32_t read_PHY (uint32_t PhyReg) -{ - /* Read a PHY register 'PhyReg'. */ - uint32_t tout; - - LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; - LPC_EMAC->MCMD = EMAC_MCMD_READ; - - /* Wait until operation completed */ - tout = 0; - for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) { - if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { - LPC_EMAC->MCMD = 0; - return (LPC_EMAC->MRDD); - } - } - printf("read PHY %lu failed!\n", PhyReg); - // Time out! - return (-1); -} - -/*********************************************************************//** -* @brief Set Station MAC address for EMAC module -* @param[in] abStationAddr Pointer to Station address that contains 6-bytes -* of MAC address (should be in order from MAC Address 1 to MAC Address 6) -* @return None -**********************************************************************/ -static void setEmacAddr(uint8_t abStationAddr[]) -{ - /* Set the Ethernet MAC Address registers */ - LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4]; - LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2]; - LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0]; -} - -/*********************************************************************//** -* @brief Set specified PHY mode in EMAC peripheral -* @param[in] ulPHYMode Specified PHY mode, should be: -* - EMAC_MODE_AUTO -* - EMAC_MODE_10M_FULL -* - EMAC_MODE_10M_HALF -* - EMAC_MODE_100M_FULL -* - EMAC_MODE_100M_HALF -* @return Return (0) if no error, otherwise return (-1) -**********************************************************************/ -int32_t emac_SetPHYMode(uint32_t ulPHYMode) -{ - int32_t id1, id2, tout, regv; - - id1 = read_PHY (EMAC_PHY_REG_IDR1); - id2 = read_PHY (EMAC_PHY_REG_IDR2); - - if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_SMSC_8720A) { - switch(ulPHYMode){ - case EMAC_MODE_AUTO: - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); - /* Wait to complete Auto_Negotiation */ - for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { - regv = read_PHY (EMAC_PHY_REG_BMSR); - if (regv & EMAC_PHY_BMSR_AUTO_DONE) { - /* Auto-negotiation Complete. */ - break; - } - if (tout == 0){ - // Time out, return error - return (-1); - } - } - break; - case EMAC_MODE_10M_FULL: - /* Connect at 10MBit full-duplex */ - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M); - break; - case EMAC_MODE_10M_HALF: - /* Connect at 10MBit half-duplex */ - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M); - break; - case EMAC_MODE_100M_FULL: - /* Connect at 100MBit full-duplex */ - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M); - break; - case EMAC_MODE_100M_HALF: - /* Connect at 100MBit half-duplex */ - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M); - break; - default: - // un-supported - return (-1); - } - } - // It's not correct module ID - else { - printf("PHY reports id %04lX %04lX - not an SMSC 8720A\n", id1, id2); - return (-1); - } - - // Update EMAC configuration with current PHY status - if (EMAC_UpdatePHYStatus() < 0){ - return (-1); - } - - // Complete - return (0); -} - -_rxbuf_t LPC17XX_Ethernet::rxbuf __attribute__ ((section ("AHBSRAM1"))) __attribute__((aligned(8))); -_txbuf_t LPC17XX_Ethernet::txbuf __attribute__ ((section ("AHBSRAM1"))) __attribute__((aligned(8))); - -LPC17XX_Ethernet* LPC17XX_Ethernet::instance; - -LPC17XX_Ethernet::LPC17XX_Ethernet() -{ - // TODO these need to be configurable - // mac_address[0] = 0xAE; - // mac_address[1] = 0xF0; - // mac_address[2] = 0x28; - // mac_address[3] = 0x5D; - // mac_address[4] = 0x66; - // mac_address[5] = 0x41; - - // ip_address = IPA(192,168,3,222); - // ip_mask = 0xFFFFFF00; - - for (int i = 0; i < LPC17XX_RXBUFS; i++) { - rxbuf.rxdesc[i].packet = rxbuf.buf[i]; - rxbuf.rxdesc[i].control = (LPC17XX_MAX_PACKET - 1) | EMAC_RCTRL_INT; - - rxbuf.rxstat[i].Info = 0; - rxbuf.rxstat[i].HashCRC = 0; - } - - for (int i = 0; i < LPC17XX_TXBUFS; i++) { - txbuf.txdesc[i].packet = txbuf.buf[i]; - txbuf.txdesc[i].control = (LPC17XX_MAX_PACKET - 1) | EMAC_TCTRL_PAD | EMAC_TCTRL_CRC | EMAC_TCTRL_LAST | EMAC_TCTRL_INT; - - txbuf.txstat[i].Info = 0; - } - - interface_name = (uint8_t*) malloc(5); - memcpy(interface_name, "eth0", 5); - - instance = this; - - up = false; -} - -void LPC17XX_Ethernet::on_module_loaded() -{ - LPC_PINCON->PINSEL2 = (1 << 0) | (1 << 2) | (1 << 8) | (1 << 16) | (1 << 18) | (1 << 20) | (1 << 28) | (1 << 30); - LPC_PINCON->PINSEL3 &= (2 << 0) | (2 << 2); - LPC_PINCON->PINSEL3 |= (1 << 0) | (1 << 2); - - printf("EMAC_INIT\n"); - emac_init(); - printf("INIT OK\n"); - - //register_for_event(ON_IDLE); - register_for_event(ON_SECOND_TICK); -} - -void LPC17XX_Ethernet::on_idle(void*) -{ - //_receive_frame(); -} - -void LPC17XX_Ethernet::on_second_tick(void *) { - check_interface(); -} - -void LPC17XX_Ethernet::check_interface() -{ -// LPC_EMAC->Command = 0x303; -// setEmacAddr(mac_address); - - uint32_t st; - st = read_PHY (EMAC_PHY_REG_BMSR); - - if ((st & EMAC_PHY_BMSR_LINK_ESTABLISHED) && (st & EMAC_PHY_BMSR_AUTO_DONE) && (up == false)) - { - // TODO: link up event - up = true; -// net->set_interface_status(this, up); - uint32_t scsr = read_PHY(EMAC_PHY_REG_SCSR); - printf("%s: link up: ", interface_name); - switch ((scsr >> 2) & 0x7) - { - case 1: - printf("10MBit Half Duplex\n"); - break; - case 5: - printf("10MBit Full Duplex\n"); - break; - case 2: - printf("100MBit Half Duplex\n"); - break; - case 6: - printf("100MBit Full Duplex\n"); - break; - default: - printf("Unknown speed: SCSR = 0x%04lX\n", scsr); - break; - } - printf("MAC Address: %02lX:%02lX:%02lX:%02lX:%02lX:%02lX\n", (LPC_EMAC->SA2) & 0xFF, (LPC_EMAC->SA2 >> 8) & 0xFF, (LPC_EMAC->SA1) & 0xFF, (LPC_EMAC->SA1 >> 8) & 0xFF, (LPC_EMAC->SA0) & 0xFF, (LPC_EMAC->SA0 >> 8) & 0xFF); - } - else if (((st & EMAC_PHY_BMSR_LINK_ESTABLISHED) == 0) && up) - { - // TODO: link down event - up = false; -// net->set_interface_status(this, up); - printf("%s: link down\n", interface_name); - } - - //printf("PHY: id:%04lX %04lX st:%04lX\n", id1, id2, st); - // printf("ETH: Rx:%lu/%lu Tx:%lu/%lu\n", LPC_EMAC->RxConsumeIndex, LPC_EMAC->RxProduceIndex, LPC_EMAC->TxProduceIndex, LPC_EMAC->TxConsumeIndex); - // printf("MII: 0x%1lX\n", LPC_EMAC->MIND); - // printf("Command: 0x%03lX Status: 0x%1lX\n", LPC_EMAC->Command, LPC_EMAC->Status); - // printf("RxN: %lu TxN: %lu\n", LPC_EMAC->RxDescriptorNumber, LPC_EMAC->TxDescriptorNumber); - // printf("MAC1: 0x%04lX MAC2: 0x%04lX\n", LPC_EMAC->MAC1, LPC_EMAC->MAC2); - // printf("MAC Address: %02lX:%02lX:%02lX:%02lX:%02lX:%02lX\n", (LPC_EMAC->SA2) & 0xFF, (LPC_EMAC->SA2 >> 8) & 0xFF, (LPC_EMAC->SA1) & 0xFF, (LPC_EMAC->SA1 >> 8) & 0xFF, (LPC_EMAC->SA0) & 0xFF, (LPC_EMAC->SA0 >> 8) & 0xFF); -} - -void LPC17XX_Ethernet::emac_init() -{ - /* Initialize the EMAC Ethernet controller. */ - int32_t regv,tout, tmp; - volatile uint32_t d; - - /* Set up clock and power for Ethernet module */ - CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE); - - /* Reset all EMAC internal modules */ - LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX | - EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES; - - LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES; - - /* A short delay after reset. */ - for (d = 256; d; d--); - - /* Initialize MAC control registers. */ - LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; - LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN | EMAC_MAC2_FULL_DUP; - LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; - /* - * Find the clock that close to desired target clock - */ - tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK; - for (tout = 0; tout < (int32_t) sizeof (EMAC_clkdiv); tout++){ - if (EMAC_clkdiv[tout] >= tmp) break; - } - tout++; - // Write to MAC configuration register and reset - LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII; - // release reset - LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII); - LPC_EMAC->CLRT = EMAC_CLRT_DEF; - LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF; - - /* Enable Reduced MII interface. */ - LPC_EMAC->Command = EMAC_CR_RMII; - - /* Reset Reduced MII Logic. */ - LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII; - - for (d = 256; d; d--); - LPC_EMAC->SUPP = EMAC_SUPP_SPEED; - - /* Put the DP83848C in reset mode */ - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET); - - /* Wait for hardware reset to end. */ - for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { - regv = read_PHY (EMAC_PHY_REG_BMCR); - if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) { - /* Reset complete, device not Power Down. */ - break; - } - if (tout == 0){ - // Time out, return ERROR - printf("ETH: PHY TIMEOUT\n"); - return; - } - } - - // Set PHY mode -// if (emac_SetPHYMode(EMAC_MODE_AUTO) < 0){ -// printf("ETH: Error Setting Mode\n"); -// return; -// } - write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); - - // Set EMAC address - setEmacAddr(mac_address); - - /* Initialize Tx and Rx DMA Descriptors */ - LPC_EMAC->RxDescriptor = (uint32_t) rxbuf.rxdesc; - LPC_EMAC->RxStatus = (uint32_t) rxbuf.rxstat; - LPC_EMAC->RxDescriptorNumber = LPC17XX_RXBUFS-1; - - LPC_EMAC->TxDescriptor = (uint32_t) txbuf.txdesc; - LPC_EMAC->TxStatus = (uint32_t) txbuf.txstat; - LPC_EMAC->TxDescriptorNumber = LPC17XX_TXBUFS-1; - - // Set Receive Filter register: enable broadcast and multicast - LPC_EMAC->RxFilterCtrl = EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN; - - /* Enable Rx Done and Tx Done interrupt for EMAC */ - LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE; - - /* Reset all interrupts */ - LPC_EMAC->IntClear = 0xFFFF; - - /* Enable receive and transmit mode of MAC Ethernet core */ - LPC_EMAC->Command = EMAC_CR_RX_EN | EMAC_CR_TX_EN | EMAC_CR_RMII | EMAC_CR_FULL_DUP | EMAC_CR_PASS_RUNT_FRM; - LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; - - printf("ETH:EMAC INITIALISED\n"); -} - -void LPC17XX_Ethernet::set_mac(uint8_t* newmac) -{ - memcpy(mac_address, newmac, 6); -} - -bool LPC17XX_Ethernet::_receive_frame(void *packet, int *size) -{ - if (can_read_packet() && can_write_packet()) - { - int i = LPC_EMAC->RxConsumeIndex; - RX_Stat* stat = &(rxbuf.rxstat[i]); - *size = stat->Info & EMAC_RINFO_SIZE; - memcpy(packet, rxbuf.buf[i], *size); - - //printf("Received %d byte Ethernet frame %lu/%lu\n", *size, LPC_EMAC->RxProduceIndex, LPC_EMAC->RxConsumeIndex); - - uint32_t r = LPC_EMAC->RxConsumeIndex + 1; - if (r > LPC_EMAC->RxDescriptorNumber) - r = 0; - LPC_EMAC->RxConsumeIndex = r; - - return true; - } - - return false; -} - -void LPC17XX_Ethernet::irq() -{ - // if (EMAC_IntGetStatus(EMAC_INT_RX_DONE)) - // { - // //_receive_frame(); - // } - - // if (EMAC_IntGetStatus(EMAC_INT_TX_DONE)) - // { - // } -} - -bool LPC17XX_Ethernet::can_read_packet() -{ - return (LPC_EMAC->RxProduceIndex != LPC_EMAC->RxConsumeIndex); -} - -int LPC17XX_Ethernet::read_packet(uint8_t** buf) -{ - *buf = rxbuf.buf[LPC_EMAC->RxConsumeIndex]; - return rxbuf.rxstat[LPC_EMAC->RxConsumeIndex].Info & EMAC_RINFO_SIZE; -} - -void LPC17XX_Ethernet::release_read_packet(uint8_t*) -{ - uint32_t r = LPC_EMAC->RxConsumeIndex + 1; - if (r > LPC_EMAC->RxDescriptorNumber) - r = 0; - LPC_EMAC->RxConsumeIndex = r; -} - -bool LPC17XX_Ethernet::can_write_packet() -{ - uint32_t r = LPC_EMAC->TxProduceIndex + 1; - if (r > LPC_EMAC->TxDescriptorNumber) - r = 0; - return (r != LPC_EMAC->TxConsumeIndex); -} - -int LPC17XX_Ethernet::write_packet(uint8_t* buf, int size) -{ - txbuf.txdesc[LPC_EMAC->TxProduceIndex].control = ((size - 1) & 0x7ff) | EMAC_TCTRL_LAST | EMAC_TCTRL_CRC | EMAC_TCTRL_PAD | EMAC_TCTRL_INT; - - uint32_t r = LPC_EMAC->TxProduceIndex + 1; - if (r > LPC_EMAC->TxDescriptorNumber) - r = 0; - - if (r == LPC_EMAC->TxConsumeIndex) - return 0; - - LPC_EMAC->TxProduceIndex = r; - - return size; -} - -void* LPC17XX_Ethernet::request_packet_buffer() -{ - return txbuf.txdesc[LPC_EMAC->TxProduceIndex].packet; -} - -NET_PACKET LPC17XX_Ethernet::get_new_packet_buffer(NetworkInterface* ni) -{ - if (ni != this) - return NULL; - - return (NET_PACKET) request_packet_buffer(); -} - -NET_PAYLOAD LPC17XX_Ethernet::get_payload_buffer(NET_PACKET packet) -{ - return (NET_PAYLOAD) packet; -} - -void LPC17XX_Ethernet::set_payload_length(NET_PACKET packet, int length) -{ - uint32_t offset = ((uint8_t*) packet) - txbuf.buf[0]; - int i = (offset / LPC17XX_MAX_PACKET); - if ((i < LPC17XX_TXBUFS) && ((offset % LPC17XX_MAX_PACKET) == 0)) - { - txbuf.txdesc[i].control = (txbuf.txdesc[i].control & ~EMAC_TCTRL_SIZE) | (length & EMAC_TCTRL_SIZE); - } -} - -int LPC17XX_Ethernet::receive(NetworkInterface* ni, NET_PACKET packet, int length) -{ - if (can_write_packet()) - return write_packet((uint8_t*) packet, length); - return 0; -} - -int LPC17XX_Ethernet::construct(NetworkInterface* ni, NET_PACKET packet, int length) -{ - return length; -} - -extern "C" { - void ENET_IRQHandler() - { - LPC17XX_Ethernet::instance->irq(); - } -} - -// void LPC17XX_Ethernet::provide_net(netcore* n) -// { -// NetworkInterface::provide_net(n); -// up = false; -// n->set_interface_status(this, up); -// } - -#endif