diff options
Diffstat (limited to 'c/src/libchip/network/dwmac-1000-dma.c')
-rw-r--r-- | c/src/libchip/network/dwmac-1000-dma.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/c/src/libchip/network/dwmac-1000-dma.c b/c/src/libchip/network/dwmac-1000-dma.c new file mode 100644 index 0000000000..32e5914f08 --- /dev/null +++ b/c/src/libchip/network/dwmac-1000-dma.c @@ -0,0 +1,244 @@ +/** + * @file + * + * @brief DWMAC 1000 on-chip Ethernet controllers DMA handling + * + * Functions and data which are specific to the DWMAC 1000 DMA Handling. + */ + +/* + * 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 <errno.h> +#include "dwmac-core.h" +#include "dwmac-common.h" + +typedef enum { + DWMAC100_OPERATION_MODE_TTC_CONTROL_64 = 0x00000000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_128 = 0x00004000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_192 = 0x00008000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_256 = 0x0000c000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_40 = 0x00010000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_32 = 0x00014000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_24 = 0x00018000, + DWMAC100_OPERATION_MODE_TTC_CONTROL_16 = 0x0001c000, +} dwmac1000_operation_mode_ttc_control; + +typedef enum { + DWMAC100_OPERATION_MODE_RTC_CONTROL_64 = 0x00000000, + DWMAC100_OPERATION_MODE_RTC_CONTROL_32 = 0x00000008, + DWMAC100_OPERATION_MODE_RTC_CONTROL_96 = 0x00000010, + DWMAC100_OPERATION_MODE_RTC_CONTROL_128 = 0x00000018, +} dwmac1000_operation_mode_rtc_control; + +static int dwmac1000_dma_init( + dwmac_common_context *self, + const uint32_t pbl, + const uint32_t fb, + const uint32_t mb, + const bool use_enhanced_desc, + const uint32_t burst_len_4_support, + const uint32_t burst_len_8_support, + const uint32_t burst_len_16_support, + const uint32_t burst_boundary, + volatile dwmac_desc *dma_tx, + volatile dwmac_desc *dma_rx ) +{ + int eno = 0; + uint32_t value = self->dmagrp->bus_mode; + int limit = 10; + + + /* DMA SW reset */ + value |= DMAGRP_BUS_MODE_SWR; + self->dmagrp->bus_mode = value; + + while ( limit-- ) { + if ( !( self->dmagrp->bus_mode & DMAGRP_BUS_MODE_SWR ) ) + break; + + rtems_task_wake_after( rtems_clock_get_ticks_per_second() / 100 ); + } + + if ( limit < 0 ) { + eno = EBUSY; + } else { + /* + * Set the DMA PBL (Programmable Burst Length) mode + */ + if ( pbl >= DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_8 ) { + value = + DMAGRP_BUS_MODE_PBL( ( pbl + 1 ) / 8 ) | DMAGRP_BUS_MODE_RPBL( + ( pbl + 1 ) / 8 ) | DMAGRP_BUS_MODE_EIGHTXPBL; + } else { + value = DMAGRP_BUS_MODE_PBL( pbl + 1 ) | DMAGRP_BUS_MODE_RPBL( pbl + 1 ); + } + + /* Set the Fixed burst mode */ + if ( fb ) { + value |= DMAGRP_BUS_MODE_FB; + } + + /* Mixed Burst has no effect when fb is set */ + if ( mb ) { + value |= DMAGRP_BUS_MODE_MB; + } + + if ( use_enhanced_desc ) { + value |= DMAGRP_BUS_MODE_ATDS; + } + + self->dmagrp->bus_mode = value; + + /* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE + * for supported bursts. + * + * Note: This is applicable only for revision GMACv3.61a. For + * older version this register is reserved and shall have no + * effect. + * + * Note: + * For Fixed Burst Mode: if we directly write 0xFF to this + * register using the configurations pass from platform code, + * this would ensure that all bursts supported by core are set + * and those which are not supported would remain ineffective. + * + * For Non Fixed Burst Mode: provide the maximum value of the + * burst length. Any burst equal or below the provided burst + * length would be allowed to perform. */ + value = self->dmagrp->axi_bus_mode; + + if ( burst_len_4_support ) { + value |= DMAGRP_AXI_BUS_MODE_BLEND4; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_BLEND4; + } + + if ( burst_len_8_support ) { + value |= DMAGRP_AXI_BUS_MODE_BLEND8; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_BLEND8; + } + + if ( burst_len_16_support ) { + value |= DMAGRP_AXI_BUS_MODE_BLEND16; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_BLEND16; + } + + if ( burst_boundary ) { + value |= DMAGRP_AXI_BUS_MODE_ONEKBBE; + } else { + value &= ~DMAGRP_AXI_BUS_MODE_ONEKBBE; + } + + self->dmagrp->axi_bus_mode = value; + + /* Mask interrupts by writing to CSR7 */ + dwmac_core_enable_dma_irq_rx( self ); + dwmac_core_enable_dma_irq_tx( self ); + + /* The base address of the RX/TX descriptor lists must be written into + * DMA CSR3 and CSR4, respectively. */ + self->dmagrp->transmit_descr_list_addr = (uintptr_t) &dma_tx[0]; + self->dmagrp->receive_descr_list_addr = (uintptr_t) &dma_rx[0]; + } + + return eno; +} + +static void dwmac1000_dma_operation_mode( + dwmac_common_context *self, + const unsigned int txmode, + const unsigned int rxmode ) +{ + uint32_t value = self->dmagrp->operation_mode; + + + if ( txmode == DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD ) { + /* Transmit COE type 2 cannot be done in cut-through mode. */ + value |= DMAGRP_OPERATION_MODE_TSF; + + /* Operating on second frame increase the performance + * especially when transmit store-and-forward is used.*/ + value |= DMAGRP_OPERATION_MODE_OSF; + } else { + value &= ~DMAGRP_OPERATION_MODE_TSF; + value &= ~DMAGRP_OPERATION_MODE_TTC_GET( value ); + + /* Set the transmit threshold */ + if ( txmode <= 32 ) { + value |= DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_32 + ); + } else if ( txmode <= 64 ) { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_64 + ); + } else if ( txmode <= 128 ) { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_128 + ); + } else if ( txmode <= 192 ) { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_192 + ); + } else { + value = DMAGRP_OPERATION_MODE_TTC_SET( + value, + DWMAC100_OPERATION_MODE_TTC_CONTROL_256 + ); + } + } + + if ( rxmode == DWMAC_COMMON_DMA_MODE_STORE_AND_FORWARD ) { + value |= DMAGRP_OPERATION_MODE_RSF; + } else { + value &= ~DMAGRP_OPERATION_MODE_RSF; + value &= DMAGRP_OPERATION_MODE_RTC_GET( value ); + + if ( rxmode <= 32 ) { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_32 + ); + } else if ( rxmode <= 64 ) { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_64 + ); + } else if ( rxmode <= 96 ) { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_96 + ); + } else { + value = DMAGRP_OPERATION_MODE_RTC_SET( + value, + DWMAC100_OPERATION_MODE_RTC_CONTROL_128 + ); + } + } + + self->dmagrp->operation_mode = value; +} + +const dwmac_common_dma_ops dwmac_dma_ops_1000 = { + .init = dwmac1000_dma_init, + .dma_mode = dwmac1000_dma_operation_mode, +}; |