diff options
Diffstat (limited to 'c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c')
-rw-r--r-- | c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c | 1242 |
1 files changed, 0 insertions, 1242 deletions
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c b/c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c deleted file mode 100644 index 53683b1206..0000000000 --- a/c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c +++ /dev/null @@ -1,1242 +0,0 @@ -/** - * @file - * - * @brief Network Driver - * - * This driver is a wrapper for the DWMAC 1000 driver from libchip. - * The DWMAC 1000 driver is an on-chip Synopsys IP Ethernet controllers - */ - -/* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - - -#include <rtems.h> - -#if defined(RTEMS_NETWORKING) - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> -#include <errno.h> -#include <rtems.h> -#include <rtems/config.h> -#include <bsp.h> -#include <bsp/irq.h> -#include <bsp/linker-symbols.h> -#include <bsp/hwlib.h> -#include <bsp/alt_clock_manager.h> -#include <bsp/alt_generalpurpose_io.h> -#include "socal/alt_rstmgr.h" -#include "socal/alt_sysmgr.h" -#include "socal/hps.h" -#include "socal/socal.h" -#include <libchip/dwmac.h> - -/** @brief Pin mask for the interrupt from the ethernet PHY */ -#define NETWORK_PIN_MASK_PHY_INTERRUPT 0x00000040U - -/** @brief Ethernet PHY status */ -typedef enum { - /** @brief The ethernet PHY is off */ - NETWORK_IF_PHY_STATUS_OFF, - - /** @brief The ethernet PHY is on an initialized, but stopped */ - NETWORK_IF_PHY_STATUS_STOPPED, - - /** @brief The ethernet PHY is started and will generate requested events */ - NETWORK_IF_PHY_STATUS_STARTED, - - /** @brief Number of ethernet PHY statuses */ - NETWORK_IF_PHY_STATUS_COUNT -} network_if_phy_status; - -/** @brief Phy context - * - * ethernet PHY device context - */ -typedef struct { - /** @brief PHY device status */ - network_if_phy_status status; - - /** @brief Interrupt mask which corresponds to currently requested events */ - uint16_t irq_mask; -} network_if_phy_context; - -/** @brief Phy context initializer - * - * @retval Initialized network PHY context - */ -#define NETWORK_IF_PHY_CONTEXT_INITIALIZER( \ - ) \ - { \ - NETWORK_IF_PHY_STATUS_OFF, \ - 0 \ - } - -/** @brief Network interface controller ID - * - * Identifies the network interface controller handled by the driver - */ -typedef enum { - /** @brief ID for EMAC0 */ - NETWORK_IF_NIC_ID_EMAC0, - - /** @brief ID for EMAC1 */ - NETWORK_IF_NIC_ID_EMAC1, - - /** @brief Number of network interface controller IDs */ - NETWORK_IF_NIC_ID_COUNT -} network_if_nic_id; - -/** @brief Network interface context - * - * Context for the micro controller specific part of the DWMAC 1000 n - * etwork driver - */ -typedef struct { - /** @brief Network interface controller ID */ - network_if_nic_id nic_id; - - /** @brief Driver context - * - * Address of the context of the low level DWMAC 1000 driver from libchip */ - void *driver_context; - - /** @brief Ethernet PHY context */ - network_if_phy_context phy; - - /* TODO: Create network context on micro controller level */ -} network_if_context; - -/** @brief Network interface context initializer - * - * Initializer for the context of a network interface - * @param nic_id ID of the network interface controller - * @param driver_context Address of the context of the low level DWMAC 1000 - * driver from libchip - * @retval Initialized network interface context - */ -#define NETWORK_IF_CONTEXT_INITIALIZER( \ - nic_id, \ - driver_context \ - ) \ - { \ - nic_id, \ - driver_context, \ - NETWORK_IF_PHY_CONTEXT_INITIALIZER() \ - } - -/****************************************************************************** -* Helper Methods -******************************************************************************/ - -/** @brief Altera status code to errno - * - * Convert Altera status code to errno error number - * @param status Altera status code as returned by methods from Alteras HWLib - * @retval Converted errno error number from errno.h - */ -static int network_if_altera_status_code_to_errno( ALT_STATUS_CODE status ) -{ - int eno = 0; - - switch ( status ) { - /*! - * Indicates a FALSE condition. - */ - case ALT_E_FALSE: - - /*! - * Indicates a TRUE condition. - */ - case ALT_E_TRUE: - - /*! The operation was successful. */ - /* case ALT_E_SUCCESS: */ - eno = 0; - break; - - /*! The operation failed. */ - case ALT_E_ERROR: - - /*! An invalid option was selected. */ - case ALT_E_INV_OPTION: - eno = EIO; /* I/O error */ - break; - - /*! FPGA configuration error detected.*/ - case ALT_E_FPGA_CFG: - eno = ECANCELED; /* Operation canceled */ - break; - - /*! FPGA CRC error detected. */ - case ALT_E_FPGA_CRC: - - /*! An error occurred on the FPGA configuration bitstream input source. */ - case ALT_E_FPGA_CFG_STM: - eno = EPROTO; /* Protocol error */ - break; - - /*! The FPGA is powered off. */ - case ALT_E_FPGA_PWR_OFF: - eno = ENODEV; /* No such device */ - break; - - /*! The SoC does not currently control the FPGA. */ - case ALT_E_FPGA_NO_SOC_CTRL: - - /*! The FPGA is not in USER mode. */ - case ALT_E_FPGA_NOT_USER_MODE: - eno = EPERM; /* Not super-user */ - break; - - /*! An argument violates a range constraint. */ - case ALT_E_ARG_RANGE: - - /*! A bad argument value was passed. */ - case ALT_E_BAD_ARG: - - /*! The argument value is reserved or unavailable. */ - case ALT_E_RESERVED: - eno = EINVAL; /* Invalid argument */ - break; - - /*! The operation is invalid or illegal. */ - case ALT_E_BAD_OPERATION: - - /*! The version ID is invalid. */ - case ALT_E_BAD_VERSION: - eno = EFAULT; /* Bad address */ - break; - - /*! An operation or response timeout period expired. */ - case ALT_E_TMO: - - /*! A clock is not enabled or violates an operational constraint. */ - case ALT_E_BAD_CLK: - eno = ETIME; /* Timer expired */ - break; - - /*! The buffer does not contain enough free space for the operation. */ - case ALT_E_BUF_OVF: - eno = ENOMEM; /* Not enough core */ - break; - default: - - /* Unknown case. Implement it! */ - assert( 0 == 1 ); - eno = EIO; - break; - } - - return eno; -} - -/** @brief PHY check chip ID - * - * Check the chip-ID of the KSZ8842 ethernet PHY. - * @param context Address of the network context - * @retval 0 if chip could be identified, error code from errno.h otherwise. - */ -static int network_if_phy_check_chip_id( network_if_context *context ) -{ - int eno; - uint16_t reg; - - eno = dwmac_if_read_from_phy( - context->driver_context, - 2, - ® - ); - - if ( eno == 0 ) { - if ( reg != 0x0022 ) { /* PHY ID part 1 */ - eno = ENXIO; - } else { - eno = dwmac_if_read_from_phy( - context->driver_context, - 3, - ® - ); - - if ( eno == 0 ) { - /* PHY ID part 2 and - * Manufacturers model number */ - if ( ( ( reg & 0xFC00 ) >> 10 ) != 0x0005 ) { - eno = ENXIO; - } else if ( ( ( reg & 0x03F0 ) >> 4 ) != 0x0021 ) { - eno = ENXIO; - } - } - } - } - - return eno; -} - -/****************************************************************************** -* Callback Methods -******************************************************************************/ - -/** @brief NIC enable - * - * Enables (powers up) the network interface card. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_nic_enable( void *arg ) -{ - int eno = 0; - network_if_context *context = (network_if_context *) arg; - ALT_CLK_t module_clk = ALT_CLK_EMAC0; - uint32_t permodrst_clr_msk = ALT_RSTMGR_PERMODRST_EMAC0_CLR_MSK; - - switch ( context->nic_id ) { - case NETWORK_IF_NIC_ID_EMAC0: - { - module_clk = ALT_CLK_EMAC0; - permodrst_clr_msk = ALT_RSTMGR_PERMODRST_EMAC0_CLR_MSK; - } - break; - case NETWORK_IF_NIC_ID_EMAC1: - { - module_clk = ALT_CLK_EMAC1; - permodrst_clr_msk = ALT_RSTMGR_PERMODRST_EMAC1_CLR_MSK; - } - break; - - case NETWORK_IF_NIC_ID_COUNT: - - /* Invalid case */ - eno = ENODEV; - break; - default: - - /* Unknown case */ - eno = ENOTSUP; - break; - } - - /* Pin mux configuration is handled by the Preloader. Thus no - * pin mux configuration here. */ - - /* Enable the clock for the EMAC module */ - if ( eno == 0 ) { - if ( ALT_E_FALSE == alt_clk_is_enabled( module_clk ) ) { - ALT_STATUS_CODE status = alt_clk_clock_enable( module_clk ); - eno = network_if_altera_status_code_to_errno( status ); - } - } - - /* Finish reset for the EMAC module */ - if ( eno == 0 ) { - uint32_t reg = alt_read_word( ALT_RSTMGR_PERMODRST_ADDR ); - alt_write_word( ALT_RSTMGR_PERMODRST_ADDR, reg & permodrst_clr_msk ); - } - - return eno; -} - -/** @brief NIC disable. - * - * Disables (powers down) the network interface card. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_nic_disable( void *arg ) -{ - int eno = 0; - network_if_context *context = (network_if_context *) arg; - ALT_CLK_t module_clk = ALT_CLK_EMAC0; - uint32_t permodrst_set_msk = ALT_RSTMGR_PERMODRST_EMAC0_SET_MSK; - - switch ( context->nic_id ) { - case NETWORK_IF_NIC_ID_EMAC0: - module_clk = ALT_CLK_EMAC0; - permodrst_set_msk = ALT_RSTMGR_PERMODRST_EMAC0_SET_MSK; - break; - case NETWORK_IF_NIC_ID_EMAC1: - module_clk = ALT_CLK_EMAC1; - permodrst_set_msk = ALT_RSTMGR_PERMODRST_EMAC1_SET_MSK; - break; - - case NETWORK_IF_NIC_ID_COUNT: - - /* Invalid case */ - eno = ENODEV; - break; - default: - - /* Unknown case */ - eno = ENOTSUP; - break; - } - - /* Enter rest status for the EMAC module */ - if ( eno == 0 ) { - uint32_t reg = alt_read_word( ALT_RSTMGR_PERMODRST_ADDR ); - alt_write_word( ALT_RSTMGR_PERMODRST_ADDR, reg | permodrst_set_msk ); - } - - /* Disable the clock for the EMAC module */ - if ( eno == 0 ) { - if ( ALT_E_TRUE == alt_clk_is_enabled( module_clk ) ) { - ALT_STATUS_CODE status = alt_clk_clock_disable( module_clk ); - eno = network_if_altera_status_code_to_errno( status ); - } - } - - return eno; -} - -/** @brief PHY disable. - * - * Disables (powers down) the network PHY. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_disable( void *arg ) -{ - int eno = 0; - network_if_context *self = (network_if_context *) arg; - uint32_t mask; - ALT_STATUS_CODE status_code; - - /* The power pin of the PHY is hard wire to board power control and - * the PHY supports interrupts, This means we can not power it down - * and we don't need to stop a timer for polling PHY events. */ - - status_code = alt_gpio_port_int_mask_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - - if ( eno == 0 ) { - mask = alt_gpio_port_int_enable_get( ALT_GPIO_PORTB ); - status_code = alt_gpio_port_int_enable( - ALT_GPIO_PORTB, - mask & ~NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - status_code = alt_gpio_port_int_status_clear( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - self->phy.status = NETWORK_IF_PHY_STATUS_OFF; - } - - return eno; -} - -/** @brief PHY enable. - * - * Enables (powers up) the network PHY. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_enable( void *arg ) -{ - int eno = 0; - network_if_context *self = (network_if_context *) arg; - ALT_STATUS_CODE status_code; - - /* The power pin of the PHY is hard wire to board power control and - * the PHY supports interrupts, This means we can not power it up - * and we don't need to start a timer for polling PHY events. */ - - eno = network_if_phy_check_chip_id( self ); - - if ( eno == 0 ) { - /* The phy is already enabled and we will reset it */ - eno = network_if_phy_disable( self ); - - if ( eno == 0 ) { - rtems_task_wake_after( rtems_clock_get_ticks_per_second() / 100 ); - } - } else { - eno = 0; - } - - status_code = alt_gpio_port_datadir_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - 0 - ); - eno = network_if_altera_status_code_to_errno( status_code ); - - if ( eno == 0 ) { - status_code = alt_gpio_port_int_type_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - 0 - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - status_code = alt_gpio_port_int_pol_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - 1 - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - status_code = alt_gpio_port_debounce_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - 0 - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - status_code = alt_gpio_port_int_enable( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - status_code = alt_gpio_port_int_mask_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - 0 - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - status_code = alt_gpio_port_int_status_clear( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - if ( eno == 0 ) { - self->phy.status = NETWORK_IF_PHY_STATUS_STOPPED; - } - - return eno; -} - -/** @brief Clear phy event status. - * - * Clears all PHY event statuses. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_event_status_clear( void *arg ) -{ - int eno; - ALT_STATUS_CODE status_code; - - (void) arg; - - /* Clear the interrupt status */ - status_code = alt_gpio_port_int_status_clear( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - - if ( eno == 0 ) { - /* Unmask the interrupt (was masked within interrupt handler) */ - status_code = alt_gpio_port_int_mask_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - 0 - ); - eno = network_if_altera_status_code_to_errno( status_code ); - } - - return eno; -} - -/** - * @brief Get the PHY event status. - * - * Reports status on PHY events (e.g. PHY interrupts). - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @param[out] event_set Pointer to a buffer for a set of events for which a - * PHY status change was detected. - * For events see @see dwmac_phy_event. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_events_status_get( - void *arg, - dwmac_phy_event *event_set ) -{ - int eno = 0; - uint16_t reg = 0; - network_if_context *self = (network_if_context *) arg; - - eno = dwmac_if_read_from_phy( - self->driver_context, - 0x1B, - ® - ); - - if ( eno == 0 ) { - if ( ( reg & 0x80 ) != 0 ) { - *event_set |= PHY_EVENT_JABBER; - } - - if ( ( reg & 0x40 ) != 0 ) { - *event_set |= PHY_EVENT_RECEIVE_ERROR; - } - - if ( ( reg & 0x20 ) != 0 ) { - *event_set |= PHY_EVENT_PAGE_RECEIVE; - } - - if ( ( reg & 0x10 ) != 0 ) { - *event_set |= PHY_EVENT_PARALLEL_DETECT_FAULT; - } - - if ( ( reg & 0x08 ) != 0 ) { - *event_set |= PHY_EVENT_LINK_PARTNER_ACK; - } - - if ( ( reg & 0x04 ) != 0 ) { - *event_set |= PHY_EVENT_LINK_DOWN; - } - - if ( ( reg & 0x02 ) != 0 ) { - *event_set |= PHY_EVENT_REMOTE_FAULT; - } - - if ( ( reg & 0x01 ) != 0 ) { - *event_set |= PHY_EVENT_LINK_UP; - } - } - - return eno; -} - -/** @brief Network PHY interrupt handler - * - * Handling method for interrupts from the PHY. - * @param arg Address of the network interface context - */ -static void network_if_phy_interrupt_handler( void *arg ) -{ - int eno = 0; - network_if_context *self = (network_if_context *) arg; - uint32_t reg; - - reg = alt_gpio_port_int_status_get( ALT_GPIO_PORTB ); - - if ( reg & NETWORK_PIN_MASK_PHY_INTERRUPT ) { - /* We have a level interrupt and we expect the driver to do - * the actual interrupt handling from within a task context. - * Thus we have to mask the interrupt. A call to - * network_if_phy_event_status_clear() will unmask it */ - ALT_STATUS_CODE status_code = alt_gpio_port_int_mask_set( - ALT_GPIO_PORTB, - NETWORK_PIN_MASK_PHY_INTERRUPT, - NETWORK_PIN_MASK_PHY_INTERRUPT - ); - eno = network_if_altera_status_code_to_errno( status_code ); - - if ( eno == 0 ) { - eno = dwmac_if_handle_phy_event( - self->driver_context - ); - } - } - - assert( eno == 0 ); -} - -/** @brief PHY event enable. - * - * Enables generation of events for an event set. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @param[in] event_set Set of events. For these events shall get generated - * upon PHY status change. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_event_enable( - void *arg, - const dwmac_phy_event event_set ) -{ - int eno = 0; - uint16_t reg = 0; - network_if_context *self = (network_if_context *) arg; - network_if_phy_status old_status = self->phy.status; - - if ( arg != NULL ) { - switch ( self->phy.status ) { - case NETWORK_IF_PHY_STATUS_OFF: - break; - case NETWORK_IF_PHY_STATUS_STOPPED: - break; - case NETWORK_IF_PHY_STATUS_STARTED: - { - eno = dwmac_if_read_from_phy( - self->driver_context, - 0x1B, - ® - ); - - if ( eno == 0 ) { - /* Disable all interrupts, but leave interrupt status - * bits untouched */ - reg &= 0x00FF; - eno = dwmac_if_write_to_phy( - self->driver_context, - 0x1B, - reg - ); - } - - if ( eno == 0 ) { - self->phy.irq_mask = 0; - self->phy.status = NETWORK_IF_PHY_STATUS_STOPPED; - } - } - break; - case NETWORK_IF_PHY_STATUS_COUNT: - { - /* Invalid case */ - assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT ); - eno = ENOTSUP; - } - break; - default: - { - /* Unknown case */ - assert( - self->phy.status == NETWORK_IF_PHY_STATUS_OFF - || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED - || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED - ); - eno = ENOTSUP; - } - break; - } - - if ( eno == 0 ) { - /* Select interrupts to enable */ - if ( ( event_set & PHY_EVENT_JABBER ) != 0 ) { - reg |= 0x8000; - } - - if ( ( event_set & PHY_EVENT_RECEIVE_ERROR ) != 0 ) { - reg |= 0x4000; - } - - if ( ( event_set & PHY_EVENT_PAGE_RECEIVE ) != 0 ) { - reg |= 0x2000; - } - - if ( ( event_set & PHY_EVENT_PARALLEL_DETECT_FAULT ) != 0 ) { - reg |= 0x1000; - } - - if ( ( event_set & PHY_EVENT_LINK_PARTNER_ACK ) != 0 ) { - reg |= 0x0800; - } - - if ( ( event_set & PHY_EVENT_LINK_DOWN ) != 0 ) { - reg |= 0x0400; - } - - if ( ( event_set & PHY_EVENT_REMOTE_FAULT ) != 0 ) { - reg |= 0x0200; - } - - if ( ( event_set & PHY_EVENT_LINK_UP ) != 0 ) { - reg |= 0x100; - } - - switch ( old_status ) { - case NETWORK_IF_PHY_STATUS_OFF: - break; - case NETWORK_IF_PHY_STATUS_STOPPED: - break; - case NETWORK_IF_PHY_STATUS_STARTED: - { - if ( eno == 0 ) { - /* Modify interrupt enable bits, but leave - * interrupt status bits untouched */ - eno = dwmac_if_write_to_phy( - self->driver_context, - 0x1B, - reg & 0xFF00 - ); - } - } - break; - case NETWORK_IF_PHY_STATUS_COUNT: - { - /* Invalid case */ - assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT ); - eno = ENOTSUP; - } - break; - default: - { - /* Unknown case */ - assert( - self->phy.status == NETWORK_IF_PHY_STATUS_OFF - || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED - || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED - ); - eno = ENOTSUP; - } - break; - } - - if ( eno == 0 ) { - self->phy.irq_mask = reg & 0xFF00; - } - } - } - - return eno; -} - -/** - * @brief Stop the network PHY. - * - * Do anything necessary to stop the network PHY (stop generating events, ...). - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_stop( void *arg ) -{ - int eno = 0; - rtems_status_code sc = RTEMS_SUCCESSFUL; - network_if_context *self = (network_if_context *) arg; - - switch ( self->phy.status ) { - case NETWORK_IF_PHY_STATUS_OFF: - break; - case NETWORK_IF_PHY_STATUS_STOPPED: - break; - case NETWORK_IF_PHY_STATUS_STARTED: - { - /* Remove any selected interrupts */ - eno = dwmac_if_write_to_phy( - self->driver_context, - 0x1B, - 0 - ); - - if ( eno == 0 ) { - uint16_t reg; - - /* Clear interrupt status bits by reading them */ - eno = dwmac_if_read_from_phy( - self->driver_context, - 0x1B, - ® - ); - } - - if ( eno == 0 ) { - self->phy.irq_mask = 0; - - /* Remove interrupt handler */ - sc = rtems_interrupt_handler_remove( - ALT_INT_INTERRUPT_GPIO1, - network_if_phy_interrupt_handler, - self - ); - eno = rtems_status_code_to_errno( sc ); - - if ( eno == 0 ) { - self->phy.status = NETWORK_IF_PHY_STATUS_STOPPED; - } - } - } - break; - case NETWORK_IF_PHY_STATUS_COUNT: - { - /* Invalid case */ - assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT ); - eno = ENOTSUP; - } - break; - default: - { - /* Unknown case */ - assert( - self->phy.status == NETWORK_IF_PHY_STATUS_OFF - || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED - || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED - ); - eno = ENOTSUP; - } - break; - } - - return eno; -} - -/** - * @brief Start the network PHY. - * - * Do anything necessary to start the network PHY (start generating - * events, ...). - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_phy_start( void *arg ) -{ - int eno = 0; - rtems_status_code sc = RTEMS_SUCCESSFUL; - network_if_context *self = (network_if_context *) arg; - - switch ( self->phy.status ) { - case NETWORK_IF_PHY_STATUS_OFF: - { - assert( self->phy.status != NETWORK_IF_PHY_STATUS_OFF ); - eno = EHOSTDOWN; - } - break; - case NETWORK_IF_PHY_STATUS_STOPPED: - - /* Disable all interrupts */ - eno = dwmac_if_write_to_phy( - self->driver_context, - 0x1B, - 0 - ); - - if ( eno == 0 ) { - } - - if ( eno == 0 ) { - /* Install interrupt handler */ - sc = rtems_interrupt_handler_install( - ALT_INT_INTERRUPT_GPIO1, - NULL, - RTEMS_INTERRUPT_SHARED, - network_if_phy_interrupt_handler, - self - ); - eno = rtems_status_code_to_errno( sc ); - } - - if ( eno == 0 ) { - /* Enable interrupts */ - eno = dwmac_if_write_to_phy( - self->driver_context, - 0x1B, - self->phy.irq_mask - ); - } - - break; - case NETWORK_IF_PHY_STATUS_STARTED: - { - uint16_t irq_mask = self->phy.irq_mask; - - /* Re-start the phy */ - eno = network_if_phy_stop( self ); - - if ( eno == 0 ) { - self->phy.irq_mask = irq_mask; - - eno = network_if_phy_start( - self - ); - } - } - break; - - case NETWORK_IF_PHY_STATUS_COUNT: - { - /* Invalid case */ - assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT ); - eno = ENOTSUP; - } - break; - default: - { - /* Unknown case */ - assert( - self->phy.status == NETWORK_IF_PHY_STATUS_OFF - || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED - || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED - ); - eno = ENOTSUP; - } - break; - } - - if ( eno == 0 ) { - self->phy.status = NETWORK_IF_PHY_STATUS_STARTED; - } - - return eno; -} - -/** - * @brief Allocate nocache RAM. - * - * Allocate uncached RAM. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @param[out] memory Pointer of a buffer to write the address of the - * allocated memory to. - * @param[in] size Number of bytes to be allocated - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_mem_alloc_nocache( - void *arg, - void **memory, - const size_t size ) -{ - int eno = EINVAL; - - (void) arg; - - assert( memory != NULL ); - - if ( memory != NULL ) { - *memory = rtems_cache_coherent_allocate( size, 0, 0 ); - - if ( *memory != NULL ) { - eno = 0; - } else { - eno = ENOMEM; - } - } - - return eno; -} - -/** - * @brief Free nocache RAM. - * - * Release uncached RAM. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @param[in] memory Pointer to the memory to be freed. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_mem_free_nocache( - void *arg, - void *memory ) -{ - (void) arg; - - rtems_cache_coherent_free( memory ); - - return 0; -} - -/** - * @brief Bus setup. - * - * Callback method for setting up the system bus for the network driver. - * @param[in] arg The void pointer argument passed to - * dwmac_network_if_attach_detach. - * @retval 0 on success, error code from errno.h on failure. - */ -static int network_if_bus_setup( void *arg ) -{ - volatile uint32_t reg = alt_read_word( ALT_SYSMGR_EMAC_L3MST_ADDR ); - - (void) arg; - - reg &= ALT_SYSMGR_EMAC_L3MST_AWCACHE_1_CLR_MSK; - reg &= ALT_SYSMGR_EMAC_L3MST_ARCACHE_1_CLR_MSK; - reg |= ALT_SYSMGR_EMAC_L3MST_AWCACHE_1_SET( - ALT_SYSMGR_EMAC_L3MST_AWCACHE_1_E_CACHE_WRBACK_ALLOC - ); - reg |= ALT_SYSMGR_EMAC_L3MST_ARCACHE_1_SET( - ALT_SYSMGR_EMAC_L3MST_ARCACHE_1_E_CACHE_WRBACK_ALLOC - ); - - alt_write_word( ALT_SYSMGR_EMAC_L3MST_ADDR, reg ); - - return 0; -} - -/***************************************************************************** -* Context Data -******************************************************************************/ - -/** @brief Network interface context */ -static network_if_context context = NETWORK_IF_CONTEXT_INITIALIZER( - - /** @brief Use EMAC1 */ - NETWORK_IF_NIC_ID_EMAC1, - - /** @brief Address of driver context - * - * To be assigned with return value of dwmac_network_if_attach_detach */ - NULL - ); - -/** @brief Network driver DMA configuration data */ -static const dwmac_dma_cfg NETWORK_DMA_CFG = DWMAC_DMA_CFG_INITIALIZER( - - /** @brief Bus mode burst length */ - DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_64, - - /** @brief Bus mode fixed burst? */ - DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_SINGLE_OR_INCR, - - /** @brief Bus mode mixed burst? */ - DWMAC_DMA_CFG_BUS_MODE_BURST_NOT_MIXED, - - /** @brief Permit AXI burst length of 4 */ - DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_NOT_SUPPORTED, - - /** @brief Permit AXI burst length of 8 */ - DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_NOT_SUPPORTED, - - /** @brief Permit AXI burst length of 16 */ - DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_NOT_SUPPORTED, - - /** @brief Select boundary crossing mode */ - DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_4_KB - ); - -/** @brief Network driver configuration data */ -static const dwmac_cfg NETWORK_DRIVER_CFG = DWMAC_CFG_INITIALIZER( - - /** @brief GMII clock rate */ - 75000000, - - /** @brief Address of the GMAC registers for emac1 */ - ALT_EMAC1_GMACGRP_ADDR, - - /** @brief Address of the DMA registers for emac1 */ - ALT_EMAC1_DMAGRP_ADDR, - - /** @brief Address of the PHY on the mdio bus */ - 4, - - /** @brief Bytes per L1 cache line */ - 32, - - /** @brief Interrupt number for the EMAC */ - ALT_INT_INTERRUPT_EMAC1_IRQ, - - /** @brief DMA configuration */ - &NETWORK_DMA_CFG, - - /** @brief Callback method for enabling the network controller */ - network_if_nic_enable, - - /** @brief Callback method for disabling the network controller */ - network_if_nic_disable, - - /** @brief Callback method for enabling the PHY */ - network_if_phy_enable, - - /** @brief Callback method for disabling the PHY */ - network_if_phy_disable, - - /** @brief Callback which enables PHY events for forwarding to driver */ - network_if_phy_event_enable, - - /** @brief Callback method for clearing PHY interrupt status */ - network_if_phy_event_status_clear, - - /** @brief Callback method for getting a set of events from the PHY */ - network_if_phy_events_status_get, - - /** @brief Callback method for making the PHY start forwarding events */ - network_if_phy_start, - - /** @brief Callback method for making the PHY stop forwarding events */ - network_if_phy_stop, - - /** @brief Callback method for allocating uncached memory */ - network_if_mem_alloc_nocache, - - /** @brief Callback method for freeing uncached memory */ - network_if_mem_free_nocache, - - /** @brief Callback method for setting up bus upon driver startup */ - network_if_bus_setup, - - /** @brief Operations for the ethernet mac 1000 */ - &DWMAC_1000_ETHERNET_MAC_OPS, - - /** @brief Operations for the enhanced DMA descriptors */ - &DWMAC_DESCRIPTOR_OPS_ENHANCED - ); - -/****************************************************************************** -* API -******************************************************************************/ - -/** @brief Network interface attach/detach - * - * The standard attach/detach method for network interfaces. - * This methods will call the DWMAC 1000 attach/detach method and pass - * configuration data and callback methods into it. Via these the general - * DWMAC 1000 driver is able the handle micro controller specific things. - * NOTE: Detaching is NOT supported! - * @param config Configuration parameters from and for the BSD network - * stack. - * @param attaching True if attaching the driver to the network stack, false if - * detaching. - * @retval 0 if successful, error code from errno.h if not. - */ -int altera_cyclone_v_network_if_attach_detach( - struct rtems_bsdnet_ifconfig *config, - int attaching ) -{ - int eno = 0; - - assert( config != NULL ); - - /* Network controller initialization */ - context.driver_context = dwmac_network_if_attach_detach( - config, - &NETWORK_DRIVER_CFG, - &context, - attaching - ); - - if ( context.driver_context == NULL ) { - eno = EFAULT; - } - - return eno; -} - -#endif /* defined(RTEMS_NETWORKING) */ |