numam-dpdk/drivers/net/pfe/pfe_hal.c
Gagandeep Singh 5253fe372e net/pfe: add MAC and host interface initialisation
HIF or host interface is responsible for transmit
and receive packets between physical ethernet
interfaces and HIF library defined logical interfaces.

This patch initialise that host interface and MAC.

Signed-off-by: Gagandeep Singh <g.singh@nxp.com>
Signed-off-by: Akhil Goyal <akhil.goyal@nxp.com>
Acked-by: Nipun Gupta <nipun.gupta@nxp.com>
2019-10-23 16:43:08 +02:00

630 lines
16 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2019 NXP
*/
#include "pfe_logs.h"
#include "pfe_mod.h"
#define PFE_MTU_RESET_MASK 0xC000FFFF
void *cbus_base_addr;
void *ddr_base_addr;
unsigned long ddr_phys_base_addr;
unsigned int ddr_size;
static struct pe_info pe[MAX_PE];
/* Initializes the PFE library.
* Must be called before using any of the library functions.
*
* @param[in] cbus_base CBUS virtual base address (as mapped in
* the host CPU address space)
* @param[in] ddr_base PFE DDR range virtual base address (as
* mapped in the host CPU address space)
* @param[in] ddr_phys_base PFE DDR range physical base address (as
* mapped in platform)
* @param[in] size PFE DDR range size (as defined by the host
* software)
*/
void
pfe_lib_init(void *cbus_base, void *ddr_base, unsigned long ddr_phys_base,
unsigned int size)
{
cbus_base_addr = cbus_base;
ddr_base_addr = ddr_base;
ddr_phys_base_addr = ddr_phys_base;
ddr_size = size;
pe[CLASS0_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(0);
pe[CLASS0_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(0);
pe[CLASS0_ID].pmem_size = CLASS_IMEM_SIZE;
pe[CLASS0_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
pe[CLASS0_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
pe[CLASS0_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
pe[CLASS1_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(1);
pe[CLASS1_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(1);
pe[CLASS1_ID].pmem_size = CLASS_IMEM_SIZE;
pe[CLASS1_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
pe[CLASS1_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
pe[CLASS1_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
pe[CLASS2_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(2);
pe[CLASS2_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(2);
pe[CLASS2_ID].pmem_size = CLASS_IMEM_SIZE;
pe[CLASS2_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
pe[CLASS2_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
pe[CLASS2_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
pe[CLASS3_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(3);
pe[CLASS3_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(3);
pe[CLASS3_ID].pmem_size = CLASS_IMEM_SIZE;
pe[CLASS3_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
pe[CLASS3_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
pe[CLASS3_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
pe[CLASS4_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(4);
pe[CLASS4_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(4);
pe[CLASS4_ID].pmem_size = CLASS_IMEM_SIZE;
pe[CLASS4_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
pe[CLASS4_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
pe[CLASS4_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
pe[CLASS5_ID].dmem_base_addr = CLASS_DMEM_BASE_ADDR(5);
pe[CLASS5_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(5);
pe[CLASS5_ID].pmem_size = CLASS_IMEM_SIZE;
pe[CLASS5_ID].mem_access_wdata = CLASS_MEM_ACCESS_WDATA;
pe[CLASS5_ID].mem_access_addr = CLASS_MEM_ACCESS_ADDR;
pe[CLASS5_ID].mem_access_rdata = CLASS_MEM_ACCESS_RDATA;
pe[TMU0_ID].dmem_base_addr = TMU_DMEM_BASE_ADDR(0);
pe[TMU0_ID].pmem_base_addr = TMU_IMEM_BASE_ADDR(0);
pe[TMU0_ID].pmem_size = TMU_IMEM_SIZE;
pe[TMU0_ID].mem_access_wdata = TMU_MEM_ACCESS_WDATA;
pe[TMU0_ID].mem_access_addr = TMU_MEM_ACCESS_ADDR;
pe[TMU0_ID].mem_access_rdata = TMU_MEM_ACCESS_RDATA;
pe[TMU1_ID].dmem_base_addr = TMU_DMEM_BASE_ADDR(1);
pe[TMU1_ID].pmem_base_addr = TMU_IMEM_BASE_ADDR(1);
pe[TMU1_ID].pmem_size = TMU_IMEM_SIZE;
pe[TMU1_ID].mem_access_wdata = TMU_MEM_ACCESS_WDATA;
pe[TMU1_ID].mem_access_addr = TMU_MEM_ACCESS_ADDR;
pe[TMU1_ID].mem_access_rdata = TMU_MEM_ACCESS_RDATA;
pe[TMU3_ID].dmem_base_addr = TMU_DMEM_BASE_ADDR(3);
pe[TMU3_ID].pmem_base_addr = TMU_IMEM_BASE_ADDR(3);
pe[TMU3_ID].pmem_size = TMU_IMEM_SIZE;
pe[TMU3_ID].mem_access_wdata = TMU_MEM_ACCESS_WDATA;
pe[TMU3_ID].mem_access_addr = TMU_MEM_ACCESS_ADDR;
pe[TMU3_ID].mem_access_rdata = TMU_MEM_ACCESS_RDATA;
#if !defined(CONFIG_FSL_PFE_UTIL_DISABLED)
pe[UTIL_ID].dmem_base_addr = UTIL_DMEM_BASE_ADDR;
pe[UTIL_ID].mem_access_wdata = UTIL_MEM_ACCESS_WDATA;
pe[UTIL_ID].mem_access_addr = UTIL_MEM_ACCESS_ADDR;
pe[UTIL_ID].mem_access_rdata = UTIL_MEM_ACCESS_RDATA;
#endif
}
/**************************** MTIP GEMAC ***************************/
/* Enable Rx Checksum Engine. With this enabled, Frame with bad IP,
* TCP or UDP checksums are discarded
*
* @param[in] base GEMAC base address.
*/
void
gemac_enable_rx_checksum_offload(__rte_unused void *base)
{
/*Do not find configuration to do this */
}
/* Disable Rx Checksum Engine.
*
* @param[in] base GEMAC base address.
*/
void
gemac_disable_rx_checksum_offload(__rte_unused void *base)
{
/*Do not find configuration to do this */
}
/* GEMAC set speed.
* @param[in] base GEMAC base address
* @param[in] speed GEMAC speed (10, 100 or 1000 Mbps)
*/
void
gemac_set_speed(void *base, enum mac_speed gem_speed)
{
u32 ecr = readl(base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_SPEED;
u32 rcr = readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_RMII_10T;
switch (gem_speed) {
case SPEED_10M:
rcr |= EMAC_RCNTRL_RMII_10T;
break;
case SPEED_1000M:
ecr |= EMAC_ECNTRL_SPEED;
break;
case SPEED_100M:
default:
/*It is in 100M mode */
break;
}
writel(ecr, (base + EMAC_ECNTRL_REG));
writel(rcr, (base + EMAC_RCNTRL_REG));
}
/* GEMAC set duplex.
* @param[in] base GEMAC base address
* @param[in] duplex GEMAC duplex mode (Full, Half)
*/
void
gemac_set_duplex(void *base, int duplex)
{
if (duplex == DUPLEX_HALF) {
writel(readl(base + EMAC_TCNTRL_REG) & ~EMAC_TCNTRL_FDEN, base
+ EMAC_TCNTRL_REG);
writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_DRT, (base
+ EMAC_RCNTRL_REG));
} else {
writel(readl(base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_FDEN, base
+ EMAC_TCNTRL_REG);
writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_DRT, (base
+ EMAC_RCNTRL_REG));
}
}
/* GEMAC set mode.
* @param[in] base GEMAC base address
* @param[in] mode GEMAC operation mode (MII, RMII, RGMII, SGMII)
*/
void
gemac_set_mode(void *base, __rte_unused int mode)
{
u32 val = readl(base + EMAC_RCNTRL_REG);
/*Remove loopbank*/
val &= ~EMAC_RCNTRL_LOOP;
/*Enable flow control and MII mode*/
val |= (EMAC_RCNTRL_FCE | EMAC_RCNTRL_MII_MODE | EMAC_RCNTRL_CRC_FWD);
writel(val, base + EMAC_RCNTRL_REG);
}
/* GEMAC enable function.
* @param[in] base GEMAC base address
*/
void
gemac_enable(void *base)
{
writel(readl(base + EMAC_ECNTRL_REG) | EMAC_ECNTRL_ETHER_EN, base +
EMAC_ECNTRL_REG);
}
/* GEMAC disable function.
* @param[in] base GEMAC base address
*/
void
gemac_disable(void *base)
{
writel(readl(base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_ETHER_EN, base +
EMAC_ECNTRL_REG);
}
/* GEMAC TX disable function.
* @param[in] base GEMAC base address
*/
void
gemac_tx_disable(void *base)
{
writel(readl(base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_GTS, base +
EMAC_TCNTRL_REG);
}
void
gemac_tx_enable(void *base)
{
writel(readl(base + EMAC_TCNTRL_REG) & ~EMAC_TCNTRL_GTS, base +
EMAC_TCNTRL_REG);
}
/* Sets the hash register of the MAC.
* This register is used for matching unicast and multicast frames.
*
* @param[in] base GEMAC base address.
* @param[in] hash 64-bit hash to be configured.
*/
void
gemac_set_hash(void *base, struct pfe_mac_addr *hash)
{
writel(hash->bottom, base + EMAC_GALR);
writel(hash->top, base + EMAC_GAUR);
}
void
gemac_set_laddrN(void *base, struct pfe_mac_addr *address,
unsigned int entry_index)
{
if (entry_index < 1 || entry_index > EMAC_SPEC_ADDR_MAX)
return;
entry_index = entry_index - 1;
if (entry_index < 1) {
writel(htonl(address->bottom), base + EMAC_PHY_ADDR_LOW);
writel((htonl(address->top) | 0x8808), base +
EMAC_PHY_ADDR_HIGH);
} else {
writel(htonl(address->bottom), base + ((entry_index - 1) * 8)
+ EMAC_SMAC_0_0);
writel((htonl(address->top) | 0x8808), base + ((entry_index -
1) * 8) + EMAC_SMAC_0_1);
}
}
void
gemac_clear_laddrN(void *base, unsigned int entry_index)
{
if (entry_index < 1 || entry_index > EMAC_SPEC_ADDR_MAX)
return;
entry_index = entry_index - 1;
if (entry_index < 1) {
writel(0, base + EMAC_PHY_ADDR_LOW);
writel(0, base + EMAC_PHY_ADDR_HIGH);
} else {
writel(0, base + ((entry_index - 1) * 8) + EMAC_SMAC_0_0);
writel(0, base + ((entry_index - 1) * 8) + EMAC_SMAC_0_1);
}
}
/* Set the loopback mode of the MAC. This can be either no loopback for
* normal operation, local loopback through MAC internal loopback module or PHY
* loopback for external loopback through a PHY. This asserts the external
* loop pin.
*
* @param[in] base GEMAC base address.
* @param[in] gem_loop Loopback mode to be enabled. LB_LOCAL - MAC
* Loopback,
* LB_EXT - PHY Loopback.
*/
void
gemac_set_loop(void *base, __rte_unused enum mac_loop gem_loop)
{
pr_info("%s()\n", __func__);
writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_LOOP, (base +
EMAC_RCNTRL_REG));
}
/* GEMAC allow frames
* @param[in] base GEMAC base address
*/
void
gemac_enable_copy_all(void *base)
{
writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_PROM, (base +
EMAC_RCNTRL_REG));
}
/* GEMAC do not allow frames
* @param[in] base GEMAC base address
*/
void
gemac_disable_copy_all(void *base)
{
writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_PROM, (base +
EMAC_RCNTRL_REG));
}
/* GEMAC allow broadcast function.
* @param[in] base GEMAC base address
*/
void
gemac_allow_broadcast(void *base)
{
writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_BC_REJ, base +
EMAC_RCNTRL_REG);
}
/* GEMAC no broadcast function.
* @param[in] base GEMAC base address
*/
void
gemac_no_broadcast(void *base)
{
writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_BC_REJ, base +
EMAC_RCNTRL_REG);
}
/* GEMAC enable 1536 rx function.
* @param[in] base GEMAC base address
*/
void
gemac_enable_1536_rx(void *base)
{
/* Set 1536 as Maximum frame length */
writel((readl(base + EMAC_RCNTRL_REG) & PFE_MTU_RESET_MASK)
| (1536 << 16),
base + EMAC_RCNTRL_REG);
}
/* GEMAC set Max rx function.
* @param[in] base GEMAC base address
*/
int
gemac_set_rx(void *base, int mtu)
{
if (mtu < HIF_RX_PKT_MIN_SIZE || mtu > JUMBO_FRAME_SIZE) {
PFE_PMD_ERR("Invalid or not support MTU size");
return -1;
}
if (pfe_svr == SVR_LS1012A_REV1 &&
mtu > (MAX_MTU_ON_REV1 + PFE_ETH_OVERHEAD)) {
PFE_PMD_ERR("Max supported MTU on Rev1 is %d", MAX_MTU_ON_REV1);
return -1;
}
writel((readl(base + EMAC_RCNTRL_REG) & PFE_MTU_RESET_MASK)
| (mtu << 16),
base + EMAC_RCNTRL_REG);
return 0;
}
/* GEMAC enable jumbo function.
* @param[in] base GEMAC base address
*/
void
gemac_enable_rx_jmb(void *base)
{
if (pfe_svr == SVR_LS1012A_REV1) {
PFE_PMD_ERR("Jumbo not supported on Rev1");
return;
}
writel((readl(base + EMAC_RCNTRL_REG) & PFE_MTU_RESET_MASK) |
(JUMBO_FRAME_SIZE << 16), base + EMAC_RCNTRL_REG);
}
/* GEMAC enable stacked vlan function.
* @param[in] base GEMAC base address
*/
void
gemac_enable_stacked_vlan(__rte_unused void *base)
{
/* MTIP doesn't support stacked vlan */
}
/* GEMAC enable pause rx function.
* @param[in] base GEMAC base address
*/
void
gemac_enable_pause_rx(void *base)
{
writel(readl(base + EMAC_RCNTRL_REG) | EMAC_RCNTRL_FCE,
base + EMAC_RCNTRL_REG);
}
/* GEMAC disable pause rx function.
* @param[in] base GEMAC base address
*/
void
gemac_disable_pause_rx(void *base)
{
writel(readl(base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_FCE,
base + EMAC_RCNTRL_REG);
}
/* GEMAC enable pause tx function.
* @param[in] base GEMAC base address
*/
void
gemac_enable_pause_tx(void *base)
{
writel(EMAC_RX_SECTION_EMPTY_V, base + EMAC_RX_SECTION_EMPTY);
}
/* GEMAC disable pause tx function.
* @param[in] base GEMAC base address
*/
void
gemac_disable_pause_tx(void *base)
{
writel(0x0, base + EMAC_RX_SECTION_EMPTY);
}
/* GEMAC wol configuration
* @param[in] base GEMAC base address
* @param[in] wol_conf WoL register configuration
*/
void
gemac_set_wol(void *base, u32 wol_conf)
{
u32 val = readl(base + EMAC_ECNTRL_REG);
if (wol_conf)
val |= (EMAC_ECNTRL_MAGIC_ENA | EMAC_ECNTRL_SLEEP);
else
val &= ~(EMAC_ECNTRL_MAGIC_ENA | EMAC_ECNTRL_SLEEP);
writel(val, base + EMAC_ECNTRL_REG);
}
/* Sets Gemac bus width to 64bit
* @param[in] base GEMAC base address
* @param[in] width gemac bus width to be set possible values are 32/64/128
*/
void
gemac_set_bus_width(__rte_unused void *base, __rte_unused int width)
{
}
/* Sets Gemac configuration.
* @param[in] base GEMAC base address
* @param[in] cfg GEMAC configuration
*/
void
gemac_set_config(void *base, struct gemac_cfg *cfg)
{
/*GEMAC config taken from VLSI */
writel(0x00000004, base + EMAC_TFWR_STR_FWD);
writel(0x00000005, base + EMAC_RX_SECTION_FULL);
if (pfe_svr == SVR_LS1012A_REV1)
writel(0x00000768, base + EMAC_TRUNC_FL);
else
writel(0x00003fff, base + EMAC_TRUNC_FL);
writel(0x00000030, base + EMAC_TX_SECTION_EMPTY);
writel(0x00000000, base + EMAC_MIB_CTRL_STS_REG);
gemac_set_mode(base, cfg->mode);
gemac_set_speed(base, cfg->speed);
gemac_set_duplex(base, cfg->duplex);
}
/**************************** GPI ***************************/
/* Initializes a GPI block.
* @param[in] base GPI base address
* @param[in] cfg GPI configuration
*/
void
gpi_init(void *base, struct gpi_cfg *cfg)
{
gpi_reset(base);
gpi_disable(base);
gpi_set_config(base, cfg);
}
/* Resets a GPI block.
* @param[in] base GPI base address
*/
void
gpi_reset(void *base)
{
writel(CORE_SW_RESET, base + GPI_CTRL);
}
/* Enables a GPI block.
* @param[in] base GPI base address
*/
void
gpi_enable(void *base)
{
writel(CORE_ENABLE, base + GPI_CTRL);
}
/* Disables a GPI block.
* @param[in] base GPI base address
*/
void
gpi_disable(void *base)
{
writel(CORE_DISABLE, base + GPI_CTRL);
}
/* Sets the configuration of a GPI block.
* @param[in] base GPI base address
* @param[in] cfg GPI configuration
*/
void
gpi_set_config(void *base, struct gpi_cfg *cfg)
{
writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_ALLOC_CTRL), base
+ GPI_LMEM_ALLOC_ADDR);
writel(CBUS_VIRT_TO_PFE(BMU1_BASE_ADDR + BMU_FREE_CTRL), base
+ GPI_LMEM_FREE_ADDR);
writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_ALLOC_CTRL), base
+ GPI_DDR_ALLOC_ADDR);
writel(CBUS_VIRT_TO_PFE(BMU2_BASE_ADDR + BMU_FREE_CTRL), base
+ GPI_DDR_FREE_ADDR);
writel(CBUS_VIRT_TO_PFE(CLASS_INQ_PKTPTR), base + GPI_CLASS_ADDR);
writel(DDR_HDR_SIZE, base + GPI_DDR_DATA_OFFSET);
writel(LMEM_HDR_SIZE, base + GPI_LMEM_DATA_OFFSET);
writel(0, base + GPI_LMEM_SEC_BUF_DATA_OFFSET);
writel(0, base + GPI_DDR_SEC_BUF_DATA_OFFSET);
writel((DDR_HDR_SIZE << 16) | LMEM_HDR_SIZE, base + GPI_HDR_SIZE);
writel((DDR_BUF_SIZE << 16) | LMEM_BUF_SIZE, base + GPI_BUF_SIZE);
writel(((cfg->lmem_rtry_cnt << 16) | (GPI_DDR_BUF_EN << 1) |
GPI_LMEM_BUF_EN), base + GPI_RX_CONFIG);
writel(cfg->tmlf_txthres, base + GPI_TMLF_TX);
writel(cfg->aseq_len, base + GPI_DTX_ASEQ);
writel(1, base + GPI_TOE_CHKSUM_EN);
if (cfg->mtip_pause_reg) {
writel(cfg->mtip_pause_reg, base + GPI_CSR_MTIP_PAUSE_REG);
writel(EGPI_PAUSE_TIME, base + GPI_TX_PAUSE_TIME);
}
}
/**************************** HIF ***************************/
/* Initializes HIF copy block.
*
*/
void
hif_init(void)
{
/*Initialize HIF registers*/
writel((HIF_RX_POLL_CTRL_CYCLE << 16) | HIF_TX_POLL_CTRL_CYCLE,
HIF_POLL_CTRL);
}
/* Enable hif tx DMA and interrupt
*
*/
void
hif_tx_enable(void)
{
writel(HIF_CTRL_DMA_EN, HIF_TX_CTRL);
writel((readl(HIF_INT_ENABLE) | HIF_INT_EN | HIF_TXPKT_INT_EN),
HIF_INT_ENABLE);
}
/* Disable hif tx DMA and interrupt
*
*/
void
hif_tx_disable(void)
{
u32 hif_int;
writel(0, HIF_TX_CTRL);
hif_int = readl(HIF_INT_ENABLE);
hif_int &= HIF_TXPKT_INT_EN;
writel(hif_int, HIF_INT_ENABLE);
}
/* Enable hif rx DMA and interrupt
*
*/
void
hif_rx_enable(void)
{
hif_rx_dma_start();
writel((readl(HIF_INT_ENABLE) | HIF_INT_EN | HIF_RXPKT_INT_EN),
HIF_INT_ENABLE);
}
/* Disable hif rx DMA and interrupt
*
*/
void
hif_rx_disable(void)
{
u32 hif_int;
writel(0, HIF_RX_CTRL);
hif_int = readl(HIF_INT_ENABLE);
hif_int &= HIF_RXPKT_INT_EN;
writel(hif_int, HIF_INT_ENABLE);
}