/**
* @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,
};