From 9a8a75e827d36abfafc2f30822331a9cd655c485 Mon Sep 17 00:00:00 2001 From: Masao Hamanaka Date: Fri, 31 Oct 2014 17:01:59 +0900 Subject: [PATCH] Add Ethernet functionality Although the Ethernet functionality is not for review. --- .../hal/TARGET_RENESAS/TARGET_RZ_A1H/device.h | 2 +- .../TARGET_RZ_A1H/ethernet_api.c | 699 ++++++++++++++++++ .../TARGET_RZ_A1H/ethernetext_api.h | 20 + .../eth/EthernetInterface/EthernetInterface.h | 2 +- .../arch/TARGET_RZ_A1H/lwipopts_conf.h | 26 + .../lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c | 193 +++++ libraries/net/lwip/lwip-sys/arch/sys_arch.c | 2 + libraries/net/lwip/lwip/core/memp.c | 2 +- 8 files changed, 943 insertions(+), 3 deletions(-) create mode 100644 libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernet_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernetext_api.h create mode 100644 libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h create mode 100644 libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c diff --git a/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/device.h b/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/device.h index 23089470a2..15fc46b103 100644 --- a/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/device.h +++ b/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/device.h @@ -38,7 +38,7 @@ #define DEVICE_RTC 0 -#define DEVICE_ETHERNET 0 +#define DEVICE_ETHERNET 1 #define DEVICE_PWMOUT 1 diff --git a/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernet_api.c b/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernet_api.c new file mode 100644 index 0000000000..63aca8cc96 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernet_api.c @@ -0,0 +1,699 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "ethernet_api.h" +#include "cmsis.h" +#include "mbed_interface.h" +#include "toolchain.h" +#include "mbed_error.h" +#include "ether_iodefine.h" +#include "ethernetext_api.h" + +/* Descriptor info */ +#define NUM_OF_TX_DESCRIPTOR (16) +#define NUM_OF_RX_DESCRIPTOR (16) +#define SIZE_OF_BUFFER (1600) /* Must be an integral multiple of 32 */ +#define MAX_SEND_SIZE (1514) +#define BUFF_BOUNDARY_MSK (0x0000000F) +/* Ethernet Descriptor Value Define */ +#define TD0_TFP_TOP_BOTTOM (0x30000000) +#define TD0_TACT (0x80000000) +#define TD0_TDLE (0x40000000) +#define RD0_RACT (0x80000000) +#define RD0_RDLE (0x40000000) +#define RD0_RFE (0x08000000) +#define RD0_RCSE (0x04000000) +#define RD0_RFS (0x03FF0000) +#define RD0_RCS (0x0000FFFF) +#define RD0_RFS_RFOF (0x02000000) +#define RD0_RFS_RUAF (0x00400000) +#define RD0_RFS_RRF (0x00100000) +#define RD0_RFS_RTLF (0x00080000) +#define RD0_RFS_RTSF (0x00040000) +#define RD0_RFS_PRE (0x00020000) +#define RD0_RFS_CERF (0x00010000) +#define RD0_RFS_ERROR (RD0_RFS_RFOF | RD0_RFS_RUAF | RD0_RFS_RRF | RD0_RFS_RTLF | \ + RD0_RFS_RTSF | RD0_RFS_PRE | RD0_RFS_CERF) +#define RD1_RDL_MSK (0x0000FFFF) +/* PHY Register */ +#define BASIC_MODE_CONTROL_REG (0) +#define BASIC_MODE_STATUS_REG (1) +#define PHY_IDENTIFIER1_REG (2) +#define PHY_IDENTIFIER2_REG (3) +#define PHY_SP_CTL_STS_REG (31) +/* MII management interface access */ +#define PHY_ADDR (0) /* Confirm the pin connection of the PHY-LSI */ +#define PHY_ST (1) +#define PHY_WRITE (1) +#define PHY_READ (2) +#define MDC_WAIT (6) /* 400ns/4 */ +#define BASIC_STS_MSK_LINK (0x0004) /* Link Status */ +#define BASIC_STS_MSK_AUTO_CMP (0x0010) /* Auto-Negotiate Complete */ +#define M_PHY_ID (0xFFFFFFF0) +#define PHY_ID_LAN8710A (0x0007C0F0) +/* ETHERPIR0 */ +#define PIR0_MDI (0x00000008) +#define PIR0_MDO (0x00000004) +#define PIR0_MMD (0x00000002) +#define PIR0_MDC (0x00000001) +#define PIR0_MDC_HIGH (0x00000001) +#define PIR0_MDC_LOW (0x00000000) +/* ETHEREDRRR0 */ +#define EDRRR0_RR (0x00000001) +/* ETHEREDTRR0 */ +#define EDTRR0_TR (0x00000003) +/* software wait */ +#define LOOP_100us (6700) /* Loop counter for software wait 6666=100us/((1/400MHz)*6cyc) */ + +#define EDMAC_EESIPR_INI_RECV (0x0205001F) /* 0x02000000 : Detect reception suspended */ + /* 0x00040000 : Detect frame reception */ + /* 0x00010000 : Receive FIFO overflow */ + /* 0x00000010 : Residual bit frame reception */ + /* 0x00000008 : Long frame reception */ + /* 0x00000004 : Short frame reception */ + /* 0x00000002 : PHY-LSI reception error */ + /* 0x00000001 : Receive frame CRC error */ +#define EDMAC_EESIPR_INI_EtherC (0x00400000) /* 0x00400000 : E-MAC status register */ + +/* Send descriptor */ +typedef struct tag_edmac_send_desc { + uint32_t td0; + uint32_t td1; + uint8_t *td2; + uint32_t padding4; +} edmac_send_desc_t; + +/* Receive descriptor */ +typedef struct tag_edmac_recv_desc { + uint32_t rd0; + uint32_t rd1; + uint8_t *rd2; + uint32_t padding4; +} edmac_recv_desc_t; + +/* memory */ +#pragma arm section zidata="NC_BSS" +/* The whole transmit/receive descriptors (must be allocated in 16-byte boundaries) */ +/* Transmit/receive buffers (must be allocated in 16-byte boundaries) */ +static uint8_t ehernet_nc_memory[(sizeof(edmac_send_desc_t) * NUM_OF_TX_DESCRIPTOR) + + (sizeof(edmac_recv_desc_t) * NUM_OF_RX_DESCRIPTOR) + + (NUM_OF_TX_DESCRIPTOR * SIZE_OF_BUFFER) + + (NUM_OF_RX_DESCRIPTOR * SIZE_OF_BUFFER) + BUFF_BOUNDARY_MSK]; +#pragma arm section zidata +static int32_t rx_read_offset; /* read offset */ +static int32_t tx_wite_offset; /* write offset */ +static uint32_t send_top_index; +static uint32_t recv_top_index; +static int32_t Interrupt_priority; +static edmac_send_desc_t *p_eth_desc_dsend = NULL; +static edmac_recv_desc_t *p_eth_desc_drecv = NULL; +static edmac_recv_desc_t *p_recv_end_desc = NULL; +static ethernetext_cb_fnc *p_recv_cb_fnc = NULL; +static char mac_addr[6] = {0x00, 0x02, 0xF7, 0xF0, 0x00, 0x00}; /* MAC Address */ +static uint32_t phy_id = 0; +static uint32_t start_stop = 1; /* 0:stop 1:start */ + +/* function */ +static void lan_reg_reset(void); +static void lan_desc_create(void); +static void lan_reg_set(int32_t link); +static uint16_t phy_reg_read(uint16_t reg_addr); +static void phy_reg_write(uint16_t reg_addr, uint16_t data); +static void mii_preamble(void); +static void mii_cmd(uint16_t reg_addr, uint32_t option); +static void mii_reg_read(uint16_t *data); +static void mii_reg_write(uint16_t data); +static void mii_z(void); +static void mii_write_1(void); +static void mii_write_0(void); +static void set_ether_pir(uint32_t set_data); +static void wait_100us(int32_t wait_cnt); + + +int ethernetext_init(ethernet_cfg_t *p_ethcfg) { + int32_t i; + uint16_t val; + + CPGSTBCR7 &= ~(CPG_STBCR7_BIT_MSTP74); /* enable ETHER clock */ + + /* P4_2(PHY Reset) */ + GPIOP4 &= ~0x0004; /* Outputs low level */ + GPIOPMC4 &= ~0x0004; /* Port mode */ + GPIOPM4 &= ~0x0004; /* Output mode */ + + /* GPIO P1 P1_14(ET_COL) */ + GPIOPMC1 |= 0x4000; + GPIOPFCAE1 &= ~0x4000; + GPIOPFCE1 |= 0x4000; + GPIOPFC1 |= 0x4000; + + /* P3_3(ET_MDIO), P3_4(ET_RXCLK), P3_5(ET_RXER), P3_6(ET_RXDV) */ + GPIOPMC3 |= 0x0078; + GPIOPFCAE3 &= ~0x0078; + GPIOPFCE3 &= ~0x0078; + GPIOPFC3 |= 0x0078; + GPIOPIPC3 |= 0x0078; + + /* P5_9(ET_MDC) */ + GPIOPMC5 |= 0x0200; + GPIOPFCAE5 &= ~0x0200; + GPIOPFCE5 &= ~0x0200; + GPIOPFC5 |= 0x0200; + GPIOPIPC5 |= 0x0200; + + /* P10_0(ET_TXCLK), P10_1(ET_TXER), P10_2(ET_TXEN), P10_3(ET_CRS), P10_4(ET_TXD0), P10_5(ET_TXD1) */ + /* P10_6(ET_TXD2), P10_7(ET_TXD3), P10_8(ET_RXD0), P10_9(ET_RXD1), P10_10(ET_RXD2), P10_11(ET_RXD3) */ + GPIOPMC10 |= 0x0FFF; + GPIOPFCAE10 &= ~0x0FFF; + GPIOPFCE10 |= 0x0FFF; + GPIOPFC10 |= 0x0FFF; + GPIOPIPC10 |= 0x0FFF; + + /* Resets the E-MAC,E-DMAC */ + lan_reg_reset(); + + /* PHY Reset */ + GPIOP4 &= ~0x0004; /* P4_2 Outputs low level */ + wait_100us(250); /* 25msec */ + GPIOP4 |= 0x0004; /* P4_2 Outputs high level */ + wait_100us(100); /* 10msec */ + + /* Resets the PHY-LSI */ + phy_reg_write(BASIC_MODE_CONTROL_REG, 0x8000); + for (i = 10000; i > 0; i--) { + val = phy_reg_read(BASIC_MODE_CONTROL_REG); + if (((uint32_t)val & 0x8000uL) == 0) { + break; /* Reset complete */ + } + } + + phy_id = ((uint32_t)phy_reg_read(PHY_IDENTIFIER1_REG) << 16) + | (uint32_t)phy_reg_read(PHY_IDENTIFIER2_REG); + + Interrupt_priority = p_ethcfg->int_priority; + p_recv_cb_fnc = p_ethcfg->recv_cb; + start_stop = 1; + + if (p_ethcfg->ether_mac != NULL) { + (void)memcpy(mac_addr, p_ethcfg->ether_mac, sizeof(mac_addr)); + } else { + ethernet_address(mac_addr); /* Get MAC Address */ + } + + return 0; +} + +void ethernetext_start_stop(int32_t mode) { + if (mode == 1) { + /* start */ + ETHEREDTRR0 |= EDTRR0_TR; + ETHEREDRRR0 |= EDRRR0_RR; + start_stop = 1; + } else { + /* stop */ + ETHEREDTRR0 &= ~EDTRR0_TR; + ETHEREDRRR0 &= ~EDRRR0_RR; + start_stop = 0; + } +} + +int ethernetext_chk_link_mode(void) { + int32_t link; + uint16_t data; + + if ((phy_id & M_PHY_ID) == PHY_ID_LAN8710A) { + data = phy_reg_read(PHY_SP_CTL_STS_REG); + switch (((uint32_t)data >> 2) & 0x00000007) { + case 0x0001: + link = HALF_10M; + break; + case 0x0005: + link = FULL_10M; + break; + case 0x0002: + link = HALF_TX; + break; + case 0x0006: + link = FULL_TX; + break; + default: + link = NEGO_FAIL; + break; + } + } else { + link = NEGO_FAIL; + } + + return link; +} + +void ethernetext_set_link_mode(int32_t link) { + lan_reg_reset(); /* Resets the E-MAC,E-DMAC */ + lan_desc_create(); /* Initialize of buffer memory */ + lan_reg_set(link); /* E-DMAC, E-MAC initialization */ +} + +int ethernet_init() { + ethernet_cfg_t ethcfg; + + ethcfg.int_priority = 0; + ethcfg.recv_cb = NULL; + ethcfg.ether_mac = NULL; + ethernetext_init(ðcfg); + ethernet_set_link(-1, 0); /* Auto-Negotiation */ + + return 0; +} + +void ethernet_free() { + ETHERARSTR |= 0x00000001; /* ETHER software reset */ + CPGSTBCR7 |= CPG_STBCR7_BIT_MSTP74; /* disable ETHER clock */ +} + +int ethernet_write(const char *data, int slen) { + edmac_send_desc_t *p_send_desc; + int32_t copy_size; + + if ((p_eth_desc_dsend == NULL) || (data == NULL) || (slen < 0) + || (tx_wite_offset < 0) || (tx_wite_offset >= MAX_SEND_SIZE)) { + copy_size = 0; + } else { + p_send_desc = &p_eth_desc_dsend[send_top_index]; /* Current descriptor */ + if ((p_send_desc->td0 & TD0_TACT) != 0) { + copy_size = 0; + } else { + copy_size = MAX_SEND_SIZE - tx_wite_offset; + if (copy_size > slen) { + copy_size = slen; + } + (void)memcpy(&p_send_desc->td2[tx_wite_offset], data, copy_size); + tx_wite_offset += copy_size; + } + } + + return copy_size; +} + +int ethernet_send() { + edmac_send_desc_t *p_send_desc; + int32_t ret; + + if ((p_eth_desc_dsend == NULL) || (tx_wite_offset <= 0)) { + ret = 0; + } else { + /* Transfer 1 frame */ + p_send_desc = &p_eth_desc_dsend[send_top_index]; /* Current descriptor */ + + /* Sets the frame length */ + p_send_desc->td1 = ((uint32_t)tx_wite_offset << 16); + tx_wite_offset = 0; + + /* Sets the transmit descriptor to transmit again */ + p_send_desc->td0 &= (TD0_TACT | TD0_TDLE | TD0_TFP_TOP_BOTTOM); + p_send_desc->td0 |= TD0_TACT; + if ((start_stop == 1) && ((ETHEREDTRR0 & EDTRR0_TR) != EDTRR0_TR)) { + ETHEREDTRR0 |= EDTRR0_TR; + } + + /* Update the current descriptor */ + send_top_index++; + if (send_top_index >= NUM_OF_TX_DESCRIPTOR) { + send_top_index = 0; + } + ret = 1; + } + + return ret; +} + +int ethernet_receive() { + edmac_recv_desc_t *p_recv_desc; + int32_t receive_size = 0; + + if (p_eth_desc_drecv != NULL) { + if (p_recv_end_desc != NULL) { + /* Sets the receive descriptor to receive again */ + p_recv_end_desc->rd0 &= (RD0_RACT | RD0_RDLE); + p_recv_end_desc->rd0 |= RD0_RACT; + if ((start_stop == 1) && ((ETHEREDRRR0 & EDRRR0_RR) == 0)) { + ETHEREDRRR0 |= EDRRR0_RR; + } + p_recv_end_desc = NULL; + } + + p_recv_desc = &p_eth_desc_drecv[recv_top_index]; /* Current descriptor */ + if ((p_recv_desc->rd0 & RD0_RACT) == 0) { + /* Receives 1 frame */ + if (((p_recv_desc->rd0 & RD0_RFE) != 0) && ((p_recv_desc->rd0 & RD0_RFS_ERROR) != 0)) { + /* Receive frame error */ + /* Sets the receive descriptor to receive again */ + p_recv_desc->rd0 &= (RD0_RACT | RD0_RDLE); + p_recv_desc->rd0 |= RD0_RACT; + if ((start_stop == 1) && ((ETHEREDRRR0 & EDRRR0_RR) == 0)) { + ETHEREDRRR0 |= EDRRR0_RR; + } + } else { + /* Copies the received frame */ + rx_read_offset = 0; + p_recv_end_desc = p_recv_desc; + receive_size = (p_recv_desc->rd1 & RD1_RDL_MSK); /* number of bytes received */ + } + + /* Update the current descriptor */ + recv_top_index++; + if (recv_top_index >= NUM_OF_TX_DESCRIPTOR) { + recv_top_index = 0; + } + } + } + + return receive_size; +} + +int ethernet_read(char *data, int dlen) { + edmac_recv_desc_t *p_recv_desc = p_recv_end_desc; /* Read top descriptor */ + int32_t copy_size; + + if ((data == NULL) || (dlen < 0) || (p_recv_desc == NULL)) { + copy_size = 0; + } else { + copy_size = (p_recv_desc->rd1 & RD1_RDL_MSK) - rx_read_offset; + if (copy_size > dlen) { + copy_size = dlen; + } + (void)memcpy(data, &p_recv_desc->rd2[rx_read_offset], (size_t)copy_size); + rx_read_offset += copy_size; + } + + return copy_size; +} + +void ethernet_address(char *mac) { + if (mac != NULL) { + mbed_mac_address(mac); /* Get MAC Address */ + } +} + +int ethernet_link(void) { + int32_t ret; + uint16_t data; + + data = phy_reg_read(BASIC_MODE_STATUS_REG); + if (((uint32_t)data & BASIC_STS_MSK_LINK) != 0) { + ret = 1; + } else { + ret = 0; + } + + return ret; +} + +void ethernet_set_link(int speed, int duplex) { + uint16_t data; + int32_t i; + int32_t link; + + if ((speed < 0) || (speed > 1)) { + data = 0x1000; /* Auto-Negotiation Enable */ + phy_reg_write(BASIC_MODE_CONTROL_REG, data); + data = phy_reg_read(BASIC_MODE_STATUS_REG); + for (i = 0; i < 1000; i++) { + if (((uint32_t)data & BASIC_STS_MSK_AUTO_CMP) != 0) { + break; + } + wait_100us(10); + } + } else { + data = (uint16_t)(((uint32_t)speed << 13) | ((uint32_t)duplex << 8)); + phy_reg_write(BASIC_MODE_CONTROL_REG, data); + wait_100us(1); + } + + link = ethernetext_chk_link_mode(); + ethernetext_set_link_mode(link); +} + +void INT_Ether(void) +{ + uint32_t stat_edmac; + uint32_t stat_etherc; + + /* Clear the interrupt request flag */ + stat_edmac = (ETHEREESR0 & ETHEREESIPR0); /* Targets are restricted to allowed interrupts */ + ETHEREESR0 = stat_edmac; + /* Reception-related */ + if (stat_edmac & EDMAC_EESIPR_INI_RECV) { + if (p_recv_cb_fnc != NULL) { + p_recv_cb_fnc(); + } + } + /* E-MAC-related */ + if (stat_edmac & EDMAC_EESIPR_INI_EtherC) { + /* Clear the interrupt request flag */ + stat_etherc = (ETHERECSR0 & ETHERECSIPR0); /* Targets are restricted to allowed interrupts */ + ETHERECSR0 = stat_etherc; + } +} + +static void lan_reg_reset(void) { + volatile int32_t j = 400; /* Wait for B dia 256 cycles ((I dia/B dia)*256)/6cyc = 8*256/6 = 342 */ + + ETHERARSTR |= 0x00000001; /* ETHER software reset */ + while (j--) { + /* Do Nothing */ + } + + ETHEREDSR0 |= 0x00000003; /* E-DMAC software reset */ + ETHEREDMR0 |= 0x00000003; /* Set SWRR and SWRT simultaneously */ + + /* Check clear software reset */ + while ((ETHEREDMR0 & 0x00000003) != 0) { + /* Do Nothing */ + } +} + +static void lan_desc_create(void) { + int32_t i; + uint8_t *p_memory_top; + + (void)memset((void *)ehernet_nc_memory, 0, sizeof(ehernet_nc_memory)); + p_memory_top = (uint8_t *)(((uint32_t)ehernet_nc_memory + BUFF_BOUNDARY_MSK) & ~BUFF_BOUNDARY_MSK); + + /* Descriptor area configuration */ + p_eth_desc_dsend = (edmac_send_desc_t *)p_memory_top; + p_memory_top += (sizeof(edmac_send_desc_t) * NUM_OF_TX_DESCRIPTOR); + p_eth_desc_drecv = (edmac_recv_desc_t *)p_memory_top; + p_memory_top += (sizeof(edmac_recv_desc_t) * NUM_OF_RX_DESCRIPTOR); + + /* Transmit descriptor */ + for (i = 0; i < NUM_OF_TX_DESCRIPTOR; i++) { + p_eth_desc_dsend[i].td2 = p_memory_top; /* TD2 TBA */ + p_memory_top += SIZE_OF_BUFFER; + p_eth_desc_dsend[i].td1 = 0; /* TD1 TDL */ + p_eth_desc_dsend[i].td0 = TD0_TFP_TOP_BOTTOM; /* TD0:1frame/1buf1buf, transmission disabled */ + } + p_eth_desc_dsend[i - 1].td0 |= TD0_TDLE; /* Set the last descriptor */ + + /* Receive descriptor */ + for (i = 0; i < NUM_OF_RX_DESCRIPTOR; i++) { + p_eth_desc_drecv[i].rd2 = p_memory_top; /* RD2 RBA */ + p_memory_top += SIZE_OF_BUFFER; + p_eth_desc_drecv[i].rd1 = ((uint32_t)SIZE_OF_BUFFER << 16); /* RD1 RBL */ + p_eth_desc_drecv[i].rd0 = RD0_RACT; /* RD0:reception enabled */ + } + p_eth_desc_drecv[i - 1].rd0 |= RD0_RDLE; /* Set the last descriptor */ + + /* Initialize descriptor management information */ + send_top_index = 0; + recv_top_index = 0; + rx_read_offset = 0; + tx_wite_offset = 0; + p_recv_end_desc = NULL; +} + +static void lan_reg_set(int32_t link) { + /* MAC address setting */ + ETHERMAHR0 = ((uint32_t)mac_addr[0] << 24) + | ((uint32_t)mac_addr[1] << 16) + | ((uint32_t)mac_addr[2] << 8) + | (uint32_t)mac_addr[3]; + ETHERMALR0 = ((uint32_t)mac_addr[4] << 8) + | (uint32_t)mac_addr[5]; + + /* E-DMAC */ + ETHERTDLAR0 = (uint32_t)&p_eth_desc_dsend[0]; + ETHERRDLAR0 = (uint32_t)&p_eth_desc_drecv[0]; + ETHERTDFAR0 = (uint32_t)&p_eth_desc_dsend[0]; + ETHERRDFAR0 = (uint32_t)&p_eth_desc_drecv[0]; + ETHERTDFXR0 = (uint32_t)&p_eth_desc_dsend[NUM_OF_TX_DESCRIPTOR - 1]; + ETHERRDFXR0 = (uint32_t)&p_eth_desc_drecv[NUM_OF_RX_DESCRIPTOR - 1]; + ETHERTDFFR0 |= 0x00000001; /* TDLF Transmit Descriptor Queue Last Flag : Last descriptor (1) */ + ETHERRDFFR0 |= 0x00000001; /* RDLF Receive Descriptor Queue Last Flag : Last descriptor (1) */ + ETHEREDMR0 |= 0x00000040; /* Little endian */ + ETHERTRSCER0 &= ~0x0003009F; /* All clear */ + ETHERTFTR0 &= ~0x000007FF; /* TFT[10:0] Transmit FIFO Threshold : Store and forward modes (H'000) */ + ETHERFDR0 |= 0x00000707; /* Transmit FIFO Size:2048 bytes, Receive FIFO Size:2048 bytes */ + ETHERRMCR0 |= 0x00000001; /* RNC Receive Enable Control : Continuous reception enabled (1) */ + ETHERFCFTR0 &= ~0x001F00FF; + ETHERFCFTR0 |= 0x00070007; + ETHERRPADIR0 &= ~0x001FFFFF; /* Padding Size:No padding insertion, Padding Slot:Inserts at first byte */ + + /* E-MAC */ + ETHERECMR0 &= ~0x04BF2063; /* All clear */ + ETHERRFLR0 &= ~0x0003FFFF; /* RFL[17:0] Receive Frame Length : 1518 bytes (H'00000) */ + ETHERAPR0 &= ~0x0000FFFF; /* AP[15:0] Automatic PAUSE : Flow control is disabled (H'0000) */ + ETHERMPR0 &= ~0x0000FFFF; /* MP[15:0] Manual PAUSE : Flow control is disabled (H'0000) */ + ETHERTPAUSER0 &= ~0x0000FFFF; /* Upper Limit for Automatic PAUSE Frame : Retransmit count is unlimited */ + ETHERCSMR &= ~0xC000003F; /* The result of checksum is not written back to the receive descriptor */ + if ((link == FULL_TX) || (link == FULL_10M) || (link == NEGO_FAIL)) { + ETHERECMR0 |= 0x00000002; /* Set to full-duplex mode */ + } else { + ETHERECMR0 &= ~0x00000002; /* Set to half-duplex mode */ + } + + /* Interrupt-related */ + if (p_recv_cb_fnc != NULL) { + ETHEREESR0 |= 0xFF7F009F; /* Clear all status (by writing 1) */ + ETHEREESIPR0 |= 0x00040000; /* FR Frame Reception (1) */ + ETHERECSR0 |= 0x00000011; /* Clear all status (clear by writing 1) */ + ETHERECSIPR0 &= ~0x00000011; /* PFROIP Disable, ICDIP Disable */ + InterruptHandlerRegister(ETHERI_IRQn, INT_Ether); /* Ethernet interrupt handler registration */ + GIC_SetPriority(ETHERI_IRQn, Interrupt_priority); /* Ethernet interrupt priority */ + GIC_EnableIRQ(ETHERI_IRQn); /* Enables the E-DMAC interrupt */ + } + + ETHERECMR0 |= 0x00000060; /* RE Enable, TE Enable */ + + /* Enable transmission/reception */ + if ((start_stop == 1) && ((ETHEREDRRR0 & 0x00000001) == 0)) { + ETHEREDRRR0 |= 0x00000001; /* RR */ + } +} + +static uint16_t phy_reg_read(uint16_t reg_addr) { + uint16_t data; + + mii_preamble(); + mii_cmd(reg_addr, PHY_READ); + mii_z(); + mii_reg_read(&data); + mii_z(); + + return data; +} + +static void phy_reg_write(uint16_t reg_addr, uint16_t data) { + mii_preamble(); + mii_cmd(reg_addr, PHY_WRITE); + mii_write_1(); + mii_write_0(); + mii_reg_write(data); + mii_z(); +} + +static void mii_preamble(void) { + int32_t i = 32; + + for (i = 32; i > 0; i--) { + /* 1 is output via the MII (Media Independent Interface) block. */ + mii_write_1(); + } +} + +static void mii_cmd(uint16_t reg_addr, uint32_t option) { + int32_t i; + uint16_t data = 0; + + data |= (PHY_ST << 14); /* ST code */ + data |= (option << 12); /* OP code */ + data |= (PHY_ADDR << 7); /* PHY Address */ + data |= (uint16_t)(reg_addr << 2); /* Reg Address */ + for (i = 14; i > 0; i--) { + if ((data & 0x8000) == 0) { + mii_write_0(); + } else { + mii_write_1(); + } + data <<= 1; + } +} + +static void mii_reg_read(uint16_t *data) { + int32_t i; + uint16_t reg_data = 0; + + /* Data are read in one bit at a time */ + for (i = 16; i > 0; i--) { + set_ether_pir(PIR0_MDC_LOW); + set_ether_pir(PIR0_MDC_HIGH); + reg_data <<= 1; + reg_data |= (uint16_t)((ETHERPIR0 & PIR0_MDI) >> 3); /* MDI read */ + set_ether_pir(PIR0_MDC_HIGH); + set_ether_pir(PIR0_MDC_LOW); + } + *data = reg_data; +} + +static void mii_reg_write(uint16_t data) { + int32_t i; + + /* Data are written one bit at a time */ + for (i = 16; i > 0; i--) { + if ((data & 0x8000) == 0) { + mii_write_0(); + } else { + mii_write_1(); + } + data <<= 1; + } +} + +static void mii_z(void) { + set_ether_pir(PIR0_MDC_LOW); + set_ether_pir(PIR0_MDC_HIGH); + set_ether_pir(PIR0_MDC_HIGH); + set_ether_pir(PIR0_MDC_LOW); +} + +static void mii_write_1(void) { + set_ether_pir(PIR0_MDO | PIR0_MMD); + set_ether_pir(PIR0_MDO | PIR0_MMD | PIR0_MDC); + set_ether_pir(PIR0_MDO | PIR0_MMD | PIR0_MDC); + set_ether_pir(PIR0_MDO | PIR0_MMD); +} + +static void mii_write_0(void) { + set_ether_pir(PIR0_MMD); + set_ether_pir(PIR0_MMD | PIR0_MDC); + set_ether_pir(PIR0_MMD | PIR0_MDC); + set_ether_pir(PIR0_MMD); +} + +static void set_ether_pir(uint32_t set_data) { + int32_t i; + + for (i = MDC_WAIT; i > 0; i--) { + ETHERPIR0 = set_data; + } +} + +static void wait_100us(int32_t wait_cnt) { + volatile int32_t j = LOOP_100us * wait_cnt; + + while (--j) { + /* Do Nothing */ + } +} diff --git a/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernetext_api.h b/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernetext_api.h new file mode 100644 index 0000000000..abf62eb9f8 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_RENESAS/TARGET_RZ_A1H/ethernetext_api.h @@ -0,0 +1,20 @@ + +/* PHY link mode */ +#define NEGO_FAIL (0) +#define HALF_10M (1) +#define FULL_10M (2) +#define HALF_TX (3) +#define FULL_TX (4) + +typedef void (ethernetext_cb_fnc)(void); + +typedef struct tag_ethernet_cfg { + int int_priority; + ethernetext_cb_fnc *recv_cb; + char *ether_mac; +} ethernet_cfg_t; + +extern int ethernetext_init(ethernet_cfg_t *p_ethcfg); +extern void ethernetext_start_stop(int32_t mode); +extern int ethernetext_chk_link_mode(void); +extern void ethernetext_set_link_mode(int link); diff --git a/libraries/net/eth/EthernetInterface/EthernetInterface.h b/libraries/net/eth/EthernetInterface/EthernetInterface.h index 632072dbf8..5d085d1c16 100644 --- a/libraries/net/eth/EthernetInterface/EthernetInterface.h +++ b/libraries/net/eth/EthernetInterface/EthernetInterface.h @@ -20,7 +20,7 @@ #ifndef ETHERNETINTERFACE_H_ #define ETHERNETINTERFACE_H_ -#if !defined(TARGET_LPC1768) && !defined(TARGET_LPC4088) && !defined(TARGET_K64F) +#if !defined(TARGET_LPC1768) && !defined(TARGET_LPC4088) && !defined(TARGET_K64F) && !defined(TARGET_RZ_A1H) #error The Ethernet Interface library is not supported on this target #endif diff --git a/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h b/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h new file mode 100644 index 0000000000..1ad186c7a1 --- /dev/null +++ b/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/lwipopts_conf.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2012 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LWIPOPTS_CONF_H +#define LWIPOPTS_CONF_H + +#define LWIP_TRANSPORT_ETHERNET 1 + +#define MEM_SIZE (1600 * 16) + +#endif diff --git a/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c b/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c new file mode 100644 index 0000000000..13165da925 --- /dev/null +++ b/libraries/net/eth/lwip-eth/arch/TARGET_RZ_A1H/rza1_emac.c @@ -0,0 +1,193 @@ +#include "lwip/opt.h" +#include "lwip/tcpip.h" +#include "netif/etharp.h" +#include "mbed_interface.h" +#include "ethernet_api.h" +#include "ethernetext_api.h" + +#define RECV_TASK_PRI (osPriorityNormal) +#define PHY_TASK_PRI (osPriorityNormal) +#define PHY_TASK_WAIT (200) + +/* memory */ +static sys_sem_t recv_ready_sem; /* receive ready semaphore */ + +/* function */ +static void rza1_recv_task(void *arg); +static void rza1_phy_task(void *arg); +static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr); +static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p); +static void rza1_recv_callback(void); + +static void rza1_recv_task(void *arg) { + struct netif *netif = (struct netif*)arg; + struct eth_hdr *ethhdr; + u16_t recv_size; + struct pbuf *p; + struct pbuf *q; + + while (1) { + sys_arch_sem_wait(&recv_ready_sem, 0); + recv_size = ethernet_receive(); + if (recv_size != 0) { + p = pbuf_alloc(PBUF_RAW, recv_size, PBUF_POOL); + if (p != NULL) { + for (q = p; q != NULL; q = q->next) { + (void)ethernet_read((char *)q->payload, q->len); + } + ethhdr = p->payload; + switch (htons(ethhdr->type)) { + case ETHTYPE_IP: + case ETHTYPE_ARP: +#if PPPOE_SUPPORT + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + /* full packet send to tcpip_thread to process */ + if (netif->input(p, netif) != ERR_OK) { + /* Free buffer */ + pbuf_free(p); + } + break; + default: + /* Return buffer */ + pbuf_free(p); + break; + } + } + } + } +} + +static void rza1_phy_task(void *arg) { + struct netif *netif = (struct netif*)arg; + s32_t connect_sts = 0; /* 0: disconnect, 1:connect */ + s32_t link_sts; + s32_t link_mode_new; + s32_t link_mode_old = NEGO_FAIL; + + while (1) { + link_sts = ethernet_link(); + if (link_sts == 1) { + link_mode_new = ethernetext_chk_link_mode(); + if (link_mode_new != link_mode_old) { + if (connect_sts == 1) { + tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1); + } + if (link_mode_new != NEGO_FAIL) { + ethernetext_set_link_mode(link_mode_new); + tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1); + connect_sts = 1; + } + } + } else { + if (connect_sts != 0) { + tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1); + link_mode_new = NEGO_FAIL; + connect_sts = 0; + } + } + link_mode_old = link_mode_new; + osDelay(PHY_TASK_WAIT); + } +} + +static err_t rza1_etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) { + /* Only send packet is link is up */ + if (netif->flags & NETIF_FLAG_LINK_UP) { + return etharp_output(netif, q, ipaddr); + } + + return ERR_CONN; +} + +static err_t rza1_low_level_output(struct netif *netif, struct pbuf *p) { + struct pbuf *q; + s32_t cnt; + err_t err = ERR_MEM; + s32_t write_size = 0; + + if ((p->payload != NULL) && (p->len != 0)) { + /* If the first data can't be written, transmit descriptor is full. */ + for (cnt = 0; cnt < 100; cnt++) { + write_size = ethernet_write((char *)p->payload, p->len); + if (write_size != 0) { + break; + } + osDelay(1); + } + if (write_size != 0) { + for (q = p->next; q != NULL; q = q->next) { + (void)ethernet_write((char *)q->payload, q->len); + } + if (ethernet_send() == 1) { + err = ERR_OK; + } + } + } + pbuf_free(p); + + return err; +} + +static void rza1_recv_callback(void) { + sys_sem_signal(&recv_ready_sem); +} + +err_t eth_arch_enetif_init(struct netif *netif) +{ + ethernet_cfg_t ethcfg; + + /* set MAC hardware address */ +#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) + netif->hwaddr[0] = MBED_MAC_ADDR_0; + netif->hwaddr[1] = MBED_MAC_ADDR_1; + netif->hwaddr[2] = MBED_MAC_ADDR_2; + netif->hwaddr[3] = MBED_MAC_ADDR_3; + netif->hwaddr[4] = MBED_MAC_ADDR_4; + netif->hwaddr[5] = MBED_MAC_ADDR_5; +#else + mbed_mac_address((char *)netif->hwaddr); +#endif + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwiprza1"; +#endif /* LWIP_NETIF_HOSTNAME */ + + netif->name[0] = 'e'; + netif->name[1] = 'n'; + + netif->output = rza1_etharp_output; + netif->linkoutput = rza1_low_level_output; + + /* Initialize the hardware */ + ethcfg.int_priority = 6; + ethcfg.recv_cb = &rza1_recv_callback; + ethcfg.ether_mac = (char *)netif->hwaddr; + ethernetext_init(ðcfg); + + /* semaphore */ + sys_sem_new(&recv_ready_sem, 0); + + /* task */ + sys_thread_new("rza1_recv_task", rza1_recv_task, netif, DEFAULT_THREAD_STACKSIZE, RECV_TASK_PRI); + sys_thread_new("rza1_phy_task", rza1_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_TASK_PRI); + + return ERR_OK; +} + +void eth_arch_enable_interrupts(void) { + ethernetext_start_stop(1); +} + +void eth_arch_disable_interrupts(void) { + ethernetext_start_stop(0); +} diff --git a/libraries/net/lwip/lwip-sys/arch/sys_arch.c b/libraries/net/lwip/lwip-sys/arch/sys_arch.c index 9186ab6e0e..c7f2c0f875 100644 --- a/libraries/net/lwip/lwip-sys/arch/sys_arch.c +++ b/libraries/net/lwip/lwip-sys/arch/sys_arch.c @@ -426,10 +426,12 @@ sys_thread_t sys_thread_new(const char *pcName, t->def.pthread = (os_pthread)thread; t->def.tpriority = (osPriority)priority; t->def.stacksize = stacksize; +#ifndef __MBED_CMSIS_RTOS_CA9 t->def.stack_pointer = (unsigned char*)malloc(stacksize); if (t->def.stack_pointer == NULL) { error("Error allocating the stack memory"); } +#endif #endif t->id = osThreadCreate(&t->def, arg); if (t->id == NULL) diff --git a/libraries/net/lwip/lwip/core/memp.c b/libraries/net/lwip/lwip/core/memp.c index dc5ae51d46..a206c94537 100644 --- a/libraries/net/lwip/lwip/core/memp.c +++ b/libraries/net/lwip/lwip/core/memp.c @@ -168,7 +168,7 @@ static u8_t *const memp_bases[] = { #if defined(TARGET_LPC1768) # define ETHMEM_SECTION __attribute((section("AHBSRAM1"))) -#elif defined(TARGET_LPC4088) || defined(TARGET_K64F) +#elif defined(TARGET_LPC4088) || defined(TARGET_K64F) || defined(TARGET_RZ_A1H) # define ETHMEM_SECTION #endif