mirror of
https://github.com/plappermaul/realtek-doc.git
synced 2025-12-10 07:44:41 +01:00
Compare commits
14 commits
7342b19546
...
7eaa7a866d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7eaa7a866d | ||
|
|
e779d22744 | ||
|
|
70966621fe | ||
|
|
7784885531 | ||
|
|
a5df4c7f92 | ||
|
|
3206f0ea1b | ||
|
|
7476476f19 | ||
|
|
ffc566094b | ||
|
|
13158f996d | ||
|
|
c01cc521d4 | ||
|
|
d677b9e6c9 | ||
|
|
dc6a53c04c | ||
|
|
febe023171 | ||
|
|
9b3bf98ee9 |
680 changed files with 487130 additions and 1 deletions
13
README.md
13
README.md
|
|
@ -1,13 +1,24 @@
|
|||
This repository serves as a well selected collection of Realtek switch SoC documentation and source. Focus is on the Otto platform with the RTL838x (maple), RTL839x (cypress), RTL930x (longan) and RTL931x (mango) chips.
|
||||
|
||||
- Roadmap https://github.com/plappermaul/realtek-doc/blob/main/Roadmap.pdf
|
||||
- [Roadmap](/datasheets/Roadmap.pdf) for the Realtek switch platform
|
||||
- Additional infos can be found at https://svanheule.net/switches/start
|
||||
|
||||
What RTK (development kit) we have
|
||||
|
||||
- Some fragments from the TP-Link BE550 GPL. It has several drivers for Realtek PHYs that are mainly used on non-Realtek platforms. Download from https://www.tp-link.com/en/support/download/
|
||||
- The most recent SDK from 2022 is based on the D-Link DMS-1250 GPL source. It contains a lot of modern PHY code for RTL8218E, RTL8224, RTL8261 and RTL8264. Download from https://tsd.dlink.com.tw/GPL.asp
|
||||
- An older SDK from 2016 is based on the Zyxel XGS1210-12 GPL source. It contains code for a totally unknown RTL8284 PHY. Download can be requested from https://www.zyxel.com/global/en/form/gpl-oss-software-notice
|
||||
|
||||
PHY Direct Links
|
||||
|
||||
PHY | BE550 | DMS-1250 | XGS-1210
|
||||
--- | --- | --- | ---
|
||||
RTL8226x/RTL8221B | [U-Boot](/sources/uboot-be550/drivers/net/rtl8221b) | [RTK](/sources/rtk-dms1250/src/hal/phy) [U-Boot](/sources/uboot-xgs1210/board/Realtek/switch/sdk/src/hal/phy) | [RTK](/sources/rtk-xgs1210/src/hal/phy) [U-Boot](/sources/uboot-xgs1210/board/Realtek/switch/sdk/src/hal/phy)
|
||||
RTL8251B | [U-Boot](/sources/uboot-be550/drivers/net/rtl8251b) | - | -
|
||||
RTL8261x/RTL8264x | [U-Boot](/sources/uboot-be550/drivers/net/ipq_common) [RTK](/sources/rtk-be550/src/hal/phy) | [RTK](/sources/rtk-dms1250/src/hal/phy) |
|
||||
... | ... | ...
|
||||
|
||||
|
||||
The PDFs we have
|
||||
|
||||
- GPON/EON controller RTL9601 datasheets
|
||||
|
|
|
|||
0
sources/rtk-be550/include/empty
Normal file
0
sources/rtk-be550/include/empty
Normal file
10
sources/rtk-be550/src/hal/phy/Kconfig
Executable file
10
sources/rtk-be550/src/hal/phy/Kconfig
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
|
||||
config RTK_MSSDK_PHY
|
||||
tristate "Realtek MSSDK PHYs"
|
||||
help
|
||||
Currently supports the RTL8261N,RTL8264B PHYs.
|
||||
|
||||
25
sources/rtk-be550/src/hal/phy/Makefile
Executable file
25
sources/rtk-be550/src/hal/phy/Makefile
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
|
||||
ccflags-y := -DRTK_PHYDRV_IN_LINUX
|
||||
ccflags-y += -DDEBUG
|
||||
|
||||
obj-$(CONFIG_RTK_MSSDK_PHY) += rtk-ms-phy.o
|
||||
|
||||
rtk-ms-phy-objs := rtk_phy.o
|
||||
rtk-ms-phy-objs += rtk_osal.o
|
||||
|
||||
# files from SDK
|
||||
rtk-ms-phy-objs += phy_patch.o
|
||||
rtk-ms-phy-objs += phy_rtl826xb_patch.o
|
||||
|
||||
# rtk phylib
|
||||
rtk-ms-phy-objs += rtk_phylib.o
|
||||
rtk-ms-phy-objs += rtk_phylib_rtl826xb.o
|
||||
|
||||
ifdef CONFIG_MACSEC
|
||||
rtk-ms-phy-objs += rtk_macsec.o
|
||||
rtk-ms-phy-objs += rtk_phylib_macsec.o
|
||||
endif
|
||||
2144
sources/rtk-be550/src/hal/phy/construct/conf_rtl8261n_c.c
Executable file
2144
sources/rtk-be550/src/hal/phy/construct/conf_rtl8261n_c.c
Executable file
File diff suppressed because it is too large
Load diff
2243
sources/rtk-be550/src/hal/phy/construct/conf_rtl8261n_c_lp.c
Executable file
2243
sources/rtk-be550/src/hal/phy/construct/conf_rtl8261n_c_lp.c
Executable file
File diff suppressed because it is too large
Load diff
2331
sources/rtk-be550/src/hal/phy/construct/conf_rtl8264b.c
Executable file
2331
sources/rtk-be550/src/hal/phy/construct/conf_rtl8264b.c
Executable file
File diff suppressed because it is too large
Load diff
165
sources/rtk-be550/src/hal/phy/error.h
Executable file
165
sources/rtk-be550/src/hal/phy/error.h
Executable file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __COMMON_ERROR_H__
|
||||
#define __COMMON_ERROR_H__
|
||||
|
||||
/*
|
||||
* Include Files
|
||||
*/
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#include "type.h"
|
||||
#else
|
||||
#include <common/type.h>
|
||||
#endif
|
||||
/*
|
||||
* Data Type Declaration
|
||||
*/
|
||||
typedef enum rt_error_common_e
|
||||
{
|
||||
RT_ERR_FAILED = -1, /* General Error */
|
||||
|
||||
/* 0x0000xxxx for common error code */
|
||||
RT_ERR_OK = 0, /* 0x00000000, OK */
|
||||
RT_ERR_INPUT = 0xF001, /* 0x0000F001, invalid input parameter */
|
||||
RT_ERR_UNIT_ID, /* 0x0000F002, invalid unit id */
|
||||
RT_ERR_PORT_ID, /* 0x0000F003, invalid port id */
|
||||
RT_ERR_PORT_MASK, /* 0x0000F004, invalid port mask */
|
||||
RT_ERR_PORT_LINKDOWN, /* 0x0000F005, link down port status */
|
||||
RT_ERR_ENTRY_INDEX, /* 0x0000F006, invalid entry index */
|
||||
RT_ERR_NULL_POINTER, /* 0x0000F007, input parameter is null pointer */
|
||||
RT_ERR_QUEUE_ID, /* 0x0000F008, invalid queue id */
|
||||
RT_ERR_QUEUE_NUM, /* 0x0000F009, invalid queue number */
|
||||
RT_ERR_BUSYWAIT_TIMEOUT, /* 0x0000F00a, busy watting time out */
|
||||
RT_ERR_MAC, /* 0x0000F00b, invalid mac address */
|
||||
RT_ERR_OUT_OF_RANGE, /* 0x0000F00c, input parameter out of range */
|
||||
RT_ERR_CHIP_NOT_SUPPORTED, /* 0x0000F00d, functions not supported by this chip model */
|
||||
RT_ERR_SMI, /* 0x0000F00e, SMI error */
|
||||
RT_ERR_NOT_INIT, /* 0x0000F00f, The module is not initial */
|
||||
RT_ERR_CHIP_NOT_FOUND, /* 0x0000F010, The chip can not found */
|
||||
RT_ERR_NOT_ALLOWED, /* 0x0000F011, actions not allowed by the function */
|
||||
RT_ERR_DRIVER_NOT_FOUND, /* 0x0000F012, The driver can not found */
|
||||
RT_ERR_SEM_LOCK_FAILED, /* 0x0000F013, Failed to lock semaphore */
|
||||
RT_ERR_SEM_UNLOCK_FAILED, /* 0x0000F014, Failed to unlock semaphore */
|
||||
RT_ERR_THREAD_EXIST, /* 0x0000F015, Thread exist */
|
||||
RT_ERR_THREAD_CREATE_FAILED, /* 0x0000F016, Thread create fail */
|
||||
RT_ERR_FWD_ACTION, /* 0x0000F017, Invalid forwarding Action */
|
||||
RT_ERR_IPV4_ADDRESS, /* 0x0000F018, Invalid IPv4 address */
|
||||
RT_ERR_IPV6_ADDRESS, /* 0x0000F019, Invalid IPv6 address */
|
||||
RT_ERR_PRIORITY, /* 0x0000F01a, Invalid Priority value */
|
||||
RT_ERR_FID, /* 0x0000F01b, invalid fid */
|
||||
RT_ERR_ENTRY_NOTFOUND, /* 0x0000F01c, specified entry not found */
|
||||
RT_ERR_DROP_PRECEDENCE, /* 0x0000F01d, invalid drop precedence */
|
||||
RT_ERR_NOT_FINISH, /* 0x0000F01e, Action not finish, still need to wait */
|
||||
RT_ERR_TIMEOUT, /* 0x0000F01f, Time out */
|
||||
RT_ERR_REG_ARRAY_INDEX_1, /* 0x0000F020, invalid index 1 of register array */
|
||||
RT_ERR_REG_ARRAY_INDEX_2, /* 0x0000F021, invalid index 2 of register array */
|
||||
RT_ERR_ETHER_TYPE, /* 0x0000F022, invalid ether type */
|
||||
RT_ERR_MBUF_PKT_NOT_AVAILABLE, /* 0x0000F023, mbuf->packet is not available */
|
||||
RT_ERR_QOS_INVLD_RSN, /* 0x0000F024, invalid pkt to CPU reason */
|
||||
RT_ERR_CB_FUNCTION_EXIST, /* 0x0000F025, Callback function exist */
|
||||
RT_ERR_CB_FUNCTION_FULL, /* 0x0000F026, Callback function number is full */
|
||||
RT_ERR_CB_FUNCTION_NOT_FOUND, /* 0x0000F027, Callback function can not found */
|
||||
RT_ERR_TBL_FULL, /* 0x0000F028, The table is full */
|
||||
RT_ERR_TRUNK_ID, /* 0x0000F029, invalid trunk id */
|
||||
RT_ERR_TYPE, /* 0x0000F02a, invalid type */
|
||||
RT_ERR_ENTRY_EXIST, /* 0x0000F02b, entry exists */
|
||||
RT_ERR_CHIP_UNDEFINED_VALUE, /* 0x0000F02c, chip returned an undefined value */
|
||||
RT_ERR_EXCEEDS_CAPACITY, /* 0x0000F02d, exceeds the capacity of hardware */
|
||||
RT_ERR_ENTRY_REFERRED, /* 0x0000F02e, entry is still being referred */
|
||||
RT_ERR_OPER_DENIED, /* 0x0000F02f, operation denied */
|
||||
RT_ERR_PORT_NOT_SUPPORTED, /* 0x0000F030, functions not supported by this port */
|
||||
RT_ERR_SOCKET, /* 0x0000F031, socket error */
|
||||
RT_ERR_MEM_ALLOC, /* 0x0000F032, insufficient memory resource */
|
||||
RT_ERR_ABORT, /* 0x0000F033, operation aborted */
|
||||
RT_ERR_DEV_ID, /* 0x0000F034, invalid device id */
|
||||
RT_ERR_DRIVER_NOT_SUPPORTED, /* 0x0000F035, functions not supported by this driver */
|
||||
RT_ERR_NOT_SUPPORTED, /* 0x0000F036, functions not supported */
|
||||
RT_ERR_SER, /* 0x0000F037, ECC or parity error */
|
||||
RT_ERR_MEM_NOT_ALIGN, /* 0x0000F038, memory address is not aligned */
|
||||
RT_ERR_SEM_FAKELOCK_OK, /* 0x0000F039, attach thread lock a semaphore which was already locked */
|
||||
RT_ERR_CHECK_FAILED, /* 0x0000F03a, check result is failed */
|
||||
|
||||
RT_ERR_COMMON_END = 0xFFFF /* The symbol is the latest symbol of common error */
|
||||
} rt_error_common_t;
|
||||
|
||||
/*
|
||||
* Macro Definition
|
||||
*/
|
||||
#define RT_PARAM_CHK(expr, errCode)\
|
||||
do {\
|
||||
if ((int32)(expr)) {\
|
||||
return errCode; \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RT_PARAM_CHK_EHDL(expr, errCode, err_hdl)\
|
||||
do {\
|
||||
if ((int32)(expr)) {\
|
||||
{err_hdl}\
|
||||
return errCode; \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RT_INIT_CHK(state)\
|
||||
do {\
|
||||
if (INIT_COMPLETED != (state)) {\
|
||||
return RT_ERR_NOT_INIT;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RT_INIT_REENTRY_CHK(state)\
|
||||
do {\
|
||||
if (INIT_COMPLETED == (state)) {\
|
||||
osal_printf(" %s had already been initialized!\n", __FUNCTION__);\
|
||||
return RT_ERR_OK;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RT_INIT_REENTRY_CHK_NO_WARNING(state)\
|
||||
do {\
|
||||
if (INIT_COMPLETED == (state)) {\
|
||||
return RT_ERR_OK;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RT_ERR_CHK(op, ret)\
|
||||
do {\
|
||||
if ((ret = (op)) != RT_ERR_OK)\
|
||||
return ret;\
|
||||
} while(0)
|
||||
|
||||
#define RT_ERR_HDL(op, errHandle, ret)\
|
||||
do {\
|
||||
if ((ret = (op)) != RT_ERR_OK)\
|
||||
goto errHandle;\
|
||||
} while(0)
|
||||
|
||||
#define RT_ERR_CHK_EHDL(op, ret, err_hdl)\
|
||||
do {\
|
||||
if ((ret = (op)) != RT_ERR_OK)\
|
||||
{\
|
||||
{err_hdl}\
|
||||
return ret;\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
#define RT_NULL_HDL(pointer, err_label)\
|
||||
do {\
|
||||
if (NULL == (pointer)) {\
|
||||
goto err_label;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define RT_ERR_VOID_CHK(op, ret)\
|
||||
do {\
|
||||
if ((ret = (op)) != RT_ERR_OK) {\
|
||||
osal_printf("Fail in %s %d, ret %x!\n", __FUNCTION__, __LINE__, ret);\
|
||||
return ;}\
|
||||
} while(0)
|
||||
|
||||
#endif /* __COMMON_ERROR_H__ */
|
||||
|
||||
179
sources/rtk-be550/src/hal/phy/phy_patch.c
Executable file
179
sources/rtk-be550/src/hal/phy/phy_patch.c
Executable file
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Include Files
|
||||
*/
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#include "rtk_osal.h"
|
||||
#else
|
||||
#include <common/rt_type.h>
|
||||
#include <common/rt_error.h>
|
||||
#include <common/debug/rt_log.h>
|
||||
#include <hal/common/halctrl.h>
|
||||
#include <hal/phy/phy_patch.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function Declaration
|
||||
*/
|
||||
uint8 phy_patch_op_translate(uint8 patch_mode, uint8 patch_op, uint8 compare_op)
|
||||
{
|
||||
if (patch_mode != PHY_PATCH_MODE_CMP)
|
||||
{
|
||||
return patch_op;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (compare_op)
|
||||
{
|
||||
case RTK_PATCH_CMP_WS:
|
||||
return RTK_PATCH_OP_SKIP;
|
||||
case RTK_PATCH_CMP_W:
|
||||
case RTK_PATCH_CMP_WC:
|
||||
case RTK_PATCH_CMP_SWC:
|
||||
default:
|
||||
return RTK_PATCH_OP_TO_CMP(patch_op, compare_op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 phy_patch_op(rt_phy_patch_db_t *pPhy_patchDb, uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_op, uint16 portmask, uint16 pagemmd, uint16 addr, uint8 msb, uint8 lsb, uint16 data, uint8 patch_mode)
|
||||
{
|
||||
rtk_hwpatch_t op;
|
||||
|
||||
op.patch_op = patch_op;
|
||||
op.portmask = portmask;
|
||||
op.pagemmd = pagemmd;
|
||||
op.addr = addr;
|
||||
op.msb = msb;
|
||||
op.lsb = lsb;
|
||||
op.data = data;
|
||||
op.compare_op = RTK_PATCH_CMP_W;
|
||||
|
||||
return pPhy_patchDb->fPatch_op(unit, port, portOffset, &op, patch_mode);
|
||||
}
|
||||
|
||||
static int32 _phy_patch_process(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch, int32 size, uint8 patch_mode)
|
||||
{
|
||||
int32 i = 0;
|
||||
int32 ret = 0;
|
||||
int32 chk_ret = RT_ERR_OK;
|
||||
int32 n;
|
||||
rtk_hwpatch_t *patch = pPatch;
|
||||
rt_phy_patch_db_t *pPatchDb = NULL;
|
||||
|
||||
PHYPATCH_DB_GET(unit, port, pPatchDb);
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
return RT_ERR_OK;
|
||||
}
|
||||
n = size / sizeof(rtk_hwpatch_t);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
ret = pPatchDb->fPatch_op(unit, port, portOffset, &patch[i], patch_mode);
|
||||
if ((ret != RT_ERR_ABORT) && (ret != RT_ERR_OK))
|
||||
{
|
||||
if ((ret == RT_ERR_CHECK_FAILED) && (patch_mode == PHY_PATCH_MODE_CMP))
|
||||
{
|
||||
osal_printf("PATCH CHECK: Failed entry:%u|%u|0x%X|0x%X|%u|%u|0x%X\n",
|
||||
i + 1, patch[i].patch_op, patch[i].pagemmd, patch[i].addr, patch[i].msb, patch[i].lsb, patch[i].data);
|
||||
chk_ret = RT_ERR_CHECK_FAILED;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u %s failed! %u[%u][0x%X][0x%X][0x%X] ret=0x%X\n", unit, port, __FUNCTION__,
|
||||
i+1, patch[i].patch_op, patch[i].pagemmd, patch[i].addr, patch[i].data, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return (chk_ret == RT_ERR_CHECK_FAILED) ? chk_ret : RT_ERR_OK;
|
||||
}
|
||||
|
||||
/* Function Name:
|
||||
* phy_patch
|
||||
* Description:
|
||||
* apply initial patch data to PHY
|
||||
* Input:
|
||||
* unit - unit id
|
||||
* port - port id
|
||||
* portOffset - the index offset of port based the base port in the PHY chip
|
||||
* Output:
|
||||
* None
|
||||
* Return:
|
||||
* RT_ERR_OK
|
||||
* RT_ERR_FAILED
|
||||
* RT_ERR_CHECK_FAILED
|
||||
* RT_ERR_NOT_SUPPORTED
|
||||
* Note:
|
||||
* None
|
||||
*/
|
||||
int32 phy_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode)
|
||||
{
|
||||
int32 ret = RT_ERR_OK;
|
||||
int32 chk_ret = RT_ERR_OK;
|
||||
uint32 i = 0;
|
||||
uint8 patch_type = 0;
|
||||
rt_phy_patch_db_t *pPatchDb = NULL;
|
||||
rtk_hwpatch_seq_t *table = NULL;
|
||||
|
||||
PHYPATCH_DB_GET(unit, port, pPatchDb);
|
||||
|
||||
if ((pPatchDb == NULL) || (pPatchDb->fPatch_op == NULL) || (pPatchDb->fPatch_flow == NULL))
|
||||
{
|
||||
RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u phy_patch, db is NULL\n", unit, port);
|
||||
return RT_ERR_DRIVER_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (patch_mode == PHY_PATCH_MODE_CMP)
|
||||
{
|
||||
table = pPatchDb->cmp_table;
|
||||
}
|
||||
else
|
||||
{
|
||||
table = pPatchDb->seq_table;
|
||||
}
|
||||
RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "phy_patch: U%u P%u portOffset:%u patch_mode:%u\n", unit, port, portOffset, patch_mode);
|
||||
|
||||
for (i = 0; i < RTK_PATCH_SEQ_MAX; i++)
|
||||
{
|
||||
patch_type = table[i].patch_type;
|
||||
RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "phy_patch: table[%u] patch_type:%u\n", i, patch_type);
|
||||
|
||||
if (RTK_PATCH_TYPE_IS_DATA(patch_type))
|
||||
{
|
||||
ret = _phy_patch_process(unit, port, portOffset, table[i].patch.data.conf, table[i].patch.data.size, patch_mode);
|
||||
|
||||
if (ret == RT_ERR_CHECK_FAILED)
|
||||
chk_ret = ret;
|
||||
else if (ret != RT_ERR_OK)
|
||||
{
|
||||
RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (RTK_PATCH_TYPE_IS_FLOW(patch_type))
|
||||
{
|
||||
RT_ERR_CHK_EHDL(pPatchDb->fPatch_flow(unit, port, portOffset, table[i].patch.flow_id, patch_mode),
|
||||
ret, RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret););
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (chk_ret == RT_ERR_CHECK_FAILED) ? chk_ret : RT_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
174
sources/rtk-be550/src/hal/phy/phy_patch.h
Executable file
174
sources/rtk-be550/src/hal/phy/phy_patch.h
Executable file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __HAL_PHY_PATCH_H__
|
||||
#define __HAL_PHY_PATCH_H__
|
||||
|
||||
/*
|
||||
* Include Files
|
||||
*/
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#include "rtk_phylib_def.h"
|
||||
#else
|
||||
#include <common/rt_type.h>
|
||||
#include <common/rt_autoconf.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Symbol Definition
|
||||
*/
|
||||
#define PHYPATCH_PHYCTRL_IN_HALCTRL 0 /* 3.6.x: 1 ,4.0.x: 1, 4.1.x+: 0 */
|
||||
#define PHYPATCH_FMAILY_IN_HWP 0 /* 3.6.x: 1 ,4.0.x: 0, 4.1.x+: 0 */
|
||||
#define PHY_PATCH_MODE_BCAST_DEFAULT PHY_PATCH_MODE_BCAST /* 3.6.x: PHY_PATCH_MODE_BCAST_BUS ,4.0.x+: PHY_PATCH_MODE_BCAST */
|
||||
|
||||
#define PHY_PATCH_MODE_NORMAL 0
|
||||
#define PHY_PATCH_MODE_CMP 1
|
||||
#define PHY_PATCH_MODE_BCAST 2
|
||||
#define PHY_PATCH_MODE_BCAST_BUS 3
|
||||
|
||||
#define RTK_PATCH_CMP_W 0 /* write */
|
||||
#define RTK_PATCH_CMP_WC 1 /* compare */
|
||||
#define RTK_PATCH_CMP_SWC 2 /* sram compare */
|
||||
#define RTK_PATCH_CMP_WS 3 /* skip */
|
||||
|
||||
#define RTK_PATCH_OP_SECTION_SIZE 50
|
||||
#define RTK_PATCH_OP_TO_CMP(_op, _cmp) (_op + (RTK_PATCH_OP_SECTION_SIZE * _cmp))
|
||||
/* 0~49 normal op */
|
||||
#define RTK_PATCH_OP_PHY 0
|
||||
#define RTK_PATCH_OP_PHYOCP 1
|
||||
#define RTK_PATCH_OP_TOP 2
|
||||
#define RTK_PATCH_OP_TOPOCP 3
|
||||
#define RTK_PATCH_OP_PSDS0 4
|
||||
#define RTK_PATCH_OP_PSDS1 5
|
||||
#define RTK_PATCH_OP_MSDS 6
|
||||
#define RTK_PATCH_OP_MAC 7
|
||||
|
||||
/* 50~99 normal op for compare */
|
||||
#define RTK_PATCH_OP_CMP_PHY RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHY , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_PHYOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHYOCP , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_TOP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOP , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_TOPOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOPOCP , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_PSDS0 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS0 , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_PSDS1 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS1 , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_MSDS RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MSDS , RTK_PATCH_CMP_WC)
|
||||
#define RTK_PATCH_OP_CMP_MAC RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MAC , RTK_PATCH_CMP_WC)
|
||||
|
||||
/* 100~149 normal op for sram compare */
|
||||
#define RTK_PATCH_OP_CMP_SRAM_PHY RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHY , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_PHYOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHYOCP , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_TOP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOP , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_TOPOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOPOCP , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_PSDS0 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS0 , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_PSDS1 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS1 , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_MSDS RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MSDS , RTK_PATCH_CMP_SWC)
|
||||
#define RTK_PATCH_OP_CMP_SRAM_MAC RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MAC , RTK_PATCH_CMP_SWC)
|
||||
|
||||
/* 200~255 control op */
|
||||
#define RTK_PATCH_OP_DELAY_MS 200
|
||||
#define RTK_PATCH_OP_SKIP 255
|
||||
|
||||
|
||||
/*
|
||||
patch type PHY_PATCH_TYPE_NONE => empty
|
||||
patch type: PHY_PATCH_TYPE_TOP ~ (PHY_PATCH_TYPE_END-1) => data array
|
||||
patch type: PHY_PATCH_TYPE_END ~ (PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOW_MAX) => flow
|
||||
*/
|
||||
#define RTK_PATCH_TYPE_IS_DATA(_patch_type) (_patch_type > PHY_PATCH_TYPE_NONE && _patch_type < PHY_PATCH_TYPE_END)
|
||||
#define RTK_PATCH_TYPE_IS_FLOW(_patch_type) (_patch_type >= PHY_PATCH_TYPE_END && _patch_type <= (PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOWID_MAX))
|
||||
|
||||
|
||||
/*
|
||||
* Macro Definition
|
||||
*/
|
||||
#if PHYPATCH_PHYCTRL_IN_HALCTRL
|
||||
#define PHYPATCH_DB_GET(_unit, _port, _pPatchDb) \
|
||||
do {\
|
||||
hal_control_t *pHalCtrl = NULL;\
|
||||
if ((pHalCtrl = hal_ctrlInfo_get(_unit)) == NULL)\
|
||||
return RT_ERR_FAILED;\
|
||||
_pPatchDb = (pHalCtrl->pPhy_ctrl[_port]->pPhy_patchDb);\
|
||||
} while(0)
|
||||
#else
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#else
|
||||
#include <hal/phy/phydef.h>
|
||||
#include <hal/phy/phy_probe.h>
|
||||
#endif
|
||||
#define PHYPATCH_DB_GET(_unit, _port, _pPatchDb) \
|
||||
do {\
|
||||
rt_phyctrl_t *pPhyCtrl = NULL;\
|
||||
if ((pPhyCtrl = phy_phyctrl_get(_unit, _port)) == NULL)\
|
||||
return RT_ERR_FAILED;\
|
||||
_pPatchDb = (pPhyCtrl->pPhy_patchDb);\
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#if PHYPATCH_FMAILY_IN_HWP
|
||||
#define PHYPATCH_IS_RTKSDS(_unit) (HWP_9300_FAMILY_ID(_unit) || HWP_9310_FAMILY_ID(_unit))
|
||||
#else
|
||||
#define PHYPATCH_IS_RTKSDS(_unit) (RTK_9300_FAMILY_ID(_unit) || RTK_9310_FAMILY_ID(_unit) || RTK_9311B_FAMILY_ID(_unit) || RTK_9330_FAMILY_ID(_unit))
|
||||
#endif
|
||||
|
||||
#define PHYPATCH_TABLE_ASSIGN(_pPatchDb, _table, _idx, _patch_type, _para) \
|
||||
do {\
|
||||
if (RTK_PATCH_TYPE_IS_DATA(_patch_type)) {\
|
||||
_pPatchDb->_table[_idx].patch_type = _patch_type;\
|
||||
_pPatchDb->_table[_idx].patch.data.conf = _para;\
|
||||
_pPatchDb->_table[_idx].patch.data.size = sizeof(_para);\
|
||||
}\
|
||||
else if (RTK_PATCH_TYPE_IS_FLOW(_patch_type)) {\
|
||||
_pPatchDb->_table[_idx].patch_type = _patch_type;\
|
||||
_pPatchDb->_table[_idx].patch.flow_id = _patch_type;\
|
||||
}\
|
||||
else {\
|
||||
_pPatchDb->_table[_idx].patch_type = PHY_PATCH_TYPE_NONE;\
|
||||
}\
|
||||
} while(0)
|
||||
#define PHYPATCH_SEQ_TABLE_ASSIGN(_pPatchDb, _idx, _patch_type, _para) PHYPATCH_TABLE_ASSIGN(_pPatchDb, seq_table, _idx, _patch_type, _para)
|
||||
#define PHYPATCH_CMP_TABLE_ASSIGN(_pPatchDb, _idx, _patch_type, _para) PHYPATCH_TABLE_ASSIGN(_pPatchDb, cmp_table, _idx, _patch_type, _para)
|
||||
|
||||
#define PHYPATCH_COMPARE(_mmdpage, _reg, _msb, _lsb, _exp, _real, _mask) \
|
||||
do {\
|
||||
uint32 _rData = REG32_FIELD_GET(_real, _lsb, _mask);\
|
||||
if (_exp != _rData) {\
|
||||
osal_printf("PATCH CHECK: %u(0x%X).%u(0x%X)[%u:%u] = 0x%X (!= 0x%X)\n", _mmdpage, _mmdpage, _reg, _reg, _msb, _lsb, _rData, _exp);\
|
||||
return RT_ERR_CHECK_FAILED;\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Function Declaration
|
||||
*/
|
||||
|
||||
extern uint8 phy_patch_op_translate(uint8 patch_mode, uint8 patch_op, uint8 compare_op);
|
||||
extern int32 phy_patch_op(rt_phy_patch_db_t *pPhy_patchDb, uint32 unit, rtk_port_t port, uint8 portOffset,
|
||||
uint8 patch_op, uint16 portmask, uint16 pagemmd, uint16 addr, uint8 msb, uint8 lsb, uint16 data,
|
||||
uint8 patch_mode);
|
||||
|
||||
|
||||
/* Function Name:
|
||||
* phy_patch
|
||||
* Description:
|
||||
* apply initial patch data to PHY
|
||||
* Input:
|
||||
* unit - unit id
|
||||
* port - port id
|
||||
* portOffset - the index offset of port based the base port in the PHY chip
|
||||
* Output:
|
||||
* None
|
||||
* Return:
|
||||
* RT_ERR_OK
|
||||
* RT_ERR_FAILED
|
||||
* RT_ERR_CHECK_FAILED
|
||||
* RT_ERR_NOT_SUPPORTED
|
||||
* Note:
|
||||
* None
|
||||
*/
|
||||
extern int32 phy_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode);
|
||||
|
||||
|
||||
|
||||
#endif /* __HAL_PHY_PATCH_H__ */
|
||||
1123
sources/rtk-be550/src/hal/phy/phy_rtl826xb_patch.c
Executable file
1123
sources/rtk-be550/src/hal/phy/phy_rtl826xb_patch.c
Executable file
File diff suppressed because it is too large
Load diff
63
sources/rtk-be550/src/hal/phy/phy_rtl826xb_patch.h
Executable file
63
sources/rtk-be550/src/hal/phy/phy_rtl826xb_patch.h
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __HAL_PHY_PHY_RTL826XB_PATCH_H__
|
||||
#define __HAL_PHY_PHY_RTL826XB_PATCH_H__
|
||||
|
||||
/*
|
||||
* Include Files
|
||||
*/
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#include "rtk_osal.h"
|
||||
#include "rtk_phylib_def.h"
|
||||
#else
|
||||
#include <common/rt_type.h>
|
||||
#include <rtk/port.h>
|
||||
#endif
|
||||
|
||||
/* Function Name:
|
||||
* phy_rtl826xb_patch
|
||||
* Description:
|
||||
* apply patch data to PHY
|
||||
* Input:
|
||||
* unit - unit id
|
||||
* baseport - base port id on the PHY chip
|
||||
* portOffset - the index offset base on baseport for the port to patch
|
||||
* Output:
|
||||
* None
|
||||
* Return:
|
||||
* RT_ERR_OK
|
||||
* RT_ERR_FAILED
|
||||
* RT_ERR_NOT_SUPPORTED
|
||||
* RT_ERR_ABORT
|
||||
* Note:
|
||||
* None
|
||||
*/
|
||||
extern int32 phy_rtl826xb_patch(uint32 unit, rtk_port_t baseport, uint8 portOffset);
|
||||
|
||||
/* Function Name:
|
||||
* phy_rtl826xb_broadcast_patch
|
||||
* Description:
|
||||
* apply patch data to PHY
|
||||
* Input:
|
||||
* unit - unit id
|
||||
* baseport - base port id on the PHY chip
|
||||
* portOffset - the index offset base on baseport for the port to patch
|
||||
* perChip - 1 for per-chip mode, 0 for per-bus mode
|
||||
* Output:
|
||||
* None
|
||||
* Return:
|
||||
* RT_ERR_OK
|
||||
* RT_ERR_FAILED
|
||||
* RT_ERR_NOT_SUPPORTED
|
||||
* RT_ERR_ABORT
|
||||
* Note:
|
||||
* None
|
||||
*/
|
||||
extern int32 phy_rtl826xb_broadcast_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 perChip);
|
||||
|
||||
extern int32 phy_rtl826xb_patch_db_init(uint32 unit, rtk_port_t port, rt_phy_patch_db_t **pPhy_patchDb);
|
||||
#endif /* __HAL_PHY_PHY_RTL826XB_PATCH_H__ */
|
||||
888
sources/rtk-be550/src/hal/phy/rtk_macsec.c
Executable file
888
sources/rtk-be550/src/hal/phy/rtk_macsec.c
Executable file
|
|
@ -0,0 +1,888 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <net/macsec.h>
|
||||
#include "rtk_phylib_macsec.h"
|
||||
#include "rtk_phylib_rtl826xb.h"
|
||||
#include "rtk_phylib.h"
|
||||
#include "rtk_phy.h"
|
||||
|
||||
static int rtk_macsec_del_txsa(struct macsec_context *ctx);
|
||||
static int rtk_macsec_del_rxsa(struct macsec_context *ctx);
|
||||
|
||||
static int __rtk_macsec_clear_txsc(struct macsec_context *ctx, uint32 sc_id)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_del(ctx->phydev, RTK_MACSEC_DIR_EGRESS, sc_id));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __rtk_macsec_clear_rxsc(struct macsec_context *ctx, uint32 sc_id)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_del(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_dev_open(struct macsec_context *ctx)
|
||||
{
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
return 0;
|
||||
|
||||
return rtk_phylib_macsec_enable_set(ctx->phydev, 1);
|
||||
}
|
||||
|
||||
static int rtk_macsec_dev_stop(struct macsec_context *ctx)
|
||||
{
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
return 0;
|
||||
|
||||
return rtk_phylib_macsec_enable_set(ctx->phydev, 0);
|
||||
}
|
||||
|
||||
static int rtk_macsec_add_secy(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(MACSEC_SC_IS_USED(macsec_db, RTK_MACSEC_DIR_EGRESS, 0))
|
||||
{
|
||||
PR_ERR("[%s]MACSEC_SC_IS_USED\n",__FUNCTION__);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/* create TX SC */
|
||||
{
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sc_t sc;
|
||||
memset(&sc, 0x0, sizeof(rtk_macsec_sc_t));
|
||||
|
||||
switch (ctx->secy->key_len)
|
||||
{
|
||||
case 16:
|
||||
sc.tx.cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_128 : RTK_MACSEC_CIPHER_GCM_ASE_128;
|
||||
break;
|
||||
case 32:
|
||||
sc.tx.cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_256 : RTK_MACSEC_CIPHER_GCM_ASE_256;
|
||||
break;
|
||||
default:
|
||||
PR_ERR("Not support key_len %d\n", ctx->secy->key_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_VAL_TO_BYTE_ARRAY(ctx->secy->sci, 8, sc.tx.sci, 0, 8);
|
||||
PR_DBG("[%s]secy->sci: 0x%llX\n", __FUNCTION__, ctx->secy->sci);
|
||||
sc.tx.flow_match = RTK_MACSEC_MATCH_NON_CTRL;
|
||||
sc.tx.protect_frame = ctx->secy->protect_frames;
|
||||
sc.tx.include_sci = ctx->secy->tx_sc.send_sci;
|
||||
sc.tx.use_es = ctx->secy->tx_sc.end_station;
|
||||
sc.tx.use_scb = ctx->secy->tx_sc.scb;
|
||||
sc.tx.conf_protect = ctx->secy->tx_sc.encrypt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_create(ctx->phydev, RTK_MACSEC_DIR_EGRESS, &sc, &sc_id, (ctx->secy->tx_sc.active) ? 1 : 0));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_del_secy(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
uint32 i = 0;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < MACSEC_SC_MAX(macsec_db); i++)
|
||||
{
|
||||
if(MACSEC_SC_IS_USED(macsec_db, RTK_MACSEC_DIR_EGRESS, i))
|
||||
{
|
||||
PR_DBG("[%s] clear TX SC %u\n", __FUNCTION__, i);
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_clear_txsc(ctx, i));
|
||||
}
|
||||
|
||||
if(MACSEC_SC_IS_USED(macsec_db, RTK_MACSEC_DIR_INGRESS, i))
|
||||
{
|
||||
PR_DBG("[%s] clear RX SC %u\n", __FUNCTION__, i);
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_clear_rxsc(ctx, i));
|
||||
}
|
||||
}
|
||||
memset(&(macsec_db->port_stats), 0x0, sizeof(rtk_macsec_sc_t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_upd_secy(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
|
||||
rtk_macsec_cipher_t cipher_suite;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(MACSEC_SC_IS_CLEAR(macsec_db, RTK_MACSEC_DIR_EGRESS, 0))
|
||||
{
|
||||
PR_ERR("[%s]MACSEC_SC_IS_CLEAR\n",__FUNCTION__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* create TX SC */
|
||||
{
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sc_t sc;
|
||||
rtk_macsec_sc_t cur_sc;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_get(ctx->phydev, RTK_MACSEC_DIR_EGRESS, 0, &sc));
|
||||
memcpy(&cur_sc, &sc, sizeof(rtk_macsec_sc_t));
|
||||
|
||||
switch (ctx->secy->key_len)
|
||||
{
|
||||
case 16:
|
||||
cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_128 : RTK_MACSEC_CIPHER_GCM_ASE_128;
|
||||
break;
|
||||
case 32:
|
||||
cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_256 : RTK_MACSEC_CIPHER_GCM_ASE_256;
|
||||
break;
|
||||
default:
|
||||
PR_ERR("Not support key_len %d\n", ctx->secy->key_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_VAL_TO_BYTE_ARRAY(ctx->secy->sci, 8, sc.tx.sci, 0, 8);
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
PR_DBG("[%s]secy->sci: 0x%llX\n", __FUNCTION__, ctx->secy->sci);
|
||||
PR_DBG("cipher_suite %u => %u\n", sc.tx.cipher_suite, cipher_suite);
|
||||
PR_DBG("flow_match %u => %u\n", sc.tx.flow_match, RTK_MACSEC_MATCH_NON_CTRL);
|
||||
PR_DBG("protect_frame %u => %u\n", sc.tx.protect_frame, ctx->secy->protect_frames);
|
||||
PR_DBG("include_sci %u => %u\n", sc.tx.include_sci, ctx->secy->tx_sc.send_sci);
|
||||
PR_DBG("use_es %u => %u\n", sc.tx.use_es, ctx->secy->tx_sc.end_station);
|
||||
PR_DBG("use_scb %u => %u\n", sc.tx.use_scb, ctx->secy->tx_sc.scb);
|
||||
PR_DBG("conf_protect %u => %u\n", sc.tx.conf_protect, ctx->secy->tx_sc.encrypt);
|
||||
#endif
|
||||
sc.tx.cipher_suite = cipher_suite;
|
||||
sc.tx.flow_match = RTK_MACSEC_MATCH_NON_CTRL;
|
||||
sc.tx.protect_frame = ctx->secy->protect_frames;
|
||||
sc.tx.include_sci = ctx->secy->tx_sc.send_sci;
|
||||
sc.tx.use_es = ctx->secy->tx_sc.end_station;
|
||||
sc.tx.use_scb = ctx->secy->tx_sc.scb;
|
||||
sc.tx.conf_protect = ctx->secy->tx_sc.encrypt;
|
||||
|
||||
if(memcmp(&cur_sc, &sc, sizeof(rtk_macsec_sc_t)) != 0)
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_update(ctx->phydev, RTK_MACSEC_DIR_EGRESS, &sc, &sc_id, (ctx->secy->tx_sc.active) ? 1 : 0));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_add_rxsc(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sc_t sc;
|
||||
memset(&sc, 0x0, sizeof(rtk_macsec_sc_t));
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->rx_sc->sci, &sc_id);
|
||||
if(ret != RTK_PHYLIB_ERR_ENTRY_NOTFOUND) //sc is existed
|
||||
{
|
||||
PR_DBG("[%s] ret:%d sc_id:%d is existed \n", __FUNCTION__, ret, sc_id);
|
||||
return -EEXIST;
|
||||
}
|
||||
PR_DBG("[%s]rx_sc->sci: 0x%llX\n", __FUNCTION__, ctx->rx_sc->sci);
|
||||
|
||||
switch (ctx->secy->key_len)
|
||||
{
|
||||
case 16:
|
||||
sc.rx.cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_128 : RTK_MACSEC_CIPHER_GCM_ASE_128;
|
||||
break;
|
||||
case 32:
|
||||
sc.rx.cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_256 : RTK_MACSEC_CIPHER_GCM_ASE_256;
|
||||
break;
|
||||
default:
|
||||
PR_ERR("Not support key_len %d\n", ctx->secy->key_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
PR_DBG("[%s]rx_sc->sci: 0x%llX\n", __FUNCTION__, ctx->rx_sc->sci);
|
||||
RTK_PHYLIB_VAL_TO_BYTE_ARRAY(ctx->rx_sc->sci, 8, sc.rx.sci, 0, 8);
|
||||
sc.rx.flow_match = RTK_MACSEC_MATCH_SCI;
|
||||
|
||||
switch (ctx->secy->validate_frames)
|
||||
{
|
||||
case MACSEC_VALIDATE_DISABLED:
|
||||
sc.rx.validate_frames = RTK_MACSEC_VALIDATE_DISABLE;
|
||||
break;
|
||||
case MACSEC_VALIDATE_CHECK:
|
||||
sc.rx.validate_frames = RTK_MACSEC_VALIDATE_CHECK;
|
||||
break;
|
||||
case MACSEC_VALIDATE_STRICT:
|
||||
sc.rx.validate_frames = RTK_MACSEC_VALIDATE_STRICT;
|
||||
break;
|
||||
default:
|
||||
PR_ERR("Not support validate_frames %d\n", ctx->secy->validate_frames);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc.rx.replay_protect = ctx->secy->replay_protect;
|
||||
sc.rx.replay_window = ctx->secy->replay_window;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_create(ctx->phydev, RTK_MACSEC_DIR_INGRESS, &sc, &sc_id, (ctx->rx_sc->active) ? 1 : 0));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_del_rxsc(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->rx_sc->sci, &sc_id));
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_clear_rxsc(ctx, sc_id));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_upd_rxsc(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sc_t sc;
|
||||
rtk_macsec_sc_t cur_sc;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->rx_sc->sci, &sc_id);
|
||||
if(ret == RTK_PHYLIB_ERR_ENTRY_NOTFOUND) //sc is not existed
|
||||
{
|
||||
PR_DBG("[%s] ret:%d sc_id:%d is not existed \n", __FUNCTION__, ret, sc_id);
|
||||
return -ENOENT;
|
||||
}
|
||||
PR_DBG("[%s]rx_sc->sci: 0x%llX\n", __FUNCTION__, ctx->rx_sc->sci);
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_get(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id, &sc));
|
||||
memcpy(&cur_sc, &sc, sizeof(rtk_macsec_sc_t));
|
||||
|
||||
switch (ctx->secy->key_len)
|
||||
{
|
||||
case 16:
|
||||
sc.rx.cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_128 : RTK_MACSEC_CIPHER_GCM_ASE_128;
|
||||
break;
|
||||
case 32:
|
||||
sc.rx.cipher_suite = (ctx->secy->xpn) ? RTK_MACSEC_CIPHER_GCM_ASE_XPN_256 : RTK_MACSEC_CIPHER_GCM_ASE_256;
|
||||
break;
|
||||
default:
|
||||
PR_ERR("Not support key_len %d\n", ctx->secy->key_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
PR_DBG("[%s]rx_sc->sci: 0x%llX\n", __FUNCTION__, ctx->rx_sc->sci);
|
||||
RTK_PHYLIB_VAL_TO_BYTE_ARRAY(ctx->rx_sc->sci, 8, sc.rx.sci, 0, 8);
|
||||
sc.rx.flow_match = RTK_MACSEC_MATCH_SCI;
|
||||
|
||||
switch (ctx->secy->validate_frames)
|
||||
{
|
||||
case MACSEC_VALIDATE_DISABLED:
|
||||
sc.rx.validate_frames = RTK_MACSEC_VALIDATE_DISABLE;
|
||||
break;
|
||||
case MACSEC_VALIDATE_CHECK:
|
||||
sc.rx.validate_frames = RTK_MACSEC_VALIDATE_CHECK;
|
||||
break;
|
||||
case MACSEC_VALIDATE_STRICT:
|
||||
sc.rx.validate_frames = RTK_MACSEC_VALIDATE_STRICT;
|
||||
break;
|
||||
default:
|
||||
PR_ERR("Not support validate_frames %d\n", ctx->secy->validate_frames);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc.rx.replay_protect = ctx->secy->replay_protect;
|
||||
sc.rx.replay_window = ctx->secy->replay_window;
|
||||
|
||||
if(memcmp(&cur_sc, &sc, sizeof(rtk_macsec_sc_t)) != 0)
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sc_update(ctx->phydev, RTK_MACSEC_DIR_INGRESS, &sc, &sc_id, (ctx->rx_sc->active) ? 1 : 0));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __rtk_macsec_set_rxsa(struct macsec_context *ctx, bool update)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sa_t sa;
|
||||
memset(&sa, 0x0, sizeof(rtk_macsec_sa_t));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->sa.rx_sa->sc->sci, &sc_id));
|
||||
|
||||
if (update)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_get(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id, ctx->sa.assoc_num, &sa));
|
||||
}
|
||||
else
|
||||
{
|
||||
sa.key_bytes = ctx->secy->key_len;
|
||||
memcpy(sa.key, ctx->sa.key, sa.key_bytes);
|
||||
if(ctx->secy->xpn)
|
||||
{
|
||||
memcpy(sa.salt, ctx->sa.rx_sa->key.salt.bytes, MACSEC_SALT_LEN);
|
||||
RTK_PHYLIB_VAL_TO_BYTE_ARRAY(ctx->sa.rx_sa->ssci, 4, sa.ssci, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
sa.pn = ctx->sa.tx_sa->next_pn_halves.lower;
|
||||
sa.pn_h = ctx->sa.tx_sa->next_pn_halves.upper;
|
||||
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
{
|
||||
PR_DBG("[%s,%d] update:%u \n", __FUNCTION__, __LINE__, update);
|
||||
PR_DBG(" KEY 0-15 = 0x%02X%02X%02X%02X%02X%02X%02X%02X %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
sa.key[0], sa.key[1], sa.key[2], sa.key[3],
|
||||
sa.key[4], sa.key[5], sa.key[6], sa.key[7],
|
||||
sa.key[8], sa.key[9], sa.key[10],sa.key[11],
|
||||
sa.key[12],sa.key[13],sa.key[14],sa.key[15]);
|
||||
if (ctx->secy->key_len == 32)
|
||||
{
|
||||
PR_DBG(" KEY16-31 = 0x%02X%02X%02X%02X%02X%02X%02X%02X %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
sa.key[16],sa.key[17],sa.key[18],sa.key[19],
|
||||
sa.key[20],sa.key[21],sa.key[22],sa.key[23],
|
||||
sa.key[24],sa.key[25],sa.key[26],sa.key[27],
|
||||
sa.key[28],sa.key[29],sa.key[30],sa.key[31]);
|
||||
}
|
||||
PR_DBG(" ctx->sa.rx_sa->active: %u\n", ctx->sa.rx_sa->active);
|
||||
PR_DBG(" ctx->secy->xpn: %u\n", ctx->secy->xpn);
|
||||
PR_DBG(" sa.pn: 0x%X, sa.pn_h: 0x%X\n", sa.pn, sa.pn_h);
|
||||
if(ctx->secy->xpn)
|
||||
{
|
||||
PR_DBG(" ctx->sa.tx_sa->key.salt = 0x%02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X\n",
|
||||
sa.salt[0], sa.salt[1], sa.salt[2], sa.salt[3],
|
||||
sa.salt[4], sa.salt[5], sa.salt[6], sa.salt[7],
|
||||
sa.salt[8], sa.salt[9], sa.salt[10], sa.salt[11]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_create(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id, ctx->sa.assoc_num, &sa));
|
||||
|
||||
if (ctx->sa.rx_sa->active)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_activate(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id, ctx->sa.assoc_num));
|
||||
}
|
||||
else
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_rxsa_disable(ctx->phydev, sc_id, ctx->sa.assoc_num));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_add_rxsa(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0, sa_id = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_set_rxsa(ctx, false));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->sa.rx_sa->sc->sci, &sc_id));
|
||||
sa_id = PHY_MACSEC_HW_SA_ID(sc_id, ctx->sa.assoc_num);
|
||||
macsec_db->rxsa_stats[sa_id] = kzalloc(sizeof(rtk_macsec_rxsa_stats_t), GFP_KERNEL);
|
||||
if (macsec_db->rxsa_stats[sa_id] == NULL)
|
||||
{
|
||||
rtk_macsec_del_rxsa(ctx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_del_rxsa(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0, sa_id = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->sa.rx_sa->sc->sci, &sc_id));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_del(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id, ctx->sa.assoc_num));
|
||||
|
||||
sa_id = PHY_MACSEC_HW_SA_ID(sc_id, ctx->sa.assoc_num);
|
||||
if (macsec_db->rxsa_stats[sa_id] != NULL)
|
||||
{
|
||||
kfree(macsec_db->rxsa_stats[sa_id]);
|
||||
macsec_db->rxsa_stats[sa_id] = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_upd_rxsa(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_set_rxsa(ctx, true));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __rtk_macsec_set_txsa(struct macsec_context *ctx, bool update)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sa_t sa;
|
||||
memset(&sa, 0x0, sizeof(rtk_macsec_sa_t));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_EGRESS, ctx->secy->sci, &sc_id));
|
||||
|
||||
if (update)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_get(ctx->phydev, RTK_MACSEC_DIR_EGRESS, sc_id, ctx->sa.assoc_num, &sa));
|
||||
}
|
||||
else
|
||||
{
|
||||
sa.key_bytes = ctx->secy->key_len;
|
||||
memcpy(sa.key, ctx->sa.key, sa.key_bytes);
|
||||
if(ctx->secy->xpn)
|
||||
{
|
||||
memcpy(sa.salt, ctx->sa.tx_sa->key.salt.bytes, MACSEC_SALT_LEN);
|
||||
RTK_PHYLIB_VAL_TO_BYTE_ARRAY(ctx->sa.tx_sa->ssci, 4, sa.ssci, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
sa.pn = ctx->sa.tx_sa->next_pn_halves.lower;
|
||||
sa.pn_h = ctx->sa.tx_sa->next_pn_halves.upper;
|
||||
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
{
|
||||
PR_DBG("[%s,%d] update:%u \n", __FUNCTION__, __LINE__, update);
|
||||
PR_DBG(" KEY 0-15 = 0x%02X%02X%02X%02X%02X%02X%02X%02X %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
sa.key[0], sa.key[1], sa.key[2], sa.key[3],
|
||||
sa.key[4], sa.key[5], sa.key[6], sa.key[7],
|
||||
sa.key[8], sa.key[9], sa.key[10],sa.key[11],
|
||||
sa.key[12],sa.key[13],sa.key[14],sa.key[15]);
|
||||
if (ctx->secy->key_len == 32)
|
||||
{
|
||||
PR_DBG(" KEY16-31 = 0x%02X%02X%02X%02X%02X%02X%02X%02X %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
sa.key[16],sa.key[17],sa.key[18],sa.key[19],
|
||||
sa.key[20],sa.key[21],sa.key[22],sa.key[23],
|
||||
sa.key[24],sa.key[25],sa.key[26],sa.key[27],
|
||||
sa.key[28],sa.key[29],sa.key[30],sa.key[31]);
|
||||
}
|
||||
PR_DBG(" ctx->sa.tx_sa->active: %u\n", ctx->sa.tx_sa->active);
|
||||
PR_DBG(" ctx->secy->xpn: %u\n", ctx->secy->xpn);
|
||||
PR_DBG(" sa.pn: 0x%X, sa.pn_h: 0x%X\n", sa.pn, sa.pn_h);
|
||||
if(ctx->secy->xpn)
|
||||
{
|
||||
PR_DBG(" ctx->sa.tx_sa->key.salt = 0x%02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X\n",
|
||||
sa.salt[0], sa.salt[1], sa.salt[2], sa.salt[3],
|
||||
sa.salt[4], sa.salt[5], sa.salt[6], sa.salt[7],
|
||||
sa.salt[8], sa.salt[9], sa.salt[10], sa.salt[11]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_create(ctx->phydev, RTK_MACSEC_DIR_EGRESS, sc_id, ctx->sa.assoc_num, &sa));
|
||||
|
||||
if (ctx->sa.tx_sa->active)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_activate(ctx->phydev, RTK_MACSEC_DIR_EGRESS, sc_id, ctx->sa.assoc_num));
|
||||
}
|
||||
else
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_txsa_disable(ctx->phydev, sc_id));
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_add_txsa(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0, sa_id = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_set_txsa(ctx, false));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_EGRESS, ctx->secy->sci, &sc_id));
|
||||
sa_id = PHY_MACSEC_HW_SA_ID(sc_id, ctx->sa.assoc_num);
|
||||
macsec_db->txsa_stats[sa_id] = kzalloc(sizeof(rtk_macsec_txsa_stats_t), GFP_KERNEL);
|
||||
if (macsec_db->txsa_stats[sa_id] == NULL)
|
||||
{
|
||||
rtk_macsec_del_txsa(ctx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_del_txsa(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 sc_id = 0, sa_id = 0;
|
||||
struct rtk_phy_priv *priv = ctx->phydev->priv;
|
||||
rtk_macsec_port_info_t *macsec_db = priv->macsec;
|
||||
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_EGRESS, ctx->secy->sci, &sc_id));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_del(ctx->phydev, RTK_MACSEC_DIR_EGRESS, sc_id, ctx->sa.assoc_num));
|
||||
|
||||
sa_id = PHY_MACSEC_HW_SA_ID(sc_id, ctx->sa.assoc_num);
|
||||
if (macsec_db->txsa_stats[sa_id] != NULL)
|
||||
{
|
||||
kfree(macsec_db->txsa_stats[sa_id]);
|
||||
macsec_db->txsa_stats[sa_id] = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_upd_txsa(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
PR_DBG("[%s] ctx->prepare: %u\n", __FUNCTION__, ctx->prepare);
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(__rtk_macsec_set_txsa(ctx, true));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int rtk_macsec_get_dev_stats(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint64 cnt = 0;
|
||||
uint32 sc_id = 0, an = 0;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_port_get(ctx->phydev, RTK_MACSEC_STAT_OutPktsUntagged, &cnt));
|
||||
ctx->stats.dev_stats->OutPktsUntagged = cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_port_get(ctx->phydev, RTK_MACSEC_STAT_InPktsUntagged, &cnt));
|
||||
ctx->stats.dev_stats->InPktsUntagged = cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_port_get(ctx->phydev, RTK_MACSEC_STAT_InPktsNoTag, &cnt));
|
||||
ctx->stats.dev_stats->InPktsNoTag = cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_port_get(ctx->phydev, RTK_MACSEC_STAT_InPktsBadTag, &cnt));
|
||||
ctx->stats.dev_stats->InPktsBadTag = cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_port_get(ctx->phydev, RTK_MACSEC_STAT_InPktsUnknownSCI, &cnt));
|
||||
ctx->stats.dev_stats->InPktsUnknownSCI = cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_port_get(ctx->phydev, RTK_MACSEC_STAT_InPktsNoSCI, &cnt));
|
||||
ctx->stats.dev_stats->InPktsNoSCI = cnt;
|
||||
|
||||
ctx->stats.dev_stats->InPktsOverrun = 0; /* not support */
|
||||
|
||||
/* accumulate over each egress SA */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_EGRESS, ctx->secy->sci, &sc_id));
|
||||
for (an = 0; an < MACSEC_NUM_AN; an++)
|
||||
{
|
||||
if (0 == rtk_phylib_macsec_stat_txsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_TXSA_STAT_OutPktsTooLong, &cnt))
|
||||
{
|
||||
ctx->stats.dev_stats->OutPktsTooLong += cnt;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_get_txsc_stats(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint64 cnt = 0;
|
||||
uint32 sc_id = 0, an = 0;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_EGRESS, ctx->secy->sci, &sc_id));
|
||||
|
||||
/* accumulate over each egress SA */
|
||||
for (an = 0; an < MACSEC_NUM_AN; an++)
|
||||
{
|
||||
if (0 == rtk_phylib_macsec_stat_txsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_TXSA_STAT_OutPktsProtectedEncrypted, &cnt))
|
||||
{
|
||||
if (ctx->secy->tx_sc.encrypt)
|
||||
{
|
||||
ctx->stats.tx_sc_stats->OutPktsEncrypted += cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->stats.tx_sc_stats->OutPktsProtected += cnt;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == rtk_phylib_macsec_stat_txsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_TXSA_STAT_OutOctetsProtectedEncrypted, &cnt))
|
||||
{
|
||||
if (ctx->secy->tx_sc.encrypt)
|
||||
{
|
||||
ctx->stats.tx_sc_stats->OutOctetsEncrypted += cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->stats.tx_sc_stats->OutOctetsProtected += cnt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_get_rxsc_stats(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint64 cnt = 0;
|
||||
uint32 sc_id = 0, an = 0;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->rx_sc->sci, &sc_id));
|
||||
|
||||
/* accumulate over each ingress SA */
|
||||
for (an = 0; an < MACSEC_NUM_AN; an++)
|
||||
{
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InOctetsDecryptedValidated, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InOctetsValidated += cnt;
|
||||
ctx->stats.rx_sc_stats->InOctetsDecrypted = ctx->stats.rx_sc_stats->InOctetsValidated;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsUnchecked, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsUnchecked += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsDelayed, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsDelayed += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsOK, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsOK += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsInvalid, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsInvalid += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsLate, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsLate += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsNotValid, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsNotValid += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsNotUsingSA, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsNotUsingSA += cnt;
|
||||
}
|
||||
if (0 == rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, an, RTK_MACSEC_RXSA_STAT_InPktsUnusedSA, &cnt))
|
||||
{
|
||||
ctx->stats.rx_sc_stats->InPktsUnusedSA += cnt;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_get_txsa_stats(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint64 cnt = 0;
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sa_t sa;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_EGRESS, ctx->secy->sci, &sc_id));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_txsa_get(ctx->phydev, sc_id, ctx->sa.assoc_num, RTK_MACSEC_TXSA_STAT_OutPktsProtectedEncrypted, &cnt));
|
||||
if (ctx->secy->tx_sc.encrypt)
|
||||
{
|
||||
ctx->stats.tx_sa_stats->OutPktsEncrypted = (uint32)cnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->stats.tx_sa_stats->OutPktsProtected = (uint32)cnt;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_get(ctx->phydev, RTK_MACSEC_DIR_EGRESS, sc_id, ctx->sa.assoc_num, &sa));
|
||||
ctx->sa.tx_sa->next_pn_halves.lower = sa.pn;
|
||||
ctx->sa.tx_sa->next_pn_halves.upper = sa.pn_h;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtk_macsec_get_rxsa_stats(struct macsec_context *ctx)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint64 cnt = 0;
|
||||
uint32 sc_id = 0;
|
||||
rtk_macsec_sa_t sa;
|
||||
|
||||
if (ctx->prepare)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sci_to_scid(ctx->phydev, RTK_MACSEC_DIR_INGRESS, ctx->rx_sc->sci, &sc_id));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, ctx->sa.assoc_num, RTK_MACSEC_RXSA_STAT_InPktsOK, &cnt));
|
||||
ctx->stats.rx_sa_stats->InPktsOK = (uint32)cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, ctx->sa.assoc_num, RTK_MACSEC_RXSA_STAT_InPktsInvalid, &cnt));
|
||||
ctx->stats.rx_sa_stats->InPktsInvalid = (uint32)cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, ctx->sa.assoc_num, RTK_MACSEC_RXSA_STAT_InPktsNotValid, &cnt));
|
||||
ctx->stats.rx_sa_stats->InPktsNotValid = (uint32)cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, ctx->sa.assoc_num, RTK_MACSEC_RXSA_STAT_InPktsNotUsingSA, &cnt));
|
||||
ctx->stats.rx_sa_stats->InPktsNotUsingSA = (uint32)cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_stat_rxsa_get(ctx->phydev, sc_id, ctx->sa.assoc_num, RTK_MACSEC_RXSA_STAT_InPktsUnusedSA, &cnt));
|
||||
ctx->stats.rx_sa_stats->InPktsUnusedSA = (uint32)cnt;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_sa_get(ctx->phydev, RTK_MACSEC_DIR_INGRESS, sc_id, ctx->sa.assoc_num, &sa));
|
||||
ctx->sa.rx_sa->next_pn_halves.lower = sa.pn;
|
||||
ctx->sa.rx_sa->next_pn_halves.upper = sa.pn_h;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct macsec_ops rtk_macsec_ops = {
|
||||
/* Device wide */
|
||||
.mdo_dev_open = rtk_macsec_dev_open,
|
||||
.mdo_dev_stop = rtk_macsec_dev_stop,
|
||||
/* SecY */
|
||||
.mdo_add_secy = rtk_macsec_add_secy,
|
||||
.mdo_upd_secy = rtk_macsec_upd_secy,
|
||||
.mdo_del_secy = rtk_macsec_del_secy,
|
||||
/* Security channels */
|
||||
.mdo_add_rxsc = rtk_macsec_add_rxsc,
|
||||
.mdo_upd_rxsc = rtk_macsec_upd_rxsc,
|
||||
.mdo_del_rxsc = rtk_macsec_del_rxsc,
|
||||
/* Security associations */
|
||||
.mdo_add_rxsa = rtk_macsec_add_rxsa,
|
||||
.mdo_upd_rxsa = rtk_macsec_upd_rxsa,
|
||||
.mdo_del_rxsa = rtk_macsec_del_rxsa,
|
||||
.mdo_add_txsa = rtk_macsec_add_txsa,
|
||||
.mdo_upd_txsa = rtk_macsec_upd_txsa,
|
||||
.mdo_del_txsa = rtk_macsec_del_txsa,
|
||||
/* Statistics */
|
||||
.mdo_get_dev_stats = rtk_macsec_get_dev_stats,
|
||||
.mdo_get_tx_sc_stats = rtk_macsec_get_txsc_stats,
|
||||
.mdo_get_rx_sc_stats = rtk_macsec_get_rxsc_stats,
|
||||
.mdo_get_tx_sa_stats = rtk_macsec_get_txsa_stats,
|
||||
.mdo_get_rx_sa_stats = rtk_macsec_get_rxsa_stats,
|
||||
};
|
||||
|
||||
int rtk_macsec_init(struct phy_device *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
struct rtk_phy_priv *priv = phydev->priv;
|
||||
|
||||
priv->macsec = kzalloc(sizeof(*(priv->macsec)), GFP_KERNEL);
|
||||
if (!priv->macsec)
|
||||
return -ENOMEM;
|
||||
memset(priv->macsec, 0, sizeof(*(priv->macsec)));
|
||||
|
||||
switch (phydev->drv->phy_id)
|
||||
{
|
||||
case REALTEK_PHY_ID_RTL8261N:
|
||||
case REALTEK_PHY_ID_RTL8264B:
|
||||
phydev->macsec_ops = &rtk_macsec_ops;
|
||||
priv->macsec->max_sa_num = 64;
|
||||
priv->macsec->max_sc_num = 64/4;
|
||||
ret = rtk_phylib_826xb_macsec_init(phydev);
|
||||
if (ret != 0)
|
||||
{
|
||||
phydev_err(phydev, "[%s]rtk_phylib_826xb_macsec_init failed!! 0x%X\n", __FUNCTION__, ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PR_ERR("[%s]phy_id: 0x%X not support!\n", __FUNCTION__, phydev->drv->phy_id);
|
||||
kfree(priv->macsec);
|
||||
priv->macsec = NULL;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_macsec_init(phydev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
56
sources/rtk-be550/src/hal/phy/rtk_osal.c
Executable file
56
sources/rtk-be550/src/hal/phy/rtk_osal.c
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "type.h"
|
||||
#include "error.h"
|
||||
#include "rtk_phylib_def.h"
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
int32
|
||||
osal_time_usecs_get(osal_usecs_t *pUsec)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
|
||||
RT_PARAM_CHK((NULL == pUsec), RT_ERR_NULL_POINTER);
|
||||
|
||||
ktime_get_ts64(&ts);
|
||||
*pUsec = (osal_usecs_t)((ts.tv_sec * USEC_PER_SEC) + (ts.tv_nsec / NSEC_PER_USEC));
|
||||
return RT_ERR_OK;
|
||||
}
|
||||
|
||||
void *
|
||||
osal_alloc(uint32 size)
|
||||
{
|
||||
void *p;
|
||||
p = kmalloc((size_t)size, GFP_ATOMIC);
|
||||
return p;
|
||||
}
|
||||
|
||||
int32
|
||||
phy_common_general_reg_mmd_get(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 *pData)
|
||||
{
|
||||
int32 rData = 0;
|
||||
rData = phy_read_mmd(port, mmdAddr, mmdReg);
|
||||
if (rData < 0)
|
||||
return RT_ERR_FAILED;
|
||||
*pData = (uint32)rData;
|
||||
return RT_ERR_OK;
|
||||
}
|
||||
|
||||
int32
|
||||
phy_common_general_reg_mmd_set(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data)
|
||||
{
|
||||
int ret = phy_write_mmd(port, mmdAddr, mmdReg, data);
|
||||
return (ret < 0) ? RT_ERR_FAILED : RT_ERR_OK;
|
||||
}
|
||||
99
sources/rtk-be550/src/hal/phy/rtk_osal.h
Executable file
99
sources/rtk-be550/src/hal/phy/rtk_osal.h
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __RTK_PHY_OSAL_H
|
||||
#define __RTK_PHY_OSAL_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/phy.h>
|
||||
#include "type.h"
|
||||
#include "error.h"
|
||||
#include "phy_patch.h"
|
||||
#include "rtk_phylib.h"
|
||||
|
||||
#ifdef PHYPATCH_DB_GET
|
||||
#undef PHYPATCH_DB_GET
|
||||
#endif
|
||||
|
||||
#define PHYPATCH_DB_GET(_unit, _pPhy_device, _pPatchDb) \
|
||||
do { \
|
||||
struct rtk_phy_priv *_pPriv = (_pPhy_device)->priv; \
|
||||
rt_phy_patch_db_t *_pDb = _pPriv->patch; _pPatchDb = _pDb; \
|
||||
/*printk("[PHYPATCH_DB_GET] ? [%s]\n", (_pDb != NULL) ? "E":"N");*/ \
|
||||
} while(0)
|
||||
|
||||
#define HWP_9300_FAMILY_ID(_unit) 0
|
||||
#define HWP_9310_FAMILY_ID(_unit) 0
|
||||
#define RTK_9300_FAMILY_ID(_unit) 0
|
||||
#define RTK_9310_FAMILY_ID(_unit) 0
|
||||
#define RTK_9311B_FAMILY_ID(_unit) 0
|
||||
#define RTK_9330_FAMILY_ID(_unit) 0
|
||||
|
||||
#ifndef WAIT_COMPLETE_VAR
|
||||
#define WAIT_COMPLETE_VAR() \
|
||||
osal_usecs_t _t, _now, _t_wait=0, _timeout; \
|
||||
int32 _chkCnt=0;
|
||||
|
||||
#define WAIT_COMPLETE(_timeout_us) \
|
||||
_timeout = _timeout_us; \
|
||||
for(osal_time_usecs_get(&_t),osal_time_usecs_get(&_now),_t_wait=0,_chkCnt=0 ; \
|
||||
(_t_wait <= _timeout); \
|
||||
osal_time_usecs_get(&_now), _chkCnt++, _t_wait += ((_now >= _t) ? (_now - _t) : (0xFFFFFFFF - _t + _now)),_t = _now \
|
||||
)
|
||||
|
||||
#define WAIT_COMPLETE_IS_TIMEOUT() (_t_wait > _timeout)
|
||||
#endif
|
||||
|
||||
/* OSAL */
|
||||
#include <linux/slab.h>
|
||||
int32 osal_time_usecs_get(osal_usecs_t *pUsec);
|
||||
void *osal_alloc(uint32 size);
|
||||
#define osal_time_mdelay mdelay
|
||||
|
||||
#include <linux/ctype.h> /* for Kernel Space */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#define osal_strlen strlen
|
||||
#define osal_strcmp strcmp
|
||||
#define osal_strcpy strcpy
|
||||
#define osal_strncpy strncpy
|
||||
#define osal_strcat strcat
|
||||
#define osal_strchr strchr
|
||||
#define osal_memset memset
|
||||
#define osal_memcpy memcpy
|
||||
#define osal_memcmp memcmp
|
||||
#define osal_strdup strdup
|
||||
#define osal_strncmp strncmp
|
||||
#define osal_strstr strstr
|
||||
#define osal_strtok strtok
|
||||
#define osal_strtok_r strtok_r
|
||||
#define osal_toupper toupper
|
||||
|
||||
#define osal_printf printk
|
||||
|
||||
/* HWP */
|
||||
#define HWP_PORT_SMI(unit, port) 0
|
||||
#define HWP_PHY_MODEL_BY_PORT(unit, port) 0
|
||||
#define HWP_PHY_ADDR(unit, port) 0
|
||||
#define HWP_PHY_BASE_MACID(unit, p) 0
|
||||
#define HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) if (bcast_phyad < 0x1F && p != NULL)
|
||||
|
||||
|
||||
/* RT_LOG */
|
||||
//#define RT_LOG(level, module, fmt, args...) do { printk("RT_LOG:"fmt, ## args); } while(0)
|
||||
#define RT_LOG(level, module, fmt, args...) do {} while(0)
|
||||
#define RT_ERR(error_code, module, fmt, args...) do {} while(0)
|
||||
#define RT_INIT_ERR(error_code, module, fmt, args...) do {} while(0)
|
||||
#define RT_INIT_MSG(fmt, args...) do {} while(0)
|
||||
|
||||
#define phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, bcast_phyad) 0
|
||||
|
||||
/* reg access */
|
||||
int32 phy_common_general_reg_mmd_get(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 *pData);
|
||||
int32 phy_common_general_reg_mmd_set(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data);
|
||||
|
||||
|
||||
#endif /* __RTK_PHY_OSAL_H */
|
||||
654
sources/rtk-be550/src/hal/phy/rtk_phy.c
Executable file
654
sources/rtk-be550/src/hal/phy/rtk_phy.c
Executable file
|
|
@ -0,0 +1,654 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include "phy_rtl826xb_patch.h"
|
||||
|
||||
#include "rtk_phylib_rtl826xb.h"
|
||||
#include "rtk_phylib_macsec.h"
|
||||
#include "rtk_phylib.h"
|
||||
|
||||
#include "rtk_phy.h"
|
||||
|
||||
static struct dentry *phy_sm_barrier = NULL;
|
||||
static struct dentry *allow_phy_up_toggle = NULL;
|
||||
static unsigned int allow_phy_up = 0;
|
||||
|
||||
static int rtkphy_c45_suspend(struct phy_device *phydev);
|
||||
|
||||
#if 0
|
||||
static int rtk_phy_cable_test_report_trans(rtk_rtct_channel_result_t *result)
|
||||
{
|
||||
if(result->cable_status == 0)
|
||||
return ETHTOOL_A_CABLE_RESULT_CODE_OK;
|
||||
|
||||
if(result->cable_status & RTK_PHYLIB_CABLE_STATUS_INTER_PAIR_SHORT)
|
||||
return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
|
||||
if(result->cable_status & RTK_PHYLIB_CABLE_STATUS_SHORT)
|
||||
return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
|
||||
if(result->cable_status & RTK_PHYLIB_CABLE_STATUS_OPEN)
|
||||
return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
|
||||
if(result->cable_status & RTK_PHYLIB_CABLE_STATUS_CROSS)
|
||||
return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
|
||||
|
||||
return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rtl826xb_get_features(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
struct rtk_phy_priv *priv = phydev->priv;
|
||||
|
||||
ret = genphy_c45_pma_read_abilities(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
linkmode_or(phydev->supported, phydev->supported, PHY_BASIC_FEATURES);
|
||||
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->supported);
|
||||
/* not support 10M modes */
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
|
||||
switch (priv->phytype)
|
||||
{
|
||||
case RTK_PHYLIB_RTL8251L:
|
||||
case RTK_PHYLIB_RTL8254B:
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl826xb_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct rtk_phy_priv *priv = NULL;
|
||||
int data = 0;
|
||||
|
||||
phy_sm_barrier = debugfs_create_dir("rtk_phy_sm_barrier", NULL);
|
||||
if ( !phy_sm_barrier )
|
||||
{
|
||||
printk("cannot create rtk debugfs dir phy_sm_barrier.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
allow_phy_up_toggle = debugfs_create_u32("allow_phy_up", S_IRUGO | S_IWUSR, phy_sm_barrier, &allow_phy_up);
|
||||
if ( !allow_phy_up_toggle )
|
||||
{
|
||||
printk("cannot create rtk debugfs allow_phy_up.\n");
|
||||
debugfs_remove_recursive(phy_sm_barrier);
|
||||
phy_sm_barrier = NULL;
|
||||
}
|
||||
else
|
||||
printk("create rtk debugfs allow_phy_up.\n");
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct rtk_phy_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(priv, 0, sizeof(struct rtk_phy_priv));
|
||||
|
||||
if (phy_rtl826xb_patch_db_init(0, phydev, &(priv->patch)) != RT_ERR_OK)
|
||||
return -ENOMEM;
|
||||
|
||||
if (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N)
|
||||
{
|
||||
data = phy_read_mmd(phydev, 30, 0x103);
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
if (data == 0x8251)
|
||||
{
|
||||
priv->phytype = RTK_PHYLIB_RTL8251L;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->phytype = RTK_PHYLIB_RTL8261N;
|
||||
}
|
||||
}
|
||||
else if (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8264B)
|
||||
{
|
||||
data = phy_read_mmd(phydev, 30, 0x103);
|
||||
if (data < 0)
|
||||
return data;
|
||||
|
||||
if (data == 0x8254)
|
||||
{
|
||||
priv->phytype = RTK_PHYLIB_RTL8254B;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->phytype = RTK_PHYLIB_RTL8264B;
|
||||
}
|
||||
}
|
||||
priv->isBasePort = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (1) : (((phydev->mdio.addr % 4) == 0) ? (1) : (0));
|
||||
phydev->priv = priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtkphy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
switch (phydev->drv->phy_id)
|
||||
{
|
||||
case REALTEK_PHY_ID_RTL8261N:
|
||||
case REALTEK_PHY_ID_RTL8264B:
|
||||
phydev_info(phydev, "%s:%u [RTL8261N/RTL826XB] phy_id: 0x%X PHYAD:%d\n", __FUNCTION__, __LINE__, phydev->drv->phy_id, phydev->mdio.addr);
|
||||
|
||||
#if 1 /* toggle reset */
|
||||
phy_write_mmd(phydev, 30, 0x145, 0x0001);
|
||||
phy_write_mmd(phydev, 30, 0x145, 0x0000);
|
||||
mdelay(30);
|
||||
#endif
|
||||
|
||||
ret = phy_patch(0, phydev, 0, PHY_PATCH_MODE_NORMAL);
|
||||
if (ret)
|
||||
{
|
||||
phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] patch failed!! 0x%X\n", __FUNCTION__, __LINE__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rtk_phylib_826xb_intr_init(phydev);
|
||||
if (ret)
|
||||
{
|
||||
phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] rtk_phylib_826xb_intr_init failed!! 0x%X\n", __FUNCTION__, __LINE__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rtk_macsec_init(phydev);
|
||||
if (ret)
|
||||
{
|
||||
phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] rtk_macsec_init failed!! 0x%X\n", __FUNCTION__, __LINE__, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = rtk_phylib_826xb_sds_write(phydev, 6, 3, 15, 0, 0x88C6);
|
||||
if (ret)
|
||||
{
|
||||
phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] SerDes init failed!! 0x%X\n", __FUNCTION__, __LINE__, ret);
|
||||
return ret;
|
||||
}
|
||||
rtkphy_c45_suspend(phydev);
|
||||
#if 0 /* Debug: patch check */
|
||||
ret = phy_patch(0, phydev, 0, PHY_PATCH_MODE_CMP);
|
||||
if (ret)
|
||||
{
|
||||
phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] phy_patch failed!! 0x%X\n", __FUNCTION__, __LINE__, ret);
|
||||
return ret;
|
||||
}
|
||||
printk("[%s,%u] patch chk %s\n", __FUNCTION__, __LINE__, (ret == 0) ? "PASS" : "FAIL");
|
||||
#endif
|
||||
#if 0 /* Debug: USXGMII*/
|
||||
{
|
||||
uint32 data = 0;
|
||||
rtk_phylib_826xb_sds_read(phydev, 0x07, 0x10, 15, 0, &data);
|
||||
printk("[%s,%u] SDS 0x07, 0x10 : 0x%X\n", __FUNCTION__, __LINE__, data);
|
||||
rtk_phylib_826xb_sds_read(phydev, 0x06, 0x12, 15, 0, &data);
|
||||
printk("[%s,%u] SDS 0x06, 0x12 : 0x%X\n", __FUNCTION__, __LINE__, data);
|
||||
}
|
||||
{
|
||||
u16 sdspage = 0x5, sdsreg = 0x0;
|
||||
u16 regData = (sdspage & 0x3f) | ((sdsreg & 0x1f) << 6) | BIT(15);
|
||||
u16 readData = 0;
|
||||
phy_write_mmd(phydev, 30, 323, regData);
|
||||
do
|
||||
{
|
||||
udelay(10);
|
||||
readData = phy_read_mmd(phydev, 30, 323);
|
||||
} while ((readData & BIT(15)) != 0);
|
||||
readData = phy_read_mmd(phydev, 30, 322);
|
||||
printk("[%s,%d] sds link [%s] (0x%X)\n", __FUNCTION__, __LINE__, (readData & BIT(12)) ? "UP" : "DOWN", readData);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
default:
|
||||
phydev_err(phydev, "%s:%u Unknow phy_id: 0x%X\n", __FUNCTION__, __LINE__, phydev->drv->phy_id);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtkphy_c45_suspend(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = rtk_phylib_c45_power_low(phydev);
|
||||
|
||||
phydev->speed = SPEED_UNKNOWN;
|
||||
phydev->duplex = DUPLEX_UNKNOWN;
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtkphy_c45_resume(struct phy_device *phydev)
|
||||
{
|
||||
if ( !likely(READ_ONCE(allow_phy_up)) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return rtk_phylib_c45_power_normal(phydev);
|
||||
}
|
||||
|
||||
static int rtkphy_c45_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
bool changed = false;
|
||||
u16 reg = 0;
|
||||
int ret = 0;
|
||||
u32 adv,status;
|
||||
|
||||
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
|
||||
if (phydev->autoneg == AUTONEG_DISABLE)
|
||||
{
|
||||
if (phydev->speed != SPEED_100)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
return genphy_c45_pma_setup_forced(phydev);
|
||||
}
|
||||
|
||||
linkmode_and(phydev->advertising, phydev->advertising,
|
||||
phydev->supported);
|
||||
|
||||
status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||
phydev->advertising, status & ADVERTISE_PAUSE_CAP);
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||
phydev->advertising, status & ADVERTISE_PAUSE_ASYM);
|
||||
|
||||
adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
|
||||
|
||||
ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
|
||||
ADVERTISE_ALL | ADVERTISE_100BASE4,
|
||||
adv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
|
||||
|
||||
ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
|
||||
MDIO_AN_10GBT_CTRL_ADV10G |
|
||||
MDIO_AN_10GBT_CTRL_ADV5G |
|
||||
MDIO_AN_10GBT_CTRL_ADV2_5G, adv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
reg = 0;
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->advertising))
|
||||
reg |= BIT(9);
|
||||
|
||||
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
|
||||
phydev->advertising))
|
||||
reg |= BIT(8);
|
||||
|
||||
ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xA412,
|
||||
BIT(9) | BIT(8) , reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
changed = true;
|
||||
|
||||
return genphy_c45_check_and_restart_aneg(phydev, changed);
|
||||
}
|
||||
|
||||
static int rtkphy_c45_aneg_done(struct phy_device *phydev)
|
||||
{
|
||||
return genphy_c45_aneg_done(phydev);
|
||||
}
|
||||
|
||||
static int rtkphy_c45_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0, status = 0;
|
||||
phydev->speed = SPEED_UNKNOWN;
|
||||
phydev->duplex = DUPLEX_UNKNOWN;
|
||||
phydev->pause = 0;
|
||||
phydev->asym_pause = 0;
|
||||
|
||||
ret = genphy_c45_read_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE)
|
||||
{
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->lp_advertising);
|
||||
|
||||
ret = genphy_c45_read_lpa(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
status = phy_read_mmd(phydev, 31, 0xA414);
|
||||
if (status < 0)
|
||||
return status;
|
||||
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->lp_advertising, status & BIT(11));
|
||||
|
||||
phy_resolve_aneg_linkmode(phydev);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = genphy_c45_read_pma(phydev);
|
||||
}
|
||||
|
||||
/* mdix*/
|
||||
status = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_SWAPPOL);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
switch (status & 0x3)
|
||||
{
|
||||
case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
|
||||
phydev->mdix = ETH_TP_MDI;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
phydev->mdix = ETH_TP_MDI_X;
|
||||
break;
|
||||
|
||||
default:
|
||||
phydev->mdix = ETH_TP_MDI_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtkphy_c45_pcs_loopback(struct phy_device *phydev, bool enable)
|
||||
{
|
||||
return rtk_phylib_c45_pcs_loopback(phydev, (enable == true) ? 1 : 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int rtl826xb_cable_test_start(struct phy_device *phydev)
|
||||
{
|
||||
return rtk_phylib_826xb_cable_test_start(phydev);
|
||||
}
|
||||
|
||||
static int rtl826xb_cable_test_get_status(struct phy_device *phydev, bool *finished)
|
||||
{
|
||||
uint32 finish_read = 0;
|
||||
int32 ret = 0;
|
||||
uint32 pair = 0;
|
||||
rtk_rtct_channel_result_t reslut;
|
||||
|
||||
*finished = false;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_cable_test_finished_get(phydev, &finish_read));
|
||||
*finished = (finish_read == 1) ? true : false;
|
||||
|
||||
if (finish_read == 1)
|
||||
{
|
||||
for (pair = 0; pair < 4; pair++)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_cable_test_result_get(phydev, pair, &reslut));
|
||||
ethnl_cable_test_result(phydev, pair, rtk_phy_cable_test_report_trans(&reslut));
|
||||
|
||||
if(reslut.cable_status != RTK_PHYLIB_CABLE_STATUS_NORMAL)
|
||||
ethnl_cable_test_fault_length(phydev, pair, reslut.length_cm);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rtl826xb_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_intr_enable(phydev, (phydev->interrupts == PHY_INTERRUPT_ENABLED)? 1 : 0));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl826xb_ack_intr(struct phy_device *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 status = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_intr_read_clear(phydev, &status));
|
||||
if (status & RTK_PHY_INTR_WOL)
|
||||
{
|
||||
rtk_phylib_826xb_wol_reset(phydev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl826xb_handle_intr(struct phy_device *phydev)
|
||||
{
|
||||
irqreturn_t ret;
|
||||
uint32 status = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_intr_read_clear(phydev, &status));
|
||||
if (status & RTK_PHY_INTR_LINK_CHANGE)
|
||||
{
|
||||
pr_debug("[%s,%d] RTK_PHY_INTR_LINK_CHANGE\n", __FUNCTION__, __LINE__);
|
||||
phy_mac_interrupt(phydev);
|
||||
}
|
||||
|
||||
if (status & RTK_PHY_INTR_WOL)
|
||||
{
|
||||
pr_debug("[%s,%d] RTK_PHY_INTR_WOL\n", __FUNCTION__, __LINE__);
|
||||
rtk_phylib_826xb_wol_reset(phydev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl826xb_get_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, void *data)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 val = 0;
|
||||
|
||||
switch (tuna->id)
|
||||
{
|
||||
case ETHTOOL_PHY_EDPD:
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_link_down_power_saving_get(phydev, &val));
|
||||
*(u16 *)data = (val == 0) ? ETHTOOL_PHY_EDPD_DISABLE : ETHTOOL_PHY_EDPD_DFLT_TX_MSECS;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int rtl826xb_set_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, const void *data)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 val = 0;
|
||||
|
||||
switch (tuna->id)
|
||||
{
|
||||
case ETHTOOL_PHY_EDPD:
|
||||
switch (*(const u16 *)data)
|
||||
{
|
||||
case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:
|
||||
val = 1;
|
||||
break;
|
||||
case ETHTOOL_PHY_EDPD_DISABLE:
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_link_down_power_saving_set(phydev, val));
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int rtl826xb_set_wol(struct phy_device *phydev,
|
||||
struct ethtool_wolinfo *wol)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint8 *mac_addr = NULL;
|
||||
uint32 rtk_wol_opts = 0;
|
||||
|
||||
struct net_device *ndev = phydev->attached_dev;
|
||||
if (!ndev)
|
||||
return RTK_PHYLIB_ERR_FAILED;
|
||||
|
||||
if (wol->wolopts & ~( WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (wol->wolopts & (WAKE_MAGIC | WAKE_UCAST))
|
||||
{
|
||||
mac_addr = (uint8 *) ndev->dev_addr;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_wol_unicast_addr_set(phydev, mac_addr));
|
||||
}
|
||||
|
||||
if (wol->wolopts & WAKE_MCAST)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_wol_multicast_mask_reset(phydev));
|
||||
|
||||
if (!netdev_mc_empty(ndev))
|
||||
{
|
||||
struct netdev_hw_addr *ha;
|
||||
netdev_for_each_mc_addr(ha, ndev)
|
||||
{
|
||||
pr_info("[%s,%d] mac: %pM \n", __FUNCTION__, __LINE__, ha->addr);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_wol_multicast_mask_add(phydev, rtk_phylib_826xb_wol_multicast_mac2offset(ha->addr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wol->wolopts & WAKE_PHY)
|
||||
rtk_wol_opts |= RTK_WOL_OPT_LINK;
|
||||
if (wol->wolopts & WAKE_MAGIC)
|
||||
rtk_wol_opts |= RTK_WOL_OPT_MAGIC;
|
||||
if (wol->wolopts & WAKE_UCAST)
|
||||
rtk_wol_opts |= RTK_WOL_OPT_UCAST;
|
||||
if (wol->wolopts & WAKE_BCAST)
|
||||
rtk_wol_opts |= RTK_WOL_OPT_BCAST;
|
||||
if (wol->wolopts & WAKE_MCAST)
|
||||
rtk_wol_opts |= RTK_WOL_OPT_MCAST;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_wol_set(phydev, rtk_wol_opts));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void rtl826xb_get_wol(struct phy_device *phydev,
|
||||
struct ethtool_wolinfo *wol)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 rtk_wol_opts = 0;
|
||||
|
||||
wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST;
|
||||
wol->wolopts = 0;
|
||||
|
||||
ret = rtk_phylib_826xb_wol_get(phydev, &rtk_wol_opts);
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
if (rtk_wol_opts & RTK_WOL_OPT_LINK)
|
||||
wol->wolopts |= WAKE_PHY;
|
||||
if (rtk_wol_opts & RTK_WOL_OPT_MAGIC)
|
||||
wol->wolopts |= WAKE_MAGIC;
|
||||
if (rtk_wol_opts & RTK_WOL_OPT_UCAST)
|
||||
wol->wolopts |= WAKE_UCAST;
|
||||
if (rtk_wol_opts & RTK_WOL_OPT_MCAST)
|
||||
wol->wolopts |= WAKE_MCAST;
|
||||
if (rtk_wol_opts & RTK_WOL_OPT_BCAST)
|
||||
wol->wolopts |= WAKE_BCAST;
|
||||
}
|
||||
|
||||
static struct phy_driver rtk_phy_drivers[] = {
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N),
|
||||
.name = "Realtek RTL8261N/8261BE/8251L",
|
||||
.get_features = rtl826xb_get_features,
|
||||
.config_init = rtkphy_config_init,
|
||||
.probe = rtl826xb_probe,
|
||||
.suspend = rtkphy_c45_suspend,
|
||||
.resume = rtkphy_c45_resume,
|
||||
.config_aneg = rtkphy_c45_config_aneg,
|
||||
.aneg_done = rtkphy_c45_aneg_done,
|
||||
.read_status = rtkphy_c45_read_status,
|
||||
.set_loopback = rtkphy_c45_pcs_loopback,
|
||||
#if 0
|
||||
.cable_test_start = rtl826xb_cable_test_start,
|
||||
.cable_test_get_status = rtl826xb_cable_test_get_status,
|
||||
#endif
|
||||
.config_intr = rtl826xb_config_intr,
|
||||
.ack_interrupt = rtl826xb_ack_intr,
|
||||
.handle_interrupt = rtl826xb_handle_intr,
|
||||
.get_tunable = rtl826xb_get_tunable,
|
||||
.set_tunable = rtl826xb_set_tunable,
|
||||
.set_wol = rtl826xb_set_wol,
|
||||
.get_wol = rtl826xb_get_wol,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B),
|
||||
.name = "Realtek RTL8264B/8254B",
|
||||
.get_features = rtl826xb_get_features,
|
||||
.config_init = rtkphy_config_init,
|
||||
.probe = rtl826xb_probe,
|
||||
.suspend = rtkphy_c45_suspend,
|
||||
.resume = rtkphy_c45_resume,
|
||||
.config_aneg = rtkphy_c45_config_aneg,
|
||||
.aneg_done = rtkphy_c45_aneg_done,
|
||||
.read_status = rtkphy_c45_read_status,
|
||||
.set_loopback = rtkphy_c45_pcs_loopback,
|
||||
#if 0
|
||||
.cable_test_start = rtl826xb_cable_test_start,
|
||||
.cable_test_get_status = rtl826xb_cable_test_get_status,
|
||||
#endif
|
||||
.config_intr = rtl826xb_config_intr,
|
||||
.ack_interrupt = rtl826xb_ack_intr,
|
||||
.handle_interrupt = rtl826xb_handle_intr,
|
||||
.get_tunable = rtl826xb_get_tunable,
|
||||
.set_tunable = rtl826xb_set_tunable,
|
||||
.set_wol = rtl826xb_set_wol,
|
||||
.get_wol = rtl826xb_get_wol,
|
||||
},
|
||||
};
|
||||
|
||||
module_phy_driver(rtk_phy_drivers);
|
||||
|
||||
|
||||
static struct mdio_device_id __maybe_unused rtk_phy_tbl[] = {
|
||||
{ PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N) },
|
||||
{ PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B) },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(mdio, rtk_phy_tbl);
|
||||
|
||||
MODULE_AUTHOR("Realtek");
|
||||
MODULE_DESCRIPTION("Realtek PHY drivers");
|
||||
MODULE_LICENSE("GPL");
|
||||
20
sources/rtk-be550/src/hal/phy/rtk_phy.h
Executable file
20
sources/rtk-be550/src/hal/phy/rtk_phy.h
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#define REALTEK_PHY_ID_RTL8261N 0x001CCAF3
|
||||
#define REALTEK_PHY_ID_RTL8264B 0x001CC813
|
||||
|
||||
#if IS_ENABLED(CONFIG_MACSEC)
|
||||
int rtk_macsec_init(struct phy_device *phydev);
|
||||
#else
|
||||
static inline int rtk_macsec_init(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
117
sources/rtk-be550/src/hal/phy/rtk_phylib.c
Executable file
117
sources/rtk-be550/src/hal/phy/rtk_phylib.c
Executable file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "rtk_phylib.h"
|
||||
#include <linux/phy.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
/* OSAL */
|
||||
|
||||
void rtk_phylib_mdelay(uint32 msec)
|
||||
{
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
mdelay(msec);
|
||||
#else
|
||||
osal_time_mdelay(msec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void rtk_phylib_udelay(uint32 usec)
|
||||
{
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
if (1000 <= usec)
|
||||
{
|
||||
mdelay(usec/1000);
|
||||
usec = usec % 1000;
|
||||
}
|
||||
udelay(usec);
|
||||
#else
|
||||
osal_time_udelay(usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 rtk_phylib_time_usecs_get(uint32 *pUsec)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
|
||||
if(NULL == pUsec)
|
||||
return RTK_PHYLIB_ERR_INPUT;
|
||||
|
||||
ktime_get_ts64(&ts);
|
||||
*pUsec = ((ts.tv_sec * USEC_PER_SEC) + (ts.tv_nsec / NSEC_PER_USEC));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register Access APIs */
|
||||
int32 rtk_phylib_mmd_write(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 data)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 mask = 0;
|
||||
mask = UINT32_BITS_MASK(msb,lsb);
|
||||
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
ret = phy_modify_mmd(phydev, mmd, reg, mask, (data << lsb));
|
||||
#else
|
||||
{
|
||||
uint32 rData = 0, wData = 0;
|
||||
if ((msb != 15) || (lsb != 0))
|
||||
{
|
||||
if ((ret = phy_common_general_reg_mmd_get(phydev->unit, phydev->port, page, reg, &rData)) != RT_ERR_OK)
|
||||
return ret;
|
||||
}
|
||||
wData = REG32_FIELD_SET(rData, data, lsb, mask);
|
||||
ret = phy_common_general_reg_mmd_set(phydev->unit, phydev->port, page, reg, wData);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32 rtk_phylib_mmd_read(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 rData = 0;
|
||||
uint32 mask = 0;
|
||||
mask = UINT32_BITS_MASK(msb,lsb);
|
||||
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
rData = phy_read_mmd(phydev, mmd, reg);
|
||||
#else
|
||||
{
|
||||
ret = phy_common_general_reg_mmd_get(phydev->unit, phydev->port, page, reg, &rData);
|
||||
}
|
||||
#endif
|
||||
|
||||
*pData = REG32_FIELD_GET(rData, lsb, mask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function Driver */
|
||||
|
||||
int32 rtk_phylib_c45_power_normal(rtk_phydev *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 1, 0, 11, 11, 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 rtk_phylib_c45_power_low(rtk_phydev *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 1, 0, 11, 11, 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 rtk_phylib_c45_pcs_loopback(rtk_phydev *phydev, uint32 enable)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 3, 0, 14, 14, (enable == 0) ? 0 : 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
257
sources/rtk-be550/src/hal/phy/rtk_phylib.h
Executable file
257
sources/rtk-be550/src/hal/phy/rtk_phylib.h
Executable file
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __RTK_PHYLIB_H
|
||||
#define __RTK_PHYLIB_H
|
||||
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#include <linux/phy.h>
|
||||
#include "type.h"
|
||||
#include "rtk_phylib_def.h"
|
||||
#else
|
||||
//#include SDK headers
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define MACSEC_DBG_PRINT 1
|
||||
#endif
|
||||
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#define PR_INFO(_fmt, _args...) pr_info(_fmt, ##_args)
|
||||
#define PR_DBG(_fmt, _args...) pr_debug(_fmt, ##_args)
|
||||
#define PR_ERR(_fmt, _args...) pr_err("ERROR: "_fmt, ##_args)
|
||||
|
||||
#define RTK_PHYLIB_ERR_FAILED (-EPERM)
|
||||
#define RTK_PHYLIB_ERR_INPUT (-EINVAL)
|
||||
#define RTK_PHYLIB_ERR_EXCEEDS_CAPACITY (-ENOSPC)
|
||||
#define RTK_PHYLIB_ERR_TIMEOUT (-ETIME)
|
||||
#define RTK_PHYLIB_ERR_ENTRY_NOTFOUND (-ENODATA)
|
||||
#define RTK_PHYLIB_ERR_OPER_DENIED (-EACCES)
|
||||
#else
|
||||
#define PR_INFO(_fmt, _args...) RT_LOG(LOG_INFO, (MOD_HAL|MOD_PHY), _fmt, ##_args)
|
||||
#define PR_DBG(_fmt, _args...) RT_LOG(LOG_DEBUG, (MOD_HAL|MOD_PHY), _fmt, ##_args)
|
||||
#define PR_ERR(_fmt, _args...) RT_LOG(LOG_MAJOR_ERR, (MOD_HAL|MOD_PHY), _fmt, ##_args)
|
||||
|
||||
#define RTK_PHYLIB_ERR_FAILED (RT_ERR_FAILED)
|
||||
#define RTK_PHYLIB_ERR_INPUT (RT_ERR_INPUT)
|
||||
#define RTK_PHYLIB_ERR_EXCEEDS_CAPACITY (RT_ERR_EXCEEDS_CAPACITY)
|
||||
#define RTK_PHYLIB_ERR_TIMEOUT (RT_ERR_BUSYWAIT_TIMEOUT)
|
||||
#define RTK_PHYLIB_ERR_ENTRY_NOTFOUND (RT_ERR_ENTRY_NOTFOUND)
|
||||
#define RTK_PHYLIB_ERR_OPER_DENIED (RT_ERR_OPER_DENIED)
|
||||
#endif
|
||||
|
||||
typedef enum rtk_phylib_phy_e
|
||||
{
|
||||
RTK_PHYLIB_NONE,
|
||||
RTK_PHYLIB_RTL8261N,
|
||||
RTK_PHYLIB_RTL8264B,
|
||||
RTK_PHYLIB_RTL8251L,
|
||||
RTK_PHYLIB_RTL8254B,
|
||||
RTK_PHYLIB_END
|
||||
} rtk_phylib_phy_t;
|
||||
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
typedef struct phy_device rtk_phydev;
|
||||
#else
|
||||
struct rtk_phy_dev_s
|
||||
{
|
||||
uint32 unit;
|
||||
rtk_port_t port;
|
||||
|
||||
struct rtk_phy_priv *priv;
|
||||
};
|
||||
typedef struct rtk_phy_dev_s rtk_phydev;
|
||||
#endif
|
||||
|
||||
#define RTK_PHYLIB_ERR_CHK(op)\
|
||||
do {\
|
||||
if ((ret = (op)) != 0)\
|
||||
return ret;\
|
||||
} while(0)
|
||||
|
||||
#define RTK_PHYLIB_VAL_TO_BYTE_ARRAY(_val, _valbytes, _array, _start, _bytes)\
|
||||
do{\
|
||||
uint32 _i = 0;\
|
||||
for (_i = 0; _i < _bytes; _i++)\
|
||||
_array[(_bytes-1)-_i] = (_val >> (8* (_valbytes - _i - 1)));\
|
||||
}while(0)
|
||||
|
||||
#define RTK_PHYLIB_BYTE_ARRAY_TO_VAL(_val, _array, _start, _bytes)\
|
||||
do{\
|
||||
uint32 _i = 0;\
|
||||
_val = 0;\
|
||||
for (_i = 0; _i < _bytes; _i++)\
|
||||
_val = (_val << 8) | _array[(_bytes-1)-_i];\
|
||||
}while(0)
|
||||
|
||||
|
||||
/* RTCT */
|
||||
#define RTK_PHYLIB_CABLE_STATUS_NORMAL (0)
|
||||
#define RTK_PHYLIB_CABLE_STATUS_UNKNOWN (1u << 0)
|
||||
#define RTK_PHYLIB_CABLE_STATUS_SHORT (1u << 1)
|
||||
#define RTK_PHYLIB_CABLE_STATUS_OPEN (1u << 2)
|
||||
#define RTK_PHYLIB_CABLE_STATUS_MISMATCH (1u << 3)
|
||||
#define RTK_PHYLIB_CABLE_STATUS_CROSS (1u << 4)
|
||||
#define RTK_PHYLIB_CABLE_STATUS_INTER_PAIR_SHORT (1u << 5)
|
||||
|
||||
typedef struct rtk_rtct_channel_result_s
|
||||
{
|
||||
uint32 cable_status;
|
||||
uint32 length_cm;
|
||||
} rtk_rtct_channel_result_t;
|
||||
|
||||
/* MACsec */
|
||||
typedef struct rtk_macsec_sa_info_s
|
||||
{
|
||||
uint8 ssci[4];
|
||||
} rtk_macsec_sa_info_t;
|
||||
|
||||
#define MACSEC_SA_IS_USED(macsec_port_info_ptr, dir, sa_id) (macsec_port_info_ptr->sa_used[dir][sa_id])
|
||||
#define MACSEC_SC_IS_USED(macsec_port_info_ptr, dir, sc_id) (macsec_port_info_ptr->sc_used[dir][sc_id])
|
||||
|
||||
#define MACSEC_SA_IS_CLEAR(macsec_port_info_ptr, dir, sa_id) (!MACSEC_SA_IS_USED(macsec_port_info_ptr, dir, sa_id))
|
||||
#define MACSEC_SC_IS_CLEAR(macsec_port_info_ptr, dir, sc_id) (!MACSEC_SC_IS_USED(macsec_port_info_ptr, dir, sc_id))
|
||||
|
||||
#define MACSEC_SA_SET_USED(macsec_port_info_ptr, dir, sa_id) do { macsec_port_info_ptr->sa_used[dir][sa_id] = 1; }while(0)
|
||||
#define MACSEC_SC_SET_USED(macsec_port_info_ptr, dir, sc_id) do { macsec_port_info_ptr->sc_used[dir][sc_id] = 1; }while(0)
|
||||
|
||||
#define MACSEC_SA_UNSET_USED(macsec_port_info_ptr, dir, sa_id) do { macsec_port_info_ptr->sa_used[dir][sa_id] = 0; }while(0)
|
||||
#define MACSEC_SC_UNSET_USED(macsec_port_info_ptr, dir, sc_id) do { macsec_port_info_ptr->sc_used[dir][sc_id] = 0; }while(0)
|
||||
|
||||
#define MACSEC_SA_MAX(macsec_port_info_ptr) macsec_port_info_ptr->max_sa_num
|
||||
#define MACSEC_SC_MAX(macsec_port_info_ptr) macsec_port_info_ptr->max_sc_num
|
||||
#define MACSEC_SC_CS(macsec_port_info_ptr, dir, sc_id) macsec_port_info_ptr->cipher_suite[dir][sc_id]
|
||||
#define MACSEC_SC_MATCH(macsec_port_info_ptr, dir, sc_id) macsec_port_info_ptr->flow_match[dir][sc_id]
|
||||
#define MACSEC_SA_SSCI(macsec_port_info_ptr, sa_id) macsec_port_info_ptr->sa_info[sa_id].ssci
|
||||
|
||||
|
||||
typedef struct rtk_macsec_port_stats_s
|
||||
{
|
||||
uint64 InPktsUntagged;
|
||||
uint64 InPktsNoTag;
|
||||
uint64 InPktsBadTag;
|
||||
uint64 InPktsUnknownSCI;
|
||||
uint64 InPktsNoSCI;
|
||||
uint64 OutPktsUntagged;
|
||||
}rtk_macsec_port_stats_t;
|
||||
|
||||
typedef struct rtk_macsec_txsa_stats_s
|
||||
{
|
||||
uint64 OutPktsTooLong;
|
||||
uint64 OutOctetsProtectedEncrypted;
|
||||
uint64 OutPktsProtectedEncrypted;
|
||||
}rtk_macsec_txsa_stats_t;
|
||||
|
||||
typedef struct rtk_macsec_rxsa_stats_s
|
||||
{
|
||||
uint64 InPktsUnusedSA;
|
||||
uint64 InPktsNotUsingSA;
|
||||
uint64 InPktsUnchecked;
|
||||
uint64 InPktsDelayed;
|
||||
uint64 InPktsLate;
|
||||
uint64 InPktsOK;
|
||||
uint64 InPktsInvalid;
|
||||
uint64 InPktsNotValid;
|
||||
uint64 InOctetsDecryptedValidated;
|
||||
}rtk_macsec_rxsa_stats_t;
|
||||
|
||||
typedef struct rtk_macsec_port_info_s
|
||||
{
|
||||
int32 (*macsec_reg_get)(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData);
|
||||
int32 (*macsec_reg_set)(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 reg, uint8 msb, uint8 lsb, uint32 data);
|
||||
|
||||
uint16 sa_gen_seq;
|
||||
uint32 max_sa_num;
|
||||
uint32 max_sc_num;
|
||||
rtk_macsec_cipher_t cipher_suite[RTK_MACSEC_DIR_END][RTK_MAX_MACSEC_SC_PER_PORT];
|
||||
uint32 flow_match[RTK_MACSEC_DIR_END][RTK_MAX_MACSEC_SC_PER_PORT];
|
||||
uint8 sc_used[RTK_MACSEC_DIR_END][RTK_MAX_MACSEC_SC_PER_PORT];
|
||||
uint8 sa_used[RTK_MACSEC_DIR_END][RTK_MAX_MACSEC_SA_PER_PORT];
|
||||
rtk_macsec_sa_info_t sa_info[RTK_MAX_MACSEC_SA_PER_PORT];
|
||||
uint64 sci[RTK_MACSEC_DIR_END][RTK_MAX_MACSEC_SC_PER_PORT];
|
||||
|
||||
rtk_macsec_port_stats_t port_stats;
|
||||
rtk_macsec_txsa_stats_t *txsa_stats[RTK_MAX_MACSEC_SA_PER_PORT];
|
||||
rtk_macsec_rxsa_stats_t *rxsa_stats[RTK_MAX_MACSEC_SA_PER_PORT];
|
||||
} rtk_macsec_port_info_t;
|
||||
|
||||
struct rtk_phy_priv {
|
||||
rtk_phylib_phy_t phytype;
|
||||
uint8 isBasePort;
|
||||
rt_phy_patch_db_t *patch;
|
||||
rtk_macsec_port_info_t *macsec;
|
||||
};
|
||||
|
||||
/* OSAL */
|
||||
void rtk_phylib_mdelay(uint32 msec);
|
||||
void rtk_phylib_udelay(uint32 usec);
|
||||
#define rtk_phylib_strlen strlen
|
||||
#define rtk_phylib_strcmp strcmp
|
||||
#define rtk_phylib_strcpy strcpy
|
||||
#define rtk_phylib_strncpy strncpy
|
||||
#define rtk_phylib_strcat strcat
|
||||
#define rtk_phylib_strchr strchr
|
||||
#define rtk_phylib_memset memset
|
||||
#define rtk_phylib_memcpy memcpy
|
||||
#define rtk_phylib_memcmp memcmp
|
||||
#define rtk_phylib_strdup strdup
|
||||
#define rtk_phylib_strncmp strncmp
|
||||
#define rtk_phylib_strstr strstr
|
||||
#define rtk_phylib_strtok strtok
|
||||
#define rtk_phylib_strtok_r strtok_r
|
||||
#define rtk_phylib_toupper toupper
|
||||
|
||||
int rtk_phylib_time_usecs_get(uint32 *pUsec);
|
||||
#ifndef WAIT_COMPLETE_VAR
|
||||
#define WAIT_COMPLETE_VAR() \
|
||||
uint32 _t, _now, _t_wait=0, _timeout; \
|
||||
int32 _chkCnt=0;
|
||||
|
||||
#define WAIT_COMPLETE(_timeout_us) \
|
||||
_timeout = _timeout_us; \
|
||||
for(rtk_phylib_time_usecs_get(&_t),rtk_phylib_time_usecs_get(&_now),_t_wait=0,_chkCnt=0 ; \
|
||||
(_t_wait <= _timeout); \
|
||||
rtk_phylib_time_usecs_get(&_now), _chkCnt++, _t_wait += ((_now >= _t) ? (_now - _t) : (0xFFFFFFFF - _t + _now)),_t = _now \
|
||||
)
|
||||
|
||||
#define WAIT_COMPLETE_IS_TIMEOUT() (_t_wait > _timeout)
|
||||
#endif
|
||||
|
||||
|
||||
/* Register Access APIs */
|
||||
int32 rtk_phylib_mmd_write(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 data);
|
||||
int32 rtk_phylib_mmd_read(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData);
|
||||
|
||||
/* Function Driver */
|
||||
int32 rtk_phylib_c45_power_normal(rtk_phydev *phydev);
|
||||
int32 rtk_phylib_c45_power_low(rtk_phydev *phydev);
|
||||
int32 rtk_phylib_c45_pcs_loopback(rtk_phydev *phydev, uint32 enable);
|
||||
|
||||
/* MACsec*/
|
||||
int32 rtk_phylib_macsec_init(rtk_phydev *phydev);
|
||||
int32 rtk_phylib_macsec_enable_get(rtk_phydev *phydev, uint32 *pEna);
|
||||
int32 rtk_phylib_macsec_enable_set(rtk_phydev *phydev, uint32 ena);
|
||||
|
||||
int32 rtk_phylib_macsec_sc_create(rtk_phydev *phydev, rtk_macsec_dir_t dir, rtk_macsec_sc_t *pSc, uint32 *pSc_id, uint8 active);
|
||||
int32 rtk_phylib_macsec_sc_update(rtk_phydev *phydev, rtk_macsec_dir_t dir, rtk_macsec_sc_t *pSc, uint32 *pSc_id, uint8 active);
|
||||
int32 rtk_phylib_macsec_sc_del(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 sc_id);
|
||||
int32 rtk_phylib_macsec_sci_to_scid(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint64 sci, uint32 *sc_id);
|
||||
int32 rtk_phylib_macsec_sc_status_get(rtk_phydev *phydev, rtk_macsec_dir_t dir,uint32 sc_id, rtk_macsec_sc_status_t *pSc_status);
|
||||
int32 rtk_phylib_macsec_sc_get(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 sc_id, rtk_macsec_sc_t *pSc);
|
||||
|
||||
int32 rtk_phylib_macsec_sa_activate(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 sc_id, rtk_macsec_an_t an);
|
||||
int32 rtk_phylib_macsec_rxsa_disable(rtk_phydev *phydev, uint32 rxsc_id, rtk_macsec_an_t an);
|
||||
int32 rtk_phylib_macsec_txsa_disable(rtk_phydev *phydev, uint32 txsc_id);
|
||||
int32 rtk_phylib_macsec_sa_create(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 sc_id, rtk_macsec_an_t an, rtk_macsec_sa_t *pSa);
|
||||
int32 rtk_phylib_macsec_sa_get(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 sc_id, rtk_macsec_an_t an, rtk_macsec_sa_t *pSa);
|
||||
int32 rtk_phylib_macsec_sa_del(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 sc_id, rtk_macsec_an_t an);
|
||||
|
||||
int32 rtk_phylib_macsec_stat_port_get(rtk_phydev *phydev, rtk_macsec_stat_t stat, uint64 *pCnt);
|
||||
int32 rtk_phylib_macsec_stat_txsa_get(rtk_phydev *phydev, uint32 sc_id, rtk_macsec_an_t an, rtk_macsec_txsa_stat_t stat, uint64 *pCnt);
|
||||
int32 rtk_phylib_macsec_stat_rxsa_get(rtk_phydev *phydev, uint32 sc_id, rtk_macsec_an_t an, rtk_macsec_rxsa_stat_t stat, uint64 *pCnt);
|
||||
|
||||
|
||||
#endif /* __RTK_PHYLIB_H */
|
||||
394
sources/rtk-be550/src/hal/phy/rtk_phylib_def.h
Executable file
394
sources/rtk-be550/src/hal/phy/rtk_phylib_def.h
Executable file
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __RTK_PHYLIB_DEF_H
|
||||
#define __RTK_PHYLIB_DEF_H
|
||||
|
||||
#include "type.h"
|
||||
|
||||
#define PHY_C22_MMD_PAGE 0x0A41
|
||||
#define PHY_C22_MMD_DEV_REG 13
|
||||
#define PHY_C22_MMD_ADD_REG 14
|
||||
|
||||
/* MDIO Manageable Device(MDD) address*/
|
||||
#define PHY_MMD_PMAPMD 1
|
||||
#define PHY_MMD_PCS 3
|
||||
#define PHY_MMD_AN 7
|
||||
#define PHY_MMD_VEND1 30 /* Vendor specific 1 */
|
||||
#define PHY_MMD_VEND2 31 /* Vendor specific 2 */
|
||||
|
||||
#define BIT_0 0x00000001U
|
||||
#define BIT_1 0x00000002U
|
||||
#define BIT_2 0x00000004U
|
||||
#define BIT_3 0x00000008U
|
||||
#define BIT_4 0x00000010U
|
||||
#define BIT_5 0x00000020U
|
||||
#define BIT_6 0x00000040U
|
||||
#define BIT_7 0x00000080U
|
||||
#define BIT_8 0x00000100U
|
||||
#define BIT_9 0x00000200U
|
||||
#define BIT_10 0x00000400U
|
||||
#define BIT_11 0x00000800U
|
||||
#define BIT_12 0x00001000U
|
||||
#define BIT_13 0x00002000U
|
||||
#define BIT_14 0x00004000U
|
||||
#define BIT_15 0x00008000U
|
||||
#define BIT_16 0x00010000U
|
||||
#define BIT_17 0x00020000U
|
||||
#define BIT_18 0x00040000U
|
||||
#define BIT_19 0x00080000U
|
||||
#define BIT_20 0x00100000U
|
||||
#define BIT_21 0x00200000U
|
||||
#define BIT_22 0x00400000U
|
||||
#define BIT_23 0x00800000U
|
||||
#define BIT_24 0x01000000U
|
||||
#define BIT_25 0x02000000U
|
||||
#define BIT_26 0x04000000U
|
||||
#define BIT_27 0x08000000U
|
||||
#define BIT_28 0x10000000U
|
||||
#define BIT_29 0x20000000U
|
||||
#define BIT_30 0x40000000U
|
||||
#define BIT_31 0x80000000U
|
||||
|
||||
#define MASK_1_BITS (BIT_1 - 1)
|
||||
#define MASK_2_BITS (BIT_2 - 1)
|
||||
#define MASK_3_BITS (BIT_3 - 1)
|
||||
#define MASK_4_BITS (BIT_4 - 1)
|
||||
#define MASK_5_BITS (BIT_5 - 1)
|
||||
#define MASK_6_BITS (BIT_6 - 1)
|
||||
#define MASK_7_BITS (BIT_7 - 1)
|
||||
#define MASK_8_BITS (BIT_8 - 1)
|
||||
#define MASK_9_BITS (BIT_9 - 1)
|
||||
#define MASK_10_BITS (BIT_10 - 1)
|
||||
#define MASK_11_BITS (BIT_11 - 1)
|
||||
#define MASK_12_BITS (BIT_12 - 1)
|
||||
#define MASK_13_BITS (BIT_13 - 1)
|
||||
#define MASK_14_BITS (BIT_14 - 1)
|
||||
#define MASK_15_BITS (BIT_15 - 1)
|
||||
#define MASK_16_BITS (BIT_16 - 1)
|
||||
#define MASK_17_BITS (BIT_17 - 1)
|
||||
#define MASK_18_BITS (BIT_18 - 1)
|
||||
#define MASK_19_BITS (BIT_19 - 1)
|
||||
#define MASK_20_BITS (BIT_20 - 1)
|
||||
#define MASK_21_BITS (BIT_21 - 1)
|
||||
#define MASK_22_BITS (BIT_22 - 1)
|
||||
#define MASK_23_BITS (BIT_23 - 1)
|
||||
#define MASK_24_BITS (BIT_24 - 1)
|
||||
#define MASK_25_BITS (BIT_25 - 1)
|
||||
#define MASK_26_BITS (BIT_26 - 1)
|
||||
#define MASK_27_BITS (BIT_27 - 1)
|
||||
#define MASK_28_BITS (BIT_28 - 1)
|
||||
#define MASK_29_BITS (BIT_29 - 1)
|
||||
#define MASK_30_BITS (BIT_30 - 1)
|
||||
#define MASK_31_BITS (BIT_31 - 1)
|
||||
|
||||
#define REG32_FIELD_SET(_data, _val, _fOffset, _fMask) ((_data & ~(_fMask)) | ((_val << (_fOffset)) & (_fMask)))
|
||||
#define REG32_FIELD_GET(_data, _fOffset, _fMask) ((_data & (_fMask)) >> (_fOffset))
|
||||
#define UINT32_BITS_MASK(_mBit, _lBit) ((0xFFFFFFFF >> (31 - _mBit)) ^ ((1 << _lBit) - 1))
|
||||
|
||||
typedef struct phy_device * rtk_port_t;
|
||||
|
||||
#if 1 /* ss\sdk\include\hal\phy\phydef.h */
|
||||
/* unified patch format */
|
||||
typedef enum rtk_phypatch_type_e
|
||||
{
|
||||
PHY_PATCH_TYPE_NONE = 0,
|
||||
PHY_PATCH_TYPE_TOP = 1,
|
||||
PHY_PATCH_TYPE_SDS,
|
||||
PHY_PATCH_TYPE_AFE,
|
||||
PHY_PATCH_TYPE_UC,
|
||||
PHY_PATCH_TYPE_UC2,
|
||||
PHY_PATCH_TYPE_NCTL0,
|
||||
PHY_PATCH_TYPE_NCTL1,
|
||||
PHY_PATCH_TYPE_NCTL2,
|
||||
PHY_PATCH_TYPE_ALGXG,
|
||||
PHY_PATCH_TYPE_ALG1G,
|
||||
PHY_PATCH_TYPE_NORMAL,
|
||||
PHY_PATCH_TYPE_DATARAM,
|
||||
PHY_PATCH_TYPE_RTCT,
|
||||
PHY_PATCH_TYPE_END
|
||||
} rtk_phypatch_type_t;
|
||||
|
||||
#define RTK_PATCH_TYPE_FLOW(_id) (PHY_PATCH_TYPE_END + _id)
|
||||
#define RTK_PATCH_TYPE_FLOWID_MAX PHY_PATCH_TYPE_END
|
||||
#define RTK_PATCH_SEQ_MAX ( PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOWID_MAX -1)
|
||||
|
||||
/* Interrupt */
|
||||
/* PHY Interrupt Status */
|
||||
#define RTK_PHY_INTR_NEXT_PAGE_RECV (BIT_0)
|
||||
#define RTK_PHY_INTR_AN_COMPLETE (BIT_1)
|
||||
#define RTK_PHY_INTR_LINK_CHANGE (BIT_2)
|
||||
#define RTK_PHY_INTR_ALDPS_STATE_CHANGE (BIT_3)
|
||||
#define RTK_PHY_INTR_RLFD (BIT_4)
|
||||
#define RTK_PHY_INTR_TM_LOW (BIT_5)
|
||||
#define RTK_PHY_INTR_TM_HIGH (BIT_6)
|
||||
#define RTK_PHY_INTR_FATAL_ERROR (BIT_7)
|
||||
#define RTK_PHY_INTR_MACSEC (BIT_8)
|
||||
#define RTK_PHY_INTR_PTP1588 (BIT_9)
|
||||
#define RTK_PHY_INTR_WOL (BIT_10)
|
||||
|
||||
typedef struct rtk_hwpatch_s
|
||||
{
|
||||
uint8 patch_op;
|
||||
uint8 portmask;
|
||||
uint16 pagemmd;
|
||||
uint16 addr;
|
||||
uint8 msb;
|
||||
uint8 lsb;
|
||||
uint16 data;
|
||||
uint8 compare_op;
|
||||
uint16 sram_p;
|
||||
uint16 sram_rr;
|
||||
uint16 sram_rw;
|
||||
uint16 sram_a;
|
||||
} rtk_hwpatch_t;
|
||||
|
||||
typedef struct rtk_hwpatch_data_s
|
||||
{
|
||||
rtk_hwpatch_t *conf;
|
||||
uint32 size;
|
||||
} rtk_hwpatch_data_t;
|
||||
|
||||
typedef struct rtk_hwpatch_seq_s
|
||||
{
|
||||
uint8 patch_type;
|
||||
union
|
||||
{
|
||||
rtk_hwpatch_data_t data;
|
||||
uint8 flow_id;
|
||||
} patch;
|
||||
} rtk_hwpatch_seq_t;
|
||||
|
||||
typedef struct rt_phy_patch_db_s
|
||||
{
|
||||
/* patch operation */
|
||||
int32 (*fPatch_op)(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch_data, uint8 patch_mode);
|
||||
int32 (*fPatch_flow)(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_flow, uint8 patch_mode);
|
||||
|
||||
/* patch data */
|
||||
rtk_hwpatch_seq_t seq_table[RTK_PATCH_SEQ_MAX];
|
||||
rtk_hwpatch_seq_t cmp_table[RTK_PATCH_SEQ_MAX];
|
||||
|
||||
} rt_phy_patch_db_t;
|
||||
#endif
|
||||
|
||||
/* cable type for cable test */
|
||||
typedef enum {
|
||||
RTK_RTCT_CABLE_COMMON,
|
||||
RTK_RTCT_CABLE_CAT5E,
|
||||
RTK_RTCT_CABLE_CAT6A,
|
||||
} rtk_rtct_cable_type_t;
|
||||
|
||||
/* MACSec */
|
||||
#ifndef RTK_MAX_MACSEC_SA_PER_PORT
|
||||
#define RTK_MAX_MACSEC_SA_PER_PORT 64 /* max number of Secure Association by a port*/
|
||||
#define RTK_MAX_MACSEC_SC_PER_PORT RTK_MAX_MACSEC_SA_PER_PORT/4 /* max number of Secure Channel by a port (4 AN per SC) */
|
||||
#endif
|
||||
|
||||
#define RTK_MACSEC_MAX_KEY_LEN 32
|
||||
|
||||
typedef enum rtk_macsec_reg_e
|
||||
{
|
||||
RTK_MACSEC_DIR_EGRESS = 0,
|
||||
RTK_MACSEC_DIR_INGRESS,
|
||||
RTK_MACSEC_DIR_END,
|
||||
} rtk_macsec_dir_t;
|
||||
|
||||
typedef enum rtk_macsec_an_e
|
||||
{
|
||||
RTK_MACSEC_AN0 = 0,
|
||||
RTK_MACSEC_AN1,
|
||||
RTK_MACSEC_AN2,
|
||||
RTK_MACSEC_AN3,
|
||||
RTK_MACSEC_AN_MAX,
|
||||
} rtk_macsec_an_t ;
|
||||
|
||||
typedef enum rtk_macsec_flow_e
|
||||
{
|
||||
RTK_MACSEC_FLOW_BYPASS = 0,
|
||||
RTK_MACSEC_FLOW_DROP,
|
||||
RTK_MACSEC_FLOW_INGRESS,
|
||||
RTK_MACSEC_FLOW_EGRESS,
|
||||
} rtk_macsec_flow_type_t;
|
||||
|
||||
typedef enum rtk_macsec_validate_e
|
||||
{
|
||||
RTK_MACSEC_VALIDATE_STRICT = 0,
|
||||
RTK_MACSEC_VALIDATE_CHECK,
|
||||
RTK_MACSEC_VALIDATE_DISABLE,
|
||||
} rtk_macsec_validate_t;
|
||||
|
||||
typedef enum rtk_macsec_cipher_e
|
||||
{
|
||||
RTK_MACSEC_CIPHER_GCM_ASE_128 = 0,
|
||||
RTK_MACSEC_CIPHER_GCM_ASE_256,
|
||||
RTK_MACSEC_CIPHER_GCM_ASE_XPN_128,
|
||||
RTK_MACSEC_CIPHER_GCM_ASE_XPN_256,
|
||||
RTK_MACSEC_CIPHER_MAX,
|
||||
} rtk_macsec_cipher_t;
|
||||
|
||||
typedef enum rtk_macsec_stat_e
|
||||
{
|
||||
RTK_MACSEC_STAT_InPktsUntagged = 0,
|
||||
RTK_MACSEC_STAT_InPktsNoTag,
|
||||
RTK_MACSEC_STAT_InPktsBadTag,
|
||||
RTK_MACSEC_STAT_InPktsUnknownSCI,
|
||||
RTK_MACSEC_STAT_InPktsNoSCI,
|
||||
RTK_MACSEC_STAT_OutPktsUntagged,
|
||||
RTK_MACSEC_STAT_MAX,
|
||||
} rtk_macsec_stat_t;
|
||||
|
||||
typedef enum rtk_macsec_txsa_stat_e
|
||||
{
|
||||
RTK_MACSEC_TXSA_STAT_OutPktsTooLong = 0,
|
||||
RTK_MACSEC_TXSA_STAT_OutOctetsProtectedEncrypted,
|
||||
RTK_MACSEC_TXSA_STAT_OutPktsProtectedEncrypted,
|
||||
RTK_MACSEC_TXSA_STAT_MAX,
|
||||
} rtk_macsec_txsa_stat_t;
|
||||
|
||||
typedef enum rtk_macsec_rxsa_stat_e
|
||||
{
|
||||
RTK_MACSEC_RXSA_STAT_InPktsUnusedSA = 0,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsNotUsingSA,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsUnchecked,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsDelayed,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsLate,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsOK,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsInvalid,
|
||||
RTK_MACSEC_RXSA_STAT_InPktsNotValid,
|
||||
RTK_MACSEC_RXSA_STAT_InOctetsDecryptedValidated,
|
||||
RTK_MACSEC_RXSA_STAT_MAX,
|
||||
} rtk_macsec_rxsa_stat_t;
|
||||
|
||||
|
||||
typedef enum rtk_macsec_match_tx_e
|
||||
{
|
||||
RTK_MACSEC_MATCH_NON_CTRL = 0, /* match all non-control and untagged packets */
|
||||
RTK_MACSEC_MATCH_MAC_DA, /* match all non-control and untagged packets with specific MAC DA */
|
||||
} rtk_macsec_match_tx_t;
|
||||
|
||||
typedef struct rtk_macsec_txsc_s
|
||||
{
|
||||
/* 8-byte SCI([0:5] = MAC address, [6:7] = port index) for this secure channel */
|
||||
uint8 sci[8];
|
||||
|
||||
/* cipher suite for this SC */
|
||||
rtk_macsec_cipher_t cipher_suite;
|
||||
|
||||
/* packet flow type to match this SC */
|
||||
rtk_macsec_match_tx_t flow_match;
|
||||
rtk_mac_t mac_da; /* the target address for RTK_MACSEC_MATCH_MAC_DA */
|
||||
|
||||
uint8 protect_frame; /* 1 = enable frame protection */
|
||||
uint8 include_sci; /* 1 = include explicit SCI in packet */
|
||||
uint8 use_es; /* 1 = set ES (End Station) bit in TCI field */
|
||||
uint8 use_scb; /* 1 = set SCB (Single Copy Broadcast) bit in TCI field */
|
||||
uint8 conf_protect; /* 1 = enable confidentiality protection, */
|
||||
}rtk_macsec_txsc_t;
|
||||
|
||||
typedef enum rtk_macsec_match_rx_e
|
||||
{
|
||||
RTK_MACSEC_MATCH_SCI = 0,
|
||||
RTK_MACSEC_MATCH_MAC_SA, //for pkt without SCI field/TCI.SC=0,
|
||||
} rtk_macsec_match_rx_t;
|
||||
|
||||
typedef struct rtk_macsec_rxsc_s
|
||||
{
|
||||
/* 8-byte SCI([0:5] = MAC address, [6:7] = port index) for this secure channel */
|
||||
uint8 sci[8];
|
||||
|
||||
/* cipher suite for this SC */
|
||||
rtk_macsec_cipher_t cipher_suite;
|
||||
|
||||
/* packet flow type to match this SC */
|
||||
rtk_macsec_match_rx_t flow_match;
|
||||
rtk_mac_t mac_sa; /* the target address for RTK_MACSEC_MATCH_MAC_SA */
|
||||
|
||||
/* frame validation level */
|
||||
rtk_macsec_validate_t validate_frames;
|
||||
|
||||
/* replay protection */
|
||||
uint8 replay_protect; /* 1 = enable replay protection */
|
||||
uint32 replay_window; /* the window size for replay protection, range for PN: 0 ~ 2^32 - 1, for XPN: 0 ~ 2^30 */
|
||||
|
||||
}rtk_macsec_rxsc_t;
|
||||
|
||||
typedef union rtk_macsec_sc_u
|
||||
{
|
||||
rtk_macsec_txsc_t tx;
|
||||
rtk_macsec_rxsc_t rx;
|
||||
}
|
||||
rtk_macsec_sc_t;
|
||||
|
||||
typedef struct rtk_macsec_txsc_status_s
|
||||
{
|
||||
uint32 hw_flow_index;
|
||||
uint32 hw_sa_index;
|
||||
uint8 sa_inUse;
|
||||
uint32 hw_flow_data;
|
||||
uint8 hw_sc_flow_status;
|
||||
rtk_macsec_an_t running_an;
|
||||
}
|
||||
rtk_macsec_txsc_status_t;
|
||||
|
||||
typedef struct rtk_macsec_rxsc_status_s
|
||||
{
|
||||
uint32 hw_flow_base;
|
||||
uint32 hw_sa_index[RTK_MACSEC_AN_MAX];
|
||||
uint8 sa_inUse[RTK_MACSEC_AN_MAX];
|
||||
uint32 hw_flow_data[RTK_MACSEC_AN_MAX];
|
||||
uint8 hw_sc_flow_status[RTK_MACSEC_AN_MAX];
|
||||
}
|
||||
rtk_macsec_rxsc_status_t;
|
||||
|
||||
typedef union rtk_macsec_sc_status_u
|
||||
{
|
||||
rtk_macsec_txsc_status_t tx;
|
||||
rtk_macsec_rxsc_status_t rx;
|
||||
}
|
||||
rtk_macsec_sc_status_t;
|
||||
|
||||
typedef struct rtk_macsec_sa_s
|
||||
{
|
||||
uint8 key[RTK_MACSEC_MAX_KEY_LEN]; // MACsec Key.
|
||||
uint32 key_bytes; // Size of the MACsec key in bytes (16 for AES128, 32 for AES256).
|
||||
|
||||
uint32 pn; // PN (32-bit) or lower 32-bit of XPN (64-bit)
|
||||
uint32 pn_h; // higher 32-bit of XPN (64-bit)
|
||||
uint8 salt[12]; // 12-byte salt (for XPN).
|
||||
uint8 ssci[4]; // 4-byte SSCI value (for XPN).
|
||||
} rtk_macsec_sa_t;
|
||||
|
||||
#define RTK_MACSEC_INTR_EGRESS_PN_THRESHOLD 0x00000001
|
||||
#define RTK_MACSEC_INTR_EGRESS_PN_ROLLOVER 0x00000002
|
||||
|
||||
typedef struct rtk_macsec_intr_status_s
|
||||
{
|
||||
/* a bitmap of RTK_MACSEC_INTR_* to present occured event */
|
||||
uint32 status;
|
||||
|
||||
/* When read 1b, the corresponding MACsec egress SA is about to expire due to
|
||||
the packet number crossing the rtk_macsec_port_cfg_t.pn_intr_threshold or xpn_intr_threshold*/
|
||||
uint8 egress_pn_thr_an_bmap[RTK_MAX_MACSEC_SC_PER_PORT]; //bitmap of AN3~0.
|
||||
|
||||
/* When read 1b, the corresponding MACsec egress SA has expired due to
|
||||
the packet number reaching the maximum allowed value. */
|
||||
uint8 egress_pn_exp_an_bmap[RTK_MAX_MACSEC_SC_PER_PORT]; //bitmap of AN3~0.
|
||||
}
|
||||
rtk_macsec_intr_status_t;
|
||||
|
||||
|
||||
typedef enum rtk_wol_opt_e
|
||||
{
|
||||
RTK_WOL_OPT_LINK = (0x1U << 0),
|
||||
RTK_WOL_OPT_MAGIC = (0x1U << 1),
|
||||
RTK_WOL_OPT_UCAST = (0x1U << 2),
|
||||
RTK_WOL_OPT_MCAST = (0x1U << 3),
|
||||
RTK_WOL_OPT_BCAST = (0x1U << 4),
|
||||
} rtk_wol_opt_t;
|
||||
|
||||
|
||||
#endif /* __RTK_PHYLIB_DEF_H */
|
||||
2448
sources/rtk-be550/src/hal/phy/rtk_phylib_macsec.c
Executable file
2448
sources/rtk-be550/src/hal/phy/rtk_phylib_macsec.c
Executable file
File diff suppressed because it is too large
Load diff
329
sources/rtk-be550/src/hal/phy/rtk_phylib_macsec.h
Executable file
329
sources/rtk-be550/src/hal/phy/rtk_phylib_macsec.h
Executable file
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __RTK_PHYLIB_MACSEC_H
|
||||
#define __RTK_PHYLIB_MACSEC_H
|
||||
|
||||
#if defined(RTK_PHYDRV_IN_LINUX)
|
||||
#include "type.h"
|
||||
#include "rtk_phylib_def.h"
|
||||
#endif
|
||||
|
||||
#define PHY_MACSEC_DEV_EGRESS 0
|
||||
#define PHY_MACSEC_DEV_INGRESS 1
|
||||
|
||||
#define MACSEC_REG_OFFS 4
|
||||
|
||||
#define PHY_MACSEC_HW_SA_ID(sc_id, an) (sc_id * 4 + an)
|
||||
#define PHY_MACSEC_HW_FLOW_ID(sc_id) (sc_id * 4)
|
||||
#define PHY_MACSEC_HW_SA_TO_AN(sa_id) (sa_id % 4)
|
||||
|
||||
#define PHY_MACSEC_MAX_SA_EN_SIZE 24 //32-bit words
|
||||
#define PHY_MACSEC_MAX_SA_IN_SIZE 20
|
||||
#define PHY_MACSEC_MAX_SA_SIZE PHY_MACSEC_MAX_SA_EN_SIZE
|
||||
|
||||
#define MACSEC_XFORM_REC_BASE (0x0000)
|
||||
#define MACSEC_XFORM_REC_SIZE(dir) ((RTK_MACSEC_DIR_EGRESS == dir) ? PHY_MACSEC_MAX_SA_EN_SIZE : PHY_MACSEC_MAX_SA_IN_SIZE )
|
||||
|
||||
#define MACSEC_REG_XFORM_REC(n, dir) (MACSEC_XFORM_REC_BASE + MACSEC_XFORM_REC_SIZE(dir) * \
|
||||
MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_XFORM_REC_OFFS(n, dir, off) (MACSEC_REG_XFORM_REC(n, dir) + off * MACSEC_REG_OFFS)
|
||||
|
||||
|
||||
#define MACSEC_REG_SAM_MAC_SA_MATCH_LO(n) (0x4000 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_MAC_SA_MATCH_HI(n) (0x4004 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_MAC_DA_MATCH_LO(n) (0x4008 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_MAC_DA_MATCH_HI(n) (0x400C + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
|
||||
#define MACSEC_REG_SAM_MISC_MATCH(n) (0x4010 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_SCI_MATCH_LO(n) (0x4014 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_SCI_MATCH_HI(n) (0x4018 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_MASK(n) (0x401C + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
#define MACSEC_REG_SAM_EXT_MATCH(n) (0x4020 + 16 * MACSEC_REG_OFFS * (n % 128))
|
||||
|
||||
#define MACSEC_REG_SAM_ENTRY_ENABLE(n) (0x6000 + (n * MACSEC_REG_OFFS))
|
||||
#define MACSEC_REG_SAM_ENTRY_TOGGLE(n) (0x6040 + (n * MACSEC_REG_OFFS))
|
||||
#define MACSEC_REG_SAM_ENTRY_SET(n) (0x6080 + (n * MACSEC_REG_OFFS))
|
||||
#define MACSEC_REG_SAM_ENTRY_CLEAR(n) (0x60C0 + (n * MACSEC_REG_OFFS))
|
||||
#define MACSEC_REG_SAM_ENTRY_ENABLE_CTRL (0x6100)
|
||||
#define MACSEC_REG_SAM_IN_FLIGHT (0x6104)
|
||||
|
||||
#define MACSEC_REG_SAM_FLOW_CTRL(n) (0x7000 + MACSEC_REG_OFFS * (n % 128))
|
||||
|
||||
|
||||
#define MACSEC_REG_SAM_IN_FLIGHT (0x6104)
|
||||
#define MACSEC_REG_COUNT_CTRL (0xC810)
|
||||
#define MACSEC_REG_IG_CC_CONTROL (0xE840)
|
||||
#define MACSEC_REG_COUNT_SECFAIL1 (0xF124)
|
||||
#define MACSEC_REG_CTX_CTRL (0xF408)
|
||||
#define MACSEC_REG_CTX_UPD_CTRL (0xF430)
|
||||
#define MACSEC_REG_SAM_CP_TAG (0x7900)
|
||||
#define MACSEC_REG_SAM_NM_PARAMS (0x7940)
|
||||
#define MACSEC_REG_SAM_NM_FLOW_NCP (0x7944)
|
||||
#define MACSEC_REG_SAM_NM_FLOW_CP (0x7948)
|
||||
|
||||
#define MACSEC_REG_MISC_CONTROL (0x797C)
|
||||
|
||||
// Mask last byte received of MAC source address
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_0 BIT_0
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_1 BIT_1
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_2 BIT_2
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_3 BIT_3
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_4 BIT_4
|
||||
// Mask first byte received of MAC source address
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_5 BIT_5
|
||||
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_SA_FULL (BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_5)
|
||||
|
||||
// Mask last byte received of MAC destination address
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_0 BIT_6
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_1 BIT_7
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_2 BIT_8
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_3 BIT_9
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_4 BIT_10
|
||||
// Mask first byte received of MAC destination address
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_5 BIT_11
|
||||
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_DA_FULL (BIT_6 | BIT_7 | BIT_8 | BIT_9 | BIT_10 | BIT_11)
|
||||
|
||||
#define MACSEC_SA_MATCH_MASK_MAC_ETYPE BIT_12
|
||||
#define MACSEC_SA_MATCH_MASK_VLAN_VALID BIT_13
|
||||
#define MACSEC_SA_MATCH_MASK_QINQ_FOUND BIT_14
|
||||
#define MACSEC_SA_MATCH_MASK_STAG_VALID BIT_15
|
||||
#define MACSEC_SA_MATCH_MASK_QTAG_VALID BIT_16
|
||||
#define MACSEC_SA_MATCH_MASK_VLAN_UP BIT_17
|
||||
#define MACSEC_SA_MATCH_MASK_VLAN_ID BIT_18
|
||||
#define MACSEC_SA_MATCH_MASK_SRC_PORT BIT_19
|
||||
#define MACSEC_SA_MATCH_MASK_CTRL_PKT BIT_20
|
||||
|
||||
// For ingress only
|
||||
#define MACSEC_SA_MATCH_MASK_MACSEC_SCI BIT_23
|
||||
#define MACSEC_SA_MATCH_MASK_MACSEC_TCI_AN_SC (BIT_24 | BIT_25 | BIT_29)
|
||||
|
||||
#define MACSEC_SAB_CW0_MACSEC_EG32 0x9241e066
|
||||
#define MACSEC_SAB_CW0_MACSEC_IG32 0xd241e06f
|
||||
#define MACSEC_SAB_CW0_MACSEC_EG64 0xa241e066
|
||||
#define MACSEC_SAB_CW0_MACSEC_IG64 0xe241a0ef
|
||||
#define MACSEC_SAB_CW0_AES128 0x000a0000
|
||||
#define MACSEC_SAB_CW0_AES256 0x000e0000
|
||||
|
||||
|
||||
#define RTK_MACSEC_PORT_COMMON 0
|
||||
#define RTK_MACSEC_PORT_RESERVED 1
|
||||
#define RTK_MACSEC_PORT_CONTROLLED 2
|
||||
#define RTK_MACSEC_PORT_UNCONTROLLED 3
|
||||
|
||||
|
||||
|
||||
typedef struct phy_macsec_flow_action_e_s
|
||||
{
|
||||
// 1 - enable frame protection,
|
||||
// 0 - bypass frame through device
|
||||
uint8 protect_frame;
|
||||
|
||||
// 1 - SA is in use, packets classified for it can be transformed
|
||||
// 0 - SA not in use, packets classified for it can not be transformed
|
||||
uint8 sa_in_use;
|
||||
|
||||
// 1 - inserts explicit SCI in the packet,
|
||||
// 0 - use implicit SCI (not transferred)
|
||||
uint8 include_sci;
|
||||
|
||||
// 1 - enable ES bit in the generated SecTAG
|
||||
// 0 - disable ES bit in the generated SecTAG
|
||||
uint8 use_es;
|
||||
|
||||
// 1 - enable SCB bit in the generated SecTAG
|
||||
// 0 - disable SCB bit in the generated SecTAG
|
||||
uint8 use_scb;
|
||||
|
||||
// Number of VLAN tags to bypass for egress processing.
|
||||
// Valid values: 0, 1 and 2.
|
||||
// This feature is only available on HW4.1 and possibly later versions.
|
||||
uint8 tag_bypass_size;
|
||||
|
||||
// 1 - Does not update sa_in_use flag
|
||||
// 0 - Update sa_in_use flag
|
||||
uint8 sa_index_update_by_hw;
|
||||
|
||||
// The number of bytes (in the range of 0-127) that are authenticated but
|
||||
// not encrypted following the SecTAG in the encrypted packet. Values
|
||||
// 65-127 are reserved in HW < 4.0 and should not be used there.
|
||||
uint8 confidentiality_offset;
|
||||
|
||||
// 1 - enable confidentiality protection
|
||||
// 0 - disable confidentiality protection
|
||||
uint8 conf_protect;
|
||||
|
||||
} phy_macsec_flow_action_e_t;
|
||||
|
||||
typedef struct phy_macsec_flow_action_i_s
|
||||
{
|
||||
// 1 - enable replay protection
|
||||
// 0 - disable replay protection
|
||||
uint8 replay_protect;
|
||||
|
||||
// true - SA is in use, packets classified for it can be transformed
|
||||
// false - SA not in use, packets classified for it can not be transformed
|
||||
uint8 sa_in_use;
|
||||
|
||||
// MACsec frame validation level
|
||||
rtk_macsec_validate_t validate_frames;
|
||||
|
||||
// The number of bytes (in the range of 0-127) that are authenticated but
|
||||
// not encrypted following the SecTAG in the encrypted packet.
|
||||
uint8 confidentiality_offset;
|
||||
|
||||
} phy_macsec_flow_action_i_t;
|
||||
|
||||
typedef struct phy_macsec_flow_action_bd_s
|
||||
{
|
||||
// 1 - enable statistics counting for the associated SA
|
||||
// 0 - disable statistics counting for the associated SA
|
||||
uint8 sa_in_use;
|
||||
} phy_macsec_flow_action_bd_t;
|
||||
|
||||
typedef struct phy_macsec_flow_action_s
|
||||
{
|
||||
uint32 sa_index;
|
||||
|
||||
rtk_macsec_flow_type_t flow_type;
|
||||
union
|
||||
{
|
||||
phy_macsec_flow_action_e_t egress;
|
||||
phy_macsec_flow_action_i_t ingress;
|
||||
phy_macsec_flow_action_bd_t bypass_drop;
|
||||
} params;
|
||||
|
||||
uint8 dest_port;
|
||||
|
||||
} phy_macsec_flow_action_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// index for flow control rule entry
|
||||
uint32 flow_index;
|
||||
|
||||
// Packet field values to match
|
||||
|
||||
// MAC source address
|
||||
uint8 mac_sa[6];
|
||||
|
||||
// MAC destination address
|
||||
uint8 mac_da[6];
|
||||
|
||||
// EtherType
|
||||
uint16 etherType;
|
||||
|
||||
// SCI, for ingress only
|
||||
uint8 sci[8];
|
||||
|
||||
// Parsed VLAN ID compare value
|
||||
uint16 vlan_id;
|
||||
|
||||
// Parsed VLAN valid flag compare value
|
||||
uint8 fVLANValid;
|
||||
|
||||
// Parsed QinQ found flag compare value
|
||||
uint8 fQinQFound;
|
||||
|
||||
// Parsed STAG valid flag compare value
|
||||
uint8 fSTagValid;
|
||||
|
||||
// Parsed QTAG valid flag compare value
|
||||
uint8 fQTagFound;
|
||||
|
||||
// Parsed VLAN User Priority compare value
|
||||
uint8 vlanUserPriority;
|
||||
|
||||
// Packet is a control packet (as pre-decoded) compare value
|
||||
uint8 fControlPacket;
|
||||
|
||||
// true - allow packets without a MACsec tag to match
|
||||
uint8 fUntagged;
|
||||
|
||||
// true - allow packets with a standard and valid MACsec tag to match
|
||||
uint8 fTagged;
|
||||
|
||||
// true - allow packets with an invalid MACsec tag to match
|
||||
uint8 fBadTag;
|
||||
|
||||
// true - allow packets with a MACsec tag indicating KaY handling
|
||||
// to be done to match
|
||||
uint8 fKayTag;
|
||||
|
||||
// Source port compare value
|
||||
uint8 sourcePort;
|
||||
|
||||
// Priority of this entry for determining the actual transform used
|
||||
// on a match when multiple entries match, 0 = lowest, 15 = highest.
|
||||
// In case of identical priorities, the lowest numbered entry takes
|
||||
// precedence.
|
||||
uint8 matchPriority;
|
||||
|
||||
// MACsec TCI/AN byte compare value, bits are individually masked for
|
||||
// comparing. The TCI bits are in bits [7:2] while the AN bits reside
|
||||
// in bits [1:0]. the macsec_TCI_AN field should only be set to
|
||||
// non-zero for an actual MACsec packet.
|
||||
uint8 macsec_TCI_AN;
|
||||
|
||||
// Match mask for the SA flow rules, see MACSEC_SA_MATCH_MASK_*
|
||||
uint32 matchMask;
|
||||
|
||||
// Parsed inner VLAN ID compare value
|
||||
uint16 vlanIdInner;
|
||||
|
||||
// Parsed inner VLAN UP compare value
|
||||
uint8 vlanUpInner;
|
||||
|
||||
} phy_macsec_flow_match_t;
|
||||
|
||||
typedef struct {
|
||||
uint8 key_offs;
|
||||
uint8 hkey_offs;
|
||||
uint8 seq_offs;
|
||||
uint8 mask_offs;
|
||||
uint8 ctx_salt_offs;
|
||||
uint8 iv_offs;
|
||||
uint8 upd_ctrl_offs;
|
||||
} phy_macsec_sa_offset_t;
|
||||
|
||||
#define RTK_PHY_MACSEC_SA_FLAG_XPN 0x00000001U //Extended Packet Numbering
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 context_id; //keep 0 for create
|
||||
rtk_macsec_dir_t direction;
|
||||
uint32 flow_index; //the flow entry index apply to this SA
|
||||
uint32 flags; // a bitmap of RTK_PHY_MACSEC_SA_FLAG_*
|
||||
|
||||
uint8 an; // 2-bit AN inserted in SecTAG (egress).
|
||||
uint8 sci[8]; // 8-byte SCI.([0:5] = MAC address, [6:7] = port index)
|
||||
|
||||
uint8 key[RTK_MACSEC_MAX_KEY_LEN]; // MACsec Key.
|
||||
uint32 key_bytes; // Size of the MACsec key in bytes (16 for AES128, 32 for AES256).
|
||||
|
||||
uint8 salt[12]; // 12-byte salt (64-bit sequence numbers).
|
||||
uint8 ssci[4]; // 4-byte SSCI value (64-bit sequence numbers).
|
||||
|
||||
uint32 seq; // sequence number.
|
||||
uint32 seq_h; // High part of sequence number (64-bit sequence numbers)
|
||||
uint32 replay_window; // Size of the replay window, 0 for strict ordering (ingress).
|
||||
|
||||
/* update ctrl */
|
||||
uint32 next_sa_index; // SA index of the next chained SA (egress).
|
||||
uint8 sa_expired_irq; // 1 if SA expired IRQ is to be generated.
|
||||
uint8 next_sa_valid; // SA Index field is a valid SA.
|
||||
uint8 update_en; // Set to true if the SA must be updated.
|
||||
} phy_macsec_sa_params_t;
|
||||
|
||||
typedef void (*phy_macsec_aes_cb)(
|
||||
const uint8 * const In_p,
|
||||
uint8 * const Out_p,
|
||||
const uint8 * const Key_p,
|
||||
const unsigned int KeyByteCount);
|
||||
|
||||
#endif /* __RTK_PHYLIB_MACSEC_H */
|
||||
568
sources/rtk-be550/src/hal/phy/rtk_phylib_rtl826xb.c
Executable file
568
sources/rtk-be550/src/hal/phy/rtk_phylib_rtl826xb.c
Executable file
|
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "rtk_phylib_rtl826xb.h"
|
||||
|
||||
/* Indirect Register Access APIs */
|
||||
int rtk_phylib_826xb_sds_read(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 rData = 0;
|
||||
uint32 op = (page & 0x3f) | ((reg & 0x1f) << 6) | (0x8000);
|
||||
uint32 i = 0;
|
||||
uint32 mask = 0;
|
||||
mask = UINT32_BITS_MASK(msb,lsb);
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 323, 15, 0, op));
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 323, 15, 15, &rData));
|
||||
if (rData == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rtk_phylib_udelay(10);
|
||||
}
|
||||
if (i == 10)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 322, 15, 0, &rData));
|
||||
*pData = REG32_FIELD_GET(rData, lsb, mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_sds_write(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 data)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 wData = 0, rData = 0;
|
||||
uint32 op = (page & 0x3f) | ((reg & 0x1f) << 6) | (0x8800);
|
||||
uint32 mask = 0;
|
||||
mask = UINT32_BITS_MASK(msb,lsb);
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_sds_read(phydev, page, reg, 15, 0, &rData));
|
||||
|
||||
wData = REG32_FIELD_SET(rData, data, lsb, mask);
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 321, 15, 0, wData));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 323, 15, 0, op));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_indirect_read(rtk_phydev *phydev, uint32 indr_addr, uint32 *pData)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 rData;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA436, 15, 0, indr_addr));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xA438, 15, 0, &rData));
|
||||
*pData = rData;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_sram_read(rtk_phydev *phydev, uint32 indr_addr, uint8 msb, uint8 lsb, uint32 *pData)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 mask = 0, rData = 0;
|
||||
|
||||
mask = UINT32_BITS_MASK(msb,lsb);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_indirect_read(phydev, indr_addr, &rData));
|
||||
*pData = REG32_FIELD_GET(rData, lsb, mask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* MACsec */
|
||||
int rtk_phylib_826xb_macsec_read(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 data_h = 0, data_l = 0;
|
||||
uint32 rData = 0;
|
||||
uint32 mask = 0;
|
||||
uint32 data_e = 0;
|
||||
WAIT_COMPLETE_VAR();
|
||||
|
||||
mask = UINT32_BITS_MASK(msb,lsb);
|
||||
|
||||
switch(dir)
|
||||
{
|
||||
case RTK_MACSEC_DIR_EGRESS:
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02FB, 15, 0, reg));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02FC, 15, 0, 0x10));
|
||||
WAIT_COMPLETE(10000000)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x02FC, 15, 0, &data_e));
|
||||
if ((data_e & 0x10) == 0x0)
|
||||
{
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
if (_t_wait != 0)
|
||||
PR_DBG("[%s-%u] _t_wait: %u\n", __FUNCTION__, dir, _t_wait);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WAIT_COMPLETE_IS_TIMEOUT())
|
||||
{
|
||||
PR_ERR("[%s-%u] timeout!\n", __FUNCTION__, dir);
|
||||
return RTK_PHYLIB_ERR_TIMEOUT;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x02F8, 15, 0, &data_h));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x02F9, 15, 0, &data_l));
|
||||
break;
|
||||
case RTK_MACSEC_DIR_INGRESS:
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA6EA, 1, 1, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x0300, 15, 0, reg));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x0301, 15, 0, 0x10));
|
||||
WAIT_COMPLETE(10000000)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x0301, 15, 0, &data_e));
|
||||
if ((data_e & 0x10) == 0x0)
|
||||
{
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
if (_t_wait != 0)
|
||||
PR_DBG("[%s-%u] _t_wait: %u\n", __FUNCTION__, dir, _t_wait);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WAIT_COMPLETE_IS_TIMEOUT())
|
||||
{
|
||||
PR_ERR("[%s-%u] timeout!\n", __FUNCTION__, dir);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA6EA, 1, 1, 0x0));
|
||||
return RTK_PHYLIB_ERR_TIMEOUT;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x02FD, 15, 0, &data_h));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x02FE, 15, 0, &data_l));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA6EA, 1, 1, 0x0));
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
rData = (data_h << 16) + data_l;
|
||||
*pData = REG32_FIELD_GET(rData, lsb, mask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_macsec_write(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 reg, uint8 msb, uint8 lsb, uint32 data)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 data_l = data & 0xFFFF;
|
||||
uint32 data_h = (data >> 16) & 0xFFFF;
|
||||
uint32 data_e = 0;
|
||||
WAIT_COMPLETE_VAR();
|
||||
|
||||
switch(dir)
|
||||
{
|
||||
case RTK_MACSEC_DIR_EGRESS:
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02F8 , 15, 0, data_h));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02F9 , 15, 0, data_l));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02FB , 15, 0, reg));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02FC, 15, 0, 0x1));
|
||||
WAIT_COMPLETE(10000000)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x02FC, 15, 0, &data_e));
|
||||
if ((data_e & 0x1) == 0x0)
|
||||
{
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
if (_t_wait != 0)
|
||||
PR_DBG("[%s-%u] _t_wait: %u\n", __FUNCTION__, dir, _t_wait);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WAIT_COMPLETE_IS_TIMEOUT())
|
||||
{
|
||||
PR_ERR("[%s-%u] timeout!\n", __FUNCTION__, dir);
|
||||
return RTK_PHYLIB_ERR_TIMEOUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTK_MACSEC_DIR_INGRESS:
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA6EA, 1, 1, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02FD, 15, 0, data_h));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x02FE, 15, 0, data_l));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x0300, 15, 0, reg));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x0301, 15, 0, 0x1));
|
||||
WAIT_COMPLETE(10000000)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x0301, 15, 0, &data_e));
|
||||
if ((data_e & 0x1) == 0x0)
|
||||
{
|
||||
#ifdef MACSEC_DBG_PRINT
|
||||
if (_t_wait != 0)
|
||||
PR_DBG("[%s-%u] _t_wait: %u\n", __FUNCTION__, dir, _t_wait);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WAIT_COMPLETE_IS_TIMEOUT())
|
||||
{
|
||||
PR_ERR("[%s-%u] timeout!\n", __FUNCTION__, dir);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA6EA, 1, 1, 0x0));
|
||||
return RTK_PHYLIB_ERR_TIMEOUT;
|
||||
}
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA6EA, 1, 1, 0x0));
|
||||
break;
|
||||
|
||||
default:
|
||||
return RTK_PHYLIB_ERR_INPUT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_macsec_init(rtk_phydev *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2e0, 1, 0, 0b11));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2d8, 15, 0, 0x5313));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2da, 15, 0, 0x0101));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2dc, 15, 0, 0x0101));
|
||||
|
||||
//MACSEC_RXSYS_CFG4
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3c6, 7, 0, 0xa));
|
||||
//MACSEC_TXLINE_CFG4
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x37b, 7, 0, 0x6));
|
||||
//loopback fifo_setting
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2f7, 15, 0, 0x486c));
|
||||
//RA_setting
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3f1, 15, 0, 0x72));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3f0, 15, 0, 0x0b0b));
|
||||
//RA ifg
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3ee, 15, 13, 0x2));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_macsec_bypass_set(rtk_phydev *phydev, uint32 bypass)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
if (bypass != 0)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2d8, 15, 0, 0x5313));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3f1, 15, 0, 0x72));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3f0, 15, 0, 0x0b0b));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x398, 2, 0, 0x7));
|
||||
}
|
||||
else
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2d8, 15, 0, 0x5111));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3f1, 15, 0, 0xe871));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x3f0, 15, 0, 0x0c0c));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x398, 2, 0, 0x5));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_macsec_bypass_get(rtk_phydev *phydev, uint32 *pBypass)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 bypass_rx = 0;
|
||||
uint32 bypass_tx = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x2d8, 9, 9, &bypass_rx));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0x2d8, 1, 1, &bypass_tx));
|
||||
|
||||
*pBypass = (bypass_rx == 0 && bypass_tx == 0) ? 0 : 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* RTCT */
|
||||
int rtk_phylib_826xb_cable_test_start(rtk_phydev *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xa4a0, 10, 10, 1));
|
||||
rtk_phylib_mdelay(1000);
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xa422, 15, 0, 0xF2));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xa422, 0, 0, 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_cable_test_finished_get(rtk_phydev *phydev, uint32 *finished)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 rData = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xA422, 15, 15, &rData));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xa4a0, 10, 10, 0));
|
||||
*finished = rData;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_cable_test_result_get(rtk_phydev *phydev, uint32 pair, rtk_rtct_channel_result_t *result)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 cable_factor = 7820;
|
||||
uint32 indr_add_ss = 0x8027 + (pair * 0x4);
|
||||
uint32 indr_add_lh = 0x8028 + (pair * 0x4);
|
||||
uint32 indr_add_ll = 0x8029 + (pair * 0x4);
|
||||
uint32 rtct_status = 0;
|
||||
uint32 rtct_len_h = 0;
|
||||
uint32 rtct_len_l = 0;
|
||||
int32 len_cnt = 0;
|
||||
|
||||
if (pair > 3)
|
||||
return RTK_PHYLIB_ERR_INPUT;
|
||||
|
||||
rtk_phylib_memset(result, 0x0, sizeof(rtk_rtct_channel_result_t));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_sram_read(phydev, indr_add_ss, 15, 8, &rtct_status));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_sram_read(phydev, indr_add_lh, 15, 8, &rtct_len_h));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_sram_read(phydev, indr_add_ll, 15, 8, &rtct_len_l));
|
||||
|
||||
result->cable_status = RTK_PHYLIB_CABLE_STATUS_NORMAL;
|
||||
switch (rtct_status)
|
||||
{
|
||||
case 0x60: /* normal */
|
||||
result->cable_status = RTK_PHYLIB_CABLE_STATUS_NORMAL;
|
||||
break;
|
||||
case 0x48: /* open */
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_OPEN;
|
||||
break;
|
||||
case 0x50: /* short */
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_SHORT;
|
||||
break;
|
||||
case 0xC0: /* inter pair short */
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_INTER_PAIR_SHORT;
|
||||
break;
|
||||
case 0x42: /* mismatch-open */
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_MISMATCH;
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_OPEN;
|
||||
break;
|
||||
case 0x44: /* mismatch-short */
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_MISMATCH;
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_SHORT;
|
||||
break;
|
||||
default:
|
||||
result->cable_status |= RTK_PHYLIB_CABLE_STATUS_INTER_PAIR_SHORT;
|
||||
break;
|
||||
}
|
||||
|
||||
len_cnt = ((int32)rtct_len_h << 8) + (int32)rtct_len_l - 255;
|
||||
if (len_cnt < 0)
|
||||
result->length_cm = 0;
|
||||
else
|
||||
result->length_cm = ((uint32)len_cnt * 10000)/cable_factor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Interrupt */
|
||||
int rtk_phylib_826xb_intr_enable(rtk_phydev *phydev, uint32 en)
|
||||
{
|
||||
int32 ret = 0;
|
||||
/* enable normal interrupt IMR_INT_PHY0 */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0xE1, 0, 0, (en == 0) ? 0x0 : 0x1));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_intr_read_clear(rtk_phydev *phydev, uint32 *status)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 rData = 0;
|
||||
uint32 rStatus = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xA43A, 15, 0, &rData));
|
||||
if(rData & BIT_1)
|
||||
rStatus |= RTK_PHY_INTR_RLFD;
|
||||
if(rData & BIT_2)
|
||||
rStatus |= RTK_PHY_INTR_NEXT_PAGE_RECV;
|
||||
if(rData & BIT_3)
|
||||
rStatus |= RTK_PHY_INTR_AN_COMPLETE;
|
||||
if(rData & BIT_4)
|
||||
rStatus |= RTK_PHY_INTR_LINK_CHANGE;
|
||||
if(rData & BIT_9)
|
||||
rStatus |= RTK_PHY_INTR_ALDPS_STATE_CHANGE;
|
||||
if(rData & BIT_11)
|
||||
rStatus |= RTK_PHY_INTR_FATAL_ERROR;
|
||||
if(rData & BIT_7)
|
||||
rStatus |= RTK_PHY_INTR_WOL;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 0xE2, 15, 0, &rData));
|
||||
if(rData & BIT_3)
|
||||
rStatus |= RTK_PHY_INTR_TM_LOW;
|
||||
if(rData & BIT_4)
|
||||
rStatus |= RTK_PHY_INTR_TM_HIGH;
|
||||
if(rData & BIT_6)
|
||||
rStatus |= RTK_PHY_INTR_MACSEC;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0xE2, 15, 0, 0xFF));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x2DC, 15, 0, 0xFF));
|
||||
|
||||
*status = rStatus;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_intr_init(rtk_phydev *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 status = 0;
|
||||
|
||||
/* Disable all IMR*/
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0xE1, 15, 0, 0));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0xE3, 15, 0, 0));
|
||||
|
||||
/* source */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0xE4, 15, 0, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0xE0, 15, 0, 0x2F));
|
||||
|
||||
/* init common link change */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA424, 15, 0, 0x10));
|
||||
/* init rlfd */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA442, 15, 15, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA448, 7, 7, 0x1));
|
||||
/* init tm */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x1A0, 11, 11, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x19D, 11, 11, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x1A1, 11, 11, 0x1));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 0x19F, 11, 11, 0x1));
|
||||
/* init WOL */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA424, 7, 7, 0x1));
|
||||
|
||||
/* clear status */
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_intr_read_clear(phydev, &status));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_link_down_power_saving_set(rtk_phydev *phydev, uint32 ena)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 data = (ena > 0) ? 0x1 : 0x0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xA430, 2, 2, data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_link_down_power_saving_get(rtk_phydev *phydev, uint32 *pEna)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 data = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xA430, 2, 2, &data));
|
||||
*pEna = data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_wol_reset(rtk_phydev *phydev)
|
||||
{
|
||||
int32 ret = 0;
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A2, 15, 15, 0));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A2, 15, 15, 1));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_wol_set(rtk_phydev *phydev, uint32 wol_opts)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A0, 13, 13, (wol_opts & RTK_WOL_OPT_LINK) ? 1 : 0));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A0, 12, 12, (wol_opts & RTK_WOL_OPT_MAGIC) ? 1 : 0));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A0, 10, 10, (wol_opts & RTK_WOL_OPT_UCAST) ? 1 : 0));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A0, 9, 9, (wol_opts & RTK_WOL_OPT_MCAST) ? 1 : 0));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8A0, 8, 8, (wol_opts & RTK_WOL_OPT_BCAST) ? 1 : 0));
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_wol_get(rtk_phydev *phydev, uint32 *pWol_opts)
|
||||
{
|
||||
int32 ret = 0;
|
||||
uint32 data = 0;
|
||||
uint32 wol_opts = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xD8A0, 13, 13, &data));
|
||||
wol_opts |= ((data) ? RTK_WOL_OPT_LINK : 0);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xD8A0, 12, 12, &data));
|
||||
wol_opts |= ((data) ? RTK_WOL_OPT_MAGIC : 0);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xD8A0, 10, 10, &data));
|
||||
wol_opts |= ((data) ? RTK_WOL_OPT_UCAST : 0);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xD8A0, 9, 9, &data));
|
||||
wol_opts |= ((data) ? RTK_WOL_OPT_MCAST : 0);
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, 0xD8A0, 8, 8, &data));
|
||||
wol_opts |= ((data) ? RTK_WOL_OPT_BCAST : 0);
|
||||
|
||||
*pWol_opts = wol_opts;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_wol_unicast_addr_set(rtk_phydev *phydev, uint8 *mac_addr)
|
||||
{
|
||||
int32 ret = 0;
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8C0, 15, 0, (mac_addr[1] << 8 | mac_addr[0])));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8C2, 15, 0, (mac_addr[3] << 8 | mac_addr[2])));
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, 0xD8C4, 15, 0, (mac_addr[5] << 8 | mac_addr[4])));
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 rtk_phylib_826xb_wol_multicast_mac2offset(uint8 *mac_addr)
|
||||
{
|
||||
uint32 crc = 0xFFFFFFFF;
|
||||
uint32 i = 0, j = 0;
|
||||
uint32 b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
crc ^= mac_addr[i];
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ 0xEDB88320;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
crc = ~crc;
|
||||
|
||||
b5 = ((crc & 0b000001) << 5 );
|
||||
b4 = ((crc & 0b000010) << 3 );
|
||||
b3 = ((crc & 0b000100) << 1 );
|
||||
b2 = (((crc & 0b001000) ? 0 : 1) << 2 );
|
||||
b1 = (((crc & 0b010000) ? 0 : 1) << 1 );
|
||||
b0 = (((crc & 0b100000) ? 0 : 1) << 0 );
|
||||
|
||||
return (b5 | b4 | b3 | b2 | b1 | b0);
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_wol_multicast_mask_add(rtk_phydev *phydev, uint32 offset)
|
||||
{
|
||||
const uint32 cfg_reg[4] = {0xD8C6, 0xD8C8, 0xD8CA, 0xD8CC};
|
||||
int32 ret = 0;
|
||||
uint32 idx = offset/16;
|
||||
uint32 multicast_cfg = 0;
|
||||
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 31, cfg_reg[idx], 15, 0, &multicast_cfg));
|
||||
|
||||
multicast_cfg = (multicast_cfg | (0b1 << (offset % 16)));
|
||||
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, cfg_reg[idx], 15, 0, multicast_cfg));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtk_phylib_826xb_wol_multicast_mask_reset(rtk_phydev *phydev)
|
||||
{
|
||||
const uint32 cfg_reg[4] = {0xD8C6, 0xD8C8, 0xD8CA, 0xD8CC};
|
||||
int32 ret = 0;
|
||||
uint32 idx = 0;
|
||||
|
||||
for (idx = 0; idx < 4; idx++)
|
||||
{
|
||||
RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 31, cfg_reg[idx], 15, 0, 0));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
46
sources/rtk-be550/src/hal/phy/rtk_phylib_rtl826xb.h
Executable file
46
sources/rtk-be550/src/hal/phy/rtk_phylib_rtl826xb.h
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __RTK_PHYLIB_RTL826XB_H
|
||||
#define __RTK_PHYLIB_RTL826XB_H
|
||||
|
||||
#include "rtk_phylib.h"
|
||||
|
||||
/* Register Access*/
|
||||
int rtk_phylib_826xb_sds_read(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData);
|
||||
int rtk_phylib_826xb_sds_write(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 data);
|
||||
|
||||
/* Interrupt */
|
||||
int rtk_phylib_826xb_intr_enable(rtk_phydev *phydev, uint32 en);
|
||||
int rtk_phylib_826xb_intr_read_clear(rtk_phydev *phydev, uint32 *status);
|
||||
int rtk_phylib_826xb_intr_init(rtk_phydev *phydev);
|
||||
|
||||
/* Cable Test */
|
||||
int rtk_phylib_826xb_cable_test_start(rtk_phydev *phydev);;
|
||||
int rtk_phylib_826xb_cable_test_finished_get(rtk_phydev *phydev, uint32 *finished);
|
||||
int rtk_phylib_826xb_cable_test_result_get(rtk_phydev *phydev, uint32 pair, rtk_rtct_channel_result_t *result);
|
||||
|
||||
/* MACsec */
|
||||
int rtk_phylib_826xb_macsec_init(rtk_phydev *phydev);
|
||||
int rtk_phylib_826xb_macsec_read(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData);
|
||||
int rtk_phylib_826xb_macsec_write(rtk_phydev *phydev, rtk_macsec_dir_t dir, uint32 reg, uint8 msb, uint8 lsb, uint32 data);
|
||||
int rtk_phylib_826xb_macsec_bypass_set(rtk_phydev *phydev, uint32 bypass);
|
||||
int rtk_phylib_826xb_macsec_bypass_get(rtk_phydev *phydev, uint32 *pBypass);
|
||||
|
||||
/* Link-down-power-saving/EDPD */
|
||||
int rtk_phylib_826xb_link_down_power_saving_set(rtk_phydev *phydev, uint32 ena);
|
||||
int rtk_phylib_826xb_link_down_power_saving_get(rtk_phydev *phydev, uint32 *pEna);
|
||||
|
||||
/* Wake on Lan */
|
||||
int rtk_phylib_826xb_wol_reset(rtk_phydev *phydev);
|
||||
int rtk_phylib_826xb_wol_set(rtk_phydev *phydev, uint32 wol_opts);
|
||||
int rtk_phylib_826xb_wol_get(rtk_phydev *phydev, uint32 *pWol_opts);
|
||||
int rtk_phylib_826xb_wol_unicast_addr_set(rtk_phydev *phydev, uint8 *mac_addr);
|
||||
int rtk_phylib_826xb_wol_multicast_mask_add(rtk_phydev *phydev, uint32 offset);
|
||||
int rtk_phylib_826xb_wol_multicast_mask_reset(rtk_phydev *phydev);
|
||||
uint32 rtk_phylib_826xb_wol_multicast_mac2offset(uint8 *mac_addr);
|
||||
|
||||
#endif /* __RTK_PHYLIB_RTL826XB_H */
|
||||
117
sources/rtk-be550/src/hal/phy/type.h
Executable file
117
sources/rtk-be550/src/hal/phy/type.h
Executable file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __COMMON_TYPE_H__
|
||||
#define __COMMON_TYPE_H__
|
||||
|
||||
/*
|
||||
* Symbol Definition
|
||||
*/
|
||||
|
||||
#define USING_RTSTK_PKT_AS_RAIL
|
||||
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef ETHER_ADDR_LEN
|
||||
#define ETHER_ADDR_LEN 6
|
||||
#endif
|
||||
|
||||
#ifndef IP6_ADDR_LEN
|
||||
#define IP6_ADDR_LEN 16
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Data Type Declaration
|
||||
*/
|
||||
#ifndef uint64
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
#ifndef int64
|
||||
typedef signed long long int64;
|
||||
#endif
|
||||
|
||||
#ifndef uint32
|
||||
typedef unsigned int uint32;
|
||||
#endif
|
||||
|
||||
#ifndef int32
|
||||
typedef signed int int32;
|
||||
#endif
|
||||
|
||||
#ifndef uint16
|
||||
typedef unsigned short uint16;
|
||||
#endif
|
||||
|
||||
#ifndef int16
|
||||
typedef signed short int16;
|
||||
#endif
|
||||
|
||||
#ifndef uint8
|
||||
typedef unsigned char uint8;
|
||||
#endif
|
||||
|
||||
#ifndef int8
|
||||
typedef signed char int8;
|
||||
#endif
|
||||
|
||||
//#define CONFIG_SDK_WORDSIZE_64 /* not ready */
|
||||
#ifdef CONFIG_SDK_WORDSIZE_64
|
||||
typedef long int intptr;
|
||||
typedef unsigned long int uintptr;
|
||||
#else
|
||||
typedef int intptr;
|
||||
typedef unsigned int uintptr;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ipaddr_t
|
||||
typedef uint32 ipaddr_t; /* ipv4 address type */
|
||||
#endif
|
||||
|
||||
/* configuration mode type */
|
||||
typedef enum rtk_enable_e
|
||||
{
|
||||
DISABLED = 0,
|
||||
ENABLED,
|
||||
RTK_ENABLE_END
|
||||
} rtk_enable_t;
|
||||
|
||||
/* initial state of module */
|
||||
typedef enum init_state_e
|
||||
{
|
||||
INIT_NOT_COMPLETED = 0,
|
||||
INIT_COMPLETED,
|
||||
INIT_STATE_END
|
||||
} init_state_t;
|
||||
|
||||
/* ethernet address type */
|
||||
typedef struct rtk_mac_s
|
||||
{
|
||||
uint8 octet[ETHER_ADDR_LEN];
|
||||
} rtk_mac_t;
|
||||
|
||||
typedef uint32 osal_time_t;
|
||||
typedef uint32 osal_usecs_t;
|
||||
|
||||
/*
|
||||
* Macro Definition
|
||||
*/
|
||||
|
||||
#endif /* __COMMON_TYPE_H__ */
|
||||
|
||||
2062
sources/uboot-be550/drivers/net/4xx_enet.c
Normal file
2062
sources/uboot-be550/drivers/net/4xx_enet.c
Normal file
File diff suppressed because it is too large
Load diff
124
sources/uboot-be550/drivers/net/8390.h
Normal file
124
sources/uboot-be550/drivers/net/8390.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
|
||||
Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
|
||||
|
||||
Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
|
||||
eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
|
||||
are GPL, so this is, of course, GPL.
|
||||
|
||||
*/
|
||||
|
||||
/* Generic NS8390 register definitions. */
|
||||
/* This file is part of Donald Becker's 8390 drivers, and is distributed
|
||||
under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
|
||||
Some of these names and comments originated from the Crynwr
|
||||
packet drivers, which are distributed under the GPL. */
|
||||
|
||||
#ifndef _8390_h
|
||||
#define _8390_h
|
||||
|
||||
/* Some generic ethernet register configurations. */
|
||||
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
|
||||
#define E8390_RX_IRQ_MASK 0x5
|
||||
#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
|
||||
#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
|
||||
#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
|
||||
#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
|
||||
|
||||
/* Register accessed at EN_CMD, the 8390 base addr. */
|
||||
#define E8390_STOP 0x01 /* Stop and reset the chip */
|
||||
#define E8390_START 0x02 /* Start the chip, clear reset */
|
||||
#define E8390_TRANS 0x04 /* Transmit a frame */
|
||||
#define E8390_RREAD 0x08 /* Remote read */
|
||||
#define E8390_RWRITE 0x10 /* Remote write */
|
||||
#define E8390_NODMA 0x20 /* Remote DMA */
|
||||
#define E8390_PAGE0 0x00 /* Select page chip registers */
|
||||
#define E8390_PAGE1 0x40 /* using the two high-order bits */
|
||||
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
|
||||
|
||||
/*
|
||||
* Only generate indirect loads given a machine that needs them.
|
||||
* - removed AMIGA_PCMCIA from this list, handled as ISA io now
|
||||
*/
|
||||
|
||||
#define n2k_inb(port) (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)))
|
||||
#define n2k_outb(val,port) (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)) = val)
|
||||
|
||||
#define EI_SHIFT(x) (x)
|
||||
|
||||
#define E8390_CMD EI_SHIFT(0x00) /* The command register (for all pages) */
|
||||
/* Page 0 register offsets. */
|
||||
#define EN0_CLDALO EI_SHIFT(0x01) /* Low byte of current local dma addr RD */
|
||||
#define EN0_STARTPG EI_SHIFT(0x01) /* Starting page of ring bfr WR */
|
||||
#define EN0_CLDAHI EI_SHIFT(0x02) /* High byte of current local dma addr RD */
|
||||
#define EN0_STOPPG EI_SHIFT(0x02) /* Ending page +1 of ring bfr WR */
|
||||
#define EN0_BOUNDARY EI_SHIFT(0x03) /* Boundary page of ring bfr RD WR */
|
||||
#define EN0_TSR EI_SHIFT(0x04) /* Transmit status reg RD */
|
||||
#define EN0_TPSR EI_SHIFT(0x04) /* Transmit starting page WR */
|
||||
#define EN0_NCR EI_SHIFT(0x05) /* Number of collision reg RD */
|
||||
#define EN0_TCNTLO EI_SHIFT(0x05) /* Low byte of tx byte count WR */
|
||||
#define EN0_FIFO EI_SHIFT(0x06) /* FIFO RD */
|
||||
#define EN0_TCNTHI EI_SHIFT(0x06) /* High byte of tx byte count WR */
|
||||
#define EN0_ISR EI_SHIFT(0x07) /* Interrupt status reg RD WR */
|
||||
#define EN0_CRDALO EI_SHIFT(0x08) /* low byte of current remote dma address RD */
|
||||
#define EN0_RSARLO EI_SHIFT(0x08) /* Remote start address reg 0 */
|
||||
#define EN0_CRDAHI EI_SHIFT(0x09) /* high byte, current remote dma address RD */
|
||||
#define EN0_RSARHI EI_SHIFT(0x09) /* Remote start address reg 1 */
|
||||
#define EN0_RCNTLO EI_SHIFT(0x0a) /* Remote byte count reg WR */
|
||||
#define EN0_RCNTHI EI_SHIFT(0x0b) /* Remote byte count reg WR */
|
||||
#define EN0_RSR EI_SHIFT(0x0c) /* rx status reg RD */
|
||||
#define EN0_RXCR EI_SHIFT(0x0c) /* RX configuration reg WR */
|
||||
#define EN0_TXCR EI_SHIFT(0x0d) /* TX configuration reg WR */
|
||||
#define EN0_COUNTER0 EI_SHIFT(0x0d) /* Rcv alignment error counter RD */
|
||||
#define EN0_DCFG EI_SHIFT(0x0e) /* Data configuration reg WR */
|
||||
#define EN0_COUNTER1 EI_SHIFT(0x0e) /* Rcv CRC error counter RD */
|
||||
#define EN0_IMR EI_SHIFT(0x0f) /* Interrupt mask reg WR */
|
||||
#define EN0_COUNTER2 EI_SHIFT(0x0f) /* Rcv missed frame error counter RD */
|
||||
|
||||
/* Bits in EN0_ISR - Interrupt status register */
|
||||
#define ENISR_RX 0x01 /* Receiver, no error */
|
||||
#define ENISR_TX 0x02 /* Transmitter, no error */
|
||||
#define ENISR_RX_ERR 0x04 /* Receiver, with error */
|
||||
#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
|
||||
#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
|
||||
#define ENISR_COUNTERS 0x20 /* Counters need emptying */
|
||||
#define ENISR_RDC 0x40 /* remote dma complete */
|
||||
#define ENISR_RESET 0x80 /* Reset completed */
|
||||
#define ENISR_ALL 0x3f /* Interrupts we will enable */
|
||||
|
||||
/* Bits in EN0_DCFG - Data config register */
|
||||
#define ENDCFG_WTS 0x01 /* word transfer mode selection */
|
||||
#define ENDCFG_BOS 0x02 /* byte order selection */
|
||||
#define ENDCFG_AUTO_INIT 0x10 /* Auto-init to remove packets from ring */
|
||||
#define ENDCFG_FIFO 0x40 /* 8 bytes */
|
||||
|
||||
/* Page 1 register offsets. */
|
||||
#define EN1_PHYS EI_SHIFT(0x01) /* This board's physical enet addr RD WR */
|
||||
#define EN1_PHYS_SHIFT(i) EI_SHIFT(i+1) /* Get and set mac address */
|
||||
#define EN1_CURPAG EI_SHIFT(0x07) /* Current memory page RD WR */
|
||||
#define EN1_MULT EI_SHIFT(0x08) /* Multicast filter mask array (8 bytes) RD WR */
|
||||
#define EN1_MULT_SHIFT(i) EI_SHIFT(8+i) /* Get and set multicast filter */
|
||||
|
||||
/* Bits in received packet status byte and EN0_RSR*/
|
||||
#define ENRSR_RXOK 0x01 /* Received a good packet */
|
||||
#define ENRSR_CRC 0x02 /* CRC error */
|
||||
#define ENRSR_FAE 0x04 /* frame alignment error */
|
||||
#define ENRSR_FO 0x08 /* FIFO overrun */
|
||||
#define ENRSR_MPA 0x10 /* missed pkt */
|
||||
#define ENRSR_PHY 0x20 /* physical/multicast address */
|
||||
#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
|
||||
#define ENRSR_DEF 0x80 /* deferring */
|
||||
|
||||
/* Transmitted packet status, EN0_TSR. */
|
||||
#define ENTSR_PTX 0x01 /* Packet transmitted without error */
|
||||
#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
|
||||
#define ENTSR_COL 0x04 /* The transmit collided at least once. */
|
||||
#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
|
||||
#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
|
||||
#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
|
||||
#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
|
||||
#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
|
||||
|
||||
#define NIC_RECEIVE_MONITOR_MODE 0x20
|
||||
|
||||
#endif /* _8390_h */
|
||||
158
sources/uboot-be550/drivers/net/Kconfig
Normal file
158
sources/uboot-be550/drivers/net/Kconfig
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
config DM_ETH
|
||||
bool "Enable Driver Model for Ethernet drivers"
|
||||
depends on DM
|
||||
help
|
||||
Enable driver model for Ethernet.
|
||||
|
||||
The eth_*() interface will be implemented by the UC_ETH class
|
||||
This is currently implemented in net/eth.c
|
||||
Look in include/net.h for details.
|
||||
|
||||
config PHYLIB
|
||||
bool "Ethernet PHY (physical media interface) support"
|
||||
help
|
||||
Enable Ethernet PHY (physical media interface) support.
|
||||
|
||||
menuconfig NETDEVICES
|
||||
bool "Network device support"
|
||||
depends on NET
|
||||
default y if DM_ETH
|
||||
help
|
||||
You must select Y to enable any network device support
|
||||
Generally if you have any networking support this is a given
|
||||
|
||||
If unsure, say Y
|
||||
|
||||
if NETDEVICES
|
||||
|
||||
config ALTERA_TSE
|
||||
bool "Altera Triple-Speed Ethernet MAC support"
|
||||
depends on DM_ETH
|
||||
select PHYLIB
|
||||
help
|
||||
This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
|
||||
Please find details on the "Triple-Speed Ethernet MegaCore Function
|
||||
Resource Center" of Altera.
|
||||
|
||||
config E1000
|
||||
bool "Intel PRO/1000 Gigabit Ethernet support"
|
||||
help
|
||||
This driver supports Intel(R) PRO/1000 gigabit ethernet family of
|
||||
adapters. For more information on how to identify your adapter, go
|
||||
to the Adapter & Driver ID Guide at:
|
||||
|
||||
<http://support.intel.com/support/network/adapter/pro100/21397.htm>
|
||||
|
||||
config E1000_SPI_GENERIC
|
||||
bool "Allow access to the Intel 8257x SPI bus"
|
||||
depends on E1000
|
||||
help
|
||||
Allow generic access to the SPI bus on the Intel 8257x, for
|
||||
example with the "sspi" command.
|
||||
|
||||
config E1000_SPI
|
||||
bool "Enable SPI bus utility code"
|
||||
depends on E1000
|
||||
help
|
||||
Utility code for direct access to the SPI bus on Intel 8257x.
|
||||
This does not do anything useful unless you set at least one
|
||||
of CONFIG_CMD_E1000 or CONFIG_E1000_SPI_GENERIC.
|
||||
|
||||
config CMD_E1000
|
||||
bool "Enable the e1000 command"
|
||||
depends on E1000
|
||||
help
|
||||
This enables the 'e1000' management command for E1000 devices. When
|
||||
used on devices with SPI support you can reprogram the EEPROM from
|
||||
U-Boot.
|
||||
|
||||
config ETH_SANDBOX
|
||||
depends on DM_ETH && SANDBOX
|
||||
default y
|
||||
bool "Sandbox: Mocked Ethernet driver"
|
||||
help
|
||||
This driver simply responds with fake ARP replies and ping
|
||||
replies that are used to verify network stack functionality
|
||||
|
||||
This driver is particularly useful in the test/dm/eth.c tests
|
||||
|
||||
config ETH_SANDBOX_RAW
|
||||
depends on DM_ETH && SANDBOX
|
||||
default y
|
||||
bool "Sandbox: Bridge to Linux Raw Sockets"
|
||||
help
|
||||
This driver is a bridge from the bottom of the network stack
|
||||
in U-Boot to the RAW AF_PACKET API in Linux. This allows real
|
||||
network traffic to be tested from within sandbox. See
|
||||
board/sandbox/README.sandbox for more details.
|
||||
|
||||
config ETH_DESIGNWARE
|
||||
bool "Synopsys Designware Ethernet MAC"
|
||||
select PHYLIB
|
||||
help
|
||||
This MAC is present in SoCs from various vendors. It supports
|
||||
100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to
|
||||
provide the PHY (physical media interface).
|
||||
|
||||
config PCH_GBE
|
||||
bool "Intel Platform Controller Hub EG20T GMAC driver"
|
||||
depends on DM_ETH && DM_PCI
|
||||
select PHYLIB
|
||||
help
|
||||
This MAC is present in Intel Platform Controller Hub EG20T. It
|
||||
supports 10/100/1000 Mbps operation.
|
||||
|
||||
config ZYNQ_GEM
|
||||
depends on DM_ETH && (ARCH_ZYNQ || ARCH_ZYNQMP)
|
||||
select PHYLIB
|
||||
bool "Xilinx Ethernet GEM"
|
||||
help
|
||||
This MAC is present in Xilinx Zynq and ZynqMP SoCs.
|
||||
|
||||
endif # NETDEVICES
|
||||
|
||||
config IPQ_QCA_AQUANTIA_PHY
|
||||
bool "Aquantia PHY support"
|
||||
help
|
||||
Enable Aquantia PHY support.
|
||||
|
||||
config ATHRS17C_SWITCH
|
||||
bool "QTI S17C switch support"
|
||||
help
|
||||
Enable QTI S17C switch support.
|
||||
|
||||
config QCA8084_PHY
|
||||
depends on QCA8081_PHY
|
||||
bool "Enable QCA8084 Ethernet Chip support"
|
||||
|
||||
if QCA8084_PHY
|
||||
|
||||
config QCA8084_PHY_MODE
|
||||
bool "Enable QCA8084 PHY Mode support"
|
||||
help
|
||||
Enable QCA8084 PHY Mode support.
|
||||
|
||||
config QCA8084_SWT_MODE
|
||||
bool "Enable QCA8084 Switch Mode support"
|
||||
help
|
||||
Enable QCA8084 Switch Mode support.
|
||||
|
||||
if QCA8084_SWT_MODE
|
||||
|
||||
config QCA8084_BYPASS_MODE
|
||||
bool "Enable QCA8084 By-pass support"
|
||||
help
|
||||
Enable QCA808 By-pass support.
|
||||
|
||||
endif # QCA8084_SWT_MODE
|
||||
|
||||
config QCA8084_DEBUG
|
||||
bool "Enable QCA8084 Debug support"
|
||||
help
|
||||
Enable QCA8084 Debug support.
|
||||
|
||||
endif # QCA8084_PHY
|
||||
|
||||
config IPQ_QTI_BIT_BANGMII
|
||||
bool "Enable MDIO Gpio bit bang support"
|
||||
depends on BITBANGMII
|
||||
236
sources/uboot-be550/drivers/net/Makefile
Normal file
236
sources/uboot-be550/drivers/net/Makefile
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
ccflags-y += -I$(srctree)/board/qca/arm/ipq40xx -I$(srctree)/board/qca/arm/common
|
||||
ccflags-y += -I$(srctree)/drivers/net/ipq_common
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_PHY_RTL8251B)),y)
|
||||
ccflags-y += -I$(srctree)/drivers/net/rtl8251b
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_SWITCH_RTL8367_ALL)),y)
|
||||
ccflags-y += -I$(srctree)/drivers/net/rtl8367_common_V1_4_2 -I$(srctree)/drivers/net/rtl8367_common_V1_4_2/dal/ -I$(srctree)/drivers/net/rtl8367_common_V1_4_2/dal/rtl8367d/ -I$(srctree)/drivers/net/rtl8367_common_V1_4_2/dal/rtl8367c/
|
||||
EXTRA_CFLAGS += $(TP_SDK_CFLAGS) -DMDC_MDIO_OPERATION -DCONFIG_DAL_RTL8367D
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_PHY_RTL8221B)),y)
|
||||
ccflags-y += -I$(srctree)/drivers/net/rtl8221b
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_SWITCH_RTL8372)),y)
|
||||
ccflags-y += -I$(srctree)/drivers/net/rtl8372 -I$(srctree)/drivers/net/rtl8372/dal/ -I$(srctree)/drivers/net/rtl8372/dal/rtl8373/
|
||||
EXTRA_CFLAGS += $(TP_SDK_CFLAGS) -DCONFIG_TP_EXT_SWITCH_RTL8372 -DCONFIG_TP_EXT_SWITCH -DMDC_MDIO_OPERATION
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_PPC4xx_EMAC) += 4xx_enet.o
|
||||
obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
|
||||
obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
|
||||
obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
|
||||
obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
|
||||
obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
|
||||
obj-$(CONFIG_BCM_SF2_ETH_GMAC) += bcm-sf2-eth-gmac.o
|
||||
obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
|
||||
obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
|
||||
obj-$(CONFIG_CS8900) += cs8900.o
|
||||
obj-$(CONFIG_TULIP) += dc2114x.o
|
||||
obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
|
||||
obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
|
||||
obj-$(CONFIG_DNET) += dnet.o
|
||||
obj-$(CONFIG_E1000) += e1000.o
|
||||
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
|
||||
obj-$(CONFIG_EEPRO100) += eepro100.o
|
||||
obj-$(CONFIG_SUNXI_EMAC) += sunxi_emac.o
|
||||
obj-$(CONFIG_ENC28J60) += enc28j60.o
|
||||
obj-$(CONFIG_EP93XX) += ep93xx_eth.o
|
||||
obj-$(CONFIG_ETHOC) += ethoc.o
|
||||
obj-$(CONFIG_FEC_MXC) += fec_mxc.o
|
||||
obj-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
|
||||
obj-$(CONFIG_FTGMAC100) += ftgmac100.o
|
||||
obj-$(CONFIG_FTMAC110) += ftmac110.o
|
||||
obj-$(CONFIG_FTMAC100) += ftmac100.o
|
||||
obj-$(CONFIG_GRETH) += greth.o
|
||||
obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o
|
||||
obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
|
||||
obj-$(CONFIG_LAN91C96) += lan91c96.o
|
||||
obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o
|
||||
obj-$(CONFIG_MACB) += macb.o
|
||||
obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
|
||||
obj-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
|
||||
obj-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o
|
||||
obj-$(CONFIG_MVGBE) += mvgbe.o
|
||||
obj-$(CONFIG_MVNETA) += mvneta.o
|
||||
obj-$(CONFIG_NATSEMI) += natsemi.o
|
||||
obj-$(CONFIG_DRIVER_NE2000) += ne2000.o ne2000_base.o
|
||||
obj-$(CONFIG_DRIVER_AX88796L) += ax88796.o ne2000_base.o
|
||||
obj-$(CONFIG_NETCONSOLE) += netconsole.o
|
||||
obj-$(CONFIG_NS8382X) += ns8382x.o
|
||||
obj-$(CONFIG_PCH_GBE) += pch_gbe.o
|
||||
obj-$(CONFIG_PCNET) += pcnet.o
|
||||
obj-$(CONFIG_RTL8139) += rtl8139.o
|
||||
obj-$(CONFIG_RTL8169) += rtl8169.o
|
||||
obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
|
||||
obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
|
||||
obj-$(CONFIG_SH_ETHER) += sh_eth.o
|
||||
obj-$(CONFIG_SMC91111) += smc91111.o
|
||||
obj-$(CONFIG_SMC911X) += smc911x.o
|
||||
obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
|
||||
obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
|
||||
obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o
|
||||
obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
|
||||
obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
|
||||
obj-$(CONFIG_ULI526X) += uli526x.o
|
||||
obj-$(CONFIG_VSC7385_ENET) += vsc7385.o
|
||||
obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o
|
||||
obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o
|
||||
obj-$(CONFIG_XILINX_LL_TEMAC) += xilinx_ll_temac.o xilinx_ll_temac_mdio.o \
|
||||
xilinx_ll_temac_fifo.o xilinx_ll_temac_sdma.o
|
||||
obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o
|
||||
obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
|
||||
obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
|
||||
obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
|
||||
obj-$(CONFIG_VSC9953) += vsc9953.o
|
||||
obj-$(CONFIG_IPQ40XX_EDMA) += ipq40xx/ipq40xx_edma_eth.o
|
||||
obj-$(CONFIG_IPQ40XX_ESS) += ipq40xx/ipq40xx_ess_sw.o
|
||||
obj-$(CONFIG_IPQ_SNPS_GMAC) += ipq806x/ipq_gmac_eth.o
|
||||
obj-$(CONFIG_IPQ_SWITCH_ATHRS17) += ipq806x/athrs17_phy.o
|
||||
obj-$(CONFIG_IPQ_SWITCH_QCA8511) += ipq806x/qca8511.o
|
||||
obj-$(CONFIG_IPQ807X_EDMA) += ipq807x/ipq807x_edma.o
|
||||
obj-$(CONFIG_IPQ807X_EDMA) += ipq807x/ipq807x_ppe.o
|
||||
obj-$(CONFIG_IPQ807X_EDMA) += ipq807x/ipq807x_uniphy.o
|
||||
obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_edma.o
|
||||
obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_ppe.o
|
||||
obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_uniphy.o
|
||||
obj-$(CONFIG_IPQ9574_EDMA) += ipq9574/ipq9574_ppe.o
|
||||
obj-$(CONFIG_IPQ9574_EDMA) += ipq9574/ipq9574_uniphy.o
|
||||
obj-$(CONFIG_IPQ9574_EDMA) += ipq9574/ipq9574_edma.o
|
||||
obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_gmac.o
|
||||
obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_uniphy.o
|
||||
obj-$(CONFIG_IPQ5018_MDIO) += ipq5018/ipq5018_mdio.o
|
||||
obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/athrs17_phy.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += ipq5332/ipq5332_edma.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += ipq5332/ipq5332_ppe.o
|
||||
|
||||
ifndef CONFIG_IPQ5332_RUMI
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += ipq5332/ipq5332_uniphy.o
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_SWITCH_RTL8367_ALL)),y)
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/rtl8367d_asicdrv.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/rtl8367d_smi.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_acl.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_cpu.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_dot1x.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_eee.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_gpio.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_igmp.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_interrupt.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_l2.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_leaky.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_led.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_mapper.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_mirror.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_port.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_qos.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_rate.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_rldp.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_stat.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_storm.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_svlan.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_switch.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_trap.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_trunk.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/rtl8367d/dal_rtl8367d_vlan.o
|
||||
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/rtk_switch.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/port.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/vlan.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/chip.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8367_common_V1_4_2/dal/dal_mgmt.o
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_SWITCH_RTL8372)),y)
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_switch.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_port.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_acl.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_fc.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_isolation.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/rtl8373_asicdrv.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_mirror.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_rate.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_svlan.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/rtl8373_regField_list.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_cpuTag.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_gpio.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_led.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_nic.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_rma.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_switch.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/rtl8373_reg_list.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_dos.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_hsb.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_lut.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_parser.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_rtkpp.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_trunk.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/rtl8373_smi.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_dot1x.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_i2c.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_macsec.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_sharemeter.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_vlan.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/rtl8373_tableField_list.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_drv.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_igmp.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_mapper.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_ptp.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_storm.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_wol.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/rtl8373_table_list.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_eee.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_interrupt.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_mib.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_qos.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/rtl8373/dal_rtl8373_stp.o
|
||||
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/rtk_switch.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/port.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/vlan.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/chip.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/identify.o
|
||||
obj-$(CONFIG_IPQ5332_EDMA) += rtl8372/dal/dal_mgmt.o
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_PHY_RTL8261B)),y)
|
||||
obj-$(CONFIG_TP_EXT_PHY_RTL8261B) += ipq_common/rtl8261_phy.o
|
||||
obj-$(CONFIG_TP_EXT_PHY_RTL8261B) += ipq_common/rtl8261_patch.o
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_PHY_RTL8251B)),y)
|
||||
obj-$(CONFIG_TP_EXT_PHY_RTL8251B) += rtl8251b/nic_rtl8251b.o
|
||||
obj-$(CONFIG_TP_EXT_PHY_RTL8251B) += rtl8251b/nic_rtl8251b_init.o
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(CONFIG_TP_EXT_PHY_RTL8221B)),y)
|
||||
obj-$(CONFIG_TP_EXT_PHY_RTL8221B) += rtl8221b/nic_rtl8226b.o
|
||||
obj-$(CONFIG_TP_EXT_PHY_RTL8221B) += rtl8221b/nic_rtl8226b_init.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_IPQ_MDIO) += ipq_common/ipq_mdio.o
|
||||
obj-$(CONFIG_IPQ_QTI_BIT_BANGMII) += ipq_common/ipq_bitbangmii.o
|
||||
obj-$(CONFIG_GEPHY) += ipq_common/ipq_gephy.o
|
||||
obj-$(CONFIG_QCA8075_PHY) += ipq_common/ipq_qca8075.o
|
||||
obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084.o
|
||||
obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084_clk.o
|
||||
obj-$(CONFIG_QCA8084_PHY) += ipq_common/ipq_qca8084_interface_ctrl.o
|
||||
obj-$(CONFIG_ATHRS17C_SWITCH) += ipq_common/athrs17_phy.o
|
||||
obj-$(CONFIG_IPQ9574_QCA8075_PHY) += ipq9574/ipq9574_qca8075.o
|
||||
obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o
|
||||
obj-$(CONFIG_QCA8081_PHY) += ipq_common/ipq_qca8081.o
|
||||
obj-$(CONFIG_IPQ_QCA_AQUANTIA_PHY) += ipq_common/ipq_aquantia_phy.o
|
||||
obj-$(CONFIG_QCA_AQUANTIA_PHY) += ipq807x/ipq807x_aquantia_phy.o
|
||||
obj-$(CONFIG_IPQ6018_QCA_AQUANTIA_PHY) += ipq6018/ipq6018_aquantia_phy.o
|
||||
obj-$(CONFIG_IPQ9574_QCA_AQUANTIA_PHY) += ipq9574/ipq9574_aquantia_phy.o
|
||||
714
sources/uboot-be550/drivers/net/altera_tse.c
Normal file
714
sources/uboot-be550/drivers/net/altera_tse.c
Normal file
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* Altera 10/100/1000 triple speed ethernet mac driver
|
||||
*
|
||||
* Copyright (C) 2008 Altera Corporation.
|
||||
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdt_support.h>
|
||||
#include <memalign.h>
|
||||
#include <miiphy.h>
|
||||
#include <net.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/dma-mapping.h>
|
||||
#include <asm/io.h>
|
||||
#include "altera_tse.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static inline void alt_sgdma_construct_descriptor(
|
||||
struct alt_sgdma_descriptor *desc,
|
||||
struct alt_sgdma_descriptor *next,
|
||||
void *read_addr,
|
||||
void *write_addr,
|
||||
u16 length_or_eop,
|
||||
int generate_eop,
|
||||
int read_fixed,
|
||||
int write_fixed_or_sop)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
/*
|
||||
* Mark the "next" descriptor as "not" owned by hardware. This prevents
|
||||
* The SGDMA controller from continuing to process the chain.
|
||||
*/
|
||||
next->descriptor_control = next->descriptor_control &
|
||||
~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
|
||||
|
||||
memset(desc, 0, sizeof(struct alt_sgdma_descriptor));
|
||||
desc->source = virt_to_phys(read_addr);
|
||||
desc->destination = virt_to_phys(write_addr);
|
||||
desc->next = virt_to_phys(next);
|
||||
desc->bytes_to_transfer = length_or_eop;
|
||||
|
||||
/*
|
||||
* Set the descriptor control block as follows:
|
||||
* - Set "owned by hardware" bit
|
||||
* - Optionally set "generate EOP" bit
|
||||
* - Optionally set the "read from fixed address" bit
|
||||
* - Optionally set the "write to fixed address bit (which serves
|
||||
* serves as a "generate SOP" control bit in memory-to-stream mode).
|
||||
* - Set the 4-bit atlantic channel, if specified
|
||||
*
|
||||
* Note this step is performed after all other descriptor information
|
||||
* has been filled out so that, if the controller already happens to be
|
||||
* pointing at this descriptor, it will not run (via the "owned by
|
||||
* hardware" bit) until all other descriptor has been set up.
|
||||
*/
|
||||
val = ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
|
||||
if (generate_eop)
|
||||
val |= ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK;
|
||||
if (read_fixed)
|
||||
val |= ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK;
|
||||
if (write_fixed_or_sop)
|
||||
val |= ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK;
|
||||
desc->descriptor_control = val;
|
||||
}
|
||||
|
||||
static int alt_sgdma_wait_transfer(struct alt_sgdma_registers *regs)
|
||||
{
|
||||
int status;
|
||||
ulong ctime;
|
||||
|
||||
/* Wait for the descriptor (chain) to complete */
|
||||
ctime = get_timer(0);
|
||||
while (1) {
|
||||
status = readl(®s->status);
|
||||
if (!(status & ALT_SGDMA_STATUS_BUSY_MSK))
|
||||
break;
|
||||
if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) {
|
||||
status = -ETIMEDOUT;
|
||||
debug("sgdma timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear Run */
|
||||
writel(0, ®s->control);
|
||||
/* Clear status */
|
||||
writel(0xff, ®s->status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int alt_sgdma_start_transfer(struct alt_sgdma_registers *regs,
|
||||
struct alt_sgdma_descriptor *desc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Point the controller at the descriptor */
|
||||
writel(virt_to_phys(desc), ®s->next_descriptor_pointer);
|
||||
|
||||
/*
|
||||
* Set up SGDMA controller to:
|
||||
* - Disable interrupt generation
|
||||
* - Run once a valid descriptor is written to controller
|
||||
* - Stop on an error with any particular descriptor
|
||||
*/
|
||||
val = ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK;
|
||||
writel(val, ®s->control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tse_adjust_link(struct altera_tse_priv *priv,
|
||||
struct phy_device *phydev)
|
||||
{
|
||||
struct alt_tse_mac *mac_dev = priv->mac_dev;
|
||||
u32 refvar;
|
||||
|
||||
if (!phydev->link) {
|
||||
debug("%s: No link.\n", phydev->dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
refvar = readl(&mac_dev->command_config);
|
||||
|
||||
if (phydev->duplex)
|
||||
refvar |= ALTERA_TSE_CMD_HD_ENA_MSK;
|
||||
else
|
||||
refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK;
|
||||
|
||||
switch (phydev->speed) {
|
||||
case 1000:
|
||||
refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK;
|
||||
refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK;
|
||||
break;
|
||||
case 100:
|
||||
refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK;
|
||||
refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK;
|
||||
break;
|
||||
case 10:
|
||||
refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK;
|
||||
refvar |= ALTERA_TSE_CMD_ENA_10_MSK;
|
||||
break;
|
||||
}
|
||||
writel(refvar, &mac_dev->command_config);
|
||||
}
|
||||
|
||||
static int altera_tse_send_sgdma(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct alt_sgdma_descriptor *tx_desc = priv->tx_desc;
|
||||
|
||||
alt_sgdma_construct_descriptor(
|
||||
tx_desc,
|
||||
tx_desc + 1,
|
||||
packet, /* read addr */
|
||||
NULL, /* write addr */
|
||||
length, /* length or EOP ,will change for each tx */
|
||||
1, /* gen eop */
|
||||
0, /* read fixed */
|
||||
1 /* write fixed or sop */
|
||||
);
|
||||
|
||||
/* send the packet */
|
||||
alt_sgdma_start_transfer(priv->sgdma_tx, tx_desc);
|
||||
alt_sgdma_wait_transfer(priv->sgdma_tx);
|
||||
debug("sent %d bytes\n", tx_desc->actual_bytes_transferred);
|
||||
|
||||
return tx_desc->actual_bytes_transferred;
|
||||
}
|
||||
|
||||
static int altera_tse_recv_sgdma(struct udevice *dev, int flags,
|
||||
uchar **packetp)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
|
||||
int packet_length;
|
||||
|
||||
if (rx_desc->descriptor_status &
|
||||
ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) {
|
||||
alt_sgdma_wait_transfer(priv->sgdma_rx);
|
||||
packet_length = rx_desc->actual_bytes_transferred;
|
||||
debug("recv %d bytes\n", packet_length);
|
||||
*packetp = priv->rx_buf;
|
||||
|
||||
return packet_length;
|
||||
}
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int altera_tse_free_pkt_sgdma(struct udevice *dev, uchar *packet,
|
||||
int length)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
|
||||
|
||||
alt_sgdma_construct_descriptor(
|
||||
rx_desc,
|
||||
rx_desc + 1,
|
||||
NULL, /* read addr */
|
||||
priv->rx_buf, /* write addr */
|
||||
0, /* length or EOP */
|
||||
0, /* gen eop */
|
||||
0, /* read fixed */
|
||||
0 /* write fixed or sop */
|
||||
);
|
||||
|
||||
/* setup the sgdma */
|
||||
alt_sgdma_start_transfer(priv->sgdma_rx, rx_desc);
|
||||
debug("recv setup\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void altera_tse_stop_mac(struct altera_tse_priv *priv)
|
||||
{
|
||||
struct alt_tse_mac *mac_dev = priv->mac_dev;
|
||||
u32 status;
|
||||
ulong ctime;
|
||||
|
||||
/* reset the mac */
|
||||
writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config);
|
||||
ctime = get_timer(0);
|
||||
while (1) {
|
||||
status = readl(&mac_dev->command_config);
|
||||
if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK))
|
||||
break;
|
||||
if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) {
|
||||
debug("Reset mac timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void altera_tse_stop_sgdma(struct udevice *dev)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
|
||||
struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
|
||||
struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
|
||||
int ret;
|
||||
|
||||
/* clear rx desc & wait for sgdma to complete */
|
||||
rx_desc->descriptor_control = 0;
|
||||
writel(0, &rx_sgdma->control);
|
||||
ret = alt_sgdma_wait_transfer(rx_sgdma);
|
||||
if (ret == -ETIMEDOUT)
|
||||
writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK,
|
||||
&rx_sgdma->control);
|
||||
|
||||
writel(0, &tx_sgdma->control);
|
||||
ret = alt_sgdma_wait_transfer(tx_sgdma);
|
||||
if (ret == -ETIMEDOUT)
|
||||
writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK,
|
||||
&tx_sgdma->control);
|
||||
}
|
||||
|
||||
static void msgdma_reset(struct msgdma_csr *csr)
|
||||
{
|
||||
u32 status;
|
||||
ulong ctime;
|
||||
|
||||
/* Reset mSGDMA */
|
||||
writel(MSGDMA_CSR_STAT_MASK, &csr->status);
|
||||
writel(MSGDMA_CSR_CTL_RESET, &csr->control);
|
||||
ctime = get_timer(0);
|
||||
while (1) {
|
||||
status = readl(&csr->status);
|
||||
if (!(status & MSGDMA_CSR_STAT_RESETTING))
|
||||
break;
|
||||
if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) {
|
||||
debug("Reset msgdma timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Clear status */
|
||||
writel(MSGDMA_CSR_STAT_MASK, &csr->status);
|
||||
}
|
||||
|
||||
static u32 msgdma_wait(struct msgdma_csr *csr)
|
||||
{
|
||||
u32 status;
|
||||
ulong ctime;
|
||||
|
||||
/* Wait for the descriptor to complete */
|
||||
ctime = get_timer(0);
|
||||
while (1) {
|
||||
status = readl(&csr->status);
|
||||
if (!(status & MSGDMA_CSR_STAT_BUSY))
|
||||
break;
|
||||
if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) {
|
||||
debug("sgdma timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Clear status */
|
||||
writel(MSGDMA_CSR_STAT_MASK, &csr->status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int altera_tse_send_msgdma(struct udevice *dev, void *packet,
|
||||
int length)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct msgdma_extended_desc *desc = priv->tx_desc;
|
||||
u32 tx_buf = virt_to_phys(packet);
|
||||
u32 status;
|
||||
|
||||
writel(tx_buf, &desc->read_addr_lo);
|
||||
writel(0, &desc->read_addr_hi);
|
||||
writel(0, &desc->write_addr_lo);
|
||||
writel(0, &desc->write_addr_hi);
|
||||
writel(length, &desc->len);
|
||||
writel(0, &desc->burst_seq_num);
|
||||
writel(MSGDMA_DESC_TX_STRIDE, &desc->stride);
|
||||
writel(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control);
|
||||
status = msgdma_wait(priv->sgdma_tx);
|
||||
debug("sent %d bytes, status %08x\n", length, status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_tse_recv_msgdma(struct udevice *dev, int flags,
|
||||
uchar **packetp)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct msgdma_csr *csr = priv->sgdma_rx;
|
||||
struct msgdma_response *resp = priv->rx_resp;
|
||||
u32 level, length, status;
|
||||
|
||||
level = readl(&csr->resp_fill_level);
|
||||
if (level & 0xffff) {
|
||||
length = readl(&resp->bytes_transferred);
|
||||
status = readl(&resp->status);
|
||||
debug("recv %d bytes, status %08x\n", length, status);
|
||||
*packetp = priv->rx_buf;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int altera_tse_free_pkt_msgdma(struct udevice *dev, uchar *packet,
|
||||
int length)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct msgdma_extended_desc *desc = priv->rx_desc;
|
||||
u32 rx_buf = virt_to_phys(priv->rx_buf);
|
||||
|
||||
writel(0, &desc->read_addr_lo);
|
||||
writel(0, &desc->read_addr_hi);
|
||||
writel(rx_buf, &desc->write_addr_lo);
|
||||
writel(0, &desc->write_addr_hi);
|
||||
writel(PKTSIZE_ALIGN, &desc->len);
|
||||
writel(0, &desc->burst_seq_num);
|
||||
writel(MSGDMA_DESC_RX_STRIDE, &desc->stride);
|
||||
writel(MSGDMA_DESC_CTL_RX_SINGLE, &desc->control);
|
||||
debug("recv setup\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void altera_tse_stop_msgdma(struct udevice *dev)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
|
||||
msgdma_reset(priv->sgdma_rx);
|
||||
msgdma_reset(priv->sgdma_tx);
|
||||
}
|
||||
|
||||
static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct altera_tse_priv *priv = bus->priv;
|
||||
struct alt_tse_mac *mac_dev = priv->mac_dev;
|
||||
u32 value;
|
||||
|
||||
/* set mdio address */
|
||||
writel(addr, &mac_dev->mdio_phy1_addr);
|
||||
/* get the data */
|
||||
value = readl(&mac_dev->mdio_phy1[reg]);
|
||||
|
||||
return value & 0xffff;
|
||||
}
|
||||
|
||||
static int tse_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
||||
u16 val)
|
||||
{
|
||||
struct altera_tse_priv *priv = bus->priv;
|
||||
struct alt_tse_mac *mac_dev = priv->mac_dev;
|
||||
|
||||
/* set mdio address */
|
||||
writel(addr, &mac_dev->mdio_phy1_addr);
|
||||
/* set the data */
|
||||
writel(val, &mac_dev->mdio_phy1[reg]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tse_mdio_init(const char *name, struct altera_tse_priv *priv)
|
||||
{
|
||||
struct mii_dev *bus = mdio_alloc();
|
||||
|
||||
if (!bus) {
|
||||
printf("Failed to allocate MDIO bus\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus->read = tse_mdio_read;
|
||||
bus->write = tse_mdio_write;
|
||||
snprintf(bus->name, sizeof(bus->name), name);
|
||||
|
||||
bus->priv = (void *)priv;
|
||||
|
||||
return mdio_register(bus);
|
||||
}
|
||||
|
||||
static int tse_phy_init(struct altera_tse_priv *priv, void *dev)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
unsigned int mask = 0xffffffff;
|
||||
|
||||
if (priv->phyaddr)
|
||||
mask = 1 << priv->phyaddr;
|
||||
|
||||
phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
|
||||
if (!phydev)
|
||||
return -ENODEV;
|
||||
|
||||
phy_connect_dev(phydev, dev);
|
||||
|
||||
phydev->supported &= PHY_GBIT_FEATURES;
|
||||
phydev->advertising = phydev->supported;
|
||||
|
||||
priv->phydev = phydev;
|
||||
phy_config(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_tse_write_hwaddr(struct udevice *dev)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct alt_tse_mac *mac_dev = priv->mac_dev;
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
u8 *hwaddr = pdata->enetaddr;
|
||||
u32 mac_lo, mac_hi;
|
||||
|
||||
mac_lo = (hwaddr[3] << 24) | (hwaddr[2] << 16) |
|
||||
(hwaddr[1] << 8) | hwaddr[0];
|
||||
mac_hi = (hwaddr[5] << 8) | hwaddr[4];
|
||||
debug("Set MAC address to 0x%04x%08x\n", mac_hi, mac_lo);
|
||||
|
||||
writel(mac_lo, &mac_dev->mac_addr_0);
|
||||
writel(mac_hi, &mac_dev->mac_addr_1);
|
||||
writel(mac_lo, &mac_dev->supp_mac_addr_0_0);
|
||||
writel(mac_hi, &mac_dev->supp_mac_addr_0_1);
|
||||
writel(mac_lo, &mac_dev->supp_mac_addr_1_0);
|
||||
writel(mac_hi, &mac_dev->supp_mac_addr_1_1);
|
||||
writel(mac_lo, &mac_dev->supp_mac_addr_2_0);
|
||||
writel(mac_hi, &mac_dev->supp_mac_addr_2_1);
|
||||
writel(mac_lo, &mac_dev->supp_mac_addr_3_0);
|
||||
writel(mac_hi, &mac_dev->supp_mac_addr_3_1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_tse_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
unsigned long tx_buf = (unsigned long)packet;
|
||||
|
||||
flush_dcache_range(tx_buf, tx_buf + length);
|
||||
|
||||
return priv->ops->send(dev, packet, length);
|
||||
}
|
||||
|
||||
static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return priv->ops->recv(dev, flags, packetp);
|
||||
}
|
||||
|
||||
static int altera_tse_free_pkt(struct udevice *dev, uchar *packet,
|
||||
int length)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
unsigned long rx_buf = (unsigned long)priv->rx_buf;
|
||||
|
||||
invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN);
|
||||
|
||||
return priv->ops->free_pkt(dev, packet, length);
|
||||
}
|
||||
|
||||
static void altera_tse_stop(struct udevice *dev)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->ops->stop(dev);
|
||||
altera_tse_stop_mac(priv);
|
||||
}
|
||||
|
||||
static int altera_tse_start(struct udevice *dev)
|
||||
{
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
struct alt_tse_mac *mac_dev = priv->mac_dev;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* need to create sgdma */
|
||||
debug("Configuring rx desc\n");
|
||||
altera_tse_free_pkt(dev, priv->rx_buf, PKTSIZE_ALIGN);
|
||||
/* start TSE */
|
||||
debug("Configuring TSE Mac\n");
|
||||
/* Initialize MAC registers */
|
||||
writel(PKTSIZE_ALIGN, &mac_dev->max_frame_length);
|
||||
writel(priv->rx_fifo_depth - 16, &mac_dev->rx_sel_empty_threshold);
|
||||
writel(0, &mac_dev->rx_sel_full_threshold);
|
||||
writel(priv->tx_fifo_depth - 16, &mac_dev->tx_sel_empty_threshold);
|
||||
writel(0, &mac_dev->tx_sel_full_threshold);
|
||||
writel(8, &mac_dev->rx_almost_empty_threshold);
|
||||
writel(8, &mac_dev->rx_almost_full_threshold);
|
||||
writel(8, &mac_dev->tx_almost_empty_threshold);
|
||||
writel(3, &mac_dev->tx_almost_full_threshold);
|
||||
|
||||
/* NO Shift */
|
||||
writel(0, &mac_dev->rx_cmd_stat);
|
||||
writel(0, &mac_dev->tx_cmd_stat);
|
||||
|
||||
/* enable MAC */
|
||||
val = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK;
|
||||
writel(val, &mac_dev->command_config);
|
||||
|
||||
/* Start up the PHY */
|
||||
ret = phy_startup(priv->phydev);
|
||||
if (ret) {
|
||||
debug("Could not initialize PHY %s\n",
|
||||
priv->phydev->dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tse_adjust_link(priv, priv->phydev);
|
||||
|
||||
if (!priv->phydev->link)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct tse_ops tse_sgdma_ops = {
|
||||
.send = altera_tse_send_sgdma,
|
||||
.recv = altera_tse_recv_sgdma,
|
||||
.free_pkt = altera_tse_free_pkt_sgdma,
|
||||
.stop = altera_tse_stop_sgdma,
|
||||
};
|
||||
|
||||
static const struct tse_ops tse_msgdma_ops = {
|
||||
.send = altera_tse_send_msgdma,
|
||||
.recv = altera_tse_recv_msgdma,
|
||||
.free_pkt = altera_tse_free_pkt_msgdma,
|
||||
.stop = altera_tse_stop_msgdma,
|
||||
};
|
||||
|
||||
static int altera_tse_probe(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct altera_tse_priv *priv = dev_get_priv(dev);
|
||||
void *blob = (void *)gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
const char *list, *end;
|
||||
const fdt32_t *cell;
|
||||
void *base, *desc_mem = NULL;
|
||||
unsigned long addr, size;
|
||||
int parent, addrc, sizec;
|
||||
int len, idx;
|
||||
int ret;
|
||||
|
||||
priv->dma_type = dev_get_driver_data(dev);
|
||||
if (priv->dma_type == ALT_SGDMA)
|
||||
priv->ops = &tse_sgdma_ops;
|
||||
else
|
||||
priv->ops = &tse_msgdma_ops;
|
||||
/*
|
||||
* decode regs. there are multiple reg tuples, and they need to
|
||||
* match with reg-names.
|
||||
*/
|
||||
parent = fdt_parent_offset(blob, node);
|
||||
of_bus_default_count_cells(blob, parent, &addrc, &sizec);
|
||||
list = fdt_getprop(blob, node, "reg-names", &len);
|
||||
if (!list)
|
||||
return -ENOENT;
|
||||
end = list + len;
|
||||
cell = fdt_getprop(blob, node, "reg", &len);
|
||||
if (!cell)
|
||||
return -ENOENT;
|
||||
idx = 0;
|
||||
while (list < end) {
|
||||
addr = fdt_translate_address((void *)blob,
|
||||
node, cell + idx);
|
||||
size = fdt_addr_to_cpu(cell[idx + addrc]);
|
||||
base = map_physmem(addr, size, MAP_NOCACHE);
|
||||
len = strlen(list);
|
||||
if (strcmp(list, "control_port") == 0)
|
||||
priv->mac_dev = base;
|
||||
else if (strcmp(list, "rx_csr") == 0)
|
||||
priv->sgdma_rx = base;
|
||||
else if (strcmp(list, "rx_desc") == 0)
|
||||
priv->rx_desc = base;
|
||||
else if (strcmp(list, "rx_resp") == 0)
|
||||
priv->rx_resp = base;
|
||||
else if (strcmp(list, "tx_csr") == 0)
|
||||
priv->sgdma_tx = base;
|
||||
else if (strcmp(list, "tx_desc") == 0)
|
||||
priv->tx_desc = base;
|
||||
else if (strcmp(list, "s1") == 0)
|
||||
desc_mem = base;
|
||||
idx += addrc + sizec;
|
||||
list += (len + 1);
|
||||
}
|
||||
/* decode fifo depth */
|
||||
priv->rx_fifo_depth = fdtdec_get_int(blob, node,
|
||||
"rx-fifo-depth", 0);
|
||||
priv->tx_fifo_depth = fdtdec_get_int(blob, node,
|
||||
"tx-fifo-depth", 0);
|
||||
/* decode phy */
|
||||
addr = fdtdec_get_int(blob, node,
|
||||
"phy-handle", 0);
|
||||
addr = fdt_node_offset_by_phandle(blob, addr);
|
||||
priv->phyaddr = fdtdec_get_int(blob, addr,
|
||||
"reg", 0);
|
||||
/* init desc */
|
||||
if (priv->dma_type == ALT_SGDMA) {
|
||||
len = sizeof(struct alt_sgdma_descriptor) * 4;
|
||||
if (!desc_mem) {
|
||||
desc_mem = dma_alloc_coherent(len, &addr);
|
||||
if (!desc_mem)
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(desc_mem, 0, len);
|
||||
priv->tx_desc = desc_mem;
|
||||
priv->rx_desc = priv->tx_desc +
|
||||
2 * sizeof(struct alt_sgdma_descriptor);
|
||||
}
|
||||
/* allocate recv packet buffer */
|
||||
priv->rx_buf = malloc_cache_aligned(PKTSIZE_ALIGN);
|
||||
if (!priv->rx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* stop controller */
|
||||
debug("Reset TSE & SGDMAs\n");
|
||||
altera_tse_stop(dev);
|
||||
|
||||
/* start the phy */
|
||||
priv->interface = pdata->phy_interface;
|
||||
tse_mdio_init(dev->name, priv);
|
||||
priv->bus = miiphy_get_dev_by_name(dev->name);
|
||||
|
||||
ret = tse_phy_init(priv, dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int altera_tse_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
const char *phy_mode;
|
||||
|
||||
pdata->phy_interface = -1;
|
||||
phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
|
||||
if (phy_mode)
|
||||
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
|
||||
if (pdata->phy_interface == -1) {
|
||||
debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_ops altera_tse_ops = {
|
||||
.start = altera_tse_start,
|
||||
.send = altera_tse_send,
|
||||
.recv = altera_tse_recv,
|
||||
.free_pkt = altera_tse_free_pkt,
|
||||
.stop = altera_tse_stop,
|
||||
.write_hwaddr = altera_tse_write_hwaddr,
|
||||
};
|
||||
|
||||
static const struct udevice_id altera_tse_ids[] = {
|
||||
{ .compatible = "altr,tse-msgdma-1.0", .data = ALT_MSGDMA },
|
||||
{ .compatible = "altr,tse-1.0", .data = ALT_SGDMA },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(altera_tse) = {
|
||||
.name = "altera_tse",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = altera_tse_ids,
|
||||
.ops = &altera_tse_ops,
|
||||
.ofdata_to_platdata = altera_tse_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
|
||||
.priv_auto_alloc_size = sizeof(struct altera_tse_priv),
|
||||
.probe = altera_tse_probe,
|
||||
};
|
||||
231
sources/uboot-be550/drivers/net/altera_tse.h
Normal file
231
sources/uboot-be550/drivers/net/altera_tse.h
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Altera 10/100/1000 triple speed ethernet mac
|
||||
*
|
||||
* Copyright (C) 2008 Altera Corporation.
|
||||
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef _ALTERA_TSE_H_
|
||||
#define _ALTERA_TSE_H_
|
||||
|
||||
#define __packed_1_ __packed __aligned(1)
|
||||
|
||||
/* dma type */
|
||||
#define ALT_SGDMA 0
|
||||
#define ALT_MSGDMA 1
|
||||
|
||||
/* SGDMA Stuff */
|
||||
#define ALT_SGDMA_STATUS_BUSY_MSK BIT(4)
|
||||
|
||||
#define ALT_SGDMA_CONTROL_RUN_MSK BIT(5)
|
||||
#define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK BIT(6)
|
||||
#define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK BIT(16)
|
||||
|
||||
/*
|
||||
* Descriptor control bit masks & offsets
|
||||
*
|
||||
* Note: The control byte physically occupies bits [31:24] in memory.
|
||||
* The following bit-offsets are expressed relative to the LSB of
|
||||
* the control register bitfield.
|
||||
*/
|
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK BIT(0)
|
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK BIT(1)
|
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK BIT(2)
|
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK BIT(7)
|
||||
|
||||
/*
|
||||
* Descriptor status bit masks & offsets
|
||||
*
|
||||
* Note: The status byte physically occupies bits [23:16] in memory.
|
||||
* The following bit-offsets are expressed relative to the LSB of
|
||||
* the status register bitfield.
|
||||
*/
|
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK BIT(7)
|
||||
|
||||
/*
|
||||
* The SGDMA controller buffer descriptor allocates
|
||||
* 64 bits for each address. To support ANSI C, the
|
||||
* struct implementing a descriptor places 32-bits
|
||||
* of padding directly above each address; each pad must
|
||||
* be cleared when initializing a descriptor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Buffer Descriptor data structure
|
||||
*
|
||||
*/
|
||||
struct alt_sgdma_descriptor {
|
||||
u32 source; /* the address of data to be read. */
|
||||
u32 source_pad;
|
||||
|
||||
u32 destination; /* the address to write data */
|
||||
u32 destination_pad;
|
||||
|
||||
u32 next; /* the next descriptor in the list. */
|
||||
u32 next_pad;
|
||||
|
||||
u16 bytes_to_transfer; /* the number of bytes to transfer */
|
||||
u8 read_burst;
|
||||
u8 write_burst;
|
||||
|
||||
u16 actual_bytes_transferred;/* bytes transferred by DMA */
|
||||
u8 descriptor_status;
|
||||
u8 descriptor_control;
|
||||
|
||||
} __packed_1_;
|
||||
|
||||
/* SG-DMA Control/Status Slave registers map */
|
||||
|
||||
struct alt_sgdma_registers {
|
||||
u32 status;
|
||||
u32 status_pad[3];
|
||||
u32 control;
|
||||
u32 control_pad[3];
|
||||
u32 next_descriptor_pointer;
|
||||
u32 descriptor_pad[3];
|
||||
};
|
||||
|
||||
/* mSGDMA Stuff */
|
||||
|
||||
/* mSGDMA extended descriptor format */
|
||||
struct msgdma_extended_desc {
|
||||
u32 read_addr_lo; /* data buffer source address low bits */
|
||||
u32 write_addr_lo; /* data buffer destination address low bits */
|
||||
u32 len;
|
||||
u32 burst_seq_num;
|
||||
u32 stride;
|
||||
u32 read_addr_hi; /* data buffer source address high bits */
|
||||
u32 write_addr_hi; /* data buffer destination address high bits */
|
||||
u32 control; /* characteristics of the transfer */
|
||||
};
|
||||
|
||||
/* mSGDMA descriptor control field bit definitions */
|
||||
#define MSGDMA_DESC_CTL_GEN_SOP BIT(8)
|
||||
#define MSGDMA_DESC_CTL_GEN_EOP BIT(9)
|
||||
#define MSGDMA_DESC_CTL_END_ON_EOP BIT(12)
|
||||
#define MSGDMA_DESC_CTL_END_ON_LEN BIT(13)
|
||||
#define MSGDMA_DESC_CTL_GO BIT(31)
|
||||
|
||||
/* Tx buffer control flags */
|
||||
#define MSGDMA_DESC_CTL_TX_SINGLE (MSGDMA_DESC_CTL_GEN_SOP | \
|
||||
MSGDMA_DESC_CTL_GEN_EOP | \
|
||||
MSGDMA_DESC_CTL_GO)
|
||||
|
||||
#define MSGDMA_DESC_CTL_RX_SINGLE (MSGDMA_DESC_CTL_END_ON_EOP | \
|
||||
MSGDMA_DESC_CTL_END_ON_LEN | \
|
||||
MSGDMA_DESC_CTL_GO)
|
||||
|
||||
/* mSGDMA extended descriptor stride definitions */
|
||||
#define MSGDMA_DESC_TX_STRIDE 0x00010001
|
||||
#define MSGDMA_DESC_RX_STRIDE 0x00010001
|
||||
|
||||
/* mSGDMA dispatcher control and status register map */
|
||||
struct msgdma_csr {
|
||||
u32 status; /* Read/Clear */
|
||||
u32 control; /* Read/Write */
|
||||
u32 rw_fill_level;
|
||||
u32 resp_fill_level; /* bit 15:0 */
|
||||
u32 rw_seq_num;
|
||||
u32 pad[3]; /* reserved */
|
||||
};
|
||||
|
||||
/* mSGDMA CSR status register bit definitions */
|
||||
#define MSGDMA_CSR_STAT_BUSY BIT(0)
|
||||
#define MSGDMA_CSR_STAT_RESETTING BIT(6)
|
||||
#define MSGDMA_CSR_STAT_MASK 0x3FF
|
||||
|
||||
/* mSGDMA CSR control register bit definitions */
|
||||
#define MSGDMA_CSR_CTL_RESET BIT(1)
|
||||
|
||||
/* mSGDMA response register map */
|
||||
struct msgdma_response {
|
||||
u32 bytes_transferred;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
/* TSE Stuff */
|
||||
#define ALTERA_TSE_CMD_TX_ENA_MSK BIT(0)
|
||||
#define ALTERA_TSE_CMD_RX_ENA_MSK BIT(1)
|
||||
#define ALTERA_TSE_CMD_ETH_SPEED_MSK BIT(3)
|
||||
#define ALTERA_TSE_CMD_HD_ENA_MSK BIT(10)
|
||||
#define ALTERA_TSE_CMD_SW_RESET_MSK BIT(13)
|
||||
#define ALTERA_TSE_CMD_ENA_10_MSK BIT(25)
|
||||
|
||||
#define ALT_TSE_SW_RESET_TIMEOUT (3 * CONFIG_SYS_HZ)
|
||||
#define ALT_TSE_SGDMA_BUSY_TIMEOUT (3 * CONFIG_SYS_HZ)
|
||||
|
||||
/* MAC register Space */
|
||||
|
||||
struct alt_tse_mac {
|
||||
u32 megacore_revision;
|
||||
u32 scratch_pad;
|
||||
u32 command_config;
|
||||
u32 mac_addr_0;
|
||||
u32 mac_addr_1;
|
||||
u32 max_frame_length;
|
||||
u32 pause_quanta;
|
||||
u32 rx_sel_empty_threshold;
|
||||
u32 rx_sel_full_threshold;
|
||||
u32 tx_sel_empty_threshold;
|
||||
u32 tx_sel_full_threshold;
|
||||
u32 rx_almost_empty_threshold;
|
||||
u32 rx_almost_full_threshold;
|
||||
u32 tx_almost_empty_threshold;
|
||||
u32 tx_almost_full_threshold;
|
||||
u32 mdio_phy0_addr;
|
||||
u32 mdio_phy1_addr;
|
||||
|
||||
u32 reserved1[0x29];
|
||||
|
||||
/*FIFO control register. */
|
||||
u32 tx_cmd_stat;
|
||||
u32 rx_cmd_stat;
|
||||
|
||||
u32 reserved2[0x44];
|
||||
|
||||
/*Registers 0 to 31 within PHY device 0/1 */
|
||||
u32 mdio_phy0[0x20];
|
||||
u32 mdio_phy1[0x20];
|
||||
|
||||
/*4 Supplemental MAC Addresses */
|
||||
u32 supp_mac_addr_0_0;
|
||||
u32 supp_mac_addr_0_1;
|
||||
u32 supp_mac_addr_1_0;
|
||||
u32 supp_mac_addr_1_1;
|
||||
u32 supp_mac_addr_2_0;
|
||||
u32 supp_mac_addr_2_1;
|
||||
u32 supp_mac_addr_3_0;
|
||||
u32 supp_mac_addr_3_1;
|
||||
|
||||
u32 reserved3[0x38];
|
||||
};
|
||||
|
||||
struct tse_ops {
|
||||
int (*send)(struct udevice *dev, void *packet, int length);
|
||||
int (*recv)(struct udevice *dev, int flags, uchar **packetp);
|
||||
int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
|
||||
void (*stop)(struct udevice *dev);
|
||||
};
|
||||
|
||||
struct altera_tse_priv {
|
||||
struct alt_tse_mac *mac_dev;
|
||||
void *sgdma_rx;
|
||||
void *sgdma_tx;
|
||||
unsigned int rx_fifo_depth;
|
||||
unsigned int tx_fifo_depth;
|
||||
void *rx_desc;
|
||||
void *tx_desc;
|
||||
void *rx_resp;
|
||||
unsigned char *rx_buf;
|
||||
unsigned int phyaddr;
|
||||
unsigned int interface;
|
||||
struct phy_device *phydev;
|
||||
struct mii_dev *bus;
|
||||
const struct tse_ops *ops;
|
||||
int dma_type;
|
||||
};
|
||||
|
||||
#endif /* _ALTERA_TSE_H_ */
|
||||
727
sources/uboot-be550/drivers/net/armada100_fec.c
Normal file
727
sources/uboot-be550/drivers/net/armada100_fec.c
Normal file
|
|
@ -0,0 +1,727 @@
|
|||
/*
|
||||
* (C) Copyright 2011
|
||||
* eInfochips Ltd. <www.einfochips.com>
|
||||
* Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Marvell Semiconductor <www.marvell.com>
|
||||
* Contributor: Mahavir Jain <mjain@marvell.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <net.h>
|
||||
#include <malloc.h>
|
||||
#include <miiphy.h>
|
||||
#include <netdev.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mii.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/armada100.h>
|
||||
#include "armada100_fec.h"
|
||||
|
||||
#define PHY_ADR_REQ 0xFF /* Magic number to read/write PHY address */
|
||||
|
||||
#ifdef DEBUG
|
||||
static int eth_dump_regs(struct eth_device *dev)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
unsigned int i = 0;
|
||||
|
||||
printf("\noffset: phy_adr, value: 0x%x\n", readl(®s->phyadr));
|
||||
printf("offset: smi, value: 0x%x\n", readl(®s->smi));
|
||||
for (i = 0x400; i <= 0x4e4; i += 4)
|
||||
printf("offset: 0x%x, value: 0x%x\n",
|
||||
i, readl(ARMD1_FEC_BASE + i));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int armdfec_phy_timeout(u32 *reg, u32 flag, int cond)
|
||||
{
|
||||
u32 timeout = PHY_WAIT_ITERATIONS;
|
||||
u32 reg_val;
|
||||
|
||||
while (--timeout) {
|
||||
reg_val = readl(reg);
|
||||
if (cond && (reg_val & flag))
|
||||
break;
|
||||
else if (!cond && !(reg_val & flag))
|
||||
break;
|
||||
udelay(PHY_WAIT_MICRO_SECONDS);
|
||||
}
|
||||
return !timeout;
|
||||
}
|
||||
|
||||
static int smi_reg_read(const char *devname, u8 phy_addr, u8 phy_reg,
|
||||
u16 *value)
|
||||
{
|
||||
struct eth_device *dev = eth_get_dev_by_name(devname);
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
u32 val;
|
||||
|
||||
if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
|
||||
val = readl(®s->phyadr);
|
||||
*value = val & 0x1f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check parameters */
|
||||
if (phy_addr > PHY_MASK) {
|
||||
printf("ARMD100 FEC: (%s) Invalid phy address: 0x%X\n",
|
||||
__func__, phy_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (phy_reg > PHY_MASK) {
|
||||
printf("ARMD100 FEC: (%s) Invalid register offset: 0x%X\n",
|
||||
__func__, phy_reg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* wait for the SMI register to become available */
|
||||
if (armdfec_phy_timeout(®s->smi, SMI_BUSY, false)) {
|
||||
printf("ARMD100 FEC: (%s) PHY busy timeout\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
writel((phy_addr << 16) | (phy_reg << 21) | SMI_OP_R, ®s->smi);
|
||||
|
||||
/* now wait for the data to be valid */
|
||||
if (armdfec_phy_timeout(®s->smi, SMI_R_VALID, true)) {
|
||||
val = readl(®s->smi);
|
||||
printf("ARMD100 FEC: (%s) PHY Read timeout, val=0x%x\n",
|
||||
__func__, val);
|
||||
return -1;
|
||||
}
|
||||
val = readl(®s->smi);
|
||||
*value = val & 0xffff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smi_reg_write(const char *devname,
|
||||
u8 phy_addr, u8 phy_reg, u16 value)
|
||||
{
|
||||
struct eth_device *dev = eth_get_dev_by_name(devname);
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
|
||||
if (phy_addr == PHY_ADR_REQ && phy_reg == PHY_ADR_REQ) {
|
||||
clrsetbits_le32(®s->phyadr, 0x1f, value & 0x1f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check parameters */
|
||||
if (phy_addr > PHY_MASK) {
|
||||
printf("ARMD100 FEC: (%s) Invalid phy address\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (phy_reg > PHY_MASK) {
|
||||
printf("ARMD100 FEC: (%s) Invalid register offset\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* wait for the SMI register to become available */
|
||||
if (armdfec_phy_timeout(®s->smi, SMI_BUSY, false)) {
|
||||
printf("ARMD100 FEC: (%s) PHY busy timeout\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
writel((phy_addr << 16) | (phy_reg << 21) | SMI_OP_W | (value & 0xffff),
|
||||
®s->smi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Abort any transmit and receive operations and put DMA
|
||||
* in idle state. AT and AR bits are cleared upon entering
|
||||
* in IDLE state. So poll those bits to verify operation.
|
||||
*/
|
||||
static void abortdma(struct eth_device *dev)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
int delay;
|
||||
int maxretries = 40;
|
||||
u32 tmp;
|
||||
|
||||
while (--maxretries) {
|
||||
writel(SDMA_CMD_AR | SDMA_CMD_AT, ®s->sdma_cmd);
|
||||
udelay(100);
|
||||
|
||||
delay = 10;
|
||||
while (--delay) {
|
||||
tmp = readl(®s->sdma_cmd);
|
||||
if (!(tmp & (SDMA_CMD_AR | SDMA_CMD_AT)))
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if (delay)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!maxretries)
|
||||
printf("ARMD100 FEC: (%s) DMA Stuck\n", __func__);
|
||||
}
|
||||
|
||||
static inline u32 nibble_swapping_32_bit(u32 x)
|
||||
{
|
||||
return ((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4);
|
||||
}
|
||||
|
||||
static inline u32 nibble_swapping_16_bit(u32 x)
|
||||
{
|
||||
return ((x & 0x0000f0f0) >> 4) | ((x & 0x00000f0f) << 4);
|
||||
}
|
||||
|
||||
static inline u32 flip_4_bits(u32 x)
|
||||
{
|
||||
return ((x & 0x01) << 3) | ((x & 0x002) << 1)
|
||||
| ((x & 0x04) >> 1) | ((x & 0x008) >> 3);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will calculate the hash function of the address.
|
||||
* depends on the hash mode and hash size.
|
||||
* Inputs
|
||||
* mach - the 2 most significant bytes of the MAC address.
|
||||
* macl - the 4 least significant bytes of the MAC address.
|
||||
* Outputs
|
||||
* return the calculated entry.
|
||||
*/
|
||||
static u32 hash_function(u32 mach, u32 macl)
|
||||
{
|
||||
u32 hashresult;
|
||||
u32 addrh;
|
||||
u32 addrl;
|
||||
u32 addr0;
|
||||
u32 addr1;
|
||||
u32 addr2;
|
||||
u32 addr3;
|
||||
u32 addrhswapped;
|
||||
u32 addrlswapped;
|
||||
|
||||
addrh = nibble_swapping_16_bit(mach);
|
||||
addrl = nibble_swapping_32_bit(macl);
|
||||
|
||||
addrhswapped = flip_4_bits(addrh & 0xf)
|
||||
+ ((flip_4_bits((addrh >> 4) & 0xf)) << 4)
|
||||
+ ((flip_4_bits((addrh >> 8) & 0xf)) << 8)
|
||||
+ ((flip_4_bits((addrh >> 12) & 0xf)) << 12);
|
||||
|
||||
addrlswapped = flip_4_bits(addrl & 0xf)
|
||||
+ ((flip_4_bits((addrl >> 4) & 0xf)) << 4)
|
||||
+ ((flip_4_bits((addrl >> 8) & 0xf)) << 8)
|
||||
+ ((flip_4_bits((addrl >> 12) & 0xf)) << 12)
|
||||
+ ((flip_4_bits((addrl >> 16) & 0xf)) << 16)
|
||||
+ ((flip_4_bits((addrl >> 20) & 0xf)) << 20)
|
||||
+ ((flip_4_bits((addrl >> 24) & 0xf)) << 24)
|
||||
+ ((flip_4_bits((addrl >> 28) & 0xf)) << 28);
|
||||
|
||||
addrh = addrhswapped;
|
||||
addrl = addrlswapped;
|
||||
|
||||
addr0 = (addrl >> 2) & 0x03f;
|
||||
addr1 = (addrl & 0x003) | (((addrl >> 8) & 0x7f) << 2);
|
||||
addr2 = (addrl >> 15) & 0x1ff;
|
||||
addr3 = ((addrl >> 24) & 0x0ff) | ((addrh & 1) << 8);
|
||||
|
||||
hashresult = (addr0 << 9) | (addr1 ^ addr2 ^ addr3);
|
||||
hashresult = hashresult & 0x07ff;
|
||||
return hashresult;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will add an entry to the address table.
|
||||
* depends on the hash mode and hash size that was initialized.
|
||||
* Inputs
|
||||
* mach - the 2 most significant bytes of the MAC address.
|
||||
* macl - the 4 least significant bytes of the MAC address.
|
||||
* skip - if 1, skip this address.
|
||||
* rd - the RD field in the address table.
|
||||
* Outputs
|
||||
* address table entry is added.
|
||||
* 0 if success.
|
||||
* -ENOSPC if table full
|
||||
*/
|
||||
static int add_del_hash_entry(struct armdfec_device *darmdfec, u32 mach,
|
||||
u32 macl, u32 rd, u32 skip, int del)
|
||||
{
|
||||
struct addr_table_entry_t *entry, *start;
|
||||
u32 newhi;
|
||||
u32 newlo;
|
||||
u32 i;
|
||||
|
||||
newlo = (((mach >> 4) & 0xf) << 15)
|
||||
| (((mach >> 0) & 0xf) << 11)
|
||||
| (((mach >> 12) & 0xf) << 7)
|
||||
| (((mach >> 8) & 0xf) << 3)
|
||||
| (((macl >> 20) & 0x1) << 31)
|
||||
| (((macl >> 16) & 0xf) << 27)
|
||||
| (((macl >> 28) & 0xf) << 23)
|
||||
| (((macl >> 24) & 0xf) << 19)
|
||||
| (skip << HTESKIP) | (rd << HTERDBIT)
|
||||
| HTEVALID;
|
||||
|
||||
newhi = (((macl >> 4) & 0xf) << 15)
|
||||
| (((macl >> 0) & 0xf) << 11)
|
||||
| (((macl >> 12) & 0xf) << 7)
|
||||
| (((macl >> 8) & 0xf) << 3)
|
||||
| (((macl >> 21) & 0x7) << 0);
|
||||
|
||||
/*
|
||||
* Pick the appropriate table, start scanning for free/reusable
|
||||
* entries at the index obtained by hashing the specified MAC address
|
||||
*/
|
||||
start = (struct addr_table_entry_t *)(darmdfec->htpr);
|
||||
entry = start + hash_function(mach, macl);
|
||||
for (i = 0; i < HOP_NUMBER; i++) {
|
||||
if (!(entry->lo & HTEVALID)) {
|
||||
break;
|
||||
} else {
|
||||
/* if same address put in same position */
|
||||
if (((entry->lo & 0xfffffff8) == (newlo & 0xfffffff8))
|
||||
&& (entry->hi == newhi))
|
||||
break;
|
||||
}
|
||||
if (entry == start + 0x7ff)
|
||||
entry = start;
|
||||
else
|
||||
entry++;
|
||||
}
|
||||
|
||||
if (((entry->lo & 0xfffffff8) != (newlo & 0xfffffff8)) &&
|
||||
(entry->hi != newhi) && del)
|
||||
return 0;
|
||||
|
||||
if (i == HOP_NUMBER) {
|
||||
if (!del) {
|
||||
printf("ARMD100 FEC: (%s) table section is full\n",
|
||||
__func__);
|
||||
return -ENOSPC;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the selected entry
|
||||
*/
|
||||
if (del) {
|
||||
entry->hi = 0;
|
||||
entry->lo = 0;
|
||||
} else {
|
||||
entry->hi = newhi;
|
||||
entry->lo = newlo;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an addressTable entry from MAC address info
|
||||
* found in the specifed net_device struct
|
||||
*
|
||||
* Input : pointer to ethernet interface network device structure
|
||||
* Output : N/A
|
||||
*/
|
||||
static void update_hash_table_mac_address(struct armdfec_device *darmdfec,
|
||||
u8 *oaddr, u8 *addr)
|
||||
{
|
||||
u32 mach;
|
||||
u32 macl;
|
||||
|
||||
/* Delete old entry */
|
||||
if (oaddr) {
|
||||
mach = (oaddr[0] << 8) | oaddr[1];
|
||||
macl = (oaddr[2] << 24) | (oaddr[3] << 16) |
|
||||
(oaddr[4] << 8) | oaddr[5];
|
||||
add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_DELETE);
|
||||
}
|
||||
|
||||
/* Add new entry */
|
||||
mach = (addr[0] << 8) | addr[1];
|
||||
macl = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
|
||||
add_del_hash_entry(darmdfec, mach, macl, 1, 0, HASH_ADD);
|
||||
}
|
||||
|
||||
/* Address Table Initialization */
|
||||
static void init_hashtable(struct eth_device *dev)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
memset(darmdfec->htpr, 0, HASH_ADDR_TABLE_SIZE);
|
||||
writel((u32)darmdfec->htpr, ®s->htpr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This detects PHY chip from address 0-31 by reading PHY status
|
||||
* registers. PHY chip can be connected at any of this address.
|
||||
*/
|
||||
static int ethernet_phy_detect(struct eth_device *dev)
|
||||
{
|
||||
u32 val;
|
||||
u16 tmp, mii_status;
|
||||
u8 addr;
|
||||
|
||||
for (addr = 0; addr < 32; addr++) {
|
||||
if (miiphy_read(dev->name, addr, MII_BMSR, &mii_status) != 0)
|
||||
/* try next phy */
|
||||
continue;
|
||||
|
||||
/* invalid MII status. More validation required here... */
|
||||
if (mii_status == 0 || mii_status == 0xffff)
|
||||
/* try next phy */
|
||||
continue;
|
||||
|
||||
if (miiphy_read(dev->name, addr, MII_PHYSID1, &tmp) != 0)
|
||||
/* try next phy */
|
||||
continue;
|
||||
|
||||
val = tmp << 16;
|
||||
if (miiphy_read(dev->name, addr, MII_PHYSID2, &tmp) != 0)
|
||||
/* try next phy */
|
||||
continue;
|
||||
|
||||
val |= tmp;
|
||||
|
||||
if ((val & 0xfffffff0) != 0)
|
||||
return addr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void armdfec_init_rx_desc_ring(struct armdfec_device *darmdfec)
|
||||
{
|
||||
struct rx_desc *p_rx_desc;
|
||||
int i;
|
||||
|
||||
/* initialize the Rx descriptors ring */
|
||||
p_rx_desc = darmdfec->p_rxdesc;
|
||||
for (i = 0; i < RINGSZ; i++) {
|
||||
p_rx_desc->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT;
|
||||
p_rx_desc->buf_size = PKTSIZE_ALIGN;
|
||||
p_rx_desc->byte_cnt = 0;
|
||||
p_rx_desc->buf_ptr = darmdfec->p_rxbuf + i * PKTSIZE_ALIGN;
|
||||
if (i == (RINGSZ - 1)) {
|
||||
p_rx_desc->nxtdesc_p = darmdfec->p_rxdesc;
|
||||
} else {
|
||||
p_rx_desc->nxtdesc_p = (struct rx_desc *)
|
||||
((u32)p_rx_desc + ARMDFEC_RXQ_DESC_ALIGNED_SIZE);
|
||||
p_rx_desc = p_rx_desc->nxtdesc_p;
|
||||
}
|
||||
}
|
||||
darmdfec->p_rxdesc_curr = darmdfec->p_rxdesc;
|
||||
}
|
||||
|
||||
static int armdfec_init(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
int phy_adr;
|
||||
u32 temp;
|
||||
|
||||
armdfec_init_rx_desc_ring(darmdfec);
|
||||
|
||||
/* Disable interrupts */
|
||||
writel(0, ®s->im);
|
||||
writel(0, ®s->ic);
|
||||
/* Write to ICR to clear interrupts. */
|
||||
writel(0, ®s->iwc);
|
||||
|
||||
/*
|
||||
* Abort any transmit and receive operations and put DMA
|
||||
* in idle state.
|
||||
*/
|
||||
abortdma(dev);
|
||||
|
||||
/* Initialize address hash table */
|
||||
init_hashtable(dev);
|
||||
|
||||
/* SDMA configuration */
|
||||
writel(SDCR_BSZ8 | /* Burst size = 32 bytes */
|
||||
SDCR_RIFB | /* Rx interrupt on frame */
|
||||
SDCR_BLMT | /* Little endian transmit */
|
||||
SDCR_BLMR | /* Little endian receive */
|
||||
SDCR_RC_MAX_RETRANS, /* Max retransmit count */
|
||||
®s->sdma_conf);
|
||||
/* Port Configuration */
|
||||
writel(PCR_HS, ®s->pconf); /* Hash size is 1/2kb */
|
||||
|
||||
/* Set extended port configuration */
|
||||
writel(PCXR_2BSM | /* Two byte suffix aligns IP hdr */
|
||||
PCXR_DSCP_EN | /* Enable DSCP in IP */
|
||||
PCXR_MFL_1536 | /* Set MTU = 1536 */
|
||||
PCXR_FLP | /* do not force link pass */
|
||||
PCXR_TX_HIGH_PRI, /* Transmit - high priority queue */
|
||||
®s->pconf_ext);
|
||||
|
||||
update_hash_table_mac_address(darmdfec, NULL, dev->enetaddr);
|
||||
|
||||
/* Update TX and RX queue descriptor register */
|
||||
temp = (u32)®s->txcdp[TXQ];
|
||||
writel((u32)darmdfec->p_txdesc, temp);
|
||||
temp = (u32)®s->rxfdp[RXQ];
|
||||
writel((u32)darmdfec->p_rxdesc, temp);
|
||||
temp = (u32)®s->rxcdp[RXQ];
|
||||
writel((u32)darmdfec->p_rxdesc_curr, temp);
|
||||
|
||||
/* Enable Interrupts */
|
||||
writel(ALL_INTS, ®s->im);
|
||||
|
||||
/* Enable Ethernet Port */
|
||||
setbits_le32(®s->pconf, PCR_EN);
|
||||
|
||||
/* Enable RX DMA engine */
|
||||
setbits_le32(®s->sdma_cmd, SDMA_CMD_ERD);
|
||||
|
||||
#ifdef DEBUG
|
||||
eth_dump_regs(dev);
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
|
||||
|
||||
#if defined(CONFIG_PHY_BASE_ADR)
|
||||
miiphy_write(dev->name, PHY_ADR_REQ, PHY_ADR_REQ, CONFIG_PHY_BASE_ADR);
|
||||
#else
|
||||
/* Search phy address from range 0-31 */
|
||||
phy_adr = ethernet_phy_detect(dev);
|
||||
if (phy_adr < 0) {
|
||||
printf("ARMD100 FEC: PHY not detected at address range 0-31\n");
|
||||
return -1;
|
||||
} else {
|
||||
debug("ARMD100 FEC: PHY detected at addr %d\n", phy_adr);
|
||||
miiphy_write(dev->name, PHY_ADR_REQ, PHY_ADR_REQ, phy_adr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
|
||||
/* Wait up to 5s for the link status */
|
||||
for (i = 0; i < 5; i++) {
|
||||
u16 phy_adr;
|
||||
|
||||
miiphy_read(dev->name, 0xFF, 0xFF, &phy_adr);
|
||||
/* Return if we get link up */
|
||||
if (miiphy_link(dev->name, phy_adr))
|
||||
return 0;
|
||||
udelay(1000000);
|
||||
}
|
||||
|
||||
printf("ARMD100 FEC: No link on %s\n", dev->name);
|
||||
return -1;
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void armdfec_halt(struct eth_device *dev)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
|
||||
/* Stop RX DMA */
|
||||
clrbits_le32(®s->sdma_cmd, SDMA_CMD_ERD);
|
||||
|
||||
/*
|
||||
* Abort any transmit and receive operations and put DMA
|
||||
* in idle state.
|
||||
*/
|
||||
abortdma(dev);
|
||||
|
||||
/* Disable interrupts */
|
||||
writel(0, ®s->im);
|
||||
writel(0, ®s->ic);
|
||||
writel(0, ®s->iwc);
|
||||
|
||||
/* Disable Port */
|
||||
clrbits_le32(®s->pconf, PCR_EN);
|
||||
}
|
||||
|
||||
static int armdfec_send(struct eth_device *dev, void *dataptr, int datasize)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct armdfec_reg *regs = darmdfec->regs;
|
||||
struct tx_desc *p_txdesc = darmdfec->p_txdesc;
|
||||
void *p = (void *)dataptr;
|
||||
int retry = PHY_WAIT_ITERATIONS * PHY_WAIT_MICRO_SECONDS;
|
||||
u32 cmd_sts, temp;
|
||||
|
||||
/* Copy buffer if it's misaligned */
|
||||
if ((u32)dataptr & 0x07) {
|
||||
if (datasize > PKTSIZE_ALIGN) {
|
||||
printf("ARMD100 FEC: Non-aligned data too large (%d)\n",
|
||||
datasize);
|
||||
return -1;
|
||||
}
|
||||
memcpy(darmdfec->p_aligned_txbuf, p, datasize);
|
||||
p = darmdfec->p_aligned_txbuf;
|
||||
}
|
||||
|
||||
p_txdesc->cmd_sts = TX_ZERO_PADDING | TX_GEN_CRC;
|
||||
p_txdesc->cmd_sts |= TX_FIRST_DESC | TX_LAST_DESC;
|
||||
p_txdesc->cmd_sts |= BUF_OWNED_BY_DMA;
|
||||
p_txdesc->cmd_sts |= TX_EN_INT;
|
||||
p_txdesc->buf_ptr = p;
|
||||
p_txdesc->byte_cnt = datasize;
|
||||
|
||||
/* Apply send command using high priority TX queue */
|
||||
temp = (u32)®s->txcdp[TXQ];
|
||||
writel((u32)p_txdesc, temp);
|
||||
writel(SDMA_CMD_TXDL | SDMA_CMD_TXDH | SDMA_CMD_ERD, ®s->sdma_cmd);
|
||||
|
||||
/*
|
||||
* wait for packet xmit completion
|
||||
*/
|
||||
cmd_sts = readl(&p_txdesc->cmd_sts);
|
||||
while (cmd_sts & BUF_OWNED_BY_DMA) {
|
||||
/* return fail if error is detected */
|
||||
if ((cmd_sts & (TX_ERROR | TX_LAST_DESC)) ==
|
||||
(TX_ERROR | TX_LAST_DESC)) {
|
||||
printf("ARMD100 FEC: (%s) in xmit packet\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
cmd_sts = readl(&p_txdesc->cmd_sts);
|
||||
if (!(retry--)) {
|
||||
printf("ARMD100 FEC: (%s) xmit packet timeout!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armdfec_recv(struct eth_device *dev)
|
||||
{
|
||||
struct armdfec_device *darmdfec = to_darmdfec(dev);
|
||||
struct rx_desc *p_rxdesc_curr = darmdfec->p_rxdesc_curr;
|
||||
u32 cmd_sts;
|
||||
u32 timeout = 0;
|
||||
u32 temp;
|
||||
|
||||
/* wait untill rx packet available or timeout */
|
||||
do {
|
||||
if (timeout < PHY_WAIT_ITERATIONS * PHY_WAIT_MICRO_SECONDS) {
|
||||
timeout++;
|
||||
} else {
|
||||
debug("ARMD100 FEC: %s time out...\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
} while (readl(&p_rxdesc_curr->cmd_sts) & BUF_OWNED_BY_DMA);
|
||||
|
||||
if (p_rxdesc_curr->byte_cnt != 0) {
|
||||
debug("ARMD100 FEC: %s: Received %d byte Packet @ 0x%x"
|
||||
"(cmd_sts= %08x)\n", __func__,
|
||||
(u32)p_rxdesc_curr->byte_cnt,
|
||||
(u32)p_rxdesc_curr->buf_ptr,
|
||||
(u32)p_rxdesc_curr->cmd_sts);
|
||||
}
|
||||
|
||||
/*
|
||||
* In case received a packet without first/last bits on
|
||||
* OR the error summary bit is on,
|
||||
* the packets needs to be dropeed.
|
||||
*/
|
||||
cmd_sts = readl(&p_rxdesc_curr->cmd_sts);
|
||||
|
||||
if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
|
||||
(RX_FIRST_DESC | RX_LAST_DESC)) {
|
||||
printf("ARMD100 FEC: (%s) Dropping packet spread on"
|
||||
" multiple descriptors\n", __func__);
|
||||
} else if (cmd_sts & RX_ERROR) {
|
||||
printf("ARMD100 FEC: (%s) Dropping packet with errors\n",
|
||||
__func__);
|
||||
} else {
|
||||
/* !!! call higher layer processing */
|
||||
debug("ARMD100 FEC: (%s) Sending Received packet to"
|
||||
" upper layer (net_process_received_packet)\n", __func__);
|
||||
|
||||
/*
|
||||
* let the upper layer handle the packet, subtract offset
|
||||
* as two dummy bytes are added in received buffer see
|
||||
* PORT_CONFIG_EXT register bit TWO_Byte_Stuff_Mode bit.
|
||||
*/
|
||||
net_process_received_packet(
|
||||
p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET,
|
||||
(int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
|
||||
}
|
||||
/*
|
||||
* free these descriptors and point next in the ring
|
||||
*/
|
||||
p_rxdesc_curr->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT;
|
||||
p_rxdesc_curr->buf_size = PKTSIZE_ALIGN;
|
||||
p_rxdesc_curr->byte_cnt = 0;
|
||||
|
||||
temp = (u32)&darmdfec->p_rxdesc_curr;
|
||||
writel((u32)p_rxdesc_curr->nxtdesc_p, temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int armada100_fec_register(unsigned long base_addr)
|
||||
{
|
||||
struct armdfec_device *darmdfec;
|
||||
struct eth_device *dev;
|
||||
|
||||
darmdfec = malloc(sizeof(struct armdfec_device));
|
||||
if (!darmdfec)
|
||||
goto error;
|
||||
|
||||
memset(darmdfec, 0, sizeof(struct armdfec_device));
|
||||
|
||||
darmdfec->htpr = memalign(8, HASH_ADDR_TABLE_SIZE);
|
||||
if (!darmdfec->htpr)
|
||||
goto error1;
|
||||
|
||||
darmdfec->p_rxdesc = memalign(PKTALIGN,
|
||||
ARMDFEC_RXQ_DESC_ALIGNED_SIZE * RINGSZ + 1);
|
||||
|
||||
if (!darmdfec->p_rxdesc)
|
||||
goto error1;
|
||||
|
||||
darmdfec->p_rxbuf = memalign(PKTALIGN, RINGSZ * PKTSIZE_ALIGN + 1);
|
||||
if (!darmdfec->p_rxbuf)
|
||||
goto error1;
|
||||
|
||||
darmdfec->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN);
|
||||
if (!darmdfec->p_aligned_txbuf)
|
||||
goto error1;
|
||||
|
||||
darmdfec->p_txdesc = memalign(PKTALIGN, sizeof(struct tx_desc) + 1);
|
||||
if (!darmdfec->p_txdesc)
|
||||
goto error1;
|
||||
|
||||
dev = &darmdfec->dev;
|
||||
/* Assign ARMADA100 Fast Ethernet Controller Base Address */
|
||||
darmdfec->regs = (void *)base_addr;
|
||||
|
||||
/* must be less than sizeof(dev->name) */
|
||||
strcpy(dev->name, "armd-fec0");
|
||||
|
||||
dev->init = armdfec_init;
|
||||
dev->halt = armdfec_halt;
|
||||
dev->send = armdfec_send;
|
||||
dev->recv = armdfec_recv;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
miiphy_register(dev->name, smi_reg_read, smi_reg_write);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
error1:
|
||||
free(darmdfec->p_aligned_txbuf);
|
||||
free(darmdfec->p_rxbuf);
|
||||
free(darmdfec->p_rxdesc);
|
||||
free(darmdfec->htpr);
|
||||
error:
|
||||
free(darmdfec);
|
||||
printf("AMD100 FEC: (%s) Failed to allocate memory\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
209
sources/uboot-be550/drivers/net/armada100_fec.h
Normal file
209
sources/uboot-be550/drivers/net/armada100_fec.h
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* (C) Copyright 2011
|
||||
* eInfochips Ltd. <www.einfochips.com>
|
||||
* Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Marvell Semiconductor <www.marvell.com>
|
||||
* Contributor: Mahavir Jain <mjain@marvell.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __ARMADA100_FEC_H__
|
||||
#define __ARMADA100_FEC_H__
|
||||
|
||||
#define PORT_NUM 0x0
|
||||
|
||||
/* RX & TX descriptor command */
|
||||
#define BUF_OWNED_BY_DMA (1<<31)
|
||||
|
||||
/* RX descriptor status */
|
||||
#define RX_EN_INT (1<<23)
|
||||
#define RX_FIRST_DESC (1<<17)
|
||||
#define RX_LAST_DESC (1<<16)
|
||||
#define RX_ERROR (1<<15)
|
||||
|
||||
/* TX descriptor command */
|
||||
#define TX_EN_INT (1<<23)
|
||||
#define TX_GEN_CRC (1<<22)
|
||||
#define TX_ZERO_PADDING (1<<18)
|
||||
#define TX_FIRST_DESC (1<<17)
|
||||
#define TX_LAST_DESC (1<<16)
|
||||
#define TX_ERROR (1<<15)
|
||||
|
||||
/* smi register */
|
||||
#define SMI_BUSY (1<<28) /* 0 - Write, 1 - Read */
|
||||
#define SMI_R_VALID (1<<27) /* 0 - Write, 1 - Read */
|
||||
#define SMI_OP_W (0<<26) /* Write operation */
|
||||
#define SMI_OP_R (1<<26) /* Read operation */
|
||||
|
||||
#define HASH_ADD 0
|
||||
#define HASH_DELETE 1
|
||||
#define HASH_ADDR_TABLE_SIZE 0x4000 /* 16K (1/2K address - PCR_HS == 1) */
|
||||
#define HOP_NUMBER 12
|
||||
|
||||
#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */
|
||||
#define PHY_WAIT_MICRO_SECONDS 10
|
||||
|
||||
#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */
|
||||
#define ETH_EXTRA_HEADER (6+6+2+4)
|
||||
/* dest+src addr+protocol id+crc */
|
||||
#define MAX_PKT_SIZE 1536
|
||||
|
||||
|
||||
/* Bit definitions of the SDMA Config Reg */
|
||||
#define SDCR_BSZ_OFF 12
|
||||
#define SDCR_BSZ8 (3<<SDCR_BSZ_OFF)
|
||||
#define SDCR_BSZ4 (2<<SDCR_BSZ_OFF)
|
||||
#define SDCR_BSZ2 (1<<SDCR_BSZ_OFF)
|
||||
#define SDCR_BSZ1 (0<<SDCR_BSZ_OFF)
|
||||
#define SDCR_BLMR (1<<6)
|
||||
#define SDCR_BLMT (1<<7)
|
||||
#define SDCR_RIFB (1<<9)
|
||||
#define SDCR_RC_OFF 2
|
||||
#define SDCR_RC_MAX_RETRANS (0xf << SDCR_RC_OFF)
|
||||
|
||||
/* SDMA_CMD */
|
||||
#define SDMA_CMD_AT (1<<31)
|
||||
#define SDMA_CMD_TXDL (1<<24)
|
||||
#define SDMA_CMD_TXDH (1<<23)
|
||||
#define SDMA_CMD_AR (1<<15)
|
||||
#define SDMA_CMD_ERD (1<<7)
|
||||
|
||||
|
||||
/* Bit definitions of the Port Config Reg */
|
||||
#define PCR_HS (1<<12)
|
||||
#define PCR_EN (1<<7)
|
||||
#define PCR_PM (1<<0)
|
||||
|
||||
/* Bit definitions of the Port Config Extend Reg */
|
||||
#define PCXR_2BSM (1<<28)
|
||||
#define PCXR_DSCP_EN (1<<21)
|
||||
#define PCXR_MFL_1518 (0<<14)
|
||||
#define PCXR_MFL_1536 (1<<14)
|
||||
#define PCXR_MFL_2048 (2<<14)
|
||||
#define PCXR_MFL_64K (3<<14)
|
||||
#define PCXR_FLP (1<<11)
|
||||
#define PCXR_PRIO_TX_OFF 3
|
||||
#define PCXR_TX_HIGH_PRI (7<<PCXR_PRIO_TX_OFF)
|
||||
|
||||
/*
|
||||
* * Bit definitions of the Interrupt Cause Reg
|
||||
* * and Interrupt MASK Reg is the same
|
||||
* */
|
||||
#define ICR_RXBUF (1<<0)
|
||||
#define ICR_TXBUF_H (1<<2)
|
||||
#define ICR_TXBUF_L (1<<3)
|
||||
#define ICR_TXEND_H (1<<6)
|
||||
#define ICR_TXEND_L (1<<7)
|
||||
#define ICR_RXERR (1<<8)
|
||||
#define ICR_TXERR_H (1<<10)
|
||||
#define ICR_TXERR_L (1<<11)
|
||||
#define ICR_TX_UDR (1<<13)
|
||||
#define ICR_MII_CH (1<<28)
|
||||
|
||||
#define ALL_INTS (ICR_TXBUF_H | ICR_TXBUF_L | ICR_TX_UDR |\
|
||||
ICR_TXERR_H | ICR_TXERR_L |\
|
||||
ICR_TXEND_H | ICR_TXEND_L |\
|
||||
ICR_RXBUF | ICR_RXERR | ICR_MII_CH)
|
||||
|
||||
#define PHY_MASK 0x0000001f
|
||||
|
||||
#define to_darmdfec(_kd) container_of(_kd, struct armdfec_device, dev)
|
||||
/* Size of a Tx/Rx descriptor used in chain list data structure */
|
||||
#define ARMDFEC_RXQ_DESC_ALIGNED_SIZE \
|
||||
(((sizeof(struct rx_desc) / PKTALIGN) + 1) * PKTALIGN)
|
||||
|
||||
#define RX_BUF_OFFSET 0x2
|
||||
#define RXQ 0x0 /* RX Queue 0 */
|
||||
#define TXQ 0x1 /* TX Queue 1 */
|
||||
|
||||
struct addr_table_entry_t {
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
};
|
||||
|
||||
/* Bit fields of a Hash Table Entry */
|
||||
enum hash_table_entry {
|
||||
HTEVALID = 1,
|
||||
HTESKIP = 2,
|
||||
HTERD = 4,
|
||||
HTERDBIT = 2
|
||||
};
|
||||
|
||||
struct tx_desc {
|
||||
u32 cmd_sts; /* Command/status field */
|
||||
u16 reserved;
|
||||
u16 byte_cnt; /* buffer byte count */
|
||||
u8 *buf_ptr; /* pointer to buffer for this descriptor */
|
||||
struct tx_desc *nextdesc_p; /* Pointer to next descriptor */
|
||||
};
|
||||
|
||||
struct rx_desc {
|
||||
u32 cmd_sts; /* Descriptor command status */
|
||||
u16 byte_cnt; /* Descriptor buffer byte count */
|
||||
u16 buf_size; /* Buffer size */
|
||||
u8 *buf_ptr; /* Descriptor buffer pointer */
|
||||
struct rx_desc *nxtdesc_p; /* Next descriptor pointer */
|
||||
};
|
||||
|
||||
/*
|
||||
* Armada100 Fast Ethernet controller Registers
|
||||
* Refer Datasheet Appendix A.22
|
||||
*/
|
||||
struct armdfec_reg {
|
||||
u32 phyadr; /* PHY Address */
|
||||
u32 pad1[3];
|
||||
u32 smi; /* SMI */
|
||||
u32 pad2[0xFB];
|
||||
u32 pconf; /* Port configuration */
|
||||
u32 pad3;
|
||||
u32 pconf_ext; /* Port configuration extend */
|
||||
u32 pad4;
|
||||
u32 pcmd; /* Port Command */
|
||||
u32 pad5;
|
||||
u32 pstatus; /* Port Status */
|
||||
u32 pad6;
|
||||
u32 spar; /* Serial Parameters */
|
||||
u32 pad7;
|
||||
u32 htpr; /* Hash table pointer */
|
||||
u32 pad8;
|
||||
u32 fcsal; /* Flow control source address low */
|
||||
u32 pad9;
|
||||
u32 fcsah; /* Flow control source address high */
|
||||
u32 pad10;
|
||||
u32 sdma_conf; /* SDMA configuration */
|
||||
u32 pad11;
|
||||
u32 sdma_cmd; /* SDMA command */
|
||||
u32 pad12;
|
||||
u32 ic; /* Interrupt cause */
|
||||
u32 iwc; /* Interrupt write to clear */
|
||||
u32 im; /* Interrupt mask */
|
||||
u32 pad13;
|
||||
u32 *eth_idscpp[4]; /* Eth0 IP Differentiated Services Code
|
||||
Point to Priority 0 Low */
|
||||
u32 eth_vlan_p; /* Eth0 VLAN Priority Tag to Priority */
|
||||
u32 pad14[3];
|
||||
struct rx_desc *rxfdp[4]; /* Ethernet First Rx Descriptor
|
||||
Pointer */
|
||||
u32 pad15[4];
|
||||
struct rx_desc *rxcdp[4]; /* Ethernet Current Rx Descriptor
|
||||
Pointer */
|
||||
u32 pad16[0x0C];
|
||||
struct tx_desc *txcdp[2]; /* Ethernet Current Tx Descriptor
|
||||
Pointer */
|
||||
};
|
||||
|
||||
struct armdfec_device {
|
||||
struct eth_device dev;
|
||||
struct armdfec_reg *regs;
|
||||
struct tx_desc *p_txdesc;
|
||||
struct rx_desc *p_rxdesc;
|
||||
struct rx_desc *p_rxdesc_curr;
|
||||
u8 *p_rxbuf;
|
||||
u8 *p_aligned_txbuf;
|
||||
u8 *htpr; /* hash pointer */
|
||||
};
|
||||
|
||||
#endif /* __ARMADA100_FEC_H__ */
|
||||
508
sources/uboot-be550/drivers/net/at91_emac.c
Normal file
508
sources/uboot-be550/drivers/net/at91_emac.c
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* Copyright (C) 2009 BuS Elektronik GmbH & Co. KG
|
||||
* Jens Scharsig (esw@bus-elektronik.de)
|
||||
*
|
||||
* (C) Copyright 2003
|
||||
* Author : Hamid Ikdoumi (Atmel)
|
||||
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/at91_emac.h>
|
||||
#include <asm/arch/at91_pmc.h>
|
||||
#include <asm/arch/at91_pio.h>
|
||||
#include <net.h>
|
||||
#include <netdev.h>
|
||||
#include <malloc.h>
|
||||
#include <miiphy.h>
|
||||
#include <linux/mii.h>
|
||||
|
||||
#undef MII_DEBUG
|
||||
#undef ET_DEBUG
|
||||
|
||||
#if (CONFIG_SYS_RX_ETH_BUFFER > 1024)
|
||||
#error AT91 EMAC supports max 1024 RX buffers. \
|
||||
Please decrease the CONFIG_SYS_RX_ETH_BUFFER value
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_DRIVER_AT91EMAC_PHYADDR
|
||||
#define CONFIG_DRIVER_AT91EMAC_PHYADDR 0
|
||||
#endif
|
||||
|
||||
/* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */
|
||||
#if (AT91C_MASTER_CLOCK > 80000000)
|
||||
#define HCLK_DIV AT91_EMAC_CFG_MCLK_64
|
||||
#elif (AT91C_MASTER_CLOCK > 40000000)
|
||||
#define HCLK_DIV AT91_EMAC_CFG_MCLK_32
|
||||
#elif (AT91C_MASTER_CLOCK > 20000000)
|
||||
#define HCLK_DIV AT91_EMAC_CFG_MCLK_16
|
||||
#else
|
||||
#define HCLK_DIV AT91_EMAC_CFG_MCLK_8
|
||||
#endif
|
||||
|
||||
#ifdef ET_DEBUG
|
||||
#define DEBUG_AT91EMAC 1
|
||||
#else
|
||||
#define DEBUG_AT91EMAC 0
|
||||
#endif
|
||||
|
||||
#ifdef MII_DEBUG
|
||||
#define DEBUG_AT91PHY 1
|
||||
#else
|
||||
#define DEBUG_AT91PHY 0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_DRIVER_AT91EMAC_QUIET
|
||||
#define VERBOSEP 1
|
||||
#else
|
||||
#define VERBOSEP 0
|
||||
#endif
|
||||
|
||||
#define RBF_ADDR 0xfffffffc
|
||||
#define RBF_OWNER (1<<0)
|
||||
#define RBF_WRAP (1<<1)
|
||||
#define RBF_BROADCAST (1<<31)
|
||||
#define RBF_MULTICAST (1<<30)
|
||||
#define RBF_UNICAST (1<<29)
|
||||
#define RBF_EXTERNAL (1<<28)
|
||||
#define RBF_UNKNOWN (1<<27)
|
||||
#define RBF_SIZE 0x07ff
|
||||
#define RBF_LOCAL4 (1<<26)
|
||||
#define RBF_LOCAL3 (1<<25)
|
||||
#define RBF_LOCAL2 (1<<24)
|
||||
#define RBF_LOCAL1 (1<<23)
|
||||
|
||||
#define RBF_FRAMEMAX CONFIG_SYS_RX_ETH_BUFFER
|
||||
#define RBF_FRAMELEN 0x600
|
||||
|
||||
typedef struct {
|
||||
unsigned long addr, size;
|
||||
} rbf_t;
|
||||
|
||||
typedef struct {
|
||||
rbf_t rbfdt[RBF_FRAMEMAX];
|
||||
unsigned long rbindex;
|
||||
} emac_device;
|
||||
|
||||
void at91emac_EnableMDIO(at91_emac_t *at91mac)
|
||||
{
|
||||
/* Mac CTRL reg set for MDIO enable */
|
||||
writel(readl(&at91mac->ctl) | AT91_EMAC_CTL_MPE, &at91mac->ctl);
|
||||
}
|
||||
|
||||
void at91emac_DisableMDIO(at91_emac_t *at91mac)
|
||||
{
|
||||
/* Mac CTRL reg set for MDIO disable */
|
||||
writel(readl(&at91mac->ctl) & ~AT91_EMAC_CTL_MPE, &at91mac->ctl);
|
||||
}
|
||||
|
||||
int at91emac_read(at91_emac_t *at91mac, unsigned char addr,
|
||||
unsigned char reg, unsigned short *value)
|
||||
{
|
||||
unsigned long netstat;
|
||||
at91emac_EnableMDIO(at91mac);
|
||||
|
||||
writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_R |
|
||||
AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 |
|
||||
AT91_EMAC_MAN_PHYA(addr),
|
||||
&at91mac->man);
|
||||
|
||||
do {
|
||||
netstat = readl(&at91mac->sr);
|
||||
debug_cond(DEBUG_AT91PHY, "poll SR %08lx\n", netstat);
|
||||
} while (!(netstat & AT91_EMAC_SR_IDLE));
|
||||
|
||||
*value = readl(&at91mac->man) & AT91_EMAC_MAN_DATA_MASK;
|
||||
|
||||
at91emac_DisableMDIO(at91mac);
|
||||
|
||||
debug_cond(DEBUG_AT91PHY,
|
||||
"AT91PHY read %p REG(%d)=%x\n", at91mac, reg, *value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at91emac_write(at91_emac_t *at91mac, unsigned char addr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
unsigned long netstat;
|
||||
debug_cond(DEBUG_AT91PHY,
|
||||
"AT91PHY write %p REG(%d)=%p\n", at91mac, reg, &value);
|
||||
|
||||
at91emac_EnableMDIO(at91mac);
|
||||
|
||||
writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_W |
|
||||
AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 |
|
||||
AT91_EMAC_MAN_PHYA(addr) | (value & AT91_EMAC_MAN_DATA_MASK),
|
||||
&at91mac->man);
|
||||
|
||||
do {
|
||||
netstat = readl(&at91mac->sr);
|
||||
debug_cond(DEBUG_AT91PHY, "poll SR %08lx\n", netstat);
|
||||
} while (!(netstat & AT91_EMAC_SR_IDLE));
|
||||
|
||||
at91emac_DisableMDIO(at91mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
|
||||
at91_emac_t *get_emacbase_by_name(const char *devname)
|
||||
{
|
||||
struct eth_device *netdev;
|
||||
|
||||
netdev = eth_get_dev_by_name(devname);
|
||||
return (at91_emac_t *) netdev->iobase;
|
||||
}
|
||||
|
||||
int at91emac_mii_read(const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short *value)
|
||||
{
|
||||
at91_emac_t *emac;
|
||||
|
||||
emac = get_emacbase_by_name(devname);
|
||||
at91emac_read(emac , addr, reg, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int at91emac_mii_write(const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
at91_emac_t *emac;
|
||||
|
||||
emac = get_emacbase_by_name(devname);
|
||||
at91emac_write(emac, addr, reg, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int at91emac_phy_reset(struct eth_device *netdev)
|
||||
{
|
||||
int i;
|
||||
u16 status, adv;
|
||||
at91_emac_t *emac;
|
||||
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
|
||||
adv = ADVERTISE_CSMA | ADVERTISE_ALL;
|
||||
at91emac_write(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_ADVERTISE, adv);
|
||||
debug_cond(VERBOSEP, "%s: Starting autonegotiation...\n", netdev->name);
|
||||
at91emac_write(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMCR,
|
||||
(BMCR_ANENABLE | BMCR_ANRESTART));
|
||||
|
||||
for (i = 0; i < 30000; i++) {
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_BMSR, &status);
|
||||
if (status & BMSR_ANEGCOMPLETE)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (status & BMSR_ANEGCOMPLETE) {
|
||||
debug_cond(VERBOSEP,
|
||||
"%s: Autonegotiation complete\n", netdev->name);
|
||||
} else {
|
||||
printf("%s: Autonegotiation timed out (status=0x%04x)\n",
|
||||
netdev->name, status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91emac_phy_init(struct eth_device *netdev)
|
||||
{
|
||||
u16 phy_id, status, adv, lpa;
|
||||
int media, speed, duplex;
|
||||
int i;
|
||||
at91_emac_t *emac;
|
||||
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
|
||||
/* Check if the PHY is up to snuff... */
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_PHYSID1, &phy_id);
|
||||
if (phy_id == 0xffff) {
|
||||
printf("%s: No PHY present\n", netdev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_BMSR, &status);
|
||||
|
||||
if (!(status & BMSR_LSTATUS)) {
|
||||
/* Try to re-negotiate if we don't have link already. */
|
||||
if (at91emac_phy_reset(netdev))
|
||||
return -2;
|
||||
|
||||
for (i = 0; i < 100000 / 100; i++) {
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_BMSR, &status);
|
||||
if (status & BMSR_LSTATUS)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
if (!(status & BMSR_LSTATUS)) {
|
||||
debug_cond(VERBOSEP, "%s: link down\n", netdev->name);
|
||||
return -3;
|
||||
} else {
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_ADVERTISE, &adv);
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR,
|
||||
MII_LPA, &lpa);
|
||||
media = mii_nway_result(lpa & adv);
|
||||
speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
|
||||
? 1 : 0);
|
||||
duplex = (media & ADVERTISE_FULL) ? 1 : 0;
|
||||
debug_cond(VERBOSEP, "%s: link up, %sMbps %s-duplex\n",
|
||||
netdev->name,
|
||||
speed ? "100" : "10",
|
||||
duplex ? "full" : "half");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at91emac_UpdateLinkSpeed(at91_emac_t *emac)
|
||||
{
|
||||
unsigned short stat1;
|
||||
|
||||
at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMSR, &stat1);
|
||||
|
||||
if (!(stat1 & BMSR_LSTATUS)) /* link status up? */
|
||||
return -1;
|
||||
|
||||
if (stat1 & BMSR_100FULL) {
|
||||
/*set Emac for 100BaseTX and Full Duplex */
|
||||
writel(readl(&emac->cfg) |
|
||||
AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD,
|
||||
&emac->cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat1 & BMSR_10FULL) {
|
||||
/*set MII for 10BaseT and Full Duplex */
|
||||
writel((readl(&emac->cfg) &
|
||||
~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)
|
||||
) | AT91_EMAC_CFG_FD,
|
||||
&emac->cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat1 & BMSR_100HALF) {
|
||||
/*set MII for 100BaseTX and Half Duplex */
|
||||
writel((readl(&emac->cfg) &
|
||||
~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)
|
||||
) | AT91_EMAC_CFG_SPD,
|
||||
&emac->cfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat1 & BMSR_10HALF) {
|
||||
/*set MII for 10BaseT and Half Duplex */
|
||||
writel((readl(&emac->cfg) &
|
||||
~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)),
|
||||
&emac->cfg);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91emac_init(struct eth_device *netdev, bd_t *bd)
|
||||
{
|
||||
int i;
|
||||
u32 value;
|
||||
emac_device *dev;
|
||||
at91_emac_t *emac;
|
||||
at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIO;
|
||||
at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
|
||||
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
dev = (emac_device *) netdev->priv;
|
||||
|
||||
/* PIO Disable Register */
|
||||
value = ATMEL_PMX_AA_EMDIO | ATMEL_PMX_AA_EMDC |
|
||||
ATMEL_PMX_AA_ERXER | ATMEL_PMX_AA_ERX1 |
|
||||
ATMEL_PMX_AA_ERX0 | ATMEL_PMX_AA_ECRS |
|
||||
ATMEL_PMX_AA_ETX1 | ATMEL_PMX_AA_ETX0 |
|
||||
ATMEL_PMX_AA_ETXEN | ATMEL_PMX_AA_EREFCK;
|
||||
|
||||
writel(value, &pio->pioa.pdr);
|
||||
writel(value, &pio->pioa.asr);
|
||||
|
||||
#ifdef CONFIG_RMII
|
||||
value = ATMEL_PMX_BA_ERXCK;
|
||||
#else
|
||||
value = ATMEL_PMX_BA_ERXCK | ATMEL_PMX_BA_ECOL |
|
||||
ATMEL_PMX_BA_ERXDV | ATMEL_PMX_BA_ERX3 |
|
||||
ATMEL_PMX_BA_ERX2 | ATMEL_PMX_BA_ETXER |
|
||||
ATMEL_PMX_BA_ETX3 | ATMEL_PMX_BA_ETX2;
|
||||
#endif
|
||||
writel(value, &pio->piob.pdr);
|
||||
writel(value, &pio->piob.bsr);
|
||||
|
||||
writel(1 << ATMEL_ID_EMAC, &pmc->pcer);
|
||||
writel(readl(&emac->ctl) | AT91_EMAC_CTL_CSR, &emac->ctl);
|
||||
|
||||
/* Init Ethernet buffers */
|
||||
for (i = 0; i < RBF_FRAMEMAX; i++) {
|
||||
dev->rbfdt[i].addr = (unsigned long) net_rx_packets[i];
|
||||
dev->rbfdt[i].size = 0;
|
||||
}
|
||||
dev->rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP;
|
||||
dev->rbindex = 0;
|
||||
writel((u32) &(dev->rbfdt[0]), &emac->rbqp);
|
||||
|
||||
writel(readl(&emac->rsr) &
|
||||
~(AT91_EMAC_RSR_OVR | AT91_EMAC_RSR_REC | AT91_EMAC_RSR_BNA),
|
||||
&emac->rsr);
|
||||
|
||||
value = AT91_EMAC_CFG_CAF | AT91_EMAC_CFG_NBC |
|
||||
HCLK_DIV;
|
||||
#ifdef CONFIG_RMII
|
||||
value |= AT91_EMAC_CFG_RMII;
|
||||
#endif
|
||||
writel(value, &emac->cfg);
|
||||
|
||||
writel(readl(&emac->ctl) | AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE,
|
||||
&emac->ctl);
|
||||
|
||||
if (!at91emac_phy_init(netdev)) {
|
||||
at91emac_UpdateLinkSpeed(emac);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void at91emac_halt(struct eth_device *netdev)
|
||||
{
|
||||
at91_emac_t *emac;
|
||||
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
writel(readl(&emac->ctl) & ~(AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE),
|
||||
&emac->ctl);
|
||||
debug_cond(DEBUG_AT91EMAC, "halt MAC\n");
|
||||
}
|
||||
|
||||
static int at91emac_send(struct eth_device *netdev, void *packet, int length)
|
||||
{
|
||||
at91_emac_t *emac;
|
||||
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
|
||||
while (!(readl(&emac->tsr) & AT91_EMAC_TSR_BNQ))
|
||||
;
|
||||
writel((u32) packet, &emac->tar);
|
||||
writel(AT91_EMAC_TCR_LEN(length), &emac->tcr);
|
||||
while (AT91_EMAC_TCR_LEN(readl(&emac->tcr)))
|
||||
;
|
||||
debug_cond(DEBUG_AT91EMAC, "Send %d\n", length);
|
||||
writel(readl(&emac->tsr) | AT91_EMAC_TSR_COMP, &emac->tsr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91emac_recv(struct eth_device *netdev)
|
||||
{
|
||||
emac_device *dev;
|
||||
at91_emac_t *emac;
|
||||
rbf_t *rbfp;
|
||||
int size;
|
||||
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
dev = (emac_device *) netdev->priv;
|
||||
|
||||
rbfp = &dev->rbfdt[dev->rbindex];
|
||||
while (rbfp->addr & RBF_OWNER) {
|
||||
size = rbfp->size & RBF_SIZE;
|
||||
net_process_received_packet(net_rx_packets[dev->rbindex], size);
|
||||
|
||||
debug_cond(DEBUG_AT91EMAC, "Recv[%ld]: %d bytes @ %lx\n",
|
||||
dev->rbindex, size, rbfp->addr);
|
||||
|
||||
rbfp->addr &= ~RBF_OWNER;
|
||||
rbfp->size = 0;
|
||||
if (dev->rbindex < (RBF_FRAMEMAX-1))
|
||||
dev->rbindex++;
|
||||
else
|
||||
dev->rbindex = 0;
|
||||
|
||||
rbfp = &(dev->rbfdt[dev->rbindex]);
|
||||
if (!(rbfp->addr & RBF_OWNER))
|
||||
writel(readl(&emac->rsr) | AT91_EMAC_RSR_REC,
|
||||
&emac->rsr);
|
||||
}
|
||||
|
||||
if (readl(&emac->isr) & AT91_EMAC_IxR_RBNA) {
|
||||
/* EMAC silicon bug 41.3.1 workaround 1 */
|
||||
writel(readl(&emac->ctl) & ~AT91_EMAC_CTL_RE, &emac->ctl);
|
||||
writel(readl(&emac->ctl) | AT91_EMAC_CTL_RE, &emac->ctl);
|
||||
dev->rbindex = 0;
|
||||
printf("%s: reset receiver (EMAC dead lock bug)\n",
|
||||
netdev->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91emac_write_hwaddr(struct eth_device *netdev)
|
||||
{
|
||||
at91_emac_t *emac;
|
||||
at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
|
||||
emac = (at91_emac_t *) netdev->iobase;
|
||||
|
||||
writel(1 << ATMEL_ID_EMAC, &pmc->pcer);
|
||||
debug_cond(DEBUG_AT91EMAC,
|
||||
"init MAC-ADDR %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
netdev->enetaddr[5], netdev->enetaddr[4], netdev->enetaddr[3],
|
||||
netdev->enetaddr[2], netdev->enetaddr[1], netdev->enetaddr[0]);
|
||||
writel( (netdev->enetaddr[0] | netdev->enetaddr[1] << 8 |
|
||||
netdev->enetaddr[2] << 16 | netdev->enetaddr[3] << 24),
|
||||
&emac->sa2l);
|
||||
writel((netdev->enetaddr[4] | netdev->enetaddr[5] << 8), &emac->sa2h);
|
||||
debug_cond(DEBUG_AT91EMAC, "init MAC-ADDR %x%x\n",
|
||||
readl(&emac->sa2h), readl(&emac->sa2l));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at91emac_register(bd_t *bis, unsigned long iobase)
|
||||
{
|
||||
emac_device *emac;
|
||||
emac_device *emacfix;
|
||||
struct eth_device *dev;
|
||||
|
||||
if (iobase == 0)
|
||||
iobase = ATMEL_BASE_EMAC;
|
||||
emac = malloc(sizeof(*emac)+512);
|
||||
if (emac == NULL)
|
||||
return -1;
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (dev == NULL) {
|
||||
free(emac);
|
||||
return -1;
|
||||
}
|
||||
/* alignment as per Errata (64 bytes) is insufficient! */
|
||||
emacfix = (emac_device *) (((unsigned long) emac + 0x1ff) & 0xFFFFFE00);
|
||||
memset(emacfix, 0, sizeof(emac_device));
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
sprintf(dev->name, "emac");
|
||||
dev->iobase = iobase;
|
||||
dev->priv = emacfix;
|
||||
dev->init = at91emac_init;
|
||||
dev->halt = at91emac_halt;
|
||||
dev->send = at91emac_send;
|
||||
dev->recv = at91emac_recv;
|
||||
dev->write_hwaddr = at91emac_write_hwaddr;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
miiphy_register(dev->name, at91emac_mii_read, at91emac_mii_write);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
757
sources/uboot-be550/drivers/net/ax88180.c
Normal file
757
sources/uboot-be550/drivers/net/ax88180.c
Normal file
|
|
@ -0,0 +1,757 @@
|
|||
/*
|
||||
* ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
|
||||
*
|
||||
* This program is free software; you can distribute it and/or modify
|
||||
* it under the terms of the GNU General Public License (Version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
* This program is distributed in the hope it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ========================================================================
|
||||
* ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
|
||||
*
|
||||
* The AX88180 Ethernet controller is a high performance and highly
|
||||
* integrated local CPU bus Ethernet controller with embedded 40K bytes
|
||||
* SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
|
||||
* embedded systems.
|
||||
* The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
|
||||
* controller that supports both MII and RGMII interfaces and is
|
||||
* compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
|
||||
*
|
||||
* Please visit ASIX's web site (http://www.asix.com.tw) for more
|
||||
* details.
|
||||
*
|
||||
* Module Name : ax88180.c
|
||||
* Date : 2008-07-07
|
||||
* History
|
||||
* 09/06/2006 : New release for AX88180 US2 chip.
|
||||
* 07/07/2008 : Fix up the coding style and using inline functions
|
||||
* instead of macros
|
||||
* ========================================================================
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/mii.h>
|
||||
#include "ax88180.h"
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* Local SubProgram Declaration
|
||||
* ===========================================================================
|
||||
*/
|
||||
static void ax88180_rx_handler (struct eth_device *dev);
|
||||
static int ax88180_phy_initial (struct eth_device *dev);
|
||||
static void ax88180_media_config (struct eth_device *dev);
|
||||
static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev);
|
||||
static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev);
|
||||
static unsigned short ax88180_mdio_read (struct eth_device *dev,
|
||||
unsigned long regaddr);
|
||||
static void ax88180_mdio_write (struct eth_device *dev,
|
||||
unsigned long regaddr, unsigned short regdata);
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
* Local SubProgram Bodies
|
||||
* ===========================================================================
|
||||
*/
|
||||
static int ax88180_mdio_check_complete (struct eth_device *dev)
|
||||
{
|
||||
int us_cnt = 10000;
|
||||
unsigned short tmpval;
|
||||
|
||||
/* MDIO read/write should not take more than 10 ms */
|
||||
while (--us_cnt) {
|
||||
tmpval = INW (dev, MDIOCTRL);
|
||||
if (((tmpval & READ_PHY) == 0) && ((tmpval & WRITE_PHY) == 0))
|
||||
break;
|
||||
}
|
||||
|
||||
return us_cnt;
|
||||
}
|
||||
|
||||
static unsigned short
|
||||
ax88180_mdio_read (struct eth_device *dev, unsigned long regaddr)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned long tmpval = 0;
|
||||
|
||||
OUTW (dev, (READ_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
|
||||
|
||||
if (ax88180_mdio_check_complete (dev))
|
||||
tmpval = INW (dev, MDIODP);
|
||||
else
|
||||
printf ("Failed to read PHY register!\n");
|
||||
|
||||
return (unsigned short)(tmpval & 0xFFFF);
|
||||
}
|
||||
|
||||
static void
|
||||
ax88180_mdio_write (struct eth_device *dev, unsigned long regaddr,
|
||||
unsigned short regdata)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
|
||||
OUTW (dev, regdata, MDIODP);
|
||||
|
||||
OUTW (dev, (WRITE_PHY | (regaddr << 8) | priv->PhyAddr), MDIOCTRL);
|
||||
|
||||
if (!ax88180_mdio_check_complete (dev))
|
||||
printf ("Failed to write PHY register!\n");
|
||||
}
|
||||
|
||||
static int ax88180_phy_reset (struct eth_device *dev)
|
||||
{
|
||||
unsigned short delay_cnt = 500;
|
||||
|
||||
ax88180_mdio_write (dev, MII_BMCR, (BMCR_RESET | BMCR_ANENABLE));
|
||||
|
||||
/* Wait for the reset to complete, or time out (500 ms) */
|
||||
while (ax88180_mdio_read (dev, MII_BMCR) & BMCR_RESET) {
|
||||
udelay (1000);
|
||||
if (--delay_cnt == 0) {
|
||||
printf ("Failed to reset PHY!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ax88180_mac_reset (struct eth_device *dev)
|
||||
{
|
||||
unsigned long tmpval;
|
||||
unsigned char i;
|
||||
|
||||
struct {
|
||||
unsigned short offset, value;
|
||||
} program_seq[] = {
|
||||
{
|
||||
MISC, MISC_NORMAL}, {
|
||||
RXINDICATOR, DEFAULT_RXINDICATOR}, {
|
||||
TXCMD, DEFAULT_TXCMD}, {
|
||||
TXBS, DEFAULT_TXBS}, {
|
||||
TXDES0, DEFAULT_TXDES0}, {
|
||||
TXDES1, DEFAULT_TXDES1}, {
|
||||
TXDES2, DEFAULT_TXDES2}, {
|
||||
TXDES3, DEFAULT_TXDES3}, {
|
||||
TXCFG, DEFAULT_TXCFG}, {
|
||||
MACCFG2, DEFAULT_MACCFG2}, {
|
||||
MACCFG3, DEFAULT_MACCFG3}, {
|
||||
TXLEN, DEFAULT_TXLEN}, {
|
||||
RXBTHD0, DEFAULT_RXBTHD0}, {
|
||||
RXBTHD1, DEFAULT_RXBTHD1}, {
|
||||
RXFULTHD, DEFAULT_RXFULTHD}, {
|
||||
DOGTHD0, DEFAULT_DOGTHD0}, {
|
||||
DOGTHD1, DEFAULT_DOGTHD1},};
|
||||
|
||||
OUTW (dev, MISC_RESET_MAC, MISC);
|
||||
tmpval = INW (dev, MISC);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(program_seq); i++)
|
||||
OUTW (dev, program_seq[i].value, program_seq[i].offset);
|
||||
}
|
||||
|
||||
static int ax88180_poll_tx_complete (struct eth_device *dev)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned long tmpval, txbs_txdp;
|
||||
int TimeOutCnt = 10000;
|
||||
|
||||
txbs_txdp = 1 << priv->NextTxDesc;
|
||||
|
||||
while (TimeOutCnt--) {
|
||||
|
||||
tmpval = INW (dev, TXBS);
|
||||
|
||||
if ((tmpval & txbs_txdp) == 0)
|
||||
break;
|
||||
|
||||
udelay (100);
|
||||
}
|
||||
|
||||
if (TimeOutCnt)
|
||||
return 0;
|
||||
else
|
||||
return -TimeOutCnt;
|
||||
}
|
||||
|
||||
static void ax88180_rx_handler (struct eth_device *dev)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned long data_size;
|
||||
unsigned short rxcurt_ptr, rxbound_ptr, next_ptr;
|
||||
int i;
|
||||
#if defined (CONFIG_DRIVER_AX88180_16BIT)
|
||||
unsigned short *rxdata = (unsigned short *)net_rx_packets[0];
|
||||
#else
|
||||
unsigned long *rxdata = (unsigned long *)net_rx_packets[0];
|
||||
#endif
|
||||
unsigned short count;
|
||||
|
||||
rxcurt_ptr = INW (dev, RXCURT);
|
||||
rxbound_ptr = INW (dev, RXBOUND);
|
||||
next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
|
||||
|
||||
debug ("ax88180: RX original RXBOUND=0x%04x,"
|
||||
" RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
|
||||
|
||||
while (next_ptr != rxcurt_ptr) {
|
||||
|
||||
OUTW (dev, RX_START_READ, RXINDICATOR);
|
||||
|
||||
data_size = READ_RXBUF (dev) & 0xFFFF;
|
||||
|
||||
if ((data_size == 0) || (data_size > MAX_RX_SIZE)) {
|
||||
|
||||
OUTW (dev, RX_STOP_READ, RXINDICATOR);
|
||||
|
||||
ax88180_mac_reset (dev);
|
||||
printf ("ax88180: Invalid Rx packet length!"
|
||||
" (len=0x%04lx)\n", data_size);
|
||||
|
||||
debug ("ax88180: RX RXBOUND=0x%04x,"
|
||||
"RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
rxbound_ptr += (((data_size + 0xF) & 0xFFF0) >> 4) + 1;
|
||||
rxbound_ptr &= RX_PAGE_NUM_MASK;
|
||||
|
||||
/* Comput access times */
|
||||
count = (data_size + priv->PadSize) >> priv->BusWidth;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
*(rxdata + i) = READ_RXBUF (dev);
|
||||
}
|
||||
|
||||
OUTW (dev, RX_STOP_READ, RXINDICATOR);
|
||||
|
||||
/* Pass the packet up to the protocol layers. */
|
||||
net_process_received_packet(net_rx_packets[0], data_size);
|
||||
|
||||
OUTW (dev, rxbound_ptr, RXBOUND);
|
||||
|
||||
rxcurt_ptr = INW (dev, RXCURT);
|
||||
rxbound_ptr = INW (dev, RXBOUND);
|
||||
next_ptr = (rxbound_ptr + 1) & RX_PAGE_NUM_MASK;
|
||||
|
||||
debug ("ax88180: RX updated RXBOUND=0x%04x,"
|
||||
"RXCURT=0x%04x\n", rxbound_ptr, rxcurt_ptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int ax88180_phy_initial (struct eth_device *dev)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned long tmp_regval;
|
||||
unsigned short phyaddr;
|
||||
|
||||
/* Search for first avaliable PHY chipset */
|
||||
#ifdef CONFIG_PHY_ADDR
|
||||
phyaddr = CONFIG_PHY_ADDR;
|
||||
#else
|
||||
for (phyaddr = 0; phyaddr < 32; ++phyaddr)
|
||||
#endif
|
||||
{
|
||||
priv->PhyAddr = phyaddr;
|
||||
priv->PhyID0 = ax88180_mdio_read(dev, MII_PHYSID1);
|
||||
priv->PhyID1 = ax88180_mdio_read(dev, MII_PHYSID2);
|
||||
|
||||
switch (priv->PhyID0) {
|
||||
case MARVELL_ALASKA_PHYSID0:
|
||||
debug("ax88180: Found Marvell Alaska PHY family."
|
||||
" (PHY Addr=0x%x)\n", priv->PhyAddr);
|
||||
|
||||
switch (priv->PhyID1) {
|
||||
case MARVELL_88E1118_PHYSID1:
|
||||
ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 2);
|
||||
ax88180_mdio_write(dev, M88E1118_CR,
|
||||
M88E1118_CR_DEFAULT);
|
||||
ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 3);
|
||||
ax88180_mdio_write(dev, M88E1118_LEDCTL,
|
||||
M88E1118_LEDCTL_DEFAULT);
|
||||
ax88180_mdio_write(dev, M88E1118_LEDMIX,
|
||||
M88E1118_LEDMIX_LED050 | M88E1118_LEDMIX_LED150 | 0x15);
|
||||
ax88180_mdio_write(dev, M88E1118_PAGE_SEL, 0);
|
||||
default: /* Default to 88E1111 Phy */
|
||||
tmp_regval = ax88180_mdio_read(dev, M88E1111_EXT_SSR);
|
||||
if ((tmp_regval & HWCFG_MODE_MASK) != RGMII_COPPER_MODE)
|
||||
ax88180_mdio_write(dev, M88E1111_EXT_SCR,
|
||||
DEFAULT_EXT_SCR);
|
||||
}
|
||||
|
||||
if (ax88180_phy_reset(dev) < 0)
|
||||
return 0;
|
||||
ax88180_mdio_write(dev, M88_IER, LINK_CHANGE_INT);
|
||||
|
||||
return 1;
|
||||
|
||||
case CICADA_CIS8201_PHYSID0:
|
||||
debug("ax88180: Found CICADA CIS8201 PHY"
|
||||
" chipset. (PHY Addr=0x%x)\n", priv->PhyAddr);
|
||||
|
||||
ax88180_mdio_write(dev, CIS_IMR,
|
||||
(CIS_INT_ENABLE | LINK_CHANGE_INT));
|
||||
|
||||
/* Set CIS_SMI_PRIORITY bit before force the media mode */
|
||||
tmp_regval = ax88180_mdio_read(dev, CIS_AUX_CTRL_STATUS);
|
||||
tmp_regval &= ~CIS_SMI_PRIORITY;
|
||||
ax88180_mdio_write(dev, CIS_AUX_CTRL_STATUS, tmp_regval);
|
||||
|
||||
return 1;
|
||||
|
||||
case 0xffff:
|
||||
/* No PHY at this addr */
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ax88180: Unknown PHY chipset %#x at addr %#x\n",
|
||||
priv->PhyID0, priv->PhyAddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("ax88180: Unknown PHY chipset!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ax88180_media_config (struct eth_device *dev)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned long bmcr_val, bmsr_val;
|
||||
unsigned long rxcfg_val, maccfg0_val, maccfg1_val;
|
||||
unsigned long RealMediaMode;
|
||||
int i;
|
||||
|
||||
/* Waiting 2 seconds for PHY link stable */
|
||||
for (i = 0; i < 20000; i++) {
|
||||
bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
|
||||
if (bmsr_val & BMSR_LSTATUS) {
|
||||
break;
|
||||
}
|
||||
udelay (100);
|
||||
}
|
||||
|
||||
bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
|
||||
debug ("ax88180: BMSR=0x%04x\n", (unsigned int)bmsr_val);
|
||||
|
||||
if (bmsr_val & BMSR_LSTATUS) {
|
||||
bmcr_val = ax88180_mdio_read (dev, MII_BMCR);
|
||||
|
||||
if (bmcr_val & BMCR_ANENABLE) {
|
||||
|
||||
/*
|
||||
* Waiting for Auto-negotiation completion, this may
|
||||
* take up to 5 seconds.
|
||||
*/
|
||||
debug ("ax88180: Auto-negotiation is "
|
||||
"enabled. Waiting for NWay completion..\n");
|
||||
for (i = 0; i < 50000; i++) {
|
||||
bmsr_val = ax88180_mdio_read (dev, MII_BMSR);
|
||||
if (bmsr_val & BMSR_ANEGCOMPLETE) {
|
||||
break;
|
||||
}
|
||||
udelay (100);
|
||||
}
|
||||
} else
|
||||
debug ("ax88180: Auto-negotiation is disabled.\n");
|
||||
|
||||
debug ("ax88180: BMCR=0x%04x, BMSR=0x%04x\n",
|
||||
(unsigned int)bmcr_val, (unsigned int)bmsr_val);
|
||||
|
||||
/* Get real media mode here */
|
||||
switch (priv->PhyID0) {
|
||||
case MARVELL_ALASKA_PHYSID0:
|
||||
RealMediaMode = get_MarvellPHY_media_mode(dev);
|
||||
break;
|
||||
case CICADA_CIS8201_PHYSID0:
|
||||
RealMediaMode = get_CicadaPHY_media_mode(dev);
|
||||
break;
|
||||
default:
|
||||
RealMediaMode = MEDIA_1000FULL;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->LinkState = INS_LINK_UP;
|
||||
|
||||
switch (RealMediaMode) {
|
||||
case MEDIA_1000FULL:
|
||||
debug ("ax88180: 1000Mbps Full-duplex mode.\n");
|
||||
rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
|
||||
maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
|
||||
maccfg1_val = GIGA_MODE_EN | RXFLOW_EN |
|
||||
FULLDUPLEX | DEFAULT_MACCFG1;
|
||||
break;
|
||||
|
||||
case MEDIA_1000HALF:
|
||||
debug ("ax88180: 1000Mbps Half-duplex mode.\n");
|
||||
rxcfg_val = DEFAULT_RXCFG;
|
||||
maccfg0_val = DEFAULT_MACCFG0;
|
||||
maccfg1_val = GIGA_MODE_EN | DEFAULT_MACCFG1;
|
||||
break;
|
||||
|
||||
case MEDIA_100FULL:
|
||||
debug ("ax88180: 100Mbps Full-duplex mode.\n");
|
||||
rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
|
||||
maccfg0_val = SPEED100 | TXFLOW_ENABLE
|
||||
| DEFAULT_MACCFG0;
|
||||
maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
|
||||
break;
|
||||
|
||||
case MEDIA_100HALF:
|
||||
debug ("ax88180: 100Mbps Half-duplex mode.\n");
|
||||
rxcfg_val = DEFAULT_RXCFG;
|
||||
maccfg0_val = SPEED100 | DEFAULT_MACCFG0;
|
||||
maccfg1_val = DEFAULT_MACCFG1;
|
||||
break;
|
||||
|
||||
case MEDIA_10FULL:
|
||||
debug ("ax88180: 10Mbps Full-duplex mode.\n");
|
||||
rxcfg_val = RXFLOW_ENABLE | DEFAULT_RXCFG;
|
||||
maccfg0_val = TXFLOW_ENABLE | DEFAULT_MACCFG0;
|
||||
maccfg1_val = RXFLOW_EN | FULLDUPLEX | DEFAULT_MACCFG1;
|
||||
break;
|
||||
|
||||
case MEDIA_10HALF:
|
||||
debug ("ax88180: 10Mbps Half-duplex mode.\n");
|
||||
rxcfg_val = DEFAULT_RXCFG;
|
||||
maccfg0_val = DEFAULT_MACCFG0;
|
||||
maccfg1_val = DEFAULT_MACCFG1;
|
||||
break;
|
||||
default:
|
||||
debug ("ax88180: Unknow media mode.\n");
|
||||
rxcfg_val = DEFAULT_RXCFG;
|
||||
maccfg0_val = DEFAULT_MACCFG0;
|
||||
maccfg1_val = DEFAULT_MACCFG1;
|
||||
|
||||
priv->LinkState = INS_LINK_DOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
rxcfg_val = DEFAULT_RXCFG;
|
||||
maccfg0_val = DEFAULT_MACCFG0;
|
||||
maccfg1_val = DEFAULT_MACCFG1;
|
||||
|
||||
priv->LinkState = INS_LINK_DOWN;
|
||||
}
|
||||
|
||||
OUTW (dev, rxcfg_val, RXCFG);
|
||||
OUTW (dev, maccfg0_val, MACCFG0);
|
||||
OUTW (dev, maccfg1_val, MACCFG1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned long get_MarvellPHY_media_mode (struct eth_device *dev)
|
||||
{
|
||||
unsigned long m88_ssr;
|
||||
unsigned long MediaMode;
|
||||
|
||||
m88_ssr = ax88180_mdio_read (dev, M88_SSR);
|
||||
switch (m88_ssr & SSR_MEDIA_MASK) {
|
||||
case SSR_1000FULL:
|
||||
MediaMode = MEDIA_1000FULL;
|
||||
break;
|
||||
case SSR_1000HALF:
|
||||
MediaMode = MEDIA_1000HALF;
|
||||
break;
|
||||
case SSR_100FULL:
|
||||
MediaMode = MEDIA_100FULL;
|
||||
break;
|
||||
case SSR_100HALF:
|
||||
MediaMode = MEDIA_100HALF;
|
||||
break;
|
||||
case SSR_10FULL:
|
||||
MediaMode = MEDIA_10FULL;
|
||||
break;
|
||||
case SSR_10HALF:
|
||||
MediaMode = MEDIA_10HALF;
|
||||
break;
|
||||
default:
|
||||
MediaMode = MEDIA_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return MediaMode;
|
||||
}
|
||||
|
||||
static unsigned long get_CicadaPHY_media_mode (struct eth_device *dev)
|
||||
{
|
||||
unsigned long tmp_regval;
|
||||
unsigned long MediaMode;
|
||||
|
||||
tmp_regval = ax88180_mdio_read (dev, CIS_AUX_CTRL_STATUS);
|
||||
switch (tmp_regval & CIS_MEDIA_MASK) {
|
||||
case CIS_1000FULL:
|
||||
MediaMode = MEDIA_1000FULL;
|
||||
break;
|
||||
case CIS_1000HALF:
|
||||
MediaMode = MEDIA_1000HALF;
|
||||
break;
|
||||
case CIS_100FULL:
|
||||
MediaMode = MEDIA_100FULL;
|
||||
break;
|
||||
case CIS_100HALF:
|
||||
MediaMode = MEDIA_100HALF;
|
||||
break;
|
||||
case CIS_10FULL:
|
||||
MediaMode = MEDIA_10FULL;
|
||||
break;
|
||||
case CIS_10HALF:
|
||||
MediaMode = MEDIA_10HALF;
|
||||
break;
|
||||
default:
|
||||
MediaMode = MEDIA_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return MediaMode;
|
||||
}
|
||||
|
||||
static void ax88180_halt (struct eth_device *dev)
|
||||
{
|
||||
/* Disable AX88180 TX/RX functions */
|
||||
OUTW (dev, WAKEMOD, CMD);
|
||||
}
|
||||
|
||||
static int ax88180_init (struct eth_device *dev, bd_t * bd)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned short tmp_regval;
|
||||
|
||||
ax88180_mac_reset (dev);
|
||||
|
||||
/* Disable interrupt */
|
||||
OUTW (dev, CLEAR_IMR, IMR);
|
||||
|
||||
/* Disable AX88180 TX/RX functions */
|
||||
OUTW (dev, WAKEMOD, CMD);
|
||||
|
||||
/* Fill the MAC address */
|
||||
tmp_regval =
|
||||
dev->enetaddr[0] | (((unsigned short)dev->enetaddr[1]) << 8);
|
||||
OUTW (dev, tmp_regval, MACID0);
|
||||
|
||||
tmp_regval =
|
||||
dev->enetaddr[2] | (((unsigned short)dev->enetaddr[3]) << 8);
|
||||
OUTW (dev, tmp_regval, MACID1);
|
||||
|
||||
tmp_regval =
|
||||
dev->enetaddr[4] | (((unsigned short)dev->enetaddr[5]) << 8);
|
||||
OUTW (dev, tmp_regval, MACID2);
|
||||
|
||||
ax88180_media_config (dev);
|
||||
|
||||
OUTW (dev, DEFAULT_RXFILTER, RXFILTER);
|
||||
|
||||
/* Initial variables here */
|
||||
priv->FirstTxDesc = TXDP0;
|
||||
priv->NextTxDesc = TXDP0;
|
||||
|
||||
/* Check if there is any invalid interrupt status and clear it. */
|
||||
OUTW (dev, INW (dev, ISR), ISR);
|
||||
|
||||
/* Start AX88180 TX/RX functions */
|
||||
OUTW (dev, (RXEN | TXEN | WAKEMOD), CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a data block via Ethernet */
|
||||
static int ax88180_recv (struct eth_device *dev)
|
||||
{
|
||||
unsigned short ISR_Status;
|
||||
unsigned short tmp_regval;
|
||||
|
||||
/* Read and check interrupt status here. */
|
||||
ISR_Status = INW (dev, ISR);
|
||||
|
||||
while (ISR_Status) {
|
||||
/* Clear the interrupt status */
|
||||
OUTW (dev, ISR_Status, ISR);
|
||||
|
||||
debug ("\nax88180: The interrupt status = 0x%04x\n",
|
||||
ISR_Status);
|
||||
|
||||
if (ISR_Status & ISR_PHY) {
|
||||
/* Read ISR register once to clear PHY interrupt bit */
|
||||
tmp_regval = ax88180_mdio_read (dev, M88_ISR);
|
||||
ax88180_media_config (dev);
|
||||
}
|
||||
|
||||
if ((ISR_Status & ISR_RX) || (ISR_Status & ISR_RXBUFFOVR)) {
|
||||
ax88180_rx_handler (dev);
|
||||
}
|
||||
|
||||
/* Read and check interrupt status again */
|
||||
ISR_Status = INW (dev, ISR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a data block via Ethernet. */
|
||||
static int ax88180_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
struct ax88180_private *priv = (struct ax88180_private *)dev->priv;
|
||||
unsigned short TXDES_addr;
|
||||
unsigned short txcmd_txdp, txbs_txdp;
|
||||
unsigned short tmp_data;
|
||||
int i;
|
||||
#if defined (CONFIG_DRIVER_AX88180_16BIT)
|
||||
volatile unsigned short *txdata = (volatile unsigned short *)packet;
|
||||
#else
|
||||
volatile unsigned long *txdata = (volatile unsigned long *)packet;
|
||||
#endif
|
||||
unsigned short count;
|
||||
|
||||
if (priv->LinkState != INS_LINK_UP) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv->FirstTxDesc = priv->NextTxDesc;
|
||||
txbs_txdp = 1 << priv->FirstTxDesc;
|
||||
|
||||
debug ("ax88180: TXDP%d is available\n", priv->FirstTxDesc);
|
||||
|
||||
txcmd_txdp = priv->FirstTxDesc << 13;
|
||||
TXDES_addr = TXDES0 + (priv->FirstTxDesc << 2);
|
||||
|
||||
OUTW (dev, (txcmd_txdp | length | TX_START_WRITE), TXCMD);
|
||||
|
||||
/* Comput access times */
|
||||
count = (length + priv->PadSize) >> priv->BusWidth;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
WRITE_TXBUF (dev, *(txdata + i));
|
||||
}
|
||||
|
||||
OUTW (dev, txcmd_txdp | length, TXCMD);
|
||||
OUTW (dev, txbs_txdp, TXBS);
|
||||
OUTW (dev, (TXDPx_ENABLE | length), TXDES_addr);
|
||||
|
||||
priv->NextTxDesc = (priv->NextTxDesc + 1) & TXDP_MASK;
|
||||
|
||||
/*
|
||||
* Check the available transmit descriptor, if we had exhausted all
|
||||
* transmit descriptor ,then we have to wait for at least one free
|
||||
* descriptor
|
||||
*/
|
||||
txbs_txdp = 1 << priv->NextTxDesc;
|
||||
tmp_data = INW (dev, TXBS);
|
||||
|
||||
if (tmp_data & txbs_txdp) {
|
||||
if (ax88180_poll_tx_complete (dev) < 0) {
|
||||
ax88180_mac_reset (dev);
|
||||
priv->FirstTxDesc = TXDP0;
|
||||
priv->NextTxDesc = TXDP0;
|
||||
printf ("ax88180: Transmit time out occurred!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ax88180_read_mac_addr (struct eth_device *dev)
|
||||
{
|
||||
unsigned short macid0_val, macid1_val, macid2_val;
|
||||
unsigned short tmp_regval;
|
||||
unsigned short i;
|
||||
|
||||
/* Reload MAC address from EEPROM */
|
||||
OUTW (dev, RELOAD_EEPROM, PROMCTRL);
|
||||
|
||||
/* Waiting for reload eeprom completion */
|
||||
for (i = 0; i < 500; i++) {
|
||||
tmp_regval = INW (dev, PROMCTRL);
|
||||
if ((tmp_regval & RELOAD_EEPROM) == 0)
|
||||
break;
|
||||
udelay (1000);
|
||||
}
|
||||
|
||||
/* Get MAC addresses */
|
||||
macid0_val = INW (dev, MACID0);
|
||||
macid1_val = INW (dev, MACID1);
|
||||
macid2_val = INW (dev, MACID2);
|
||||
|
||||
if (((macid0_val | macid1_val | macid2_val) != 0) &&
|
||||
((macid0_val & 0x01) == 0)) {
|
||||
dev->enetaddr[0] = (unsigned char)macid0_val;
|
||||
dev->enetaddr[1] = (unsigned char)(macid0_val >> 8);
|
||||
dev->enetaddr[2] = (unsigned char)macid1_val;
|
||||
dev->enetaddr[3] = (unsigned char)(macid1_val >> 8);
|
||||
dev->enetaddr[4] = (unsigned char)macid2_val;
|
||||
dev->enetaddr[5] = (unsigned char)(macid2_val >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
<<<<<< Exported SubProgram Bodies >>>>>>
|
||||
===========================================================================
|
||||
*/
|
||||
int ax88180_initialize (bd_t * bis)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct ax88180_private *priv;
|
||||
|
||||
dev = (struct eth_device *)malloc (sizeof *dev);
|
||||
|
||||
if (NULL == dev)
|
||||
return 0;
|
||||
|
||||
memset (dev, 0, sizeof *dev);
|
||||
|
||||
priv = (struct ax88180_private *)malloc (sizeof (*priv));
|
||||
|
||||
if (NULL == priv)
|
||||
return 0;
|
||||
|
||||
memset (priv, 0, sizeof *priv);
|
||||
|
||||
sprintf (dev->name, "ax88180");
|
||||
dev->iobase = AX88180_BASE;
|
||||
dev->priv = priv;
|
||||
dev->init = ax88180_init;
|
||||
dev->halt = ax88180_halt;
|
||||
dev->send = ax88180_send;
|
||||
dev->recv = ax88180_recv;
|
||||
|
||||
priv->BusWidth = BUS_WIDTH_32;
|
||||
priv->PadSize = 3;
|
||||
#if defined (CONFIG_DRIVER_AX88180_16BIT)
|
||||
OUTW (dev, (START_BASE >> 8), BASE);
|
||||
OUTW (dev, DECODE_EN, DECODE);
|
||||
|
||||
priv->BusWidth = BUS_WIDTH_16;
|
||||
priv->PadSize = 1;
|
||||
#endif
|
||||
|
||||
ax88180_mac_reset (dev);
|
||||
|
||||
/* Disable interrupt */
|
||||
OUTW (dev, CLEAR_IMR, IMR);
|
||||
|
||||
/* Disable AX88180 TX/RX functions */
|
||||
OUTW (dev, WAKEMOD, CMD);
|
||||
|
||||
ax88180_read_mac_addr (dev);
|
||||
|
||||
eth_register (dev);
|
||||
|
||||
return ax88180_phy_initial (dev);
|
||||
|
||||
}
|
||||
396
sources/uboot-be550/drivers/net/ax88180.h
Normal file
396
sources/uboot-be550/drivers/net/ax88180.h
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */
|
||||
/*
|
||||
*
|
||||
* This program is free software; you can distribute it and/or modify it
|
||||
* under the terms of the GNU General Public License (Version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AX88180_H_
|
||||
#define _AX88180_H_
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/types.h>
|
||||
#include <config.h>
|
||||
|
||||
typedef enum _ax88180_link_state {
|
||||
INS_LINK_DOWN,
|
||||
INS_LINK_UP,
|
||||
INS_LINK_UNKNOWN
|
||||
} ax88180_link_state;
|
||||
|
||||
struct ax88180_private {
|
||||
unsigned char BusWidth;
|
||||
unsigned char PadSize;
|
||||
unsigned short PhyAddr;
|
||||
unsigned short PhyID0;
|
||||
unsigned short PhyID1;
|
||||
unsigned short FirstTxDesc;
|
||||
unsigned short NextTxDesc;
|
||||
ax88180_link_state LinkState;
|
||||
};
|
||||
|
||||
#define BUS_WIDTH_16 1
|
||||
#define BUS_WIDTH_32 2
|
||||
|
||||
#define ENABLE_JUMBO 1
|
||||
#define DISABLE_JUMBO 0
|
||||
|
||||
#define ENABLE_BURST 1
|
||||
#define DISABLE_BURST 0
|
||||
|
||||
#define NORMAL_RX_MODE 0
|
||||
#define RX_LOOPBACK_MODE 1
|
||||
#define RX_INIFINIT_LOOP_MODE 2
|
||||
#define TX_INIFINIT_LOOP_MODE 3
|
||||
|
||||
#define DEFAULT_ETH_MTU 1500
|
||||
|
||||
/* Jumbo packet size 4086 bytes included 4 bytes CRC*/
|
||||
#define MAX_JUMBO_MTU 4072
|
||||
|
||||
/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */
|
||||
#define MAX_TX_JUMBO_SIZE 4086
|
||||
|
||||
/* Max Rx Jumbo size is 15K Bytes */
|
||||
#define MAX_RX_SIZE 0x3C00
|
||||
|
||||
#define MARVELL_ALASKA_PHYSID0 0x141
|
||||
#define MARVELL_88E1118_PHYSID1 0xE40
|
||||
|
||||
#define CICADA_CIS8201_PHYSID0 0x000F
|
||||
|
||||
#define MEDIA_AUTO 0
|
||||
#define MEDIA_1000FULL 1
|
||||
#define MEDIA_1000HALF 2
|
||||
#define MEDIA_100FULL 3
|
||||
#define MEDIA_100HALF 4
|
||||
#define MEDIA_10FULL 5
|
||||
#define MEDIA_10HALF 6
|
||||
#define MEDIA_UNKNOWN 7
|
||||
|
||||
#define AUTO_MEDIA 0
|
||||
#define FORCE_MEDIA 1
|
||||
|
||||
#define TXDP_MASK 3
|
||||
#define TXDP0 0
|
||||
#define TXDP1 1
|
||||
#define TXDP2 2
|
||||
#define TXDP3 3
|
||||
|
||||
#define CMD_MAP_SIZE 0x100
|
||||
|
||||
#if defined (CONFIG_DRIVER_AX88180_16BIT)
|
||||
#define AX88180_MEMORY_SIZE 0x00004000
|
||||
#define START_BASE 0x1000
|
||||
|
||||
#define RX_BUF_SIZE 0x1000
|
||||
#define TX_BUF_SIZE 0x0F00
|
||||
|
||||
#define TX_BASE START_BASE
|
||||
#define CMD_BASE (TX_BASE + TX_BUF_SIZE)
|
||||
#define RX_BASE (CMD_BASE + CMD_MAP_SIZE)
|
||||
#else
|
||||
#define AX88180_MEMORY_SIZE 0x00010000
|
||||
|
||||
#define RX_BUF_SIZE 0x8000
|
||||
#define TX_BUF_SIZE 0x7C00
|
||||
|
||||
#define RX_BASE 0x0000
|
||||
#define TX_BASE (RX_BASE + RX_BUF_SIZE)
|
||||
#define CMD_BASE (TX_BASE + TX_BUF_SIZE)
|
||||
#endif
|
||||
|
||||
/* AX88180 Memory Mapping Definition */
|
||||
#define RXBUFFER_START RX_BASE
|
||||
#define RX_PACKET_LEN_OFFSET 0
|
||||
#define RX_PAGE_NUM_MASK 0x7FF /* RX pages 0~7FFh */
|
||||
#define TXBUFFER_START TX_BASE
|
||||
|
||||
/* AX88180 MAC Register Definition */
|
||||
#define DECODE (0)
|
||||
#define DECODE_EN 0x00000001
|
||||
#define BASE (6)
|
||||
#define CMD (CMD_BASE + 0x0000)
|
||||
#define WAKEMOD 0x00000001
|
||||
#define TXEN 0x00000100
|
||||
#define RXEN 0x00000200
|
||||
#define DEFAULT_CMD WAKEMOD
|
||||
#define IMR (CMD_BASE + 0x0004)
|
||||
#define IMR_RXBUFFOVR 0x00000001
|
||||
#define IMR_WATCHDOG 0x00000002
|
||||
#define IMR_TX 0x00000008
|
||||
#define IMR_RX 0x00000010
|
||||
#define IMR_PHY 0x00000020
|
||||
#define CLEAR_IMR 0x00000000
|
||||
#define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\
|
||||
IMR_RXBUFFOVR | IMR_WATCHDOG)
|
||||
#define ISR (CMD_BASE + 0x0008)
|
||||
#define ISR_RXBUFFOVR 0x00000001
|
||||
#define ISR_WATCHDOG 0x00000002
|
||||
#define ISR_TX 0x00000008
|
||||
#define ISR_RX 0x00000010
|
||||
#define ISR_PHY 0x00000020
|
||||
#define TXCFG (CMD_BASE + 0x0010)
|
||||
#define AUTOPAD_CRC 0x00000050
|
||||
#define DEFAULT_TXCFG AUTOPAD_CRC
|
||||
#define TXCMD (CMD_BASE + 0x0014)
|
||||
#define TXCMD_TXDP_MASK 0x00006000
|
||||
#define TXCMD_TXDP0 0x00000000
|
||||
#define TXCMD_TXDP1 0x00002000
|
||||
#define TXCMD_TXDP2 0x00004000
|
||||
#define TXCMD_TXDP3 0x00006000
|
||||
#define TX_START_WRITE 0x00008000
|
||||
#define TX_STOP_WRITE 0x00000000
|
||||
#define DEFAULT_TXCMD 0x00000000
|
||||
#define TXBS (CMD_BASE + 0x0018)
|
||||
#define TXDP0_USED 0x00000001
|
||||
#define TXDP1_USED 0x00000002
|
||||
#define TXDP2_USED 0x00000004
|
||||
#define TXDP3_USED 0x00000008
|
||||
#define DEFAULT_TXBS 0x00000000
|
||||
#define TXDES0 (CMD_BASE + 0x0020)
|
||||
#define TXDPx_ENABLE 0x00008000
|
||||
#define TXDPx_LEN_MASK 0x00001FFF
|
||||
#define DEFAULT_TXDES0 0x00000000
|
||||
#define TXDES1 (CMD_BASE + 0x0024)
|
||||
#define TXDPx_ENABLE 0x00008000
|
||||
#define TXDPx_LEN_MASK 0x00001FFF
|
||||
#define DEFAULT_TXDES1 0x00000000
|
||||
#define TXDES2 (CMD_BASE + 0x0028)
|
||||
#define TXDPx_ENABLE 0x00008000
|
||||
#define TXDPx_LEN_MASK 0x00001FFF
|
||||
#define DEFAULT_TXDES2 0x00000000
|
||||
#define TXDES3 (CMD_BASE + 0x002C)
|
||||
#define TXDPx_ENABLE 0x00008000
|
||||
#define TXDPx_LEN_MASK 0x00001FFF
|
||||
#define DEFAULT_TXDES3 0x00000000
|
||||
#define RXCFG (CMD_BASE + 0x0030)
|
||||
#define RXBUFF_PROTECT 0x00000001
|
||||
#define RXTCPCRC_CHECK 0x00000010
|
||||
#define RXFLOW_ENABLE 0x00000100
|
||||
#define DEFAULT_RXCFG RXBUFF_PROTECT
|
||||
#define RXCURT (CMD_BASE + 0x0034)
|
||||
#define DEFAULT_RXCURT 0x00000000
|
||||
#define RXBOUND (CMD_BASE + 0x0038)
|
||||
#define DEFAULT_RXBOUND 0x7FF /* RX pages 0~7FFh */
|
||||
#define MACCFG0 (CMD_BASE + 0x0040)
|
||||
#define MACCFG0_BIT3_0 0x00000007
|
||||
#define IPGT_VAL 0x00000150
|
||||
#define TXFLOW_ENABLE 0x00001000
|
||||
#define SPEED100 0x00008000
|
||||
#define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0)
|
||||
#define MACCFG1 (CMD_BASE + 0x0044)
|
||||
#define RGMII_EN 0x00000002
|
||||
#define RXFLOW_EN 0x00000020
|
||||
#define FULLDUPLEX 0x00000040
|
||||
#define MAX_JUMBO_LEN 0x00000780
|
||||
#define RXJUMBO_EN 0x00000800
|
||||
#define GIGA_MODE_EN 0x00001000
|
||||
#define RXCRC_CHECK 0x00002000
|
||||
#define RXPAUSE_DA_CHECK 0x00004000
|
||||
|
||||
#define JUMBO_LEN_4K 0x00000200
|
||||
#define JUMBO_LEN_15K 0x00000780
|
||||
#define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK | \
|
||||
RGMII_EN)
|
||||
#define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK)
|
||||
#define MACCFG2 (CMD_BASE + 0x0048)
|
||||
#define MACCFG2_BIT15_8 0x00000100
|
||||
#define JAM_LIMIT_MASK 0x000000FC
|
||||
#define DEFAULT_JAM_LIMIT 0x00000064
|
||||
#define DEFAULT_MACCFG2 MACCFG2_BIT15_8
|
||||
#define MACCFG3 (CMD_BASE + 0x004C)
|
||||
#define IPGR2_VAL 0x0000000E
|
||||
#define IPGR1_VAL 0x00000600
|
||||
#define NOABORT 0x00008000
|
||||
#define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL)
|
||||
#define TXPAUT (CMD_BASE + 0x0054)
|
||||
#define DEFAULT_TXPAUT 0x001FE000
|
||||
#define RXBTHD0 (CMD_BASE + 0x0058)
|
||||
#define DEFAULT_RXBTHD0 0x00000300
|
||||
#define RXBTHD1 (CMD_BASE + 0x005C)
|
||||
#define DEFAULT_RXBTHD1 0x00000600
|
||||
#define RXFULTHD (CMD_BASE + 0x0060)
|
||||
#define DEFAULT_RXFULTHD 0x00000100
|
||||
#define MISC (CMD_BASE + 0x0068)
|
||||
/* Normal operation mode */
|
||||
#define MISC_NORMAL 0x00000003
|
||||
/* Clear bit 0 to reset MAC */
|
||||
#define MISC_RESET_MAC 0x00000002
|
||||
/* Clear bit 1 to reset PHY */
|
||||
#define MISC_RESET_PHY 0x00000001
|
||||
/* Clear bit 0 and 1 to reset MAC and PHY */
|
||||
#define MISC_RESET_MAC_PHY 0x00000000
|
||||
#define DEFAULT_MISC MISC_NORMAL
|
||||
#define MACID0 (CMD_BASE + 0x0070)
|
||||
#define MACID1 (CMD_BASE + 0x0074)
|
||||
#define MACID2 (CMD_BASE + 0x0078)
|
||||
#define TXLEN (CMD_BASE + 0x007C)
|
||||
#define DEFAULT_TXLEN 0x000005FC
|
||||
#define RXFILTER (CMD_BASE + 0x0080)
|
||||
#define RX_RXANY 0x00000001
|
||||
#define RX_MULTICAST 0x00000002
|
||||
#define RX_UNICAST 0x00000004
|
||||
#define RX_BROADCAST 0x00000008
|
||||
#define RX_MULTI_HASH 0x00000010
|
||||
#define DISABLE_RXFILTER 0x00000000
|
||||
#define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST)
|
||||
#define MDIOCTRL (CMD_BASE + 0x0084)
|
||||
#define PHY_ADDR_MASK 0x0000001F
|
||||
#define REG_ADDR_MASK 0x00001F00
|
||||
#define READ_PHY 0x00004000
|
||||
#define WRITE_PHY 0x00008000
|
||||
#define MDIODP (CMD_BASE + 0x0088)
|
||||
#define GPIOCTRL (CMD_BASE + 0x008C)
|
||||
#define RXINDICATOR (CMD_BASE + 0x0090)
|
||||
#define RX_START_READ 0x00000001
|
||||
#define RX_STOP_READ 0x00000000
|
||||
#define DEFAULT_RXINDICATOR RX_STOP_READ
|
||||
#define TXST (CMD_BASE + 0x0094)
|
||||
#define MDCCLKPAT (CMD_BASE + 0x00A0)
|
||||
#define RXIPCRCCNT (CMD_BASE + 0x00A4)
|
||||
#define RXCRCCNT (CMD_BASE + 0x00A8)
|
||||
#define TXFAILCNT (CMD_BASE + 0x00AC)
|
||||
#define PROMDP (CMD_BASE + 0x00B0)
|
||||
#define PROMCTRL (CMD_BASE + 0x00B4)
|
||||
#define RELOAD_EEPROM 0x00000200
|
||||
#define MAXRXLEN (CMD_BASE + 0x00B8)
|
||||
#define HASHTAB0 (CMD_BASE + 0x00C0)
|
||||
#define HASHTAB1 (CMD_BASE + 0x00C4)
|
||||
#define HASHTAB2 (CMD_BASE + 0x00C8)
|
||||
#define HASHTAB3 (CMD_BASE + 0x00CC)
|
||||
#define DOGTHD0 (CMD_BASE + 0x00E0)
|
||||
#define DEFAULT_DOGTHD0 0x0000FFFF
|
||||
#define DOGTHD1 (CMD_BASE + 0x00E4)
|
||||
#define START_WATCHDOG_TIMER 0x00008000
|
||||
#define DEFAULT_DOGTHD1 0x00000FFF
|
||||
#define SOFTRST (CMD_BASE + 0x00EC)
|
||||
#define SOFTRST_NORMAL 0x00000003
|
||||
#define SOFTRST_RESET_MAC 0x00000002
|
||||
|
||||
/* Marvell 88E1111 Gigabit PHY Register Definition */
|
||||
#define M88_SSR 0x0011
|
||||
#define SSR_SPEED_MASK 0xC000
|
||||
#define SSR_SPEED_1000 0x8000
|
||||
#define SSR_SPEED_100 0x4000
|
||||
#define SSR_SPEED_10 0x0000
|
||||
#define SSR_DUPLEX 0x2000
|
||||
#define SSR_MEDIA_RESOLVED_OK 0x0800
|
||||
|
||||
#define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX)
|
||||
#define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX)
|
||||
#define SSR_1000HALF SSR_SPEED_1000
|
||||
#define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX)
|
||||
#define SSR_100HALF SSR_SPEED_100
|
||||
#define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX)
|
||||
#define SSR_10HALF SSR_SPEED_10
|
||||
#define M88_IER 0x0012
|
||||
#define LINK_CHANGE_INT 0x0400
|
||||
#define M88_ISR 0x0013
|
||||
#define LINK_CHANGE_STATUS 0x0400
|
||||
#define M88E1111_EXT_SCR 0x0014
|
||||
#define RGMII_RXCLK_DELAY 0x0080
|
||||
#define RGMII_TXCLK_DELAY 0x0002
|
||||
#define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY)
|
||||
#define M88E1111_EXT_SSR 0x001B
|
||||
#define HWCFG_MODE_MASK 0x000F
|
||||
#define RGMII_COPPER_MODE 0x000B
|
||||
|
||||
/* Marvell 88E1118 Gigabit PHY Register Definition */
|
||||
#define M88E1118_CR 0x14
|
||||
#define M88E1118_CR_RGMII_RXCLK_DELAY 0x0020
|
||||
#define M88E1118_CR_RGMII_TXCLK_DELAY 0x0010
|
||||
#define M88E1118_CR_DEFAULT (M88E1118_CR_RGMII_TXCLK_DELAY | \
|
||||
M88E1118_CR_RGMII_RXCLK_DELAY)
|
||||
#define M88E1118_LEDCTL 0x10 /* Reg 16 on page 3 */
|
||||
#define M88E1118_LEDCTL_LED2INT 0x200
|
||||
#define M88E1118_LEDCTL_LED2BLNK 0x400
|
||||
#define M88E1118_LEDCTL_LED0DUALMODE1 0xc
|
||||
#define M88E1118_LEDCTL_LED0DUALMODE2 0xd
|
||||
#define M88E1118_LEDCTL_LED0DUALMODE3 0xe
|
||||
#define M88E1118_LEDCTL_LED0DUALMODE4 0xf
|
||||
#define M88E1118_LEDCTL_DEFAULT (M88E1118_LEDCTL_LED2BLNK | \
|
||||
M88E1118_LEDCTL_LED0DUALMODE4)
|
||||
|
||||
#define M88E1118_LEDMIX 0x11 /* Reg 17 on page 3 */
|
||||
#define M88E1118_LEDMIX_LED050 0x4
|
||||
#define M88E1118_LEDMIX_LED150 0x8
|
||||
|
||||
#define M88E1118_PAGE_SEL 0x16 /* Reg page select */
|
||||
|
||||
/* CICADA CIS8201 Gigabit PHY Register Definition */
|
||||
#define CIS_IMR 0x0019
|
||||
#define CIS_INT_ENABLE 0x8000
|
||||
#define CIS_LINK_CHANGE_INT 0x2000
|
||||
#define CIS_ISR 0x001A
|
||||
#define CIS_INT_PENDING 0x8000
|
||||
#define CIS_LINK_CHANGE_STATUS 0x2000
|
||||
#define CIS_AUX_CTRL_STATUS 0x001C
|
||||
#define CIS_AUTONEG_COMPLETE 0x8000
|
||||
#define CIS_SPEED_MASK 0x0018
|
||||
#define CIS_SPEED_1000 0x0010
|
||||
#define CIS_SPEED_100 0x0008
|
||||
#define CIS_SPEED_10 0x0000
|
||||
#define CIS_DUPLEX 0x0020
|
||||
|
||||
#define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX)
|
||||
#define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX)
|
||||
#define CIS_1000HALF CIS_SPEED_1000
|
||||
#define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX)
|
||||
#define CIS_100HALF CIS_SPEED_100
|
||||
#define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX)
|
||||
#define CIS_10HALF CIS_SPEED_10
|
||||
#define CIS_SMI_PRIORITY 0x0004
|
||||
|
||||
static inline unsigned short INW (struct eth_device *dev, unsigned long addr)
|
||||
{
|
||||
return le16_to_cpu(readw(addr + (void *)dev->iobase));
|
||||
}
|
||||
|
||||
/*
|
||||
Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer
|
||||
*/
|
||||
#if defined (CONFIG_DRIVER_AX88180_16BIT)
|
||||
static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr)
|
||||
{
|
||||
writew(cpu_to_le16(command), addr + (void *)dev->iobase);
|
||||
}
|
||||
|
||||
static inline unsigned short READ_RXBUF (struct eth_device *dev)
|
||||
{
|
||||
return le16_to_cpu(readw(RXBUFFER_START + (void *)dev->iobase));
|
||||
}
|
||||
|
||||
static inline void WRITE_TXBUF (struct eth_device *dev, unsigned short data)
|
||||
{
|
||||
writew(cpu_to_le16(data), TXBUFFER_START + (void *)dev->iobase);
|
||||
}
|
||||
#else
|
||||
static inline void OUTW (struct eth_device *dev, unsigned short command, unsigned long addr)
|
||||
{
|
||||
writel(cpu_to_le32(command), addr + (void *)dev->iobase);
|
||||
}
|
||||
|
||||
static inline unsigned long READ_RXBUF (struct eth_device *dev)
|
||||
{
|
||||
return le32_to_cpu(readl(RXBUFFER_START + (void *)dev->iobase));
|
||||
}
|
||||
|
||||
static inline void WRITE_TXBUF (struct eth_device *dev, unsigned long data)
|
||||
{
|
||||
writel(cpu_to_le32(data), TXBUFFER_START + (void *)dev->iobase);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _AX88180_H_ */
|
||||
144
sources/uboot-be550/drivers/net/ax88796.c
Normal file
144
sources/uboot-be550/drivers/net/ax88796.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* (c) 2007 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include "ax88796.h"
|
||||
|
||||
/*
|
||||
* Set 1 bit data
|
||||
*/
|
||||
static void ax88796_bitset(u32 bit)
|
||||
{
|
||||
/* DATA1 */
|
||||
if( bit )
|
||||
EEDI_HIGH;
|
||||
else
|
||||
EEDI_LOW;
|
||||
|
||||
EECLK_LOW;
|
||||
udelay(1000);
|
||||
EECLK_HIGH;
|
||||
udelay(1000);
|
||||
EEDI_LOW;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get 1 bit data
|
||||
*/
|
||||
static u8 ax88796_bitget(void)
|
||||
{
|
||||
u8 bit;
|
||||
|
||||
EECLK_LOW;
|
||||
udelay(1000);
|
||||
/* DATA */
|
||||
bit = EEDO;
|
||||
EECLK_HIGH;
|
||||
udelay(1000);
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send COMMAND to EEPROM
|
||||
*/
|
||||
static void ax88796_eep_cmd(u8 cmd)
|
||||
{
|
||||
ax88796_bitset(BIT_DUMMY);
|
||||
switch(cmd){
|
||||
case MAC_EEP_READ:
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(0);
|
||||
break;
|
||||
|
||||
case MAC_EEP_WRITE:
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(0);
|
||||
ax88796_bitset(1);
|
||||
break;
|
||||
|
||||
case MAC_EEP_ERACE:
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(1);
|
||||
break;
|
||||
|
||||
case MAC_EEP_EWEN:
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(0);
|
||||
ax88796_bitset(0);
|
||||
break;
|
||||
|
||||
case MAC_EEP_EWDS:
|
||||
ax88796_bitset(1);
|
||||
ax88796_bitset(0);
|
||||
ax88796_bitset(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ax88796_eep_setaddr(u16 addr)
|
||||
{
|
||||
int i ;
|
||||
|
||||
for( i = 7 ; i >= 0 ; i-- )
|
||||
ax88796_bitset(addr & (1 << i));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get data from EEPROM
|
||||
*/
|
||||
static u16 ax88796_eep_getdata(void)
|
||||
{
|
||||
ushort data = 0;
|
||||
int i;
|
||||
|
||||
ax88796_bitget(); /* DUMMY */
|
||||
for( i = 0 ; i < 16 ; i++ ){
|
||||
data <<= 1;
|
||||
data |= ax88796_bitget();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void ax88796_mac_read(u8 *buff)
|
||||
{
|
||||
int i ;
|
||||
u16 data;
|
||||
u16 addr = 0;
|
||||
|
||||
for( i = 0 ; i < 3; i++ )
|
||||
{
|
||||
EECS_HIGH;
|
||||
EEDI_LOW;
|
||||
udelay(1000);
|
||||
/* READ COMMAND */
|
||||
ax88796_eep_cmd(MAC_EEP_READ);
|
||||
/* ADDRESS */
|
||||
ax88796_eep_setaddr(addr++);
|
||||
/* GET DATA */
|
||||
data = ax88796_eep_getdata();
|
||||
*buff++ = (uchar)(data & 0xff);
|
||||
*buff++ = (uchar)((data >> 8) & 0xff);
|
||||
EECLK_LOW;
|
||||
EEDI_LOW;
|
||||
EECS_LOW;
|
||||
}
|
||||
}
|
||||
|
||||
int get_prom(u8* mac_addr, u8* base_addr)
|
||||
{
|
||||
u8 prom[32];
|
||||
int i;
|
||||
|
||||
ax88796_mac_read(prom);
|
||||
for (i = 0; i < 6; i++){
|
||||
mac_addr[i] = prom[i];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
67
sources/uboot-be550/drivers/net/ax88796.h
Normal file
67
sources/uboot-be550/drivers/net/ax88796.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* AX88796L(NE2000) support
|
||||
*
|
||||
* (c) 2007 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_AX88796L_H__
|
||||
#define __DRIVERS_AX88796L_H__
|
||||
|
||||
#define DP_DATA (0x10 << 1)
|
||||
#define START_PG 0x40 /* First page of TX buffer */
|
||||
#define START_PG2 0x48
|
||||
#define STOP_PG 0x80 /* Last page +1 of RX ring */
|
||||
#define TX_PAGES 12
|
||||
#define RX_START (START_PG+TX_PAGES)
|
||||
#define RX_END STOP_PG
|
||||
|
||||
#define AX88796L_BASE_ADDRESS CONFIG_DRIVER_NE2000_BASE
|
||||
#define AX88796L_BYTE_ACCESS 0x00001000
|
||||
#define AX88796L_OFFSET 0x00000400
|
||||
#define AX88796L_ADDRESS_BYTE AX88796L_BASE_ADDRESS + \
|
||||
AX88796L_BYTE_ACCESS + AX88796L_OFFSET
|
||||
#define AX88796L_REG_MEMR AX88796L_ADDRESS_BYTE + (0x14<<1)
|
||||
#define AX88796L_REG_CR AX88796L_ADDRESS_BYTE + (0x00<<1)
|
||||
|
||||
#define AX88796L_CR (*(vu_short *)(AX88796L_REG_CR))
|
||||
#define AX88796L_MEMR (*(vu_short *)(AX88796L_REG_MEMR))
|
||||
|
||||
#define EECS_HIGH (AX88796L_MEMR |= 0x10)
|
||||
#define EECS_LOW (AX88796L_MEMR &= 0xef)
|
||||
#define EECLK_HIGH (AX88796L_MEMR |= 0x80)
|
||||
#define EECLK_LOW (AX88796L_MEMR &= 0x7f)
|
||||
#define EEDI_HIGH (AX88796L_MEMR |= 0x20)
|
||||
#define EEDI_LOW (AX88796L_MEMR &= 0xdf)
|
||||
#define EEDO ((AX88796L_MEMR & 0x40)>>6)
|
||||
|
||||
#define PAGE0_SET (AX88796L_CR &= 0x3f)
|
||||
#define PAGE1_SET (AX88796L_CR = (AX88796L_CR & 0x3f) | 0x40)
|
||||
|
||||
#define BIT_DUMMY 0
|
||||
#define MAC_EEP_READ 1
|
||||
#define MAC_EEP_WRITE 2
|
||||
#define MAC_EEP_ERACE 3
|
||||
#define MAC_EEP_EWEN 4
|
||||
#define MAC_EEP_EWDS 5
|
||||
|
||||
/* R7780MP Specific code */
|
||||
#if defined(CONFIG_R7780MP)
|
||||
#define ISA_OFFSET 0x1400
|
||||
#define DP_IN(_b_, _o_, _d_) (_d_) = \
|
||||
*( (vu_short *) ((_b_) + ((_o_) * 2) + ISA_OFFSET))
|
||||
#define DP_OUT(_b_, _o_, _d_) \
|
||||
*((vu_short *)((_b_) + ((_o_) * 2) + ISA_OFFSET)) = (_d_)
|
||||
#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_short *) ((_b_) + ISA_OFFSET))
|
||||
#define DP_OUT_DATA(_b_, _d_) *( (vu_short *) ((_b_)+ISA_OFFSET)) = (_d_)
|
||||
#else
|
||||
/* Please change for your target boards */
|
||||
#define ISA_OFFSET 0x0000
|
||||
#define DP_IN(_b_, _o_, _d_) (_d_) = *( (vu_short *)((_b_)+(_o_ )+ISA_OFFSET))
|
||||
#define DP_OUT(_b_, _o_, _d_) *((vu_short *)((_b_)+(_o_)+ISA_OFFSET)) = (_d_)
|
||||
#define DP_IN_DATA(_b_, _d_) (_d_) = *( (vu_short *) ((_b_)+ISA_OFFSET))
|
||||
#define DP_OUT_DATA(_b_, _d_) *( (vu_short *) ((_b_)+ISA_OFFSET)) = (_d_)
|
||||
#endif
|
||||
|
||||
#endif /* __DRIVERS_AX88796L_H__ */
|
||||
971
sources/uboot-be550/drivers/net/bcm-sf2-eth-gmac.c
Normal file
971
sources/uboot-be550/drivers/net/bcm-sf2-eth-gmac.c
Normal file
|
|
@ -0,0 +1,971 @@
|
|||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifdef BCM_GMAC_DEBUG
|
||||
#ifndef DEBUG
|
||||
#define DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <asm/io.h>
|
||||
#include <phy.h>
|
||||
|
||||
#include "bcm-sf2-eth.h"
|
||||
#include "bcm-sf2-eth-gmac.h"
|
||||
|
||||
#define SPINWAIT(exp, us) { \
|
||||
uint countdown = (us) + 9; \
|
||||
while ((exp) && (countdown >= 10)) {\
|
||||
udelay(10); \
|
||||
countdown -= 10; \
|
||||
} \
|
||||
}
|
||||
|
||||
static int gmac_disable_dma(struct eth_dma *dma, int dir);
|
||||
static int gmac_enable_dma(struct eth_dma *dma, int dir);
|
||||
|
||||
/* DMA Descriptor */
|
||||
typedef struct {
|
||||
/* misc control bits */
|
||||
uint32_t ctrl1;
|
||||
/* buffer count and address extension */
|
||||
uint32_t ctrl2;
|
||||
/* memory address of the date buffer, bits 31:0 */
|
||||
uint32_t addrlow;
|
||||
/* memory address of the date buffer, bits 63:32 */
|
||||
uint32_t addrhigh;
|
||||
} dma64dd_t;
|
||||
|
||||
uint32_t g_dmactrlflags;
|
||||
|
||||
static uint32_t dma_ctrlflags(uint32_t mask, uint32_t flags)
|
||||
{
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
g_dmactrlflags &= ~mask;
|
||||
g_dmactrlflags |= flags;
|
||||
|
||||
/* If trying to enable parity, check if parity is actually supported */
|
||||
if (g_dmactrlflags & DMA_CTRL_PEN) {
|
||||
uint32_t control;
|
||||
|
||||
control = readl(GMAC0_DMA_TX_CTRL_ADDR);
|
||||
writel(control | D64_XC_PD, GMAC0_DMA_TX_CTRL_ADDR);
|
||||
if (readl(GMAC0_DMA_TX_CTRL_ADDR) & D64_XC_PD) {
|
||||
/*
|
||||
* We *can* disable it, therefore it is supported;
|
||||
* restore control register
|
||||
*/
|
||||
writel(control, GMAC0_DMA_TX_CTRL_ADDR);
|
||||
} else {
|
||||
/* Not supported, don't allow it to be enabled */
|
||||
g_dmactrlflags &= ~DMA_CTRL_PEN;
|
||||
}
|
||||
}
|
||||
|
||||
return g_dmactrlflags;
|
||||
}
|
||||
|
||||
static inline void reg32_clear_bits(uint32_t reg, uint32_t value)
|
||||
{
|
||||
uint32_t v = readl(reg);
|
||||
v &= ~(value);
|
||||
writel(v, reg);
|
||||
}
|
||||
|
||||
static inline void reg32_set_bits(uint32_t reg, uint32_t value)
|
||||
{
|
||||
uint32_t v = readl(reg);
|
||||
v |= value;
|
||||
writel(v, reg);
|
||||
}
|
||||
|
||||
#ifdef BCM_GMAC_DEBUG
|
||||
static void dma_tx_dump(struct eth_dma *dma)
|
||||
{
|
||||
dma64dd_t *descp = NULL;
|
||||
uint8_t *bufp;
|
||||
int i;
|
||||
|
||||
printf("TX DMA Register:\n");
|
||||
printf("control:0x%x; ptr:0x%x; addrl:0x%x; addrh:0x%x; stat0:0x%x, stat1:0x%x\n",
|
||||
readl(GMAC0_DMA_TX_CTRL_ADDR),
|
||||
readl(GMAC0_DMA_TX_PTR_ADDR),
|
||||
readl(GMAC0_DMA_TX_ADDR_LOW_ADDR),
|
||||
readl(GMAC0_DMA_TX_ADDR_HIGH_ADDR),
|
||||
readl(GMAC0_DMA_TX_STATUS0_ADDR),
|
||||
readl(GMAC0_DMA_TX_STATUS1_ADDR));
|
||||
|
||||
printf("TX Descriptors:\n");
|
||||
for (i = 0; i < TX_BUF_NUM; i++) {
|
||||
descp = (dma64dd_t *)(dma->tx_desc_aligned) + i;
|
||||
printf("ctrl1:0x%08x; ctrl2:0x%08x; addr:0x%x 0x%08x\n",
|
||||
descp->ctrl1, descp->ctrl2,
|
||||
descp->addrhigh, descp->addrlow);
|
||||
}
|
||||
|
||||
printf("TX Buffers:\n");
|
||||
/* Initialize TX DMA descriptor table */
|
||||
for (i = 0; i < TX_BUF_NUM; i++) {
|
||||
bufp = (uint8_t *)(dma->tx_buf + i * TX_BUF_SIZE);
|
||||
printf("buf%d:0x%x; ", i, (uint32_t)bufp);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void dma_rx_dump(struct eth_dma *dma)
|
||||
{
|
||||
dma64dd_t *descp = NULL;
|
||||
uint8_t *bufp;
|
||||
int i;
|
||||
|
||||
printf("RX DMA Register:\n");
|
||||
printf("control:0x%x; ptr:0x%x; addrl:0x%x; addrh:0x%x; stat0:0x%x, stat1:0x%x\n",
|
||||
readl(GMAC0_DMA_RX_CTRL_ADDR),
|
||||
readl(GMAC0_DMA_RX_PTR_ADDR),
|
||||
readl(GMAC0_DMA_RX_ADDR_LOW_ADDR),
|
||||
readl(GMAC0_DMA_RX_ADDR_HIGH_ADDR),
|
||||
readl(GMAC0_DMA_RX_STATUS0_ADDR),
|
||||
readl(GMAC0_DMA_RX_STATUS1_ADDR));
|
||||
|
||||
printf("RX Descriptors:\n");
|
||||
for (i = 0; i < RX_BUF_NUM; i++) {
|
||||
descp = (dma64dd_t *)(dma->rx_desc_aligned) + i;
|
||||
printf("ctrl1:0x%08x; ctrl2:0x%08x; addr:0x%x 0x%08x\n",
|
||||
descp->ctrl1, descp->ctrl2,
|
||||
descp->addrhigh, descp->addrlow);
|
||||
}
|
||||
|
||||
printf("RX Buffers:\n");
|
||||
for (i = 0; i < RX_BUF_NUM; i++) {
|
||||
bufp = dma->rx_buf + i * RX_BUF_SIZE;
|
||||
printf("buf%d:0x%x; ", i, (uint32_t)bufp);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dma_tx_init(struct eth_dma *dma)
|
||||
{
|
||||
dma64dd_t *descp = NULL;
|
||||
uint8_t *bufp;
|
||||
int i;
|
||||
uint32_t ctrl;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* clear descriptor memory */
|
||||
memset((void *)(dma->tx_desc_aligned), 0,
|
||||
TX_BUF_NUM * sizeof(dma64dd_t));
|
||||
memset(dma->tx_buf, 0, TX_BUF_NUM * TX_BUF_SIZE);
|
||||
|
||||
/* Initialize TX DMA descriptor table */
|
||||
for (i = 0; i < TX_BUF_NUM; i++) {
|
||||
descp = (dma64dd_t *)(dma->tx_desc_aligned) + i;
|
||||
bufp = dma->tx_buf + i * TX_BUF_SIZE;
|
||||
/* clear buffer memory */
|
||||
memset((void *)bufp, 0, TX_BUF_SIZE);
|
||||
|
||||
ctrl = 0;
|
||||
/* if last descr set endOfTable */
|
||||
if (i == (TX_BUF_NUM-1))
|
||||
ctrl = D64_CTRL1_EOT;
|
||||
descp->ctrl1 = ctrl;
|
||||
descp->ctrl2 = 0;
|
||||
descp->addrlow = (uint32_t)bufp;
|
||||
descp->addrhigh = 0;
|
||||
}
|
||||
|
||||
/* flush descriptor and buffer */
|
||||
descp = dma->tx_desc_aligned;
|
||||
bufp = dma->tx_buf;
|
||||
flush_dcache_range((unsigned long)descp,
|
||||
(unsigned long)(descp +
|
||||
sizeof(dma64dd_t) * TX_BUF_NUM));
|
||||
flush_dcache_range((unsigned long)(bufp),
|
||||
(unsigned long)(bufp + TX_BUF_SIZE * TX_BUF_NUM));
|
||||
|
||||
/* initialize the DMA channel */
|
||||
writel((uint32_t)(dma->tx_desc_aligned), GMAC0_DMA_TX_ADDR_LOW_ADDR);
|
||||
writel(0, GMAC0_DMA_TX_ADDR_HIGH_ADDR);
|
||||
|
||||
/* now update the dma last descriptor */
|
||||
writel(((uint32_t)(dma->tx_desc_aligned)) & D64_XP_LD_MASK,
|
||||
GMAC0_DMA_TX_PTR_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dma_rx_init(struct eth_dma *dma)
|
||||
{
|
||||
uint32_t last_desc;
|
||||
dma64dd_t *descp = NULL;
|
||||
uint8_t *bufp;
|
||||
uint32_t ctrl;
|
||||
int i;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* clear descriptor memory */
|
||||
memset((void *)(dma->rx_desc_aligned), 0,
|
||||
RX_BUF_NUM * sizeof(dma64dd_t));
|
||||
/* clear buffer memory */
|
||||
memset(dma->rx_buf, 0, RX_BUF_NUM * RX_BUF_SIZE);
|
||||
|
||||
/* Initialize RX DMA descriptor table */
|
||||
for (i = 0; i < RX_BUF_NUM; i++) {
|
||||
descp = (dma64dd_t *)(dma->rx_desc_aligned) + i;
|
||||
bufp = dma->rx_buf + i * RX_BUF_SIZE;
|
||||
ctrl = 0;
|
||||
/* if last descr set endOfTable */
|
||||
if (i == (RX_BUF_NUM - 1))
|
||||
ctrl = D64_CTRL1_EOT;
|
||||
descp->ctrl1 = ctrl;
|
||||
descp->ctrl2 = RX_BUF_SIZE;
|
||||
descp->addrlow = (uint32_t)bufp;
|
||||
descp->addrhigh = 0;
|
||||
|
||||
last_desc = ((uint32_t)(descp) & D64_XP_LD_MASK)
|
||||
+ sizeof(dma64dd_t);
|
||||
}
|
||||
|
||||
descp = dma->rx_desc_aligned;
|
||||
bufp = dma->rx_buf;
|
||||
/* flush descriptor and buffer */
|
||||
flush_dcache_range((unsigned long)descp,
|
||||
(unsigned long)(descp +
|
||||
sizeof(dma64dd_t) * RX_BUF_NUM));
|
||||
flush_dcache_range((unsigned long)(bufp),
|
||||
(unsigned long)(bufp + RX_BUF_SIZE * RX_BUF_NUM));
|
||||
|
||||
/* initailize the DMA channel */
|
||||
writel((uint32_t)descp, GMAC0_DMA_RX_ADDR_LOW_ADDR);
|
||||
writel(0, GMAC0_DMA_RX_ADDR_HIGH_ADDR);
|
||||
|
||||
/* now update the dma last descriptor */
|
||||
writel(last_desc, GMAC0_DMA_RX_PTR_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dma_init(struct eth_dma *dma)
|
||||
{
|
||||
debug(" %s enter\n", __func__);
|
||||
|
||||
/*
|
||||
* Default flags: For backwards compatibility both
|
||||
* Rx Overflow Continue and Parity are DISABLED.
|
||||
*/
|
||||
dma_ctrlflags(DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
|
||||
|
||||
debug("rx burst len 0x%x\n",
|
||||
(readl(GMAC0_DMA_RX_CTRL_ADDR) & D64_RC_BL_MASK)
|
||||
>> D64_RC_BL_SHIFT);
|
||||
debug("tx burst len 0x%x\n",
|
||||
(readl(GMAC0_DMA_TX_CTRL_ADDR) & D64_XC_BL_MASK)
|
||||
>> D64_XC_BL_SHIFT);
|
||||
|
||||
dma_tx_init(dma);
|
||||
dma_rx_init(dma);
|
||||
|
||||
/* From end of chip_init() */
|
||||
/* enable the overflow continue feature and disable parity */
|
||||
dma_ctrlflags(DMA_CTRL_ROC | DMA_CTRL_PEN /* mask */,
|
||||
DMA_CTRL_ROC /* value */);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dma_deinit(struct eth_dma *dma)
|
||||
{
|
||||
debug(" %s enter\n", __func__);
|
||||
|
||||
gmac_disable_dma(dma, MAC_DMA_RX);
|
||||
gmac_disable_dma(dma, MAC_DMA_TX);
|
||||
|
||||
free(dma->tx_buf);
|
||||
dma->tx_buf = NULL;
|
||||
free(dma->tx_desc);
|
||||
dma->tx_desc = NULL;
|
||||
dma->tx_desc_aligned = NULL;
|
||||
|
||||
free(dma->rx_buf);
|
||||
dma->rx_buf = NULL;
|
||||
free(dma->rx_desc);
|
||||
dma->rx_desc = NULL;
|
||||
dma->rx_desc_aligned = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmac_tx_packet(struct eth_dma *dma, void *packet, int length)
|
||||
{
|
||||
uint8_t *bufp = dma->tx_buf + dma->cur_tx_index * TX_BUF_SIZE;
|
||||
|
||||
/* kick off the dma */
|
||||
size_t len = length;
|
||||
int txout = dma->cur_tx_index;
|
||||
uint32_t flags;
|
||||
dma64dd_t *descp = NULL;
|
||||
uint32_t ctrl;
|
||||
uint32_t last_desc = (((uint32_t)dma->tx_desc_aligned) +
|
||||
sizeof(dma64dd_t)) & D64_XP_LD_MASK;
|
||||
size_t buflen;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* load the buffer */
|
||||
memcpy(bufp, packet, len);
|
||||
|
||||
/* Add 4 bytes for Ethernet FCS/CRC */
|
||||
buflen = len + 4;
|
||||
|
||||
ctrl = (buflen & D64_CTRL2_BC_MASK);
|
||||
|
||||
/* the transmit will only be one frame or set SOF, EOF */
|
||||
/* also set int on completion */
|
||||
flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF;
|
||||
|
||||
/* txout points to the descriptor to uset */
|
||||
/* if last descriptor then set EOT */
|
||||
if (txout == (TX_BUF_NUM - 1)) {
|
||||
flags |= D64_CTRL1_EOT;
|
||||
last_desc = ((uint32_t)(dma->tx_desc_aligned)) & D64_XP_LD_MASK;
|
||||
}
|
||||
|
||||
/* write the descriptor */
|
||||
descp = ((dma64dd_t *)(dma->tx_desc_aligned)) + txout;
|
||||
descp->addrlow = (uint32_t)bufp;
|
||||
descp->addrhigh = 0;
|
||||
descp->ctrl1 = flags;
|
||||
descp->ctrl2 = ctrl;
|
||||
|
||||
/* flush descriptor and buffer */
|
||||
flush_dcache_range((unsigned long)descp,
|
||||
(unsigned long)(descp + sizeof(dma64dd_t)));
|
||||
flush_dcache_range((unsigned long)bufp,
|
||||
(unsigned long)(bufp + TX_BUF_SIZE));
|
||||
|
||||
/* now update the dma last descriptor */
|
||||
writel(last_desc, GMAC0_DMA_TX_PTR_ADDR);
|
||||
|
||||
/* tx dma should be enabled so packet should go out */
|
||||
|
||||
/* update txout */
|
||||
dma->cur_tx_index = (txout + 1) & (TX_BUF_NUM - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool gmac_check_tx_done(struct eth_dma *dma)
|
||||
{
|
||||
/* wait for tx to complete */
|
||||
uint32_t intstatus;
|
||||
bool xfrdone = false;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
intstatus = readl(GMAC0_INT_STATUS_ADDR);
|
||||
|
||||
debug("int(0x%x)\n", intstatus);
|
||||
if (intstatus & (I_XI0 | I_XI1 | I_XI2 | I_XI3)) {
|
||||
xfrdone = true;
|
||||
/* clear the int bits */
|
||||
intstatus &= ~(I_XI0 | I_XI1 | I_XI2 | I_XI3);
|
||||
writel(intstatus, GMAC0_INT_STATUS_ADDR);
|
||||
} else {
|
||||
debug("Tx int(0x%x)\n", intstatus);
|
||||
}
|
||||
|
||||
return xfrdone;
|
||||
}
|
||||
|
||||
int gmac_check_rx_done(struct eth_dma *dma, uint8_t *buf)
|
||||
{
|
||||
void *bufp, *datap;
|
||||
size_t rcvlen = 0, buflen = 0;
|
||||
uint32_t stat0 = 0, stat1 = 0;
|
||||
uint32_t control, offset;
|
||||
uint8_t statbuf[HWRXOFF*2];
|
||||
|
||||
int index, curr, active;
|
||||
dma64dd_t *descp = NULL;
|
||||
|
||||
/* udelay(50); */
|
||||
|
||||
/*
|
||||
* this api will check if a packet has been received.
|
||||
* If so it will return the address of the buffer and current
|
||||
* descriptor index will be incremented to the
|
||||
* next descriptor. Once done with the frame the buffer should be
|
||||
* added back onto the descriptor and the lastdscr should be updated
|
||||
* to this descriptor.
|
||||
*/
|
||||
index = dma->cur_rx_index;
|
||||
offset = (uint32_t)(dma->rx_desc_aligned);
|
||||
stat0 = readl(GMAC0_DMA_RX_STATUS0_ADDR) & D64_RS0_CD_MASK;
|
||||
stat1 = readl(GMAC0_DMA_RX_STATUS1_ADDR) & D64_RS0_CD_MASK;
|
||||
curr = ((stat0 - offset) & D64_RS0_CD_MASK) / sizeof(dma64dd_t);
|
||||
active = ((stat1 - offset) & D64_RS0_CD_MASK) / sizeof(dma64dd_t);
|
||||
|
||||
/* check if any frame */
|
||||
if (index == curr)
|
||||
return -1;
|
||||
|
||||
debug("received packet\n");
|
||||
debug("expect(0x%x) curr(0x%x) active(0x%x)\n", index, curr, active);
|
||||
/* remove warning */
|
||||
if (index == active)
|
||||
;
|
||||
|
||||
/* get the packet pointer that corresponds to the rx descriptor */
|
||||
bufp = dma->rx_buf + index * RX_BUF_SIZE;
|
||||
|
||||
descp = (dma64dd_t *)(dma->rx_desc_aligned) + index;
|
||||
/* flush descriptor and buffer */
|
||||
flush_dcache_range((unsigned long)descp,
|
||||
(unsigned long)(descp + sizeof(dma64dd_t)));
|
||||
flush_dcache_range((unsigned long)bufp,
|
||||
(unsigned long)(bufp + RX_BUF_SIZE));
|
||||
|
||||
buflen = (descp->ctrl2 & D64_CTRL2_BC_MASK);
|
||||
|
||||
stat0 = readl(GMAC0_DMA_RX_STATUS0_ADDR);
|
||||
stat1 = readl(GMAC0_DMA_RX_STATUS1_ADDR);
|
||||
|
||||
debug("bufp(0x%x) index(0x%x) buflen(0x%x) stat0(0x%x) stat1(0x%x)\n",
|
||||
(uint32_t)bufp, index, buflen, stat0, stat1);
|
||||
|
||||
dma->cur_rx_index = (index + 1) & (RX_BUF_NUM - 1);
|
||||
|
||||
/* get buffer offset */
|
||||
control = readl(GMAC0_DMA_RX_CTRL_ADDR);
|
||||
offset = (control & D64_RC_RO_MASK) >> D64_RC_RO_SHIFT;
|
||||
rcvlen = *(uint16_t *)bufp;
|
||||
|
||||
debug("Received %d bytes\n", rcvlen);
|
||||
/* copy status into temp buf then copy data from rx buffer */
|
||||
memcpy(statbuf, bufp, offset);
|
||||
datap = (void *)((uint32_t)bufp + offset);
|
||||
memcpy(buf, datap, rcvlen);
|
||||
|
||||
/* update descriptor that is being added back on ring */
|
||||
descp->ctrl2 = RX_BUF_SIZE;
|
||||
descp->addrlow = (uint32_t)bufp;
|
||||
descp->addrhigh = 0;
|
||||
/* flush descriptor */
|
||||
flush_dcache_range((unsigned long)descp,
|
||||
(unsigned long)(descp + sizeof(dma64dd_t)));
|
||||
|
||||
/* set the lastdscr for the rx ring */
|
||||
writel(((uint32_t)descp) & D64_XP_LD_MASK, GMAC0_DMA_RX_PTR_ADDR);
|
||||
|
||||
return (int)rcvlen;
|
||||
}
|
||||
|
||||
static int gmac_disable_dma(struct eth_dma *dma, int dir)
|
||||
{
|
||||
int status;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
if (dir == MAC_DMA_TX) {
|
||||
/* address PR8249/PR7577 issue */
|
||||
/* suspend tx DMA first */
|
||||
writel(D64_XC_SE, GMAC0_DMA_TX_CTRL_ADDR);
|
||||
SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) &
|
||||
D64_XS0_XS_MASK)) !=
|
||||
D64_XS0_XS_DISABLED) &&
|
||||
(status != D64_XS0_XS_IDLE) &&
|
||||
(status != D64_XS0_XS_STOPPED), 10000);
|
||||
|
||||
/*
|
||||
* PR2414 WAR: DMA engines are not disabled until
|
||||
* transfer finishes
|
||||
*/
|
||||
writel(0, GMAC0_DMA_TX_CTRL_ADDR);
|
||||
SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) &
|
||||
D64_XS0_XS_MASK)) !=
|
||||
D64_XS0_XS_DISABLED), 10000);
|
||||
|
||||
/* wait for the last transaction to complete */
|
||||
udelay(2);
|
||||
|
||||
status = (status == D64_XS0_XS_DISABLED);
|
||||
} else {
|
||||
/*
|
||||
* PR2414 WAR: DMA engines are not disabled until
|
||||
* transfer finishes
|
||||
*/
|
||||
writel(0, GMAC0_DMA_RX_CTRL_ADDR);
|
||||
SPINWAIT(((status = (readl(GMAC0_DMA_RX_STATUS0_ADDR) &
|
||||
D64_RS0_RS_MASK)) !=
|
||||
D64_RS0_RS_DISABLED), 10000);
|
||||
|
||||
status = (status == D64_RS0_RS_DISABLED);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int gmac_enable_dma(struct eth_dma *dma, int dir)
|
||||
{
|
||||
uint32_t control;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
if (dir == MAC_DMA_TX) {
|
||||
dma->cur_tx_index = 0;
|
||||
|
||||
/*
|
||||
* These bits 20:18 (burstLen) of control register can be
|
||||
* written but will take effect only if these bits are
|
||||
* valid. So this will not affect previous versions
|
||||
* of the DMA. They will continue to have those bits set to 0.
|
||||
*/
|
||||
control = readl(GMAC0_DMA_TX_CTRL_ADDR);
|
||||
|
||||
control |= D64_XC_XE;
|
||||
if ((g_dmactrlflags & DMA_CTRL_PEN) == 0)
|
||||
control |= D64_XC_PD;
|
||||
|
||||
writel(control, GMAC0_DMA_TX_CTRL_ADDR);
|
||||
|
||||
/* initailize the DMA channel */
|
||||
writel((uint32_t)(dma->tx_desc_aligned),
|
||||
GMAC0_DMA_TX_ADDR_LOW_ADDR);
|
||||
writel(0, GMAC0_DMA_TX_ADDR_HIGH_ADDR);
|
||||
} else {
|
||||
dma->cur_rx_index = 0;
|
||||
|
||||
control = (readl(GMAC0_DMA_RX_CTRL_ADDR) &
|
||||
D64_RC_AE) | D64_RC_RE;
|
||||
|
||||
if ((g_dmactrlflags & DMA_CTRL_PEN) == 0)
|
||||
control |= D64_RC_PD;
|
||||
|
||||
if (g_dmactrlflags & DMA_CTRL_ROC)
|
||||
control |= D64_RC_OC;
|
||||
|
||||
/*
|
||||
* These bits 20:18 (burstLen) of control register can be
|
||||
* written but will take effect only if these bits are
|
||||
* valid. So this will not affect previous versions
|
||||
* of the DMA. They will continue to have those bits set to 0.
|
||||
*/
|
||||
control &= ~D64_RC_BL_MASK;
|
||||
/* Keep default Rx burstlen */
|
||||
control |= readl(GMAC0_DMA_RX_CTRL_ADDR) & D64_RC_BL_MASK;
|
||||
control |= HWRXOFF << D64_RC_RO_SHIFT;
|
||||
|
||||
writel(control, GMAC0_DMA_RX_CTRL_ADDR);
|
||||
|
||||
/*
|
||||
* the rx descriptor ring should have
|
||||
* the addresses set properly;
|
||||
* set the lastdscr for the rx ring
|
||||
*/
|
||||
writel(((uint32_t)(dma->rx_desc_aligned) +
|
||||
(RX_BUF_NUM - 1) * RX_BUF_SIZE) &
|
||||
D64_XP_LD_MASK, GMAC0_DMA_RX_PTR_ADDR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool gmac_mii_busywait(unsigned int timeout)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
|
||||
while (timeout > 10) {
|
||||
tmp = readl(GMAC_MII_CTRL_ADDR);
|
||||
if (tmp & (1 << GMAC_MII_BUSY_SHIFT)) {
|
||||
udelay(10);
|
||||
timeout -= 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tmp & (1 << GMAC_MII_BUSY_SHIFT);
|
||||
}
|
||||
|
||||
int gmac_miiphy_read(const char *devname, unsigned char phyaddr,
|
||||
unsigned char reg, unsigned short *value)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
|
||||
(void)devname;
|
||||
|
||||
/* Busy wait timeout is 1ms */
|
||||
if (gmac_mii_busywait(1000)) {
|
||||
error("%s: Prepare MII read: MII/MDIO busy\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read operation */
|
||||
tmp = GMAC_MII_DATA_READ_CMD;
|
||||
tmp |= (phyaddr << GMAC_MII_PHY_ADDR_SHIFT) |
|
||||
(reg << GMAC_MII_PHY_REG_SHIFT);
|
||||
debug("MII read cmd 0x%x, phy 0x%x, reg 0x%x\n", tmp, phyaddr, reg);
|
||||
writel(tmp, GMAC_MII_DATA_ADDR);
|
||||
|
||||
if (gmac_mii_busywait(1000)) {
|
||||
error("%s: MII read failure: MII/MDIO busy\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*value = readl(GMAC_MII_DATA_ADDR) & 0xffff;
|
||||
debug("MII read data 0x%x\n", *value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmac_miiphy_write(const char *devname, unsigned char phyaddr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
|
||||
(void)devname;
|
||||
|
||||
/* Busy wait timeout is 1ms */
|
||||
if (gmac_mii_busywait(1000)) {
|
||||
error("%s: Prepare MII write: MII/MDIO busy\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write operation */
|
||||
tmp = GMAC_MII_DATA_WRITE_CMD | (value & 0xffff);
|
||||
tmp |= ((phyaddr << GMAC_MII_PHY_ADDR_SHIFT) |
|
||||
(reg << GMAC_MII_PHY_REG_SHIFT));
|
||||
debug("MII write cmd 0x%x, phy 0x%x, reg 0x%x, data 0x%x\n",
|
||||
tmp, phyaddr, reg, value);
|
||||
writel(tmp, GMAC_MII_DATA_ADDR);
|
||||
|
||||
if (gmac_mii_busywait(1000)) {
|
||||
error("%s: MII write failure: MII/MDIO busy\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gmac_init_reset(void)
|
||||
{
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* set command config reg CC_SR */
|
||||
reg32_set_bits(UNIMAC0_CMD_CFG_ADDR, CC_SR);
|
||||
udelay(GMAC_RESET_DELAY);
|
||||
}
|
||||
|
||||
void gmac_clear_reset(void)
|
||||
{
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* clear command config reg CC_SR */
|
||||
reg32_clear_bits(UNIMAC0_CMD_CFG_ADDR, CC_SR);
|
||||
udelay(GMAC_RESET_DELAY);
|
||||
}
|
||||
|
||||
static void gmac_enable_local(bool en)
|
||||
{
|
||||
uint32_t cmdcfg;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* read command config reg */
|
||||
cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
|
||||
|
||||
/* put mac in reset */
|
||||
gmac_init_reset();
|
||||
|
||||
cmdcfg |= CC_SR;
|
||||
|
||||
/* first deassert rx_ena and tx_ena while in reset */
|
||||
cmdcfg &= ~(CC_RE | CC_TE);
|
||||
/* write command config reg */
|
||||
writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
|
||||
|
||||
/* bring mac out of reset */
|
||||
gmac_clear_reset();
|
||||
|
||||
/* if not enable exit now */
|
||||
if (!en)
|
||||
return;
|
||||
|
||||
/* enable the mac transmit and receive paths now */
|
||||
udelay(2);
|
||||
cmdcfg &= ~CC_SR;
|
||||
cmdcfg |= (CC_RE | CC_TE);
|
||||
|
||||
/* assert rx_ena and tx_ena when out of reset to enable the mac */
|
||||
writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int gmac_enable(void)
|
||||
{
|
||||
gmac_enable_local(1);
|
||||
|
||||
/* clear interrupts */
|
||||
writel(I_INTMASK, GMAC0_INT_STATUS_ADDR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmac_disable(void)
|
||||
{
|
||||
gmac_enable_local(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmac_set_speed(int speed, int duplex)
|
||||
{
|
||||
uint32_t cmdcfg;
|
||||
uint32_t hd_ena;
|
||||
uint32_t speed_cfg;
|
||||
|
||||
hd_ena = duplex ? 0 : CC_HD;
|
||||
if (speed == 1000) {
|
||||
speed_cfg = 2;
|
||||
} else if (speed == 100) {
|
||||
speed_cfg = 1;
|
||||
} else if (speed == 10) {
|
||||
speed_cfg = 0;
|
||||
} else {
|
||||
error("%s: Invalid GMAC speed(%d)!\n", __func__, speed);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
|
||||
cmdcfg &= ~(CC_ES_MASK | CC_HD);
|
||||
cmdcfg |= ((speed_cfg << CC_ES_SHIFT) | hd_ena);
|
||||
|
||||
printf("Change GMAC speed to %dMB\n", speed);
|
||||
debug("GMAC speed cfg 0x%x\n", cmdcfg);
|
||||
writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmac_set_mac_addr(unsigned char *mac)
|
||||
{
|
||||
/* set our local address */
|
||||
debug("GMAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
writel(htonl(*(uint32_t *)mac), UNIMAC0_MAC_MSB_ADDR);
|
||||
writew(htons(*(uint32_t *)&mac[4]), UNIMAC0_MAC_LSB_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmac_mac_init(struct eth_device *dev)
|
||||
{
|
||||
struct eth_info *eth = (struct eth_info *)(dev->priv);
|
||||
struct eth_dma *dma = &(eth->dma);
|
||||
|
||||
uint32_t tmp;
|
||||
uint32_t cmdcfg;
|
||||
int chipid;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* Always use GMAC0 */
|
||||
printf("Using GMAC%d\n", 0);
|
||||
|
||||
/* Reset AMAC0 core */
|
||||
writel(0, AMAC0_IDM_RESET_ADDR);
|
||||
tmp = readl(AMAC0_IO_CTRL_DIRECT_ADDR);
|
||||
/* Set clock */
|
||||
tmp &= ~(1 << AMAC0_IO_CTRL_CLK_250_SEL_SHIFT);
|
||||
tmp |= (1 << AMAC0_IO_CTRL_GMII_MODE_SHIFT);
|
||||
/* Set Tx clock */
|
||||
tmp &= ~(1 << AMAC0_IO_CTRL_DEST_SYNC_MODE_EN_SHIFT);
|
||||
writel(tmp, AMAC0_IO_CTRL_DIRECT_ADDR);
|
||||
|
||||
/* reset gmac */
|
||||
/*
|
||||
* As AMAC is just reset, NO need?
|
||||
* set eth_data into loopback mode to ensure no rx traffic
|
||||
* gmac_loopback(eth_data, TRUE);
|
||||
* ET_TRACE(("%s gmac loopback\n", __func__));
|
||||
* udelay(1);
|
||||
*/
|
||||
|
||||
cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
|
||||
cmdcfg &= ~(CC_TE | CC_RE | CC_RPI | CC_TAI | CC_HD | CC_ML |
|
||||
CC_CFE | CC_RL | CC_RED | CC_PE | CC_TPI |
|
||||
CC_PAD_EN | CC_PF);
|
||||
cmdcfg |= (CC_PROM | CC_NLC | CC_CFE);
|
||||
/* put mac in reset */
|
||||
gmac_init_reset();
|
||||
writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
|
||||
gmac_clear_reset();
|
||||
|
||||
/* enable clear MIB on read */
|
||||
reg32_set_bits(GMAC0_DEV_CTRL_ADDR, DC_MROR);
|
||||
/* PHY: set smi_master to drive mdc_clk */
|
||||
reg32_set_bits(GMAC0_PHY_CTRL_ADDR, PC_MTE);
|
||||
|
||||
/* clear persistent sw intstatus */
|
||||
writel(0, GMAC0_INT_STATUS_ADDR);
|
||||
|
||||
if (dma_init(dma) < 0) {
|
||||
error("%s: GMAC dma_init failed\n", __func__);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
chipid = CHIPID;
|
||||
printf("%s: Chip ID: 0x%x\n", __func__, chipid);
|
||||
|
||||
/* set switch bypass mode */
|
||||
tmp = readl(SWITCH_GLOBAL_CONFIG_ADDR);
|
||||
tmp |= (1 << CDRU_SWITCH_BYPASS_SWITCH_SHIFT);
|
||||
|
||||
/* Switch mode */
|
||||
/* tmp &= ~(1 << CDRU_SWITCH_BYPASS_SWITCH_SHIFT); */
|
||||
|
||||
writel(tmp, SWITCH_GLOBAL_CONFIG_ADDR);
|
||||
|
||||
tmp = readl(CRMU_CHIP_IO_PAD_CONTROL_ADDR);
|
||||
tmp &= ~(1 << CDRU_IOMUX_FORCE_PAD_IN_SHIFT);
|
||||
writel(tmp, CRMU_CHIP_IO_PAD_CONTROL_ADDR);
|
||||
|
||||
/* Set MDIO to internal GPHY */
|
||||
tmp = readl(GMAC_MII_CTRL_ADDR);
|
||||
/* Select internal MDC/MDIO bus*/
|
||||
tmp &= ~(1 << GMAC_MII_CTRL_BYP_SHIFT);
|
||||
/* select MDC/MDIO connecting to on-chip internal PHYs */
|
||||
tmp &= ~(1 << GMAC_MII_CTRL_EXT_SHIFT);
|
||||
/*
|
||||
* give bit[6:0](MDCDIV) with required divisor to set
|
||||
* the MDC clock frequency, 66MHZ/0x1A=2.5MHZ
|
||||
*/
|
||||
tmp |= 0x1A;
|
||||
|
||||
writel(tmp, GMAC_MII_CTRL_ADDR);
|
||||
|
||||
if (gmac_mii_busywait(1000)) {
|
||||
error("%s: Configure MDIO: MII/MDIO busy\n", __func__);
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
/* Configure GMAC0 */
|
||||
/* enable one rx interrupt per received frame */
|
||||
writel(1 << GMAC0_IRL_FRAMECOUNT_SHIFT, GMAC0_INTR_RECV_LAZY_ADDR);
|
||||
|
||||
/* read command config reg */
|
||||
cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR);
|
||||
/* enable 802.3x tx flow control (honor received PAUSE frames) */
|
||||
cmdcfg &= ~CC_RPI;
|
||||
/* enable promiscuous mode */
|
||||
cmdcfg |= CC_PROM;
|
||||
/* Disable loopback mode */
|
||||
cmdcfg &= ~CC_ML;
|
||||
/* set the speed */
|
||||
cmdcfg &= ~(CC_ES_MASK | CC_HD);
|
||||
/* Set to 1Gbps and full duplex by default */
|
||||
cmdcfg |= (2 << CC_ES_SHIFT);
|
||||
|
||||
/* put mac in reset */
|
||||
gmac_init_reset();
|
||||
/* write register */
|
||||
writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR);
|
||||
/* bring mac out of reset */
|
||||
gmac_clear_reset();
|
||||
|
||||
/* set max frame lengths; account for possible vlan tag */
|
||||
writel(PKTSIZE + 32, UNIMAC0_FRM_LENGTH_ADDR);
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit:
|
||||
dma_deinit(dma);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gmac_add(struct eth_device *dev)
|
||||
{
|
||||
struct eth_info *eth = (struct eth_info *)(dev->priv);
|
||||
struct eth_dma *dma = &(eth->dma);
|
||||
void *tmp;
|
||||
|
||||
/*
|
||||
* Desc has to be 16-byte aligned ?
|
||||
* If it is 8-byte aligned by malloc, fail Tx
|
||||
*/
|
||||
tmp = malloc(sizeof(dma64dd_t) * TX_BUF_NUM + 8);
|
||||
if (tmp == NULL) {
|
||||
printf("%s: Failed to allocate TX desc Buffer\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dma->tx_desc = (void *)tmp;
|
||||
dma->tx_desc_aligned = (void *)(((uint32_t)tmp) & (~0xf));
|
||||
debug("TX Descriptor Buffer: %p; length: 0x%x\n",
|
||||
dma->tx_desc_aligned, sizeof(dma64dd_t) * TX_BUF_NUM);
|
||||
|
||||
tmp = malloc(TX_BUF_SIZE * TX_BUF_NUM);
|
||||
if (tmp == NULL) {
|
||||
printf("%s: Failed to allocate TX Data Buffer\n", __func__);
|
||||
free(dma->tx_desc);
|
||||
return -1;
|
||||
}
|
||||
dma->tx_buf = (uint8_t *)tmp;
|
||||
debug("TX Data Buffer: %p; length: 0x%x\n",
|
||||
dma->tx_buf, TX_BUF_SIZE * TX_BUF_NUM);
|
||||
|
||||
/* Desc has to be 16-byte aligned ? */
|
||||
tmp = malloc(sizeof(dma64dd_t) * RX_BUF_NUM + 8);
|
||||
if (tmp == NULL) {
|
||||
printf("%s: Failed to allocate RX Descriptor\n", __func__);
|
||||
free(dma->tx_desc);
|
||||
free(dma->tx_buf);
|
||||
return -1;
|
||||
}
|
||||
dma->rx_desc = tmp;
|
||||
dma->rx_desc_aligned = (void *)(((uint32_t)tmp) & (~0xf));
|
||||
debug("RX Descriptor Buffer: %p, length: 0x%x\n",
|
||||
dma->rx_desc_aligned, sizeof(dma64dd_t) * RX_BUF_NUM);
|
||||
|
||||
tmp = malloc(RX_BUF_SIZE * RX_BUF_NUM);
|
||||
if (tmp == NULL) {
|
||||
printf("%s: Failed to allocate RX Data Buffer\n", __func__);
|
||||
free(dma->tx_desc);
|
||||
free(dma->tx_buf);
|
||||
free(dma->rx_desc);
|
||||
return -1;
|
||||
}
|
||||
dma->rx_buf = tmp;
|
||||
debug("RX Data Buffer: %p; length: 0x%x\n",
|
||||
dma->rx_buf, RX_BUF_SIZE * RX_BUF_NUM);
|
||||
|
||||
g_dmactrlflags = 0;
|
||||
|
||||
eth->phy_interface = PHY_INTERFACE_MODE_GMII;
|
||||
|
||||
dma->tx_packet = gmac_tx_packet;
|
||||
dma->check_tx_done = gmac_check_tx_done;
|
||||
|
||||
dma->check_rx_done = gmac_check_rx_done;
|
||||
|
||||
dma->enable_dma = gmac_enable_dma;
|
||||
dma->disable_dma = gmac_disable_dma;
|
||||
|
||||
eth->miiphy_read = gmac_miiphy_read;
|
||||
eth->miiphy_write = gmac_miiphy_write;
|
||||
|
||||
eth->mac_init = gmac_mac_init;
|
||||
eth->disable_mac = gmac_disable;
|
||||
eth->enable_mac = gmac_enable;
|
||||
eth->set_mac_addr = gmac_set_mac_addr;
|
||||
eth->set_mac_speed = gmac_set_speed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
224
sources/uboot-be550/drivers/net/bcm-sf2-eth-gmac.h
Normal file
224
sources/uboot-be550/drivers/net/bcm-sf2-eth-gmac.h
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _BCM_SF2_ETH_GMAC_H_
|
||||
#define _BCM_SF2_ETH_GMAC_H_
|
||||
|
||||
#define BCM_SF2_ETH_MAC_NAME "gmac"
|
||||
|
||||
#ifndef ETHHW_PORT_INT
|
||||
#define ETHHW_PORT_INT 8
|
||||
#endif
|
||||
|
||||
#define GMAC0_REG_BASE 0x18042000
|
||||
#define GMAC0_DEV_CTRL_ADDR GMAC0_REG_BASE
|
||||
#define GMAC0_INT_STATUS_ADDR (GMAC0_REG_BASE + 0x020)
|
||||
#define GMAC0_INTR_RECV_LAZY_ADDR (GMAC0_REG_BASE + 0x100)
|
||||
#define GMAC0_PHY_CTRL_ADDR (GMAC0_REG_BASE + 0x188)
|
||||
|
||||
|
||||
#define GMAC_DMA_PTR_OFFSET 0x04
|
||||
#define GMAC_DMA_ADDR_LOW_OFFSET 0x08
|
||||
#define GMAC_DMA_ADDR_HIGH_OFFSET 0x0c
|
||||
#define GMAC_DMA_STATUS0_OFFSET 0x10
|
||||
#define GMAC_DMA_STATUS1_OFFSET 0x14
|
||||
|
||||
#define GMAC0_DMA_TX_CTRL_ADDR (GMAC0_REG_BASE + 0x200)
|
||||
#define GMAC0_DMA_TX_PTR_ADDR \
|
||||
(GMAC0_DMA_TX_CTRL_ADDR + GMAC_DMA_PTR_OFFSET)
|
||||
#define GMAC0_DMA_TX_ADDR_LOW_ADDR \
|
||||
(GMAC0_DMA_TX_CTRL_ADDR + GMAC_DMA_ADDR_LOW_OFFSET)
|
||||
#define GMAC0_DMA_TX_ADDR_HIGH_ADDR \
|
||||
(GMAC0_DMA_TX_CTRL_ADDR + GMAC_DMA_ADDR_HIGH_OFFSET)
|
||||
#define GMAC0_DMA_TX_STATUS0_ADDR \
|
||||
(GMAC0_DMA_TX_CTRL_ADDR + GMAC_DMA_STATUS0_OFFSET)
|
||||
#define GMAC0_DMA_TX_STATUS1_ADDR \
|
||||
(GMAC0_DMA_TX_CTRL_ADDR + GMAC_DMA_STATUS1_OFFSET)
|
||||
|
||||
#define GMAC0_DMA_RX_CTRL_ADDR (GMAC0_REG_BASE + 0x220)
|
||||
#define GMAC0_DMA_RX_PTR_ADDR \
|
||||
(GMAC0_DMA_RX_CTRL_ADDR + GMAC_DMA_PTR_OFFSET)
|
||||
#define GMAC0_DMA_RX_ADDR_LOW_ADDR \
|
||||
(GMAC0_DMA_RX_CTRL_ADDR + GMAC_DMA_ADDR_LOW_OFFSET)
|
||||
#define GMAC0_DMA_RX_ADDR_HIGH_ADDR \
|
||||
(GMAC0_DMA_RX_CTRL_ADDR + GMAC_DMA_ADDR_HIGH_OFFSET)
|
||||
#define GMAC0_DMA_RX_STATUS0_ADDR \
|
||||
(GMAC0_DMA_RX_CTRL_ADDR + GMAC_DMA_STATUS0_OFFSET)
|
||||
#define GMAC0_DMA_RX_STATUS1_ADDR \
|
||||
(GMAC0_DMA_RX_CTRL_ADDR + GMAC_DMA_STATUS1_OFFSET)
|
||||
|
||||
#define UNIMAC0_CMD_CFG_ADDR (GMAC0_REG_BASE + 0x808)
|
||||
#define UNIMAC0_MAC_MSB_ADDR (GMAC0_REG_BASE + 0x80c)
|
||||
#define UNIMAC0_MAC_LSB_ADDR (GMAC0_REG_BASE + 0x810)
|
||||
#define UNIMAC0_FRM_LENGTH_ADDR (GMAC0_REG_BASE + 0x814)
|
||||
|
||||
#define GMAC0_IRL_FRAMECOUNT_SHIFT 24
|
||||
|
||||
/* transmit channel control */
|
||||
/* transmit enable */
|
||||
#define D64_XC_XE 0x00000001
|
||||
/* transmit suspend request */
|
||||
#define D64_XC_SE 0x00000002
|
||||
/* parity check disable */
|
||||
#define D64_XC_PD 0x00000800
|
||||
/* BurstLen bits */
|
||||
#define D64_XC_BL_MASK 0x001C0000
|
||||
#define D64_XC_BL_SHIFT 18
|
||||
|
||||
/* transmit descriptor table pointer */
|
||||
/* last valid descriptor */
|
||||
#define D64_XP_LD_MASK 0x00001fff
|
||||
|
||||
/* transmit channel status */
|
||||
/* transmit state */
|
||||
#define D64_XS0_XS_MASK 0xf0000000
|
||||
#define D64_XS0_XS_SHIFT 28
|
||||
#define D64_XS0_XS_DISABLED 0x00000000
|
||||
#define D64_XS0_XS_ACTIVE 0x10000000
|
||||
#define D64_XS0_XS_IDLE 0x20000000
|
||||
#define D64_XS0_XS_STOPPED 0x30000000
|
||||
#define D64_XS0_XS_SUSP 0x40000000
|
||||
|
||||
/* receive channel control */
|
||||
/* receive enable */
|
||||
#define D64_RC_RE 0x00000001
|
||||
/* address extension bits */
|
||||
#define D64_RC_AE 0x00030000
|
||||
/* overflow continue */
|
||||
#define D64_RC_OC 0x00000400
|
||||
/* parity check disable */
|
||||
#define D64_RC_PD 0x00000800
|
||||
/* receive frame offset */
|
||||
#define D64_RC_RO_MASK 0x000000fe
|
||||
#define D64_RC_RO_SHIFT 1
|
||||
/* BurstLen bits */
|
||||
#define D64_RC_BL_MASK 0x001C0000
|
||||
#define D64_RC_BL_SHIFT 18
|
||||
|
||||
/* flags for dma controller */
|
||||
/* partity enable */
|
||||
#define DMA_CTRL_PEN (1 << 0)
|
||||
/* rx overflow continue */
|
||||
#define DMA_CTRL_ROC (1 << 1)
|
||||
|
||||
/* receive descriptor table pointer */
|
||||
/* last valid descriptor */
|
||||
#define D64_RP_LD_MASK 0x00001fff
|
||||
|
||||
/* receive channel status */
|
||||
/* current descriptor pointer */
|
||||
#define D64_RS0_CD_MASK 0x00001fff
|
||||
/* receive state */
|
||||
#define D64_RS0_RS_MASK 0xf0000000
|
||||
#define D64_RS0_RS_SHIFT 28
|
||||
#define D64_RS0_RS_DISABLED 0x00000000
|
||||
#define D64_RS0_RS_ACTIVE 0x10000000
|
||||
#define D64_RS0_RS_IDLE 0x20000000
|
||||
#define D64_RS0_RS_STOPPED 0x30000000
|
||||
#define D64_RS0_RS_SUSP 0x40000000
|
||||
|
||||
/* descriptor control flags 1 */
|
||||
/* core specific flags */
|
||||
#define D64_CTRL_COREFLAGS 0x0ff00000
|
||||
/* end of descriptor table */
|
||||
#define D64_CTRL1_EOT ((uint32_t)1 << 28)
|
||||
/* interrupt on completion */
|
||||
#define D64_CTRL1_IOC ((uint32_t)1 << 29)
|
||||
/* end of frame */
|
||||
#define D64_CTRL1_EOF ((uint32_t)1 << 30)
|
||||
/* start of frame */
|
||||
#define D64_CTRL1_SOF ((uint32_t)1 << 31)
|
||||
|
||||
/* descriptor control flags 2 */
|
||||
/* buffer byte count. real data len must <= 16KB */
|
||||
#define D64_CTRL2_BC_MASK 0x00007fff
|
||||
/* address extension bits */
|
||||
#define D64_CTRL2_AE 0x00030000
|
||||
#define D64_CTRL2_AE_SHIFT 16
|
||||
/* parity bit */
|
||||
#define D64_CTRL2_PARITY 0x00040000
|
||||
/* control flags in the range [27:20] are core-specific and not defined here */
|
||||
#define D64_CTRL_CORE_MASK 0x0ff00000
|
||||
|
||||
#define DC_MROR 0x00000010
|
||||
#define PC_MTE 0x00800000
|
||||
|
||||
/* command config */
|
||||
#define CC_TE 0x00000001
|
||||
#define CC_RE 0x00000002
|
||||
#define CC_ES_MASK 0x0000000c
|
||||
#define CC_ES_SHIFT 2
|
||||
#define CC_PROM 0x00000010
|
||||
#define CC_PAD_EN 0x00000020
|
||||
#define CC_CF 0x00000040
|
||||
#define CC_PF 0x00000080
|
||||
#define CC_RPI 0x00000100
|
||||
#define CC_TAI 0x00000200
|
||||
#define CC_HD 0x00000400
|
||||
#define CC_HD_SHIFT 10
|
||||
#define CC_SR 0x00002000
|
||||
#define CC_ML 0x00008000
|
||||
#define CC_AE 0x00400000
|
||||
#define CC_CFE 0x00800000
|
||||
#define CC_NLC 0x01000000
|
||||
#define CC_RL 0x02000000
|
||||
#define CC_RED 0x04000000
|
||||
#define CC_PE 0x08000000
|
||||
#define CC_TPI 0x10000000
|
||||
#define CC_AT 0x20000000
|
||||
|
||||
#define I_PDEE 0x00000400
|
||||
#define I_PDE 0x00000800
|
||||
#define I_DE 0x00001000
|
||||
#define I_RDU 0x00002000
|
||||
#define I_RFO 0x00004000
|
||||
#define I_XFU 0x00008000
|
||||
#define I_RI 0x00010000
|
||||
#define I_XI0 0x01000000
|
||||
#define I_XI1 0x02000000
|
||||
#define I_XI2 0x04000000
|
||||
#define I_XI3 0x08000000
|
||||
#define I_ERRORS (I_PDEE | I_PDE | I_DE | I_RDU | I_RFO | I_XFU)
|
||||
#define DEF_INTMASK (I_XI0 | I_XI1 | I_XI2 | I_XI3 | I_RI | I_ERRORS)
|
||||
|
||||
#define I_INTMASK 0x0f01fcff
|
||||
|
||||
#define CHIP_DRU_BASE 0x0301d000
|
||||
#define CRMU_CHIP_IO_PAD_CONTROL_ADDR (CHIP_DRU_BASE + 0x0bc)
|
||||
#define SWITCH_GLOBAL_CONFIG_ADDR (CHIP_DRU_BASE + 0x194)
|
||||
|
||||
#define CDRU_IOMUX_FORCE_PAD_IN_SHIFT 0
|
||||
#define CDRU_SWITCH_BYPASS_SWITCH_SHIFT 13
|
||||
|
||||
#define AMAC0_IDM_RESET_ADDR 0x18110800
|
||||
#define AMAC0_IO_CTRL_DIRECT_ADDR 0x18110408
|
||||
#define AMAC0_IO_CTRL_CLK_250_SEL_SHIFT 6
|
||||
#define AMAC0_IO_CTRL_GMII_MODE_SHIFT 5
|
||||
#define AMAC0_IO_CTRL_DEST_SYNC_MODE_EN_SHIFT 3
|
||||
|
||||
#define CHIPA_CHIP_ID_ADDR 0x18000000
|
||||
#define CHIPID (readl(CHIPA_CHIP_ID_ADDR) & 0xFFFF)
|
||||
#define CHIPREV (((readl(CHIPA_CHIP_ID_ADDR) >> 16) & 0xF)
|
||||
#define CHIPSKU (((readl(CHIPA_CHIP_ID_ADDR) >> 20) & 0xF)
|
||||
|
||||
#define GMAC_MII_CTRL_ADDR 0x18002000
|
||||
#define GMAC_MII_CTRL_BYP_SHIFT 10
|
||||
#define GMAC_MII_CTRL_EXT_SHIFT 9
|
||||
#define GMAC_MII_DATA_ADDR 0x18002004
|
||||
#define GMAC_MII_DATA_READ_CMD 0x60020000
|
||||
#define GMAC_MII_DATA_WRITE_CMD 0x50020000
|
||||
#define GMAC_MII_BUSY_SHIFT 8
|
||||
#define GMAC_MII_PHY_ADDR_SHIFT 23
|
||||
#define GMAC_MII_PHY_REG_SHIFT 18
|
||||
|
||||
#define GMAC_RESET_DELAY 2
|
||||
#define HWRXOFF 30
|
||||
#define MAXNAMEL 8
|
||||
#define NUMTXQ 4
|
||||
|
||||
int gmac_add(struct eth_device *dev);
|
||||
|
||||
#endif /* _BCM_SF2_ETH_GMAC_H_ */
|
||||
262
sources/uboot-be550/drivers/net/bcm-sf2-eth.c
Normal file
262
sources/uboot-be550/drivers/net/bcm-sf2-eth.c
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <config.h>
|
||||
|
||||
#include <phy.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <netdev.h>
|
||||
#include "bcm-sf2-eth.h"
|
||||
|
||||
#if defined(CONFIG_BCM_SF2_ETH_GMAC)
|
||||
#include "bcm-sf2-eth-gmac.h"
|
||||
#else
|
||||
#error "bcm_sf2_eth: NEED to define a MAC!"
|
||||
#endif
|
||||
|
||||
#define BCM_NET_MODULE_DESCRIPTION "Broadcom Starfighter2 Ethernet driver"
|
||||
#define BCM_NET_MODULE_VERSION "0.1"
|
||||
#define BCM_SF2_ETH_DEV_NAME "bcm_sf2"
|
||||
|
||||
static const char banner[] =
|
||||
BCM_NET_MODULE_DESCRIPTION " " BCM_NET_MODULE_VERSION "\n";
|
||||
|
||||
static int bcm_sf2_eth_init(struct eth_device *dev)
|
||||
{
|
||||
struct eth_info *eth = (struct eth_info *)(dev->priv);
|
||||
struct eth_dma *dma = &(eth->dma);
|
||||
struct phy_device *phydev;
|
||||
int rc = 0;
|
||||
int i;
|
||||
|
||||
rc = eth->mac_init(dev);
|
||||
if (rc) {
|
||||
error("%s: Couldn't cofigure MAC!\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* disable DMA */
|
||||
dma->disable_dma(dma, MAC_DMA_RX);
|
||||
dma->disable_dma(dma, MAC_DMA_TX);
|
||||
|
||||
eth->port_num = 0;
|
||||
debug("Connecting PHY 0...\n");
|
||||
phydev = phy_connect(miiphy_get_dev_by_name(dev->name),
|
||||
0, dev, eth->phy_interface);
|
||||
if (phydev != NULL) {
|
||||
eth->port[0] = phydev;
|
||||
eth->port_num += 1;
|
||||
} else {
|
||||
debug("No PHY found for port 0\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < eth->port_num; i++)
|
||||
phy_config(eth->port[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* u-boot net functions
|
||||
*/
|
||||
|
||||
static int bcm_sf2_eth_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
|
||||
uint8_t *buf = (uint8_t *)packet;
|
||||
int rc = 0;
|
||||
int i = 0;
|
||||
|
||||
debug("%s enter\n", __func__);
|
||||
|
||||
/* load buf and start transmit */
|
||||
rc = dma->tx_packet(dma, buf, length);
|
||||
if (rc) {
|
||||
debug("ERROR - Tx failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
while (!(dma->check_tx_done(dma))) {
|
||||
udelay(100);
|
||||
debug(".");
|
||||
i++;
|
||||
if (i > 20) {
|
||||
error("%s: Tx timeout: retried 20 times\n", __func__);
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s exit rc(0x%x)\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bcm_sf2_eth_receive(struct eth_device *dev)
|
||||
{
|
||||
struct eth_dma *dma = &(((struct eth_info *)(dev->priv))->dma);
|
||||
uint8_t *buf = (uint8_t *)net_rx_packets[0];
|
||||
int rcvlen;
|
||||
int rc = 0;
|
||||
int i = 0;
|
||||
|
||||
while (1) {
|
||||
/* Poll Rx queue to get a packet */
|
||||
rcvlen = dma->check_rx_done(dma, buf);
|
||||
if (rcvlen < 0) {
|
||||
/* No packet received */
|
||||
rc = -1;
|
||||
debug("\nNO More Rx\n");
|
||||
break;
|
||||
} else if ((rcvlen == 0) || (rcvlen > RX_BUF_SIZE)) {
|
||||
error("%s: Wrong Ethernet packet size (%d B), skip!\n",
|
||||
__func__, rcvlen);
|
||||
break;
|
||||
} else {
|
||||
debug("recieved\n");
|
||||
|
||||
/* Forward received packet to uboot network handler */
|
||||
net_process_received_packet(buf, rcvlen);
|
||||
|
||||
if (++i >= PKTBUFSRX)
|
||||
i = 0;
|
||||
buf = net_rx_packets[i];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bcm_sf2_eth_write_hwaddr(struct eth_device *dev)
|
||||
{
|
||||
struct eth_info *eth = (struct eth_info *)(dev->priv);
|
||||
|
||||
printf(" ETH MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
dev->enetaddr[0], dev->enetaddr[1], dev->enetaddr[2],
|
||||
dev->enetaddr[3], dev->enetaddr[4], dev->enetaddr[5]);
|
||||
|
||||
return eth->set_mac_addr(dev->enetaddr);
|
||||
}
|
||||
|
||||
static int bcm_sf2_eth_open(struct eth_device *dev, bd_t *bt)
|
||||
{
|
||||
struct eth_info *eth = (struct eth_info *)(dev->priv);
|
||||
struct eth_dma *dma = &(eth->dma);
|
||||
int i;
|
||||
|
||||
debug("Enabling BCM SF2 Ethernet.\n");
|
||||
|
||||
eth->enable_mac();
|
||||
|
||||
/* enable tx and rx DMA */
|
||||
dma->enable_dma(dma, MAC_DMA_RX);
|
||||
dma->enable_dma(dma, MAC_DMA_TX);
|
||||
|
||||
/*
|
||||
* Need to start PHY here because link speed can change
|
||||
* before each ethernet operation
|
||||
*/
|
||||
for (i = 0; i < eth->port_num; i++) {
|
||||
if (phy_startup(eth->port[i])) {
|
||||
error("%s: PHY %d startup failed!\n", __func__, i);
|
||||
if (i == CONFIG_BCM_SF2_ETH_DEFAULT_PORT) {
|
||||
error("%s: No default port %d!\n", __func__, i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set MAC speed using default port */
|
||||
i = CONFIG_BCM_SF2_ETH_DEFAULT_PORT;
|
||||
debug("PHY %d: speed:%d, duplex:%d, link:%d\n", i,
|
||||
eth->port[i]->speed, eth->port[i]->duplex, eth->port[i]->link);
|
||||
eth->set_mac_speed(eth->port[i]->speed, eth->port[i]->duplex);
|
||||
|
||||
debug("Enable Ethernet Done.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm_sf2_eth_close(struct eth_device *dev)
|
||||
{
|
||||
struct eth_info *eth = (struct eth_info *)(dev->priv);
|
||||
struct eth_dma *dma = &(eth->dma);
|
||||
|
||||
/* disable DMA */
|
||||
dma->disable_dma(dma, MAC_DMA_RX);
|
||||
dma->disable_dma(dma, MAC_DMA_TX);
|
||||
|
||||
eth->disable_mac();
|
||||
}
|
||||
|
||||
int bcm_sf2_eth_register(bd_t *bis, u8 dev_num)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct eth_info *eth;
|
||||
int rc;
|
||||
|
||||
dev = (struct eth_device *)malloc(sizeof(struct eth_device));
|
||||
if (dev == NULL) {
|
||||
error("%s: Not enough memory!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eth = (struct eth_info *)malloc(sizeof(struct eth_info));
|
||||
if (eth == NULL) {
|
||||
error("%s: Not enough memory!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf(banner);
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
sprintf(dev->name, "%s_%s-%hu", BCM_SF2_ETH_DEV_NAME,
|
||||
BCM_SF2_ETH_MAC_NAME, dev_num);
|
||||
|
||||
dev->priv = (void *)eth;
|
||||
dev->iobase = 0;
|
||||
|
||||
dev->init = bcm_sf2_eth_open;
|
||||
dev->halt = bcm_sf2_eth_close;
|
||||
dev->send = bcm_sf2_eth_send;
|
||||
dev->recv = bcm_sf2_eth_receive;
|
||||
dev->write_hwaddr = bcm_sf2_eth_write_hwaddr;
|
||||
|
||||
#ifdef CONFIG_BCM_SF2_ETH_GMAC
|
||||
if (gmac_add(dev)) {
|
||||
free(eth);
|
||||
free(dev);
|
||||
error("%s: Adding GMAC failed!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
#error "bcm_sf2_eth: NEED to register a MAC!"
|
||||
#endif
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
#ifdef CONFIG_CMD_MII
|
||||
miiphy_register(dev->name, eth->miiphy_read, eth->miiphy_write);
|
||||
#endif
|
||||
|
||||
/* Initialization */
|
||||
debug("Ethernet initialization ...");
|
||||
|
||||
rc = bcm_sf2_eth_init(dev);
|
||||
if (rc != 0) {
|
||||
error("%s: configuration failed!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Basic ethernet functionality initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
70
sources/uboot-be550/drivers/net/bcm-sf2-eth.h
Normal file
70
sources/uboot-be550/drivers/net/bcm-sf2-eth.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _BCM_SF2_ETH_H_
|
||||
#define _BCM_SF2_ETH_H_
|
||||
|
||||
#include <phy.h>
|
||||
|
||||
#define RX_BUF_SIZE 2048
|
||||
/* RX_BUF_NUM must be power of 2 */
|
||||
#define RX_BUF_NUM 32
|
||||
|
||||
#define TX_BUF_SIZE 2048
|
||||
/* TX_BUF_NUM must be power of 2 */
|
||||
#define TX_BUF_NUM 2
|
||||
|
||||
/* Support 2 Ethernet ports now */
|
||||
#define BCM_ETH_MAX_PORT_NUM 2
|
||||
|
||||
#define CONFIG_BCM_SF2_ETH_DEFAULT_PORT 0
|
||||
|
||||
enum {
|
||||
MAC_DMA_TX = 1,
|
||||
MAC_DMA_RX = 2
|
||||
};
|
||||
|
||||
struct eth_dma {
|
||||
void *tx_desc_aligned;
|
||||
void *rx_desc_aligned;
|
||||
void *tx_desc;
|
||||
void *rx_desc;
|
||||
|
||||
uint8_t *tx_buf;
|
||||
uint8_t *rx_buf;
|
||||
|
||||
int cur_tx_index;
|
||||
int cur_rx_index;
|
||||
|
||||
int (*tx_packet)(struct eth_dma *dma, void *packet, int length);
|
||||
bool (*check_tx_done)(struct eth_dma *dma);
|
||||
|
||||
int (*check_rx_done)(struct eth_dma *dma, uint8_t *buf);
|
||||
|
||||
int (*enable_dma)(struct eth_dma *dma, int dir);
|
||||
int (*disable_dma)(struct eth_dma *dma, int dir);
|
||||
};
|
||||
|
||||
struct eth_info {
|
||||
struct eth_dma dma;
|
||||
phy_interface_t phy_interface;
|
||||
struct phy_device *port[BCM_ETH_MAX_PORT_NUM];
|
||||
int port_num;
|
||||
|
||||
int (*miiphy_read)(const char *devname, unsigned char phyaddr,
|
||||
unsigned char reg, unsigned short *value);
|
||||
int (*miiphy_write)(const char *devname, unsigned char phyaddr,
|
||||
unsigned char reg, unsigned short value);
|
||||
|
||||
int (*mac_init)(struct eth_device *dev);
|
||||
int (*enable_mac)(void);
|
||||
int (*disable_mac)(void);
|
||||
int (*set_mac_addr)(unsigned char *mac);
|
||||
int (*set_mac_speed)(int speed, int duplex);
|
||||
|
||||
};
|
||||
|
||||
#endif /* _BCM_SF2_ETH_H_ */
|
||||
498
sources/uboot-be550/drivers/net/bfin_mac.c
Normal file
498
sources/uboot-be550/drivers/net/bfin_mac.c
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* Driver for Blackfin On-Chip MAC device
|
||||
*
|
||||
* Copyright (c) 2005-2008 Analog Device, Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <net.h>
|
||||
#include <netdev.h>
|
||||
#include <command.h>
|
||||
#include <malloc.h>
|
||||
#include <miiphy.h>
|
||||
#include <linux/mii.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/portmux.h>
|
||||
#include <asm/mach-common/bits/dma.h>
|
||||
#include <asm/mach-common/bits/emac.h>
|
||||
#include <asm/mach-common/bits/pll.h>
|
||||
|
||||
#include "bfin_mac.h"
|
||||
|
||||
#ifndef CONFIG_PHY_ADDR
|
||||
# define CONFIG_PHY_ADDR 1
|
||||
#endif
|
||||
#ifndef CONFIG_PHY_CLOCK_FREQ
|
||||
# define CONFIG_PHY_CLOCK_FREQ 2500000
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_POST
|
||||
#include <post.h>
|
||||
#endif
|
||||
|
||||
#define RXBUF_BASE_ADDR 0xFF900000
|
||||
#define TXBUF_BASE_ADDR 0xFF800000
|
||||
#define TX_BUF_CNT 1
|
||||
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
static ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT];
|
||||
static ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];
|
||||
static u16 txIdx; /* index of the current RX buffer */
|
||||
static u16 rxIdx; /* index of the current TX buffer */
|
||||
|
||||
/* DMAx_CONFIG values at DMA Restart */
|
||||
static const union {
|
||||
u16 data;
|
||||
ADI_DMA_CONFIG_REG reg;
|
||||
} txdmacfg = {
|
||||
.reg = {
|
||||
.b_DMA_EN = 1, /* enabled */
|
||||
.b_WNR = 0, /* read from memory */
|
||||
.b_WDSIZE = 2, /* wordsize is 32 bits */
|
||||
.b_DMA2D = 0,
|
||||
.b_RESTART = 0,
|
||||
.b_DI_SEL = 0,
|
||||
.b_DI_EN = 0, /* no interrupt */
|
||||
.b_NDSIZE = 5, /* 5 half words is desc size */
|
||||
.b_FLOW = 7 /* large desc flow */
|
||||
},
|
||||
};
|
||||
|
||||
static int bfin_miiphy_wait(void)
|
||||
{
|
||||
/* poll the STABUSY bit */
|
||||
while (bfin_read_EMAC_STAADD() & STABUSY)
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_miiphy_read(const char *devname, uchar addr, uchar reg, ushort *val)
|
||||
{
|
||||
if (bfin_miiphy_wait())
|
||||
return 1;
|
||||
bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STABUSY);
|
||||
if (bfin_miiphy_wait())
|
||||
return 1;
|
||||
*val = bfin_read_EMAC_STADAT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_miiphy_write(const char *devname, uchar addr, uchar reg, ushort val)
|
||||
{
|
||||
if (bfin_miiphy_wait())
|
||||
return 1;
|
||||
bfin_write_EMAC_STADAT(val);
|
||||
bfin_write_EMAC_STAADD(SET_PHYAD(addr) | SET_REGAD(reg) | STAOP | STABUSY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bfin_EMAC_initialize(bd_t *bis)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (dev == NULL)
|
||||
hang();
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
strcpy(dev->name, "bfin_mac");
|
||||
|
||||
dev->iobase = 0;
|
||||
dev->priv = 0;
|
||||
dev->init = bfin_EMAC_init;
|
||||
dev->halt = bfin_EMAC_halt;
|
||||
dev->send = bfin_EMAC_send;
|
||||
dev->recv = bfin_EMAC_recv;
|
||||
dev->write_hwaddr = bfin_EMAC_setup_addr;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
miiphy_register(dev->name, bfin_miiphy_read, bfin_miiphy_write);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
int i;
|
||||
int result = 0;
|
||||
|
||||
if (length <= 0) {
|
||||
printf("Ethernet: bad packet size: %d\n", length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bfin_read_DMA2_IRQ_STATUS() & DMA_ERR) {
|
||||
printf("Ethernet: tx DMA error\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN); ++i) {
|
||||
if (i > TOUT_LOOP) {
|
||||
puts("Ethernet: tx time out\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
txbuf[txIdx]->FrmData->NoBytes = length;
|
||||
memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length);
|
||||
txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData;
|
||||
bfin_write_DMA2_NEXT_DESC_PTR(txbuf[txIdx]->Dma);
|
||||
bfin_write_DMA2_CONFIG(txdmacfg.data);
|
||||
bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
|
||||
|
||||
for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) {
|
||||
if (i > TOUT_LOOP) {
|
||||
puts("Ethernet: tx error\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
result = txbuf[txIdx]->StatusWord;
|
||||
txbuf[txIdx]->StatusWord = 0;
|
||||
if ((txIdx + 1) >= TX_BUF_CNT)
|
||||
txIdx = 0;
|
||||
else
|
||||
txIdx++;
|
||||
out:
|
||||
debug("BFIN EMAC send: length = %d\n", length);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int bfin_EMAC_recv(struct eth_device *dev)
|
||||
{
|
||||
int length = 0;
|
||||
|
||||
for (;;) {
|
||||
if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) {
|
||||
length = -1;
|
||||
break;
|
||||
}
|
||||
if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) {
|
||||
printf("Ethernet: rx dma overrun\n");
|
||||
break;
|
||||
}
|
||||
if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) {
|
||||
printf("Ethernet: rx error\n");
|
||||
break;
|
||||
}
|
||||
length = rxbuf[rxIdx]->StatusWord & 0x000007FF;
|
||||
if (length <= 4) {
|
||||
printf("Ethernet: bad frame\n");
|
||||
break;
|
||||
}
|
||||
|
||||
debug("%s: len = %d\n", __func__, length - 4);
|
||||
|
||||
net_rx_packets[rxIdx] = rxbuf[rxIdx]->FrmData->Dest;
|
||||
net_process_received_packet(net_rx_packets[rxIdx], length - 4);
|
||||
bfin_write_DMA1_IRQ_STATUS(DMA_DONE | DMA_ERR);
|
||||
rxbuf[rxIdx]->StatusWord = 0x00000000;
|
||||
if ((rxIdx + 1) >= PKTBUFSRX)
|
||||
rxIdx = 0;
|
||||
else
|
||||
rxIdx++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* Ethernet Initialization Routine
|
||||
*
|
||||
*************************************************************/
|
||||
|
||||
/* MDC = SCLK / MDC_freq / 2 - 1 */
|
||||
#define MDC_FREQ_TO_DIV(mdc_freq) (get_sclk() / (mdc_freq) / 2 - 1)
|
||||
|
||||
#ifndef CONFIG_BFIN_MAC_PINS
|
||||
# ifdef CONFIG_RMII
|
||||
# define CONFIG_BFIN_MAC_PINS P_RMII0
|
||||
# else
|
||||
# define CONFIG_BFIN_MAC_PINS P_MII0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int bfin_miiphy_init(struct eth_device *dev, int *opmode)
|
||||
{
|
||||
const unsigned short pins[] = CONFIG_BFIN_MAC_PINS;
|
||||
u16 phydat;
|
||||
size_t count;
|
||||
|
||||
/* Enable PHY output */
|
||||
bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
|
||||
|
||||
/* Set all the pins to peripheral mode */
|
||||
peripheral_request_list(pins, "bfin_mac");
|
||||
|
||||
/* Odd word alignment for Receive Frame DMA word */
|
||||
/* Configure checksum support and rcve frame word alignment */
|
||||
bfin_write_EMAC_SYSCTL(RXDWA | RXCKS | SET_MDCDIV(MDC_FREQ_TO_DIV(CONFIG_PHY_CLOCK_FREQ)));
|
||||
|
||||
/* turn on auto-negotiation and wait for link to come up */
|
||||
bfin_miiphy_write(dev->name, CONFIG_PHY_ADDR, MII_BMCR, BMCR_ANENABLE);
|
||||
count = 0;
|
||||
while (1) {
|
||||
++count;
|
||||
if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_BMSR, &phydat))
|
||||
return -1;
|
||||
if (phydat & BMSR_LSTATUS)
|
||||
break;
|
||||
if (count > 30000) {
|
||||
printf("%s: link down, check cable\n", dev->name);
|
||||
return -1;
|
||||
}
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/* see what kind of link we have */
|
||||
if (bfin_miiphy_read(dev->name, CONFIG_PHY_ADDR, MII_LPA, &phydat))
|
||||
return -1;
|
||||
if (phydat & LPA_DUPLEX)
|
||||
*opmode = FDMODE;
|
||||
else
|
||||
*opmode = 0;
|
||||
|
||||
bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
|
||||
bfin_write_EMAC_VLAN1(EMAC_VLANX_DEF_VAL);
|
||||
bfin_write_EMAC_VLAN2(EMAC_VLANX_DEF_VAL);
|
||||
|
||||
/* Initialize the TX DMA channel registers */
|
||||
bfin_write_DMA2_X_COUNT(0);
|
||||
bfin_write_DMA2_X_MODIFY(4);
|
||||
bfin_write_DMA2_Y_COUNT(0);
|
||||
bfin_write_DMA2_Y_MODIFY(0);
|
||||
|
||||
/* Initialize the RX DMA channel registers */
|
||||
bfin_write_DMA1_X_COUNT(0);
|
||||
bfin_write_DMA1_X_MODIFY(4);
|
||||
bfin_write_DMA1_Y_COUNT(0);
|
||||
bfin_write_DMA1_Y_MODIFY(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_EMAC_setup_addr(struct eth_device *dev)
|
||||
{
|
||||
bfin_write_EMAC_ADDRLO(
|
||||
dev->enetaddr[0] |
|
||||
dev->enetaddr[1] << 8 |
|
||||
dev->enetaddr[2] << 16 |
|
||||
dev->enetaddr[3] << 24
|
||||
);
|
||||
bfin_write_EMAC_ADDRHI(
|
||||
dev->enetaddr[4] |
|
||||
dev->enetaddr[5] << 8
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
u32 opmode;
|
||||
int dat;
|
||||
int i;
|
||||
debug("Eth_init: ......\n");
|
||||
|
||||
txIdx = 0;
|
||||
rxIdx = 0;
|
||||
|
||||
/* Initialize System Register */
|
||||
if (bfin_miiphy_init(dev, &dat) < 0)
|
||||
return -1;
|
||||
|
||||
/* Initialize EMAC address */
|
||||
bfin_EMAC_setup_addr(dev);
|
||||
|
||||
/* Initialize TX and RX buffer */
|
||||
for (i = 0; i < PKTBUFSRX; i++) {
|
||||
rxbuf[i] = SetupRxBuffer(i);
|
||||
if (i > 0) {
|
||||
rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = rxbuf[i]->Dma;
|
||||
if (i == (PKTBUFSRX - 1))
|
||||
rxbuf[i]->Dma[1].NEXT_DESC_PTR = rxbuf[0]->Dma;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < TX_BUF_CNT; i++) {
|
||||
txbuf[i] = SetupTxBuffer(i);
|
||||
if (i > 0) {
|
||||
txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = txbuf[i]->Dma;
|
||||
if (i == (TX_BUF_CNT - 1))
|
||||
txbuf[i]->Dma[1].NEXT_DESC_PTR = txbuf[0]->Dma;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set RX DMA */
|
||||
bfin_write_DMA1_NEXT_DESC_PTR(rxbuf[0]->Dma);
|
||||
bfin_write_DMA1_CONFIG(rxbuf[0]->Dma[0].CONFIG_DATA);
|
||||
|
||||
/* Wait MII done */
|
||||
bfin_miiphy_wait();
|
||||
|
||||
/* We enable only RX here */
|
||||
/* ASTP : Enable Automatic Pad Stripping
|
||||
PR : Promiscuous Mode for test
|
||||
PSF : Receive frames with total length less than 64 bytes.
|
||||
FDMODE : Full Duplex Mode
|
||||
LB : Internal Loopback for test
|
||||
RE : Receiver Enable */
|
||||
if (dat == FDMODE)
|
||||
opmode = ASTP | FDMODE | PSF;
|
||||
else
|
||||
opmode = ASTP | PSF;
|
||||
opmode |= RE;
|
||||
#ifdef CONFIG_RMII
|
||||
opmode |= TE | RMII;
|
||||
#endif
|
||||
/* Turn on the EMAC */
|
||||
bfin_write_EMAC_OPMODE(opmode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bfin_EMAC_halt(struct eth_device *dev)
|
||||
{
|
||||
debug("Eth_halt: ......\n");
|
||||
/* Turn off the EMAC */
|
||||
bfin_write_EMAC_OPMODE(0);
|
||||
/* Turn off the EMAC RX DMA */
|
||||
bfin_write_DMA1_CONFIG(0);
|
||||
bfin_write_DMA2_CONFIG(0);
|
||||
}
|
||||
|
||||
ADI_ETHER_BUFFER *SetupRxBuffer(int no)
|
||||
{
|
||||
ADI_ETHER_FRAME_BUFFER *frmbuf;
|
||||
ADI_ETHER_BUFFER *buf;
|
||||
int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */
|
||||
int total_size = nobytes_buffer + RECV_BUFSIZE;
|
||||
|
||||
buf = (void *) (RXBUF_BASE_ADDR + no * total_size);
|
||||
frmbuf = (void *) (RXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
|
||||
|
||||
memset(buf, 0x00, nobytes_buffer);
|
||||
buf->FrmData = frmbuf;
|
||||
memset(frmbuf, 0xfe, RECV_BUFSIZE);
|
||||
|
||||
/* set up first desc to point to receive frame buffer */
|
||||
buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
|
||||
buf->Dma[0].START_ADDR = (u32) buf->FrmData;
|
||||
buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */
|
||||
buf->Dma[0].CONFIG.b_WNR = 1; /* Write to memory */
|
||||
buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
|
||||
buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */
|
||||
buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */
|
||||
|
||||
/* set up second desc to point to status word */
|
||||
buf->Dma[1].NEXT_DESC_PTR = buf->Dma;
|
||||
buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum;
|
||||
buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */
|
||||
buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */
|
||||
buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
|
||||
buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
|
||||
buf->Dma[1].CONFIG.b_NDSIZE = 5; /* must be 0 when FLOW is 0 */
|
||||
buf->Dma[1].CONFIG.b_FLOW = 7; /* stop */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
ADI_ETHER_BUFFER *SetupTxBuffer(int no)
|
||||
{
|
||||
ADI_ETHER_FRAME_BUFFER *frmbuf;
|
||||
ADI_ETHER_BUFFER *buf;
|
||||
int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */
|
||||
int total_size = nobytes_buffer + RECV_BUFSIZE;
|
||||
|
||||
buf = (void *) (TXBUF_BASE_ADDR + no * total_size);
|
||||
frmbuf = (void *) (TXBUF_BASE_ADDR + no * total_size + nobytes_buffer);
|
||||
|
||||
memset(buf, 0x00, nobytes_buffer);
|
||||
buf->FrmData = frmbuf;
|
||||
memset(frmbuf, 0x00, RECV_BUFSIZE);
|
||||
|
||||
/* set up first desc to point to receive frame buffer */
|
||||
buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
|
||||
buf->Dma[0].START_ADDR = (u32) buf->FrmData;
|
||||
buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */
|
||||
buf->Dma[0].CONFIG.b_WNR = 0; /* Read to memory */
|
||||
buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
|
||||
buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */
|
||||
buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */
|
||||
|
||||
/* set up second desc to point to status word */
|
||||
buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
|
||||
buf->Dma[1].START_ADDR = (u32) & buf->StatusWord;
|
||||
buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */
|
||||
buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */
|
||||
buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
|
||||
buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
|
||||
buf->Dma[1].CONFIG.b_NDSIZE = 0; /* must be 0 when FLOW is 0 */
|
||||
buf->Dma[1].CONFIG.b_FLOW = 0; /* stop */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_POST) && defined(CONFIG_SYS_POST_ETHER)
|
||||
int ether_post_test(int flags)
|
||||
{
|
||||
uchar buf[64];
|
||||
int i, value = 0;
|
||||
int length;
|
||||
uint addr;
|
||||
|
||||
printf("\n--------");
|
||||
bfin_EMAC_init(NULL, NULL);
|
||||
/* construct the package */
|
||||
addr = bfin_read_EMAC_ADDRLO();
|
||||
buf[0] = buf[6] = addr;
|
||||
buf[1] = buf[7] = addr >> 8;
|
||||
buf[2] = buf[8] = addr >> 16;
|
||||
buf[3] = buf[9] = addr >> 24;
|
||||
addr = bfin_read_EMAC_ADDRHI();
|
||||
buf[4] = buf[10] = addr;
|
||||
buf[5] = buf[11] = addr >> 8;
|
||||
buf[12] = 0x08; /* Type: ARP */
|
||||
buf[13] = 0x06;
|
||||
buf[14] = 0x00; /* Hardware type: Ethernet */
|
||||
buf[15] = 0x01;
|
||||
buf[16] = 0x08; /* Protocal type: IP */
|
||||
buf[17] = 0x00;
|
||||
buf[18] = 0x06; /* Hardware size */
|
||||
buf[19] = 0x04; /* Protocol size */
|
||||
buf[20] = 0x00; /* Opcode: request */
|
||||
buf[21] = 0x01;
|
||||
|
||||
for (i = 0; i < 42; i++)
|
||||
buf[i + 22] = i;
|
||||
printf("--------Send 64 bytes......\n");
|
||||
bfin_EMAC_send(NULL, buf, 64);
|
||||
for (i = 0; i < 100; i++) {
|
||||
udelay(10000);
|
||||
if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) {
|
||||
value = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value == 0) {
|
||||
printf("--------EMAC can't receive any data\n");
|
||||
eth_halt();
|
||||
return -1;
|
||||
}
|
||||
length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) {
|
||||
printf("--------EMAC receive error data!\n");
|
||||
eth_halt();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
printf("--------receive %d bytes, matched\n", length);
|
||||
bfin_EMAC_halt(NULL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
65
sources/uboot-be550/drivers/net/bfin_mac.h
Normal file
65
sources/uboot-be550/drivers/net/bfin_mac.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* bfin_mac.h - some defines/structures for the Blackfin on-chip MAC.
|
||||
*
|
||||
* Copyright (c) 2005-2008 Analog Device, Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef __BFIN_MAC_H__
|
||||
#define __BFIN_MAC_H__
|
||||
|
||||
#define RECV_BUFSIZE (0x614)
|
||||
|
||||
typedef struct ADI_DMA_CONFIG_REG {
|
||||
u16 b_DMA_EN:1; /* 0 Enabled */
|
||||
u16 b_WNR:1; /* 1 Direction */
|
||||
u16 b_WDSIZE:2; /* 2:3 Transfer word size */
|
||||
u16 b_DMA2D:1; /* 4 DMA mode */
|
||||
u16 b_RESTART:1; /* 5 Retain FIFO */
|
||||
u16 b_DI_SEL:1; /* 6 Data interrupt timing select */
|
||||
u16 b_DI_EN:1; /* 7 Data interrupt enabled */
|
||||
u16 b_NDSIZE:4; /* 8:11 Flex descriptor size */
|
||||
u16 b_FLOW:3; /* 12:14Flow */
|
||||
} ADI_DMA_CONFIG_REG;
|
||||
|
||||
typedef struct adi_ether_frame_buffer {
|
||||
u16 NoBytes; /* the no. of following bytes */
|
||||
u8 Dest[6]; /* destination MAC address */
|
||||
u8 Srce[6]; /* source MAC address */
|
||||
u16 LTfield; /* length/type field */
|
||||
u8 Data[0]; /* payload bytes */
|
||||
} ADI_ETHER_FRAME_BUFFER;
|
||||
/* 16 bytes/struct */
|
||||
|
||||
typedef struct dma_descriptor {
|
||||
struct dma_descriptor *NEXT_DESC_PTR;
|
||||
u32 START_ADDR;
|
||||
union {
|
||||
u16 CONFIG_DATA;
|
||||
ADI_DMA_CONFIG_REG CONFIG;
|
||||
};
|
||||
} DMA_DESCRIPTOR;
|
||||
/* 10 bytes/struct in 12 bytes */
|
||||
|
||||
typedef struct adi_ether_buffer {
|
||||
DMA_DESCRIPTOR Dma[2]; /* first for the frame, second for the status */
|
||||
ADI_ETHER_FRAME_BUFFER *FrmData;/* pointer to data */
|
||||
struct adi_ether_buffer *pNext; /* next buffer */
|
||||
struct adi_ether_buffer *pPrev; /* prev buffer */
|
||||
u16 IPHdrChksum; /* the IP header checksum */
|
||||
u16 IPPayloadChksum; /* the IP header and payload checksum */
|
||||
volatile u32 StatusWord; /* the frame status word */
|
||||
} ADI_ETHER_BUFFER;
|
||||
/* 40 bytes/struct in 44 bytes */
|
||||
|
||||
static ADI_ETHER_BUFFER *SetupRxBuffer(int no);
|
||||
static ADI_ETHER_BUFFER *SetupTxBuffer(int no);
|
||||
|
||||
static int bfin_EMAC_init(struct eth_device *dev, bd_t *bd);
|
||||
static void bfin_EMAC_halt(struct eth_device *dev);
|
||||
static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length);
|
||||
static int bfin_EMAC_recv(struct eth_device *dev);
|
||||
static int bfin_EMAC_setup_addr(struct eth_device *dev);
|
||||
|
||||
#endif
|
||||
544
sources/uboot-be550/drivers/net/calxedaxgmac.c
Normal file
544
sources/uboot-be550/drivers/net/calxedaxgmac.c
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
/*
|
||||
* Copyright 2010-2011 Calxeda, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define TX_NUM_DESC 1
|
||||
#define RX_NUM_DESC 32
|
||||
|
||||
#define MAC_TIMEOUT (5*CONFIG_SYS_HZ)
|
||||
|
||||
#define ETH_BUF_SZ 2048
|
||||
#define TX_BUF_SZ (ETH_BUF_SZ * TX_NUM_DESC)
|
||||
#define RX_BUF_SZ (ETH_BUF_SZ * RX_NUM_DESC)
|
||||
|
||||
#define RXSTART 0x00000002
|
||||
#define TXSTART 0x00002000
|
||||
|
||||
#define RXENABLE 0x00000004
|
||||
#define TXENABLE 0x00000008
|
||||
|
||||
#define XGMAC_CONTROL_SPD 0x40000000
|
||||
#define XGMAC_CONTROL_SPD_MASK 0x60000000
|
||||
#define XGMAC_CONTROL_SARC 0x10000000
|
||||
#define XGMAC_CONTROL_SARK_MASK 0x18000000
|
||||
#define XGMAC_CONTROL_CAR 0x04000000
|
||||
#define XGMAC_CONTROL_CAR_MASK 0x06000000
|
||||
#define XGMAC_CONTROL_CAR_SHIFT 25
|
||||
#define XGMAC_CONTROL_DP 0x01000000
|
||||
#define XGMAC_CONTROL_WD 0x00800000
|
||||
#define XGMAC_CONTROL_JD 0x00400000
|
||||
#define XGMAC_CONTROL_JE 0x00100000
|
||||
#define XGMAC_CONTROL_LM 0x00001000
|
||||
#define XGMAC_CONTROL_IPC 0x00000400
|
||||
#define XGMAC_CONTROL_ACS 0x00000080
|
||||
#define XGMAC_CONTROL_DDIC 0x00000010
|
||||
#define XGMAC_CONTROL_TE 0x00000008
|
||||
#define XGMAC_CONTROL_RE 0x00000004
|
||||
|
||||
#define XGMAC_DMA_BUSMODE_RESET 0x00000001
|
||||
#define XGMAC_DMA_BUSMODE_DSL 0x00000004
|
||||
#define XGMAC_DMA_BUSMODE_DSL_MASK 0x0000007c
|
||||
#define XGMAC_DMA_BUSMODE_DSL_SHIFT 2
|
||||
#define XGMAC_DMA_BUSMODE_ATDS 0x00000080
|
||||
#define XGMAC_DMA_BUSMODE_PBL_MASK 0x00003f00
|
||||
#define XGMAC_DMA_BUSMODE_PBL_SHIFT 8
|
||||
#define XGMAC_DMA_BUSMODE_FB 0x00010000
|
||||
#define XGMAC_DMA_BUSMODE_USP 0x00800000
|
||||
#define XGMAC_DMA_BUSMODE_8PBL 0x01000000
|
||||
#define XGMAC_DMA_BUSMODE_AAL 0x02000000
|
||||
|
||||
#define XGMAC_DMA_AXIMODE_ENLPI 0x80000000
|
||||
#define XGMAC_DMA_AXIMODE_MGK 0x40000000
|
||||
#define XGMAC_DMA_AXIMODE_WROSR 0x00100000
|
||||
#define XGMAC_DMA_AXIMODE_WROSR_MASK 0x00F00000
|
||||
#define XGMAC_DMA_AXIMODE_WROSR_SHIFT 20
|
||||
#define XGMAC_DMA_AXIMODE_RDOSR 0x00010000
|
||||
#define XGMAC_DMA_AXIMODE_RDOSR_MASK 0x000F0000
|
||||
#define XGMAC_DMA_AXIMODE_RDOSR_SHIFT 16
|
||||
#define XGMAC_DMA_AXIMODE_AAL 0x00001000
|
||||
#define XGMAC_DMA_AXIMODE_BLEN256 0x00000080
|
||||
#define XGMAC_DMA_AXIMODE_BLEN128 0x00000040
|
||||
#define XGMAC_DMA_AXIMODE_BLEN64 0x00000020
|
||||
#define XGMAC_DMA_AXIMODE_BLEN32 0x00000010
|
||||
#define XGMAC_DMA_AXIMODE_BLEN16 0x00000008
|
||||
#define XGMAC_DMA_AXIMODE_BLEN8 0x00000004
|
||||
#define XGMAC_DMA_AXIMODE_BLEN4 0x00000002
|
||||
#define XGMAC_DMA_AXIMODE_UNDEF 0x00000001
|
||||
|
||||
#define XGMAC_CORE_OMR_RTC_SHIFT 3
|
||||
#define XGMAC_CORE_OMR_RTC_MASK 0x00000018
|
||||
#define XGMAC_CORE_OMR_RTC 0x00000010
|
||||
#define XGMAC_CORE_OMR_RSF 0x00000020
|
||||
#define XGMAC_CORE_OMR_DT 0x00000040
|
||||
#define XGMAC_CORE_OMR_FEF 0x00000080
|
||||
#define XGMAC_CORE_OMR_EFC 0x00000100
|
||||
#define XGMAC_CORE_OMR_RFA_SHIFT 9
|
||||
#define XGMAC_CORE_OMR_RFA_MASK 0x00000E00
|
||||
#define XGMAC_CORE_OMR_RFD_SHIFT 12
|
||||
#define XGMAC_CORE_OMR_RFD_MASK 0x00007000
|
||||
#define XGMAC_CORE_OMR_TTC_SHIFT 16
|
||||
#define XGMAC_CORE_OMR_TTC_MASK 0x00030000
|
||||
#define XGMAC_CORE_OMR_TTC 0x00020000
|
||||
#define XGMAC_CORE_OMR_FTF 0x00100000
|
||||
#define XGMAC_CORE_OMR_TSF 0x00200000
|
||||
|
||||
#define FIFO_MINUS_1K 0x0
|
||||
#define FIFO_MINUS_2K 0x1
|
||||
#define FIFO_MINUS_3K 0x2
|
||||
#define FIFO_MINUS_4K 0x3
|
||||
#define FIFO_MINUS_6K 0x4
|
||||
#define FIFO_MINUS_8K 0x5
|
||||
#define FIFO_MINUS_12K 0x6
|
||||
#define FIFO_MINUS_16K 0x7
|
||||
|
||||
#define XGMAC_CORE_FLOW_PT_SHIFT 16
|
||||
#define XGMAC_CORE_FLOW_PT_MASK 0xFFFF0000
|
||||
#define XGMAC_CORE_FLOW_PT 0x00010000
|
||||
#define XGMAC_CORE_FLOW_DZQP 0x00000080
|
||||
#define XGMAC_CORE_FLOW_PLT_SHIFT 4
|
||||
#define XGMAC_CORE_FLOW_PLT_MASK 0x00000030
|
||||
#define XGMAC_CORE_FLOW_PLT 0x00000010
|
||||
#define XGMAC_CORE_FLOW_UP 0x00000008
|
||||
#define XGMAC_CORE_FLOW_RFE 0x00000004
|
||||
#define XGMAC_CORE_FLOW_TFE 0x00000002
|
||||
#define XGMAC_CORE_FLOW_FCB 0x00000001
|
||||
|
||||
/* XGMAC Descriptor Defines */
|
||||
#define MAX_DESC_BUF_SZ (0x2000 - 8)
|
||||
|
||||
#define RXDESC_EXT_STATUS 0x00000001
|
||||
#define RXDESC_CRC_ERR 0x00000002
|
||||
#define RXDESC_RX_ERR 0x00000008
|
||||
#define RXDESC_RX_WDOG 0x00000010
|
||||
#define RXDESC_FRAME_TYPE 0x00000020
|
||||
#define RXDESC_GIANT_FRAME 0x00000080
|
||||
#define RXDESC_LAST_SEG 0x00000100
|
||||
#define RXDESC_FIRST_SEG 0x00000200
|
||||
#define RXDESC_VLAN_FRAME 0x00000400
|
||||
#define RXDESC_OVERFLOW_ERR 0x00000800
|
||||
#define RXDESC_LENGTH_ERR 0x00001000
|
||||
#define RXDESC_SA_FILTER_FAIL 0x00002000
|
||||
#define RXDESC_DESCRIPTOR_ERR 0x00004000
|
||||
#define RXDESC_ERROR_SUMMARY 0x00008000
|
||||
#define RXDESC_FRAME_LEN_OFFSET 16
|
||||
#define RXDESC_FRAME_LEN_MASK 0x3fff0000
|
||||
#define RXDESC_DA_FILTER_FAIL 0x40000000
|
||||
|
||||
#define RXDESC1_END_RING 0x00008000
|
||||
|
||||
#define RXDESC_IP_PAYLOAD_MASK 0x00000003
|
||||
#define RXDESC_IP_PAYLOAD_UDP 0x00000001
|
||||
#define RXDESC_IP_PAYLOAD_TCP 0x00000002
|
||||
#define RXDESC_IP_PAYLOAD_ICMP 0x00000003
|
||||
#define RXDESC_IP_HEADER_ERR 0x00000008
|
||||
#define RXDESC_IP_PAYLOAD_ERR 0x00000010
|
||||
#define RXDESC_IPV4_PACKET 0x00000040
|
||||
#define RXDESC_IPV6_PACKET 0x00000080
|
||||
#define TXDESC_UNDERFLOW_ERR 0x00000001
|
||||
#define TXDESC_JABBER_TIMEOUT 0x00000002
|
||||
#define TXDESC_LOCAL_FAULT 0x00000004
|
||||
#define TXDESC_REMOTE_FAULT 0x00000008
|
||||
#define TXDESC_VLAN_FRAME 0x00000010
|
||||
#define TXDESC_FRAME_FLUSHED 0x00000020
|
||||
#define TXDESC_IP_HEADER_ERR 0x00000040
|
||||
#define TXDESC_PAYLOAD_CSUM_ERR 0x00000080
|
||||
#define TXDESC_ERROR_SUMMARY 0x00008000
|
||||
#define TXDESC_SA_CTRL_INSERT 0x00040000
|
||||
#define TXDESC_SA_CTRL_REPLACE 0x00080000
|
||||
#define TXDESC_2ND_ADDR_CHAINED 0x00100000
|
||||
#define TXDESC_END_RING 0x00200000
|
||||
#define TXDESC_CSUM_IP 0x00400000
|
||||
#define TXDESC_CSUM_IP_PAYLD 0x00800000
|
||||
#define TXDESC_CSUM_ALL 0x00C00000
|
||||
#define TXDESC_CRC_EN_REPLACE 0x01000000
|
||||
#define TXDESC_CRC_EN_APPEND 0x02000000
|
||||
#define TXDESC_DISABLE_PAD 0x04000000
|
||||
#define TXDESC_FIRST_SEG 0x10000000
|
||||
#define TXDESC_LAST_SEG 0x20000000
|
||||
#define TXDESC_INTERRUPT 0x40000000
|
||||
|
||||
#define DESC_OWN 0x80000000
|
||||
#define DESC_BUFFER1_SZ_MASK 0x00001fff
|
||||
#define DESC_BUFFER2_SZ_MASK 0x1fff0000
|
||||
#define DESC_BUFFER2_SZ_OFFSET 16
|
||||
|
||||
struct xgmac_regs {
|
||||
u32 config;
|
||||
u32 framefilter;
|
||||
u32 resv_1[4];
|
||||
u32 flow_control;
|
||||
u32 vlantag;
|
||||
u32 version;
|
||||
u32 vlaninclude;
|
||||
u32 resv_2[2];
|
||||
u32 pacestretch;
|
||||
u32 vlanhash;
|
||||
u32 resv_3;
|
||||
u32 intreg;
|
||||
struct {
|
||||
u32 hi; /* 0x40 */
|
||||
u32 lo; /* 0x44 */
|
||||
} macaddr[16];
|
||||
u32 resv_4[0xd0];
|
||||
u32 core_opmode; /* 0x400 */
|
||||
u32 resv_5[0x2bf];
|
||||
u32 busmode; /* 0xf00 */
|
||||
u32 txpoll;
|
||||
u32 rxpoll;
|
||||
u32 rxdesclist;
|
||||
u32 txdesclist;
|
||||
u32 dma_status;
|
||||
u32 dma_opmode;
|
||||
u32 intenable;
|
||||
u32 resv_6[2];
|
||||
u32 axi_mode; /* 0xf28 */
|
||||
};
|
||||
|
||||
struct xgmac_dma_desc {
|
||||
__le32 flags;
|
||||
__le32 buf_size;
|
||||
__le32 buf1_addr; /* Buffer 1 Address Pointer */
|
||||
__le32 buf2_addr; /* Buffer 2 Address Pointer */
|
||||
__le32 ext_status;
|
||||
__le32 res[3];
|
||||
};
|
||||
|
||||
/* XGMAC Descriptor Access Helpers */
|
||||
static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz)
|
||||
{
|
||||
if (buf_sz > MAX_DESC_BUF_SZ)
|
||||
p->buf_size = cpu_to_le32(MAX_DESC_BUF_SZ |
|
||||
(buf_sz - MAX_DESC_BUF_SZ) << DESC_BUFFER2_SZ_OFFSET);
|
||||
else
|
||||
p->buf_size = cpu_to_le32(buf_sz);
|
||||
}
|
||||
|
||||
static inline int desc_get_buf_len(struct xgmac_dma_desc *p)
|
||||
{
|
||||
u32 len = le32_to_cpu(p->buf_size);
|
||||
return (len & DESC_BUFFER1_SZ_MASK) +
|
||||
((len & DESC_BUFFER2_SZ_MASK) >> DESC_BUFFER2_SZ_OFFSET);
|
||||
}
|
||||
|
||||
static inline void desc_init_rx_desc(struct xgmac_dma_desc *p, int ring_size,
|
||||
int buf_sz)
|
||||
{
|
||||
struct xgmac_dma_desc *end = p + ring_size - 1;
|
||||
|
||||
memset(p, 0, sizeof(*p) * ring_size);
|
||||
|
||||
for (; p <= end; p++)
|
||||
desc_set_buf_len(p, buf_sz);
|
||||
|
||||
end->buf_size |= cpu_to_le32(RXDESC1_END_RING);
|
||||
}
|
||||
|
||||
static inline void desc_init_tx_desc(struct xgmac_dma_desc *p, u32 ring_size)
|
||||
{
|
||||
memset(p, 0, sizeof(*p) * ring_size);
|
||||
p[ring_size - 1].flags = cpu_to_le32(TXDESC_END_RING);
|
||||
}
|
||||
|
||||
static inline int desc_get_owner(struct xgmac_dma_desc *p)
|
||||
{
|
||||
return le32_to_cpu(p->flags) & DESC_OWN;
|
||||
}
|
||||
|
||||
static inline void desc_set_rx_owner(struct xgmac_dma_desc *p)
|
||||
{
|
||||
/* Clear all fields and set the owner */
|
||||
p->flags = cpu_to_le32(DESC_OWN);
|
||||
}
|
||||
|
||||
static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags)
|
||||
{
|
||||
u32 tmpflags = le32_to_cpu(p->flags);
|
||||
tmpflags &= TXDESC_END_RING;
|
||||
tmpflags |= flags | DESC_OWN;
|
||||
p->flags = cpu_to_le32(tmpflags);
|
||||
}
|
||||
|
||||
static inline void *desc_get_buf_addr(struct xgmac_dma_desc *p)
|
||||
{
|
||||
return (void *)le32_to_cpu(p->buf1_addr);
|
||||
}
|
||||
|
||||
static inline void desc_set_buf_addr(struct xgmac_dma_desc *p,
|
||||
void *paddr, int len)
|
||||
{
|
||||
p->buf1_addr = cpu_to_le32(paddr);
|
||||
if (len > MAX_DESC_BUF_SZ)
|
||||
p->buf2_addr = cpu_to_le32(paddr + MAX_DESC_BUF_SZ);
|
||||
}
|
||||
|
||||
static inline void desc_set_buf_addr_and_size(struct xgmac_dma_desc *p,
|
||||
void *paddr, int len)
|
||||
{
|
||||
desc_set_buf_len(p, len);
|
||||
desc_set_buf_addr(p, paddr, len);
|
||||
}
|
||||
|
||||
static inline int desc_get_rx_frame_len(struct xgmac_dma_desc *p)
|
||||
{
|
||||
u32 data = le32_to_cpu(p->flags);
|
||||
u32 len = (data & RXDESC_FRAME_LEN_MASK) >> RXDESC_FRAME_LEN_OFFSET;
|
||||
if (data & RXDESC_FRAME_TYPE)
|
||||
len -= 4;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct calxeda_eth_dev {
|
||||
struct xgmac_dma_desc rx_chain[RX_NUM_DESC];
|
||||
struct xgmac_dma_desc tx_chain[TX_NUM_DESC];
|
||||
char rxbuffer[RX_BUF_SZ];
|
||||
|
||||
u32 tx_currdesc;
|
||||
u32 rx_currdesc;
|
||||
|
||||
struct eth_device *dev;
|
||||
} __aligned(32);
|
||||
|
||||
/*
|
||||
* Initialize a descriptor ring. Calxeda XGMAC is configured to use
|
||||
* advanced descriptors.
|
||||
*/
|
||||
|
||||
static void init_rx_desc(struct calxeda_eth_dev *priv)
|
||||
{
|
||||
struct xgmac_dma_desc *rxdesc = priv->rx_chain;
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)priv->dev->iobase;
|
||||
void *rxbuffer = priv->rxbuffer;
|
||||
int i;
|
||||
|
||||
desc_init_rx_desc(rxdesc, RX_NUM_DESC, ETH_BUF_SZ);
|
||||
writel((ulong)rxdesc, ®s->rxdesclist);
|
||||
|
||||
for (i = 0; i < RX_NUM_DESC; i++) {
|
||||
desc_set_buf_addr(rxdesc + i, rxbuffer + (i * ETH_BUF_SZ),
|
||||
ETH_BUF_SZ);
|
||||
desc_set_rx_owner(rxdesc + i);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_tx_desc(struct calxeda_eth_dev *priv)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)priv->dev->iobase;
|
||||
|
||||
desc_init_tx_desc(priv->tx_chain, TX_NUM_DESC);
|
||||
writel((ulong)priv->tx_chain, ®s->txdesclist);
|
||||
}
|
||||
|
||||
static int xgmac_reset(struct eth_device *dev)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
|
||||
int timeout = MAC_TIMEOUT;
|
||||
u32 value;
|
||||
|
||||
value = readl(®s->config) & XGMAC_CONTROL_SPD_MASK;
|
||||
|
||||
writel(XGMAC_DMA_BUSMODE_RESET, ®s->busmode);
|
||||
while ((timeout-- >= 0) &&
|
||||
(readl(®s->busmode) & XGMAC_DMA_BUSMODE_RESET))
|
||||
udelay(1);
|
||||
|
||||
writel(value, ®s->config);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
static void xgmac_hwmacaddr(struct eth_device *dev)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
|
||||
u32 macaddr[2];
|
||||
|
||||
memcpy(macaddr, dev->enetaddr, 6);
|
||||
writel(macaddr[1], ®s->macaddr[0].hi);
|
||||
writel(macaddr[0], ®s->macaddr[0].lo);
|
||||
}
|
||||
|
||||
static int xgmac_init(struct eth_device *dev, bd_t * bis)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
|
||||
struct calxeda_eth_dev *priv = dev->priv;
|
||||
int value;
|
||||
|
||||
if (xgmac_reset(dev) < 0)
|
||||
return -1;
|
||||
|
||||
/* set the hardware MAC address */
|
||||
xgmac_hwmacaddr(dev);
|
||||
|
||||
/* set the AXI bus modes */
|
||||
value = XGMAC_DMA_BUSMODE_ATDS |
|
||||
(16 << XGMAC_DMA_BUSMODE_PBL_SHIFT) |
|
||||
XGMAC_DMA_BUSMODE_FB | XGMAC_DMA_BUSMODE_AAL;
|
||||
writel(value, ®s->busmode);
|
||||
|
||||
value = XGMAC_DMA_AXIMODE_AAL | XGMAC_DMA_AXIMODE_BLEN16 |
|
||||
XGMAC_DMA_AXIMODE_BLEN8 | XGMAC_DMA_AXIMODE_BLEN4;
|
||||
writel(value, ®s->axi_mode);
|
||||
|
||||
/* set flow control parameters and store and forward mode */
|
||||
value = (FIFO_MINUS_12K << XGMAC_CORE_OMR_RFD_SHIFT) |
|
||||
(FIFO_MINUS_4K << XGMAC_CORE_OMR_RFA_SHIFT) |
|
||||
XGMAC_CORE_OMR_EFC | XGMAC_CORE_OMR_TSF;
|
||||
writel(value, ®s->core_opmode);
|
||||
|
||||
/* enable pause frames */
|
||||
value = (1024 << XGMAC_CORE_FLOW_PT_SHIFT) |
|
||||
(1 << XGMAC_CORE_FLOW_PLT_SHIFT) |
|
||||
XGMAC_CORE_FLOW_UP | XGMAC_CORE_FLOW_RFE | XGMAC_CORE_FLOW_TFE;
|
||||
writel(value, ®s->flow_control);
|
||||
|
||||
/* Initialize the descriptor chains */
|
||||
init_rx_desc(priv);
|
||||
init_tx_desc(priv);
|
||||
|
||||
/* must set to 0, or when started up will cause issues */
|
||||
priv->tx_currdesc = 0;
|
||||
priv->rx_currdesc = 0;
|
||||
|
||||
/* set default core values */
|
||||
value = readl(®s->config);
|
||||
value &= XGMAC_CONTROL_SPD_MASK;
|
||||
value |= XGMAC_CONTROL_DDIC | XGMAC_CONTROL_ACS |
|
||||
XGMAC_CONTROL_IPC | XGMAC_CONTROL_CAR;
|
||||
|
||||
/* Everything is ready enable both mac and DMA */
|
||||
value |= RXENABLE | TXENABLE;
|
||||
writel(value, ®s->config);
|
||||
|
||||
value = readl(®s->dma_opmode);
|
||||
value |= RXSTART | TXSTART;
|
||||
writel(value, ®s->dma_opmode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgmac_tx(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
|
||||
struct calxeda_eth_dev *priv = dev->priv;
|
||||
u32 currdesc = priv->tx_currdesc;
|
||||
struct xgmac_dma_desc *txdesc = &priv->tx_chain[currdesc];
|
||||
int timeout;
|
||||
|
||||
desc_set_buf_addr_and_size(txdesc, packet, length);
|
||||
desc_set_tx_owner(txdesc, TXDESC_FIRST_SEG |
|
||||
TXDESC_LAST_SEG | TXDESC_CRC_EN_APPEND);
|
||||
|
||||
/* write poll demand */
|
||||
writel(1, ®s->txpoll);
|
||||
|
||||
timeout = 1000000;
|
||||
while (desc_get_owner(txdesc)) {
|
||||
if (timeout-- < 0) {
|
||||
printf("xgmac: TX timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
priv->tx_currdesc = (currdesc + 1) & (TX_NUM_DESC - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xgmac_rx(struct eth_device *dev)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
|
||||
struct calxeda_eth_dev *priv = dev->priv;
|
||||
u32 currdesc = priv->rx_currdesc;
|
||||
struct xgmac_dma_desc *rxdesc = &priv->rx_chain[currdesc];
|
||||
int length = 0;
|
||||
|
||||
/* check if the host has the desc */
|
||||
if (desc_get_owner(rxdesc))
|
||||
return -1; /* something bad happened */
|
||||
|
||||
length = desc_get_rx_frame_len(rxdesc);
|
||||
|
||||
net_process_received_packet(desc_get_buf_addr(rxdesc), length);
|
||||
|
||||
/* set descriptor back to owned by XGMAC */
|
||||
desc_set_rx_owner(rxdesc);
|
||||
writel(1, ®s->rxpoll);
|
||||
|
||||
priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static void xgmac_halt(struct eth_device *dev)
|
||||
{
|
||||
struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
|
||||
struct calxeda_eth_dev *priv = dev->priv;
|
||||
int value;
|
||||
|
||||
/* Disable TX/RX */
|
||||
value = readl(®s->config);
|
||||
value &= ~(RXENABLE | TXENABLE);
|
||||
writel(value, ®s->config);
|
||||
|
||||
/* Disable DMA */
|
||||
value = readl(®s->dma_opmode);
|
||||
value &= ~(RXSTART | TXSTART);
|
||||
writel(value, ®s->dma_opmode);
|
||||
|
||||
/* must set to 0, or when started up will cause issues */
|
||||
priv->tx_currdesc = 0;
|
||||
priv->rx_currdesc = 0;
|
||||
}
|
||||
|
||||
int calxedaxgmac_initialize(u32 id, ulong base_addr)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct calxeda_eth_dev *priv;
|
||||
struct xgmac_regs *regs;
|
||||
u32 macaddr[2];
|
||||
|
||||
regs = (struct xgmac_regs *)base_addr;
|
||||
|
||||
/* check hardware version */
|
||||
if (readl(®s->version) != 0x1012)
|
||||
return -1;
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev)
|
||||
return 0;
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
/* Structure must be aligned, because it contains the descriptors */
|
||||
priv = memalign(32, sizeof(*priv));
|
||||
if (!priv) {
|
||||
free(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->iobase = (int)base_addr;
|
||||
dev->priv = priv;
|
||||
priv->dev = dev;
|
||||
sprintf(dev->name, "xgmac%d", id);
|
||||
|
||||
/* The MAC address is already configured, so read it from registers. */
|
||||
macaddr[1] = readl(®s->macaddr[0].hi);
|
||||
macaddr[0] = readl(®s->macaddr[0].lo);
|
||||
memcpy(dev->enetaddr, macaddr, 6);
|
||||
|
||||
dev->init = xgmac_init;
|
||||
dev->send = xgmac_tx;
|
||||
dev->recv = xgmac_rx;
|
||||
dev->halt = xgmac_halt;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
1294
sources/uboot-be550/drivers/net/cpsw.c
Normal file
1294
sources/uboot-be550/drivers/net/cpsw.c
Normal file
File diff suppressed because it is too large
Load diff
319
sources/uboot-be550/drivers/net/cs8900.c
Normal file
319
sources/uboot-be550/drivers/net/cs8900.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Cirrus Logic CS8900A Ethernet
|
||||
*
|
||||
* (C) 2009 Ben Warren , biggerbadderben@gmail.com
|
||||
* Converted to use CONFIG_NET_MULTI API
|
||||
*
|
||||
* (C) 2003 Wolfgang Denk, wd@denx.de
|
||||
* Extension to synchronize ethaddr environment variable
|
||||
* against value in EEPROM
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 1999 Ben Williamson <benw@pobox.com>
|
||||
*
|
||||
* This program is loaded into SRAM in bootstrap mode, where it waits
|
||||
* for commands on UART1 to read and write memory, jump to code etc.
|
||||
* A design goal for this program is to be entirely independent of the
|
||||
* target board. Anything with a CL-PS7111 or EP7211 should be able to run
|
||||
* this code in bootstrap mode. All the board specifics can be handled on
|
||||
* the host.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/io.h>
|
||||
#include <net.h>
|
||||
#include <malloc.h>
|
||||
#include "cs8900.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/* packet page register access functions */
|
||||
|
||||
#ifdef CONFIG_CS8900_BUS32
|
||||
|
||||
#define REG_WRITE(v, a) writel((v),(a))
|
||||
#define REG_READ(a) readl((a))
|
||||
|
||||
/* we don't need 16 bit initialisation on 32 bit bus */
|
||||
#define get_reg_init_bus(r,d) get_reg((r),(d))
|
||||
|
||||
#else
|
||||
|
||||
#define REG_WRITE(v, a) writew((v),(a))
|
||||
#define REG_READ(a) readw((a))
|
||||
|
||||
static u16 get_reg_init_bus(struct eth_device *dev, int regno)
|
||||
{
|
||||
/* force 16 bit busmode */
|
||||
struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
|
||||
uint8_t volatile * const iob = (uint8_t volatile * const)dev->iobase;
|
||||
|
||||
readb(iob);
|
||||
readb(iob + 1);
|
||||
readb(iob);
|
||||
readb(iob + 1);
|
||||
readb(iob);
|
||||
|
||||
REG_WRITE(regno, &priv->regs->pptr);
|
||||
return REG_READ(&priv->regs->pdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
static u16 get_reg(struct eth_device *dev, int regno)
|
||||
{
|
||||
struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
|
||||
REG_WRITE(regno, &priv->regs->pptr);
|
||||
return REG_READ(&priv->regs->pdata);
|
||||
}
|
||||
|
||||
|
||||
static void put_reg(struct eth_device *dev, int regno, u16 val)
|
||||
{
|
||||
struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
|
||||
REG_WRITE(regno, &priv->regs->pptr);
|
||||
REG_WRITE(val, &priv->regs->pdata);
|
||||
}
|
||||
|
||||
static void cs8900_reset(struct eth_device *dev)
|
||||
{
|
||||
int tmo;
|
||||
u16 us;
|
||||
|
||||
/* reset NIC */
|
||||
put_reg(dev, PP_SelfCTL, get_reg(dev, PP_SelfCTL) | PP_SelfCTL_Reset);
|
||||
|
||||
/* wait for 200ms */
|
||||
udelay(200000);
|
||||
/* Wait until the chip is reset */
|
||||
|
||||
tmo = get_timer(0) + 1 * CONFIG_SYS_HZ;
|
||||
while ((((us = get_reg_init_bus(dev, PP_SelfSTAT)) &
|
||||
PP_SelfSTAT_InitD) == 0) && tmo < get_timer(0))
|
||||
/*NOP*/;
|
||||
}
|
||||
|
||||
static void cs8900_reginit(struct eth_device *dev)
|
||||
{
|
||||
/* receive only error free packets addressed to this card */
|
||||
put_reg(dev, PP_RxCTL,
|
||||
PP_RxCTL_IA | PP_RxCTL_Broadcast | PP_RxCTL_RxOK);
|
||||
/* do not generate any interrupts on receive operations */
|
||||
put_reg(dev, PP_RxCFG, 0);
|
||||
/* do not generate any interrupts on transmit operations */
|
||||
put_reg(dev, PP_TxCFG, 0);
|
||||
/* do not generate any interrupts on buffer operations */
|
||||
put_reg(dev, PP_BufCFG, 0);
|
||||
/* enable transmitter/receiver mode */
|
||||
put_reg(dev, PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
|
||||
}
|
||||
|
||||
void cs8900_get_enetaddr(struct eth_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* verify chip id */
|
||||
if (get_reg_init_bus(dev, PP_ChipID) != 0x630e)
|
||||
return;
|
||||
cs8900_reset(dev);
|
||||
if ((get_reg(dev, PP_SelfSTAT) &
|
||||
(PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) ==
|
||||
(PP_SelfSTAT_EEPROM | PP_SelfSTAT_EEPROM_OK)) {
|
||||
|
||||
/* Load the MAC from EEPROM */
|
||||
for (i = 0; i < 3; i++) {
|
||||
u32 Addr;
|
||||
|
||||
Addr = get_reg(dev, PP_IA + i * 2);
|
||||
dev->enetaddr[i * 2] = Addr & 0xFF;
|
||||
dev->enetaddr[i * 2 + 1] = Addr >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cs8900_halt(struct eth_device *dev)
|
||||
{
|
||||
/* disable transmitter/receiver mode */
|
||||
put_reg(dev, PP_LineCTL, 0);
|
||||
|
||||
/* "shutdown" to show ChipID or kernel wouldn't find he cs8900 ... */
|
||||
get_reg_init_bus(dev, PP_ChipID);
|
||||
}
|
||||
|
||||
static int cs8900_init(struct eth_device *dev, bd_t * bd)
|
||||
{
|
||||
uchar *enetaddr = dev->enetaddr;
|
||||
u16 id;
|
||||
|
||||
/* verify chip id */
|
||||
id = get_reg_init_bus(dev, PP_ChipID);
|
||||
if (id != 0x630e) {
|
||||
printf ("CS8900 Ethernet chip not found: "
|
||||
"ID=0x%04x instead 0x%04x\n", id, 0x630e);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cs8900_reset (dev);
|
||||
/* set the ethernet address */
|
||||
put_reg(dev, PP_IA + 0, enetaddr[0] | (enetaddr[1] << 8));
|
||||
put_reg(dev, PP_IA + 2, enetaddr[2] | (enetaddr[3] << 8));
|
||||
put_reg(dev, PP_IA + 4, enetaddr[4] | (enetaddr[5] << 8));
|
||||
|
||||
cs8900_reginit(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a data block via Ethernet */
|
||||
static int cs8900_recv(struct eth_device *dev)
|
||||
{
|
||||
int i;
|
||||
u16 rxlen;
|
||||
u16 *addr;
|
||||
u16 status;
|
||||
|
||||
struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
|
||||
|
||||
status = get_reg(dev, PP_RER);
|
||||
|
||||
if ((status & PP_RER_RxOK) == 0)
|
||||
return 0;
|
||||
|
||||
status = REG_READ(&priv->regs->rtdata);
|
||||
rxlen = REG_READ(&priv->regs->rtdata);
|
||||
|
||||
if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
|
||||
debug("packet too big!\n");
|
||||
for (addr = (u16 *)net_rx_packets[0], i = rxlen >> 1; i > 0; i--)
|
||||
*addr++ = REG_READ(&priv->regs->rtdata);
|
||||
if (rxlen & 1)
|
||||
*addr++ = REG_READ(&priv->regs->rtdata);
|
||||
|
||||
/* Pass the packet up to the protocol layers. */
|
||||
net_process_received_packet(net_rx_packets[0], rxlen);
|
||||
return rxlen;
|
||||
}
|
||||
|
||||
/* Send a data block via Ethernet. */
|
||||
static int cs8900_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
volatile u16 *addr;
|
||||
int tmo;
|
||||
u16 s;
|
||||
struct cs8900_priv *priv = (struct cs8900_priv *)(dev->priv);
|
||||
|
||||
retry:
|
||||
/* initiate a transmit sequence */
|
||||
REG_WRITE(PP_TxCmd_TxStart_Full, &priv->regs->txcmd);
|
||||
REG_WRITE(length, &priv->regs->txlen);
|
||||
|
||||
/* Test to see if the chip has allocated memory for the packet */
|
||||
if ((get_reg(dev, PP_BusSTAT) & PP_BusSTAT_TxRDY) == 0) {
|
||||
/* Oops... this should not happen! */
|
||||
debug("cs: unable to send packet; retrying...\n");
|
||||
for (tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
|
||||
get_timer(0) < tmo;)
|
||||
/*NOP*/;
|
||||
cs8900_reset(dev);
|
||||
cs8900_reginit(dev);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Write the contents of the packet */
|
||||
/* assume even number of bytes */
|
||||
for (addr = packet; length > 0; length -= 2)
|
||||
REG_WRITE(*addr++, &priv->regs->rtdata);
|
||||
|
||||
/* wait for transfer to succeed */
|
||||
tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
|
||||
while ((s = get_reg(dev, PP_TER) & ~0x1F) == 0) {
|
||||
if (get_timer(0) >= tmo)
|
||||
break;
|
||||
}
|
||||
|
||||
/* nothing */ ;
|
||||
if((s & (PP_TER_CRS | PP_TER_TxOK)) != PP_TER_TxOK) {
|
||||
debug("\ntransmission error %#x\n", s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs8900_e2prom_ready(struct eth_device *dev)
|
||||
{
|
||||
while (get_reg(dev, PP_SelfSTAT) & SI_BUSY)
|
||||
;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* read a 16-bit word out of the EEPROM */
|
||||
/***********************************************************/
|
||||
|
||||
int cs8900_e2prom_read(struct eth_device *dev,
|
||||
u8 addr, u16 *value)
|
||||
{
|
||||
cs8900_e2prom_ready(dev);
|
||||
put_reg(dev, PP_EECMD, EEPROM_READ_CMD | addr);
|
||||
cs8900_e2prom_ready(dev);
|
||||
*value = get_reg(dev, PP_EEData);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************/
|
||||
/* write a 16-bit word into the EEPROM */
|
||||
/***********************************************************/
|
||||
|
||||
int cs8900_e2prom_write(struct eth_device *dev, u8 addr, u16 value)
|
||||
{
|
||||
cs8900_e2prom_ready(dev);
|
||||
put_reg(dev, PP_EECMD, EEPROM_WRITE_EN);
|
||||
cs8900_e2prom_ready(dev);
|
||||
put_reg(dev, PP_EEData, value);
|
||||
put_reg(dev, PP_EECMD, EEPROM_WRITE_CMD | addr);
|
||||
cs8900_e2prom_ready(dev);
|
||||
put_reg(dev, PP_EECMD, EEPROM_WRITE_DIS);
|
||||
cs8900_e2prom_ready(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cs8900_initialize(u8 dev_num, int base_addr)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct cs8900_priv *priv;
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev) {
|
||||
return 0;
|
||||
}
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (!priv) {
|
||||
free(dev);
|
||||
return 0;
|
||||
}
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
priv->regs = (struct cs8900_regs *)base_addr;
|
||||
|
||||
dev->iobase = base_addr;
|
||||
dev->priv = priv;
|
||||
dev->init = cs8900_init;
|
||||
dev->halt = cs8900_halt;
|
||||
dev->send = cs8900_send;
|
||||
dev->recv = cs8900_recv;
|
||||
|
||||
/* Load MAC address from EEPROM */
|
||||
cs8900_get_enetaddr(dev);
|
||||
|
||||
sprintf(dev->name, "%s-%hu", CS8900_DRIVERNAME, dev_num);
|
||||
|
||||
eth_register(dev);
|
||||
return 0;
|
||||
}
|
||||
249
sources/uboot-be550/drivers/net/cs8900.h
Normal file
249
sources/uboot-be550/drivers/net/cs8900.h
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
#ifndef CS8900_H
|
||||
#define CS8900_H
|
||||
/*
|
||||
* Cirrus Logic CS8900A Ethernet
|
||||
*
|
||||
* (C) 2009 Ben Warren , biggerbadderben@gmail.com
|
||||
* Converted to use CONFIG_NET_MULTI API
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 1999 Ben Williamson <benw@pobox.com>
|
||||
*
|
||||
* This program is loaded into SRAM in bootstrap mode, where it waits
|
||||
* for commands on UART1 to read and write memory, jump to code etc.
|
||||
* A design goal for this program is to be entirely independent of the
|
||||
* target board. Anything with a CL-PS7111 or EP7211 should be able to run
|
||||
* this code in bootstrap mode. All the board specifics can be handled on
|
||||
* the host.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <config.h>
|
||||
|
||||
#define CS8900_DRIVERNAME "CS8900"
|
||||
/* although the registers are 16 bit, they are 32-bit aligned on the
|
||||
EDB7111. so we have to read them as 32-bit registers and ignore the
|
||||
upper 16-bits. i'm not sure if this holds for the EDB7211. */
|
||||
|
||||
#ifdef CONFIG_CS8900_BUS16
|
||||
/* 16 bit aligned registers, 16 bit wide */
|
||||
#define CS8900_REG u16
|
||||
#elif defined(CONFIG_CS8900_BUS32)
|
||||
/* 32 bit aligned registers, 16 bit wide (we ignore upper 16 bits) */
|
||||
#define CS8900_REG u32
|
||||
#else
|
||||
#error unknown bussize ...
|
||||
#endif
|
||||
|
||||
struct cs8900_regs {
|
||||
CS8900_REG rtdata;
|
||||
CS8900_REG pad0;
|
||||
CS8900_REG txcmd;
|
||||
CS8900_REG txlen;
|
||||
CS8900_REG isq;
|
||||
CS8900_REG pptr;
|
||||
CS8900_REG pdata;
|
||||
};
|
||||
|
||||
struct cs8900_priv {
|
||||
struct cs8900_regs *regs;
|
||||
};
|
||||
|
||||
#define ISQ_RxEvent 0x04
|
||||
#define ISQ_TxEvent 0x08
|
||||
#define ISQ_BufEvent 0x0C
|
||||
#define ISQ_RxMissEvent 0x10
|
||||
#define ISQ_TxColEvent 0x12
|
||||
#define ISQ_EventMask 0x3F
|
||||
|
||||
/* packet page register offsets */
|
||||
|
||||
/* bus interface registers */
|
||||
#define PP_ChipID 0x0000 /* Chip identifier - must be 0x630E */
|
||||
#define PP_ChipRev 0x0002 /* Chip revision, model codes */
|
||||
|
||||
#define PP_IntReg 0x0022 /* Interrupt configuration */
|
||||
#define PP_IntReg_IRQ0 0x0000 /* Use INTR0 pin */
|
||||
#define PP_IntReg_IRQ1 0x0001 /* Use INTR1 pin */
|
||||
#define PP_IntReg_IRQ2 0x0002 /* Use INTR2 pin */
|
||||
#define PP_IntReg_IRQ3 0x0003 /* Use INTR3 pin */
|
||||
|
||||
/* status and control registers */
|
||||
|
||||
#define PP_RxCFG 0x0102 /* Receiver configuration */
|
||||
#define PP_RxCFG_Skip1 0x0040 /* Skip (i.e. discard) current frame */
|
||||
#define PP_RxCFG_Stream 0x0080 /* Enable streaming mode */
|
||||
#define PP_RxCFG_RxOK 0x0100 /* RxOK interrupt enable */
|
||||
#define PP_RxCFG_RxDMAonly 0x0200 /* Use RxDMA for all frames */
|
||||
#define PP_RxCFG_AutoRxDMA 0x0400 /* Select RxDMA automatically */
|
||||
#define PP_RxCFG_BufferCRC 0x0800 /* Include CRC characters in frame */
|
||||
#define PP_RxCFG_CRC 0x1000 /* Enable interrupt on CRC error */
|
||||
#define PP_RxCFG_RUNT 0x2000 /* Enable interrupt on RUNT frames */
|
||||
#define PP_RxCFG_EXTRA 0x4000 /* Enable interrupt on frames with extra data */
|
||||
|
||||
#define PP_RxCTL 0x0104 /* Receiver control */
|
||||
#define PP_RxCTL_IAHash 0x0040 /* Accept frames that match hash */
|
||||
#define PP_RxCTL_Promiscuous 0x0080 /* Accept any frame */
|
||||
#define PP_RxCTL_RxOK 0x0100 /* Accept well formed frames */
|
||||
#define PP_RxCTL_Multicast 0x0200 /* Accept multicast frames */
|
||||
#define PP_RxCTL_IA 0x0400 /* Accept frame that matches IA */
|
||||
#define PP_RxCTL_Broadcast 0x0800 /* Accept broadcast frames */
|
||||
#define PP_RxCTL_CRC 0x1000 /* Accept frames with bad CRC */
|
||||
#define PP_RxCTL_RUNT 0x2000 /* Accept runt frames */
|
||||
#define PP_RxCTL_EXTRA 0x4000 /* Accept frames that are too long */
|
||||
|
||||
#define PP_TxCFG 0x0106 /* Transmit configuration */
|
||||
#define PP_TxCFG_CRS 0x0040 /* Enable interrupt on loss of carrier */
|
||||
#define PP_TxCFG_SQE 0x0080 /* Enable interrupt on Signal Quality Error */
|
||||
#define PP_TxCFG_TxOK 0x0100 /* Enable interrupt on successful xmits */
|
||||
#define PP_TxCFG_Late 0x0200 /* Enable interrupt on "out of window" */
|
||||
#define PP_TxCFG_Jabber 0x0400 /* Enable interrupt on jabber detect */
|
||||
#define PP_TxCFG_Collision 0x0800 /* Enable interrupt if collision */
|
||||
#define PP_TxCFG_16Collisions 0x8000 /* Enable interrupt if > 16 collisions */
|
||||
|
||||
#define PP_TxCmd 0x0108 /* Transmit command status */
|
||||
#define PP_TxCmd_TxStart_5 0x0000 /* Start after 5 bytes in buffer */
|
||||
#define PP_TxCmd_TxStart_381 0x0040 /* Start after 381 bytes in buffer */
|
||||
#define PP_TxCmd_TxStart_1021 0x0080 /* Start after 1021 bytes in buffer */
|
||||
#define PP_TxCmd_TxStart_Full 0x00C0 /* Start after all bytes loaded */
|
||||
#define PP_TxCmd_Force 0x0100 /* Discard any pending packets */
|
||||
#define PP_TxCmd_OneCollision 0x0200 /* Abort after a single collision */
|
||||
#define PP_TxCmd_NoCRC 0x1000 /* Do not add CRC */
|
||||
#define PP_TxCmd_NoPad 0x2000 /* Do not pad short packets */
|
||||
|
||||
#define PP_BufCFG 0x010A /* Buffer configuration */
|
||||
#define PP_BufCFG_SWI 0x0040 /* Force interrupt via software */
|
||||
#define PP_BufCFG_RxDMA 0x0080 /* Enable interrupt on Rx DMA */
|
||||
#define PP_BufCFG_TxRDY 0x0100 /* Enable interrupt when ready for Tx */
|
||||
#define PP_BufCFG_TxUE 0x0200 /* Enable interrupt in Tx underrun */
|
||||
#define PP_BufCFG_RxMiss 0x0400 /* Enable interrupt on missed Rx packets */
|
||||
#define PP_BufCFG_Rx128 0x0800 /* Enable Rx interrupt after 128 bytes */
|
||||
#define PP_BufCFG_TxCol 0x1000 /* Enable int on Tx collision ctr overflow */
|
||||
#define PP_BufCFG_Miss 0x2000 /* Enable int on Rx miss ctr overflow */
|
||||
#define PP_BufCFG_RxDest 0x8000 /* Enable int on Rx dest addr match */
|
||||
|
||||
#define PP_LineCTL 0x0112 /* Line control */
|
||||
#define PP_LineCTL_Rx 0x0040 /* Enable receiver */
|
||||
#define PP_LineCTL_Tx 0x0080 /* Enable transmitter */
|
||||
#define PP_LineCTL_AUIonly 0x0100 /* AUI interface only */
|
||||
#define PP_LineCTL_AutoAUI10BT 0x0200 /* Autodetect AUI or 10BaseT interface */
|
||||
#define PP_LineCTL_ModBackoffE 0x0800 /* Enable modified backoff algorithm */
|
||||
#define PP_LineCTL_PolarityDis 0x1000 /* Disable Rx polarity autodetect */
|
||||
#define PP_LineCTL_2partDefDis 0x2000 /* Disable two-part defferal */
|
||||
#define PP_LineCTL_LoRxSquelch 0x4000 /* Reduce receiver squelch threshold */
|
||||
|
||||
#define PP_SelfCTL 0x0114 /* Chip self control */
|
||||
#define PP_SelfCTL_Reset 0x0040 /* Self-clearing reset */
|
||||
#define PP_SelfCTL_SWSuspend 0x0100 /* Initiate suspend mode */
|
||||
#define PP_SelfCTL_HWSleepE 0x0200 /* Enable SLEEP input */
|
||||
#define PP_SelfCTL_HWStandbyE 0x0400 /* Enable standby mode */
|
||||
#define PP_SelfCTL_HC0E 0x1000 /* use HCB0 for LINK LED */
|
||||
#define PP_SelfCTL_HC1E 0x2000 /* use HCB1 for BSTATUS LED */
|
||||
#define PP_SelfCTL_HCB0 0x4000 /* control LINK LED if HC0E set */
|
||||
#define PP_SelfCTL_HCB1 0x8000 /* control BSTATUS LED if HC1E set */
|
||||
|
||||
#define PP_BusCTL 0x0116 /* Bus control */
|
||||
#define PP_BusCTL_ResetRxDMA 0x0040 /* Reset RxDMA pointer */
|
||||
#define PP_BusCTL_DMAextend 0x0100 /* Extend DMA cycle */
|
||||
#define PP_BusCTL_UseSA 0x0200 /* Assert MEMCS16 on address decode */
|
||||
#define PP_BusCTL_MemoryE 0x0400 /* Enable memory mode */
|
||||
#define PP_BusCTL_DMAburst 0x0800 /* Limit DMA access burst */
|
||||
#define PP_BusCTL_IOCHRDYE 0x1000 /* Set IOCHRDY high impedence */
|
||||
#define PP_BusCTL_RxDMAsize 0x2000 /* Set DMA buffer size 64KB */
|
||||
#define PP_BusCTL_EnableIRQ 0x8000 /* Generate interrupt on interrupt event */
|
||||
|
||||
#define PP_TestCTL 0x0118 /* Test control */
|
||||
#define PP_TestCTL_DisableLT 0x0080 /* Disable link status */
|
||||
#define PP_TestCTL_ENDECloop 0x0200 /* Internal loopback */
|
||||
#define PP_TestCTL_AUIloop 0x0400 /* AUI loopback */
|
||||
#define PP_TestCTL_DisBackoff 0x0800 /* Disable backoff algorithm */
|
||||
#define PP_TestCTL_FDX 0x4000 /* Enable full duplex mode */
|
||||
|
||||
#define PP_ISQ 0x0120 /* Interrupt Status Queue */
|
||||
|
||||
#define PP_RER 0x0124 /* Receive event */
|
||||
#define PP_RER_IAHash 0x0040 /* Frame hash match */
|
||||
#define PP_RER_Dribble 0x0080 /* Frame had 1-7 extra bits after last byte */
|
||||
#define PP_RER_RxOK 0x0100 /* Frame received with no errors */
|
||||
#define PP_RER_Hashed 0x0200 /* Frame address hashed OK */
|
||||
#define PP_RER_IA 0x0400 /* Frame address matched IA */
|
||||
#define PP_RER_Broadcast 0x0800 /* Broadcast frame */
|
||||
#define PP_RER_CRC 0x1000 /* Frame had CRC error */
|
||||
#define PP_RER_RUNT 0x2000 /* Runt frame */
|
||||
#define PP_RER_EXTRA 0x4000 /* Frame was too long */
|
||||
|
||||
#define PP_TER 0x0128 /* Transmit event */
|
||||
#define PP_TER_CRS 0x0040 /* Carrier lost */
|
||||
#define PP_TER_SQE 0x0080 /* Signal Quality Error */
|
||||
#define PP_TER_TxOK 0x0100 /* Packet sent without error */
|
||||
#define PP_TER_Late 0x0200 /* Out of window */
|
||||
#define PP_TER_Jabber 0x0400 /* Stuck transmit? */
|
||||
#define PP_TER_NumCollisions 0x7800 /* Number of collisions */
|
||||
#define PP_TER_16Collisions 0x8000 /* > 16 collisions */
|
||||
|
||||
#define PP_BER 0x012C /* Buffer event */
|
||||
#define PP_BER_SWint 0x0040 /* Software interrupt */
|
||||
#define PP_BER_RxDMAFrame 0x0080 /* Received framed DMAed */
|
||||
#define PP_BER_Rdy4Tx 0x0100 /* Ready for transmission */
|
||||
#define PP_BER_TxUnderrun 0x0200 /* Transmit underrun */
|
||||
#define PP_BER_RxMiss 0x0400 /* Received frame missed */
|
||||
#define PP_BER_Rx128 0x0800 /* 128 bytes received */
|
||||
#define PP_BER_RxDest 0x8000 /* Received framed passed address filter */
|
||||
|
||||
#define PP_RxMiss 0x0130 /* Receiver miss counter */
|
||||
|
||||
#define PP_TxCol 0x0132 /* Transmit collision counter */
|
||||
|
||||
#define PP_LineSTAT 0x0134 /* Line status */
|
||||
#define PP_LineSTAT_LinkOK 0x0080 /* Line is connected and working */
|
||||
#define PP_LineSTAT_AUI 0x0100 /* Connected via AUI */
|
||||
#define PP_LineSTAT_10BT 0x0200 /* Connected via twisted pair */
|
||||
#define PP_LineSTAT_Polarity 0x1000 /* Line polarity OK (10BT only) */
|
||||
#define PP_LineSTAT_CRS 0x4000 /* Frame being received */
|
||||
|
||||
#define PP_SelfSTAT 0x0136 /* Chip self status */
|
||||
#define PP_SelfSTAT_33VActive 0x0040 /* supply voltage is 3.3V */
|
||||
#define PP_SelfSTAT_InitD 0x0080 /* Chip initialization complete */
|
||||
#define PP_SelfSTAT_SIBSY 0x0100 /* EEPROM is busy */
|
||||
#define PP_SelfSTAT_EEPROM 0x0200 /* EEPROM present */
|
||||
#define PP_SelfSTAT_EEPROM_OK 0x0400 /* EEPROM checks out */
|
||||
#define PP_SelfSTAT_ELPresent 0x0800 /* External address latch logic available */
|
||||
#define PP_SelfSTAT_EEsize 0x1000 /* Size of EEPROM */
|
||||
|
||||
#define PP_BusSTAT 0x0138 /* Bus status */
|
||||
#define PP_BusSTAT_TxBid 0x0080 /* Tx error */
|
||||
#define PP_BusSTAT_TxRDY 0x0100 /* Ready for Tx data */
|
||||
|
||||
#define PP_TDR 0x013C /* AUI Time Domain Reflectometer */
|
||||
|
||||
/* initiate transmit registers */
|
||||
|
||||
#define PP_TxCommand 0x0144 /* Tx Command */
|
||||
#define PP_TxLength 0x0146 /* Tx Length */
|
||||
|
||||
|
||||
/* address filter registers */
|
||||
|
||||
#define PP_LAF 0x0150 /* Logical address filter (6 bytes) */
|
||||
#define PP_IA 0x0158 /* Individual address (MAC) */
|
||||
|
||||
/* EEPROM Kram */
|
||||
#define SI_BUSY 0x0100
|
||||
#define PP_EECMD 0x0040 /* NVR Interface Command register */
|
||||
#define PP_EEData 0x0042 /* NVR Interface Data Register */
|
||||
#define EEPROM_WRITE_EN 0x00F0
|
||||
#define EEPROM_WRITE_DIS 0x0000
|
||||
#define EEPROM_WRITE_CMD 0x0100
|
||||
#define EEPROM_READ_CMD 0x0200
|
||||
#define EEPROM_ERASE_CMD 0x0300
|
||||
|
||||
/* Exported functions */
|
||||
int cs8900_e2prom_read(struct eth_device *dev, uchar, ushort *);
|
||||
int cs8900_e2prom_write(struct eth_device *dev, uchar, ushort);
|
||||
|
||||
#endif /* CS8900_H */
|
||||
897
sources/uboot-be550/drivers/net/davinci_emac.c
Normal file
897
sources/uboot-be550/drivers/net/davinci_emac.c
Normal file
|
|
@ -0,0 +1,897 @@
|
|||
/*
|
||||
* Ethernet driver for TI TMS320DM644x (DaVinci) chips.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
|
||||
* follows:
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dm644x_emac.c
|
||||
*
|
||||
* TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
|
||||
*
|
||||
* Copyright (C) 2005 Texas Instruments.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Modifications:
|
||||
* ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
|
||||
* ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
#include <miiphy.h>
|
||||
#include <malloc.h>
|
||||
#include <netdev.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/arch/emac_defs.h>
|
||||
#include <asm/io.h>
|
||||
#include "davinci_emac.h"
|
||||
|
||||
unsigned int emac_dbg = 0;
|
||||
#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args)
|
||||
|
||||
#ifdef EMAC_HW_RAM_ADDR
|
||||
static inline unsigned long BD_TO_HW(unsigned long x)
|
||||
{
|
||||
if (x == 0)
|
||||
return 0;
|
||||
|
||||
return x - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
|
||||
}
|
||||
|
||||
static inline unsigned long HW_TO_BD(unsigned long x)
|
||||
{
|
||||
if (x == 0)
|
||||
return 0;
|
||||
|
||||
return x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR;
|
||||
}
|
||||
#else
|
||||
#define BD_TO_HW(x) (x)
|
||||
#define HW_TO_BD(x) (x)
|
||||
#endif
|
||||
|
||||
#ifdef DAVINCI_EMAC_GIG_ENABLE
|
||||
#define emac_gigabit_enable(phy_addr) davinci_eth_gigabit_enable(phy_addr)
|
||||
#else
|
||||
#define emac_gigabit_enable(phy_addr) /* no gigabit to enable */
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_SYS_EMAC_TI_CLKDIV)
|
||||
#define CONFIG_SYS_EMAC_TI_CLKDIV ((EMAC_MDIO_BUS_FREQ / \
|
||||
EMAC_MDIO_CLOCK_FREQ) - 1)
|
||||
#endif
|
||||
|
||||
static void davinci_eth_mdio_enable(void);
|
||||
|
||||
static int gen_init_phy(int phy_addr);
|
||||
static int gen_is_phy_connected(int phy_addr);
|
||||
static int gen_get_link_speed(int phy_addr);
|
||||
static int gen_auto_negotiate(int phy_addr);
|
||||
|
||||
void eth_mdio_enable(void)
|
||||
{
|
||||
davinci_eth_mdio_enable();
|
||||
}
|
||||
|
||||
/* EMAC Addresses */
|
||||
static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR;
|
||||
static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
|
||||
static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
|
||||
|
||||
/* EMAC descriptors */
|
||||
static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
|
||||
static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
|
||||
static volatile emac_desc *emac_rx_active_head = 0;
|
||||
static volatile emac_desc *emac_rx_active_tail = 0;
|
||||
static int emac_rx_queue_active = 0;
|
||||
|
||||
/* Receive packet buffers */
|
||||
static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * EMAC_RXBUF_SIZE]
|
||||
__aligned(ARCH_DMA_MINALIGN);
|
||||
|
||||
#ifndef CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT
|
||||
#define CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT 3
|
||||
#endif
|
||||
|
||||
/* PHY address for a discovered PHY (0xff - not found) */
|
||||
static u_int8_t active_phy_addr[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT];
|
||||
|
||||
/* number of PHY found active */
|
||||
static u_int8_t num_phy;
|
||||
|
||||
phy_t phy[CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT];
|
||||
|
||||
static inline void davinci_flush_rx_descs(void)
|
||||
{
|
||||
/* flush the whole RX descs area */
|
||||
flush_dcache_range(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE,
|
||||
EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
|
||||
}
|
||||
|
||||
static inline void davinci_invalidate_rx_descs(void)
|
||||
{
|
||||
/* invalidate the whole RX descs area */
|
||||
invalidate_dcache_range(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE,
|
||||
EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
|
||||
}
|
||||
|
||||
static inline void davinci_flush_desc(emac_desc *desc)
|
||||
{
|
||||
flush_dcache_range((unsigned long)desc,
|
||||
(unsigned long)desc + sizeof(*desc));
|
||||
}
|
||||
|
||||
static int davinci_eth_set_mac_addr(struct eth_device *dev)
|
||||
{
|
||||
unsigned long mac_hi;
|
||||
unsigned long mac_lo;
|
||||
|
||||
/*
|
||||
* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
|
||||
* receive)
|
||||
* Using channel 0 only - other channels are disabled
|
||||
* */
|
||||
writel(0, &adap_emac->MACINDEX);
|
||||
mac_hi = (dev->enetaddr[3] << 24) |
|
||||
(dev->enetaddr[2] << 16) |
|
||||
(dev->enetaddr[1] << 8) |
|
||||
(dev->enetaddr[0]);
|
||||
mac_lo = (dev->enetaddr[5] << 8) |
|
||||
(dev->enetaddr[4]);
|
||||
|
||||
writel(mac_hi, &adap_emac->MACADDRHI);
|
||||
#if defined(DAVINCI_EMAC_VERSION2)
|
||||
writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
|
||||
&adap_emac->MACADDRLO);
|
||||
#else
|
||||
writel(mac_lo, &adap_emac->MACADDRLO);
|
||||
#endif
|
||||
|
||||
writel(0, &adap_emac->MACHASH1);
|
||||
writel(0, &adap_emac->MACHASH2);
|
||||
|
||||
/* Set source MAC address - REQUIRED */
|
||||
writel(mac_hi, &adap_emac->MACSRCADDRHI);
|
||||
writel(mac_lo, &adap_emac->MACSRCADDRLO);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void davinci_eth_mdio_enable(void)
|
||||
{
|
||||
u_int32_t clkdiv;
|
||||
|
||||
clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV;
|
||||
|
||||
writel((clkdiv & 0xff) |
|
||||
MDIO_CONTROL_ENABLE |
|
||||
MDIO_CONTROL_FAULT |
|
||||
MDIO_CONTROL_FAULT_ENABLE,
|
||||
&adap_mdio->CONTROL);
|
||||
|
||||
while (readl(&adap_mdio->CONTROL) & MDIO_CONTROL_IDLE)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to find an active connected PHY. Returns 1 if address if found.
|
||||
* If no active PHY (or more than one PHY) found returns 0.
|
||||
* Sets active_phy_addr variable.
|
||||
*/
|
||||
static int davinci_eth_phy_detect(void)
|
||||
{
|
||||
u_int32_t phy_act_state;
|
||||
int i;
|
||||
int j;
|
||||
unsigned int count = 0;
|
||||
|
||||
for (i = 0; i < CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT; i++)
|
||||
active_phy_addr[i] = 0xff;
|
||||
|
||||
udelay(1000);
|
||||
phy_act_state = readl(&adap_mdio->ALIVE);
|
||||
|
||||
if (phy_act_state == 0)
|
||||
return 0; /* No active PHYs */
|
||||
|
||||
debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state);
|
||||
|
||||
for (i = 0, j = 0; i < 32; i++)
|
||||
if (phy_act_state & (1 << i)) {
|
||||
count++;
|
||||
if (count <= CONFIG_SYS_DAVINCI_EMAC_PHY_COUNT) {
|
||||
active_phy_addr[j++] = i;
|
||||
} else {
|
||||
printf("%s: to many PHYs detected.\n",
|
||||
__func__);
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
num_phy = count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
|
||||
int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
|
||||
;
|
||||
|
||||
writel(MDIO_USERACCESS0_GO |
|
||||
MDIO_USERACCESS0_WRITE_READ |
|
||||
((reg_num & 0x1f) << 21) |
|
||||
((phy_addr & 0x1f) << 16),
|
||||
&adap_mdio->USERACCESS0);
|
||||
|
||||
/* Wait for command to complete */
|
||||
while ((tmp = readl(&adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO)
|
||||
;
|
||||
|
||||
if (tmp & MDIO_USERACCESS0_ACK) {
|
||||
*data = tmp & 0xffff;
|
||||
return(1);
|
||||
}
|
||||
|
||||
*data = -1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
|
||||
int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
|
||||
{
|
||||
|
||||
while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
|
||||
;
|
||||
|
||||
writel(MDIO_USERACCESS0_GO |
|
||||
MDIO_USERACCESS0_WRITE_WRITE |
|
||||
((reg_num & 0x1f) << 21) |
|
||||
((phy_addr & 0x1f) << 16) |
|
||||
(data & 0xffff),
|
||||
&adap_mdio->USERACCESS0);
|
||||
|
||||
/* Wait for command to complete */
|
||||
while (readl(&adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO)
|
||||
;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* PHY functions for a generic PHY */
|
||||
static int gen_init_phy(int phy_addr)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (gen_get_link_speed(phy_addr)) {
|
||||
/* Try another time */
|
||||
ret = gen_get_link_speed(phy_addr);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int gen_is_phy_connected(int phy_addr)
|
||||
{
|
||||
u_int16_t dummy;
|
||||
|
||||
return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy);
|
||||
}
|
||||
|
||||
static int get_active_phy(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_phy; i++)
|
||||
if (phy[i].get_link_speed(active_phy_addr[i]))
|
||||
return i;
|
||||
|
||||
return -1; /* Return error if no link */
|
||||
}
|
||||
|
||||
static int gen_get_link_speed(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
|
||||
if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) &&
|
||||
(tmp & 0x04)) {
|
||||
#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
|
||||
defined(CONFIG_MACH_DAVINCI_DA850_EVM)
|
||||
davinci_eth_phy_read(phy_addr, MII_LPA, &tmp);
|
||||
|
||||
/* Speed doesn't matter, there is no setting for it in EMAC. */
|
||||
if (tmp & (LPA_100FULL | LPA_10FULL)) {
|
||||
/* set EMAC for Full Duplex */
|
||||
writel(EMAC_MACCONTROL_MIIEN_ENABLE |
|
||||
EMAC_MACCONTROL_FULLDUPLEX_ENABLE,
|
||||
&adap_emac->MACCONTROL);
|
||||
} else {
|
||||
/*set EMAC for Half Duplex */
|
||||
writel(EMAC_MACCONTROL_MIIEN_ENABLE,
|
||||
&adap_emac->MACCONTROL);
|
||||
}
|
||||
|
||||
if (tmp & (LPA_100FULL | LPA_100HALF))
|
||||
writel(readl(&adap_emac->MACCONTROL) |
|
||||
EMAC_MACCONTROL_RMIISPEED_100,
|
||||
&adap_emac->MACCONTROL);
|
||||
else
|
||||
writel(readl(&adap_emac->MACCONTROL) &
|
||||
~EMAC_MACCONTROL_RMIISPEED_100,
|
||||
&adap_emac->MACCONTROL);
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int gen_auto_negotiate(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
u_int16_t val;
|
||||
unsigned long cntr = 0;
|
||||
|
||||
if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp))
|
||||
return 0;
|
||||
|
||||
val = tmp | BMCR_FULLDPLX | BMCR_ANENABLE |
|
||||
BMCR_SPEED100;
|
||||
davinci_eth_phy_write(phy_addr, MII_BMCR, val);
|
||||
|
||||
if (!davinci_eth_phy_read(phy_addr, MII_ADVERTISE, &val))
|
||||
return 0;
|
||||
|
||||
val |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_10HALF);
|
||||
davinci_eth_phy_write(phy_addr, MII_ADVERTISE, val);
|
||||
|
||||
if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp))
|
||||
return(0);
|
||||
|
||||
/* Restart Auto_negotiation */
|
||||
tmp |= BMCR_ANRESTART;
|
||||
davinci_eth_phy_write(phy_addr, MII_BMCR, tmp);
|
||||
|
||||
/*check AutoNegotiate complete */
|
||||
do {
|
||||
udelay(40000);
|
||||
if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp))
|
||||
return 0;
|
||||
|
||||
if (tmp & BMSR_ANEGCOMPLETE)
|
||||
break;
|
||||
|
||||
cntr++;
|
||||
} while (cntr < 200);
|
||||
|
||||
if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp))
|
||||
return(0);
|
||||
|
||||
if (!(tmp & BMSR_ANEGCOMPLETE))
|
||||
return(0);
|
||||
|
||||
return(gen_get_link_speed(phy_addr));
|
||||
}
|
||||
/* End of generic PHY functions */
|
||||
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
static int davinci_mii_phy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
|
||||
{
|
||||
return(davinci_eth_phy_read(addr, reg, value) ? 0 : 1);
|
||||
}
|
||||
|
||||
static int davinci_mii_phy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value)
|
||||
{
|
||||
return(davinci_eth_phy_write(addr, reg, value) ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __attribute__((unused)) davinci_eth_gigabit_enable(int phy_addr)
|
||||
{
|
||||
u_int16_t data;
|
||||
|
||||
if (davinci_eth_phy_read(phy_addr, 0, &data)) {
|
||||
if (data & (1 << 6)) { /* speed selection MSB */
|
||||
/*
|
||||
* Check if link detected is giga-bit
|
||||
* If Gigabit mode detected, enable gigbit in MAC
|
||||
*/
|
||||
writel(readl(&adap_emac->MACCONTROL) |
|
||||
EMAC_MACCONTROL_GIGFORCE |
|
||||
EMAC_MACCONTROL_GIGABIT_ENABLE,
|
||||
&adap_emac->MACCONTROL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Eth device open */
|
||||
static int davinci_eth_open(struct eth_device *dev, bd_t *bis)
|
||||
{
|
||||
dv_reg_p addr;
|
||||
u_int32_t clkdiv, cnt;
|
||||
volatile emac_desc *rx_desc;
|
||||
int index;
|
||||
|
||||
debug_emac("+ emac_open\n");
|
||||
|
||||
/* Reset EMAC module and disable interrupts in wrapper */
|
||||
writel(1, &adap_emac->SOFTRESET);
|
||||
while (readl(&adap_emac->SOFTRESET) != 0)
|
||||
;
|
||||
#if defined(DAVINCI_EMAC_VERSION2)
|
||||
writel(1, &adap_ewrap->softrst);
|
||||
while (readl(&adap_ewrap->softrst) != 0)
|
||||
;
|
||||
#else
|
||||
writel(0, &adap_ewrap->EWCTL);
|
||||
for (cnt = 0; cnt < 5; cnt++) {
|
||||
clkdiv = readl(&adap_ewrap->EWCTL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
|
||||
defined(CONFIG_MACH_DAVINCI_DA850_EVM)
|
||||
adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0;
|
||||
adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0;
|
||||
adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0;
|
||||
#endif
|
||||
rx_desc = emac_rx_desc;
|
||||
|
||||
writel(1, &adap_emac->TXCONTROL);
|
||||
writel(1, &adap_emac->RXCONTROL);
|
||||
|
||||
davinci_eth_set_mac_addr(dev);
|
||||
|
||||
/* Set DMA 8 TX / 8 RX Head pointers to 0 */
|
||||
addr = &adap_emac->TX0HDP;
|
||||
for(cnt = 0; cnt < 16; cnt++)
|
||||
writel(0, addr++);
|
||||
|
||||
addr = &adap_emac->RX0HDP;
|
||||
for(cnt = 0; cnt < 16; cnt++)
|
||||
writel(0, addr++);
|
||||
|
||||
/* Clear Statistics (do this before setting MacControl register) */
|
||||
addr = &adap_emac->RXGOODFRAMES;
|
||||
for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
|
||||
writel(0, addr++);
|
||||
|
||||
/* No multicast addressing */
|
||||
writel(0, &adap_emac->MACHASH1);
|
||||
writel(0, &adap_emac->MACHASH2);
|
||||
|
||||
/* Create RX queue and set receive process in place */
|
||||
emac_rx_active_head = emac_rx_desc;
|
||||
for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
|
||||
rx_desc->next = BD_TO_HW((u_int32_t)(rx_desc + 1));
|
||||
rx_desc->buffer = &emac_rx_buffers[cnt * EMAC_RXBUF_SIZE];
|
||||
rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
|
||||
rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
|
||||
rx_desc++;
|
||||
}
|
||||
|
||||
/* Finalize the rx desc list */
|
||||
rx_desc--;
|
||||
rx_desc->next = 0;
|
||||
emac_rx_active_tail = rx_desc;
|
||||
emac_rx_queue_active = 1;
|
||||
|
||||
davinci_flush_rx_descs();
|
||||
|
||||
/* Enable TX/RX */
|
||||
writel(EMAC_MAX_ETHERNET_PKT_SIZE, &adap_emac->RXMAXLEN);
|
||||
writel(0, &adap_emac->RXBUFFEROFFSET);
|
||||
|
||||
/*
|
||||
* No fancy configs - Use this for promiscous debug
|
||||
* - EMAC_RXMBPENABLE_RXCAFEN_ENABLE
|
||||
*/
|
||||
writel(EMAC_RXMBPENABLE_RXBROADEN, &adap_emac->RXMBPENABLE);
|
||||
|
||||
/* Enable ch 0 only */
|
||||
writel(1, &adap_emac->RXUNICASTSET);
|
||||
|
||||
/* Enable MII interface and Full duplex mode */
|
||||
#if defined(CONFIG_SOC_DA8XX) || \
|
||||
(defined(CONFIG_OMAP34XX) && defined(CONFIG_DRIVER_TI_EMAC_USE_RMII))
|
||||
writel((EMAC_MACCONTROL_MIIEN_ENABLE |
|
||||
EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
|
||||
EMAC_MACCONTROL_RMIISPEED_100),
|
||||
&adap_emac->MACCONTROL);
|
||||
#else
|
||||
writel((EMAC_MACCONTROL_MIIEN_ENABLE |
|
||||
EMAC_MACCONTROL_FULLDUPLEX_ENABLE),
|
||||
&adap_emac->MACCONTROL);
|
||||
#endif
|
||||
|
||||
/* Init MDIO & get link state */
|
||||
clkdiv = CONFIG_SYS_EMAC_TI_CLKDIV;
|
||||
writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
|
||||
&adap_mdio->CONTROL);
|
||||
|
||||
/* We need to wait for MDIO to start */
|
||||
udelay(1000);
|
||||
|
||||
index = get_active_phy();
|
||||
if (index == -1)
|
||||
return(0);
|
||||
|
||||
emac_gigabit_enable(active_phy_addr[index]);
|
||||
|
||||
/* Start receive process */
|
||||
writel(BD_TO_HW((u_int32_t)emac_rx_desc), &adap_emac->RX0HDP);
|
||||
|
||||
debug_emac("- emac_open\n");
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* EMAC Channel Teardown */
|
||||
static void davinci_eth_ch_teardown(int ch)
|
||||
{
|
||||
dv_reg dly = 0xff;
|
||||
dv_reg cnt;
|
||||
|
||||
debug_emac("+ emac_ch_teardown\n");
|
||||
|
||||
if (ch == EMAC_CH_TX) {
|
||||
/* Init TX channel teardown */
|
||||
writel(0, &adap_emac->TXTEARDOWN);
|
||||
do {
|
||||
/*
|
||||
* Wait here for Tx teardown completion interrupt to
|
||||
* occur. Note: A task delay can be called here to pend
|
||||
* rather than occupying CPU cycles - anyway it has
|
||||
* been found that teardown takes very few cpu cycles
|
||||
* and does not affect functionality
|
||||
*/
|
||||
dly--;
|
||||
udelay(1);
|
||||
if (dly == 0)
|
||||
break;
|
||||
cnt = readl(&adap_emac->TX0CP);
|
||||
} while (cnt != 0xfffffffc);
|
||||
writel(cnt, &adap_emac->TX0CP);
|
||||
writel(0, &adap_emac->TX0HDP);
|
||||
} else {
|
||||
/* Init RX channel teardown */
|
||||
writel(0, &adap_emac->RXTEARDOWN);
|
||||
do {
|
||||
/*
|
||||
* Wait here for Rx teardown completion interrupt to
|
||||
* occur. Note: A task delay can be called here to pend
|
||||
* rather than occupying CPU cycles - anyway it has
|
||||
* been found that teardown takes very few cpu cycles
|
||||
* and does not affect functionality
|
||||
*/
|
||||
dly--;
|
||||
udelay(1);
|
||||
if (dly == 0)
|
||||
break;
|
||||
cnt = readl(&adap_emac->RX0CP);
|
||||
} while (cnt != 0xfffffffc);
|
||||
writel(cnt, &adap_emac->RX0CP);
|
||||
writel(0, &adap_emac->RX0HDP);
|
||||
}
|
||||
|
||||
debug_emac("- emac_ch_teardown\n");
|
||||
}
|
||||
|
||||
/* Eth device close */
|
||||
static void davinci_eth_close(struct eth_device *dev)
|
||||
{
|
||||
debug_emac("+ emac_close\n");
|
||||
|
||||
davinci_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */
|
||||
if (readl(&adap_emac->RXCONTROL) & 1)
|
||||
davinci_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */
|
||||
|
||||
/* Reset EMAC module and disable interrupts in wrapper */
|
||||
writel(1, &adap_emac->SOFTRESET);
|
||||
#if defined(DAVINCI_EMAC_VERSION2)
|
||||
writel(1, &adap_ewrap->softrst);
|
||||
#else
|
||||
writel(0, &adap_ewrap->EWCTL);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
|
||||
defined(CONFIG_MACH_DAVINCI_DA850_EVM)
|
||||
adap_ewrap->c0rxen = adap_ewrap->c1rxen = adap_ewrap->c2rxen = 0;
|
||||
adap_ewrap->c0txen = adap_ewrap->c1txen = adap_ewrap->c2txen = 0;
|
||||
adap_ewrap->c0miscen = adap_ewrap->c1miscen = adap_ewrap->c2miscen = 0;
|
||||
#endif
|
||||
debug_emac("- emac_close\n");
|
||||
}
|
||||
|
||||
static int tx_send_loop = 0;
|
||||
|
||||
/*
|
||||
* This function sends a single packet on the network and returns
|
||||
* positive number (number of bytes transmitted) or negative for error
|
||||
*/
|
||||
static int davinci_eth_send_packet (struct eth_device *dev,
|
||||
void *packet, int length)
|
||||
{
|
||||
int ret_status = -1;
|
||||
int index;
|
||||
tx_send_loop = 0;
|
||||
|
||||
index = get_active_phy();
|
||||
if (index == -1) {
|
||||
printf(" WARN: emac_send_packet: No link\n");
|
||||
return (ret_status);
|
||||
}
|
||||
|
||||
emac_gigabit_enable(active_phy_addr[index]);
|
||||
|
||||
/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
|
||||
if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
|
||||
length = EMAC_MIN_ETHERNET_PKT_SIZE;
|
||||
}
|
||||
|
||||
/* Populate the TX descriptor */
|
||||
emac_tx_desc->next = 0;
|
||||
emac_tx_desc->buffer = (u_int8_t *) packet;
|
||||
emac_tx_desc->buff_off_len = (length & 0xffff);
|
||||
emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
|
||||
EMAC_CPPI_SOP_BIT |
|
||||
EMAC_CPPI_OWNERSHIP_BIT |
|
||||
EMAC_CPPI_EOP_BIT);
|
||||
|
||||
flush_dcache_range((unsigned long)packet,
|
||||
(unsigned long)packet + length);
|
||||
davinci_flush_desc(emac_tx_desc);
|
||||
|
||||
/* Send the packet */
|
||||
writel(BD_TO_HW((unsigned long)emac_tx_desc), &adap_emac->TX0HDP);
|
||||
|
||||
/* Wait for packet to complete or link down */
|
||||
while (1) {
|
||||
if (!phy[index].get_link_speed(active_phy_addr[index])) {
|
||||
davinci_eth_ch_teardown (EMAC_CH_TX);
|
||||
return (ret_status);
|
||||
}
|
||||
|
||||
emac_gigabit_enable(active_phy_addr[index]);
|
||||
|
||||
if (readl(&adap_emac->TXINTSTATRAW) & 0x01) {
|
||||
ret_status = length;
|
||||
break;
|
||||
}
|
||||
tx_send_loop++;
|
||||
}
|
||||
|
||||
return (ret_status);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles receipt of a packet from the network
|
||||
*/
|
||||
static int davinci_eth_rcv_packet (struct eth_device *dev)
|
||||
{
|
||||
volatile emac_desc *rx_curr_desc;
|
||||
volatile emac_desc *curr_desc;
|
||||
volatile emac_desc *tail_desc;
|
||||
int status, ret = -1;
|
||||
|
||||
davinci_invalidate_rx_descs();
|
||||
|
||||
rx_curr_desc = emac_rx_active_head;
|
||||
status = rx_curr_desc->pkt_flag_len;
|
||||
if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
|
||||
if (status & EMAC_CPPI_RX_ERROR_FRAME) {
|
||||
/* Error in packet - discard it and requeue desc */
|
||||
printf ("WARN: emac_rcv_pkt: Error in packet\n");
|
||||
} else {
|
||||
unsigned long tmp = (unsigned long)rx_curr_desc->buffer;
|
||||
|
||||
invalidate_dcache_range(tmp, tmp + EMAC_RXBUF_SIZE);
|
||||
net_process_received_packet(
|
||||
rx_curr_desc->buffer,
|
||||
rx_curr_desc->buff_off_len & 0xffff);
|
||||
ret = rx_curr_desc->buff_off_len & 0xffff;
|
||||
}
|
||||
|
||||
/* Ack received packet descriptor */
|
||||
writel(BD_TO_HW((ulong)rx_curr_desc), &adap_emac->RX0CP);
|
||||
curr_desc = rx_curr_desc;
|
||||
emac_rx_active_head =
|
||||
(volatile emac_desc *) (HW_TO_BD(rx_curr_desc->next));
|
||||
|
||||
if (status & EMAC_CPPI_EOQ_BIT) {
|
||||
if (emac_rx_active_head) {
|
||||
writel(BD_TO_HW((ulong)emac_rx_active_head),
|
||||
&adap_emac->RX0HDP);
|
||||
} else {
|
||||
emac_rx_queue_active = 0;
|
||||
printf ("INFO:emac_rcv_packet: RX Queue not active\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Recycle RX descriptor */
|
||||
rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
|
||||
rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
|
||||
rx_curr_desc->next = 0;
|
||||
davinci_flush_desc(rx_curr_desc);
|
||||
|
||||
if (emac_rx_active_head == 0) {
|
||||
printf ("INFO: emac_rcv_pkt: active queue head = 0\n");
|
||||
emac_rx_active_head = curr_desc;
|
||||
emac_rx_active_tail = curr_desc;
|
||||
if (emac_rx_queue_active != 0) {
|
||||
writel(BD_TO_HW((ulong)emac_rx_active_head),
|
||||
&adap_emac->RX0HDP);
|
||||
printf ("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
|
||||
emac_rx_queue_active = 1;
|
||||
}
|
||||
} else {
|
||||
tail_desc = emac_rx_active_tail;
|
||||
emac_rx_active_tail = curr_desc;
|
||||
tail_desc->next = BD_TO_HW((ulong) curr_desc);
|
||||
status = tail_desc->pkt_flag_len;
|
||||
if (status & EMAC_CPPI_EOQ_BIT) {
|
||||
davinci_flush_desc(tail_desc);
|
||||
writel(BD_TO_HW((ulong)curr_desc),
|
||||
&adap_emac->RX0HDP);
|
||||
status &= ~EMAC_CPPI_EOQ_BIT;
|
||||
tail_desc->pkt_flag_len = status;
|
||||
}
|
||||
davinci_flush_desc(tail_desc);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the emac hardware. It does NOT initialize
|
||||
* EMAC modules power or pin multiplexors, that is done by board_init()
|
||||
* much earlier in bootup process. Returns 1 on success, 0 otherwise.
|
||||
*/
|
||||
int davinci_emac_initialize(void)
|
||||
{
|
||||
u_int32_t phy_id;
|
||||
u_int16_t tmp;
|
||||
int i;
|
||||
int ret;
|
||||
struct eth_device *dev;
|
||||
|
||||
dev = malloc(sizeof *dev);
|
||||
|
||||
if (dev == NULL)
|
||||
return -1;
|
||||
|
||||
memset(dev, 0, sizeof *dev);
|
||||
sprintf(dev->name, "DaVinci-EMAC");
|
||||
|
||||
dev->iobase = 0;
|
||||
dev->init = davinci_eth_open;
|
||||
dev->halt = davinci_eth_close;
|
||||
dev->send = davinci_eth_send_packet;
|
||||
dev->recv = davinci_eth_rcv_packet;
|
||||
dev->write_hwaddr = davinci_eth_set_mac_addr;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
davinci_eth_mdio_enable();
|
||||
|
||||
/* let the EMAC detect the PHYs */
|
||||
udelay(5000);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (readl(&adap_mdio->ALIVE))
|
||||
break;
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
if (i >= 256) {
|
||||
printf("No ETH PHY detected!!!\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Find if PHY(s) is/are connected */
|
||||
ret = davinci_eth_phy_detect();
|
||||
if (!ret)
|
||||
return(0);
|
||||
else
|
||||
debug_emac(" %d ETH PHY detected\n", ret);
|
||||
|
||||
/* Get PHY ID and initialize phy_ops for a detected PHY */
|
||||
for (i = 0; i < num_phy; i++) {
|
||||
if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID1,
|
||||
&tmp)) {
|
||||
active_phy_addr[i] = 0xff;
|
||||
continue;
|
||||
}
|
||||
|
||||
phy_id = (tmp << 16) & 0xffff0000;
|
||||
|
||||
if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID2,
|
||||
&tmp)) {
|
||||
active_phy_addr[i] = 0xff;
|
||||
continue;
|
||||
}
|
||||
|
||||
phy_id |= tmp & 0x0000ffff;
|
||||
|
||||
switch (phy_id) {
|
||||
#ifdef PHY_KSZ8873
|
||||
case PHY_KSZ8873:
|
||||
sprintf(phy[i].name, "KSZ8873 @ 0x%02x",
|
||||
active_phy_addr[i]);
|
||||
phy[i].init = ksz8873_init_phy;
|
||||
phy[i].is_phy_connected = ksz8873_is_phy_connected;
|
||||
phy[i].get_link_speed = ksz8873_get_link_speed;
|
||||
phy[i].auto_negotiate = ksz8873_auto_negotiate;
|
||||
break;
|
||||
#endif
|
||||
#ifdef PHY_LXT972
|
||||
case PHY_LXT972:
|
||||
sprintf(phy[i].name, "LXT972 @ 0x%02x",
|
||||
active_phy_addr[i]);
|
||||
phy[i].init = lxt972_init_phy;
|
||||
phy[i].is_phy_connected = lxt972_is_phy_connected;
|
||||
phy[i].get_link_speed = lxt972_get_link_speed;
|
||||
phy[i].auto_negotiate = lxt972_auto_negotiate;
|
||||
break;
|
||||
#endif
|
||||
#ifdef PHY_DP83848
|
||||
case PHY_DP83848:
|
||||
sprintf(phy[i].name, "DP83848 @ 0x%02x",
|
||||
active_phy_addr[i]);
|
||||
phy[i].init = dp83848_init_phy;
|
||||
phy[i].is_phy_connected = dp83848_is_phy_connected;
|
||||
phy[i].get_link_speed = dp83848_get_link_speed;
|
||||
phy[i].auto_negotiate = dp83848_auto_negotiate;
|
||||
break;
|
||||
#endif
|
||||
#ifdef PHY_ET1011C
|
||||
case PHY_ET1011C:
|
||||
sprintf(phy[i].name, "ET1011C @ 0x%02x",
|
||||
active_phy_addr[i]);
|
||||
phy[i].init = gen_init_phy;
|
||||
phy[i].is_phy_connected = gen_is_phy_connected;
|
||||
phy[i].get_link_speed = et1011c_get_link_speed;
|
||||
phy[i].auto_negotiate = gen_auto_negotiate;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
sprintf(phy[i].name, "GENERIC @ 0x%02x",
|
||||
active_phy_addr[i]);
|
||||
phy[i].init = gen_init_phy;
|
||||
phy[i].is_phy_connected = gen_is_phy_connected;
|
||||
phy[i].get_link_speed = gen_get_link_speed;
|
||||
phy[i].auto_negotiate = gen_auto_negotiate;
|
||||
}
|
||||
|
||||
debug("Ethernet PHY: %s\n", phy[i].name);
|
||||
|
||||
miiphy_register(phy[i].name, davinci_mii_phy_read,
|
||||
davinci_mii_phy_write);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
|
||||
defined(CONFIG_MACH_DAVINCI_DA850_EVM) && \
|
||||
!defined(CONFIG_DRIVER_TI_EMAC_RMII_NO_NEGOTIATE)
|
||||
for (i = 0; i < num_phy; i++) {
|
||||
if (phy[i].is_phy_connected(i))
|
||||
phy[i].auto_negotiate(i);
|
||||
}
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
303
sources/uboot-be550/drivers/net/davinci_emac.h
Normal file
303
sources/uboot-be550/drivers/net/davinci_emac.h
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Ilya Yanok, Emcraft Systems
|
||||
*
|
||||
* Based on: mach-davinci/emac_defs.h
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _DAVINCI_EMAC_H_
|
||||
#define _DAVINCI_EMAC_H_
|
||||
/* Ethernet Min/Max packet size */
|
||||
#define EMAC_MIN_ETHERNET_PKT_SIZE 60
|
||||
#define EMAC_MAX_ETHERNET_PKT_SIZE 1518
|
||||
/* Buffer size (should be aligned on 32 byte and cache line) */
|
||||
#define EMAC_RXBUF_SIZE ALIGN(ALIGN(EMAC_MAX_ETHERNET_PKT_SIZE, 32),\
|
||||
ARCH_DMA_MINALIGN)
|
||||
|
||||
/* Number of RX packet buffers
|
||||
* NOTE: Only 1 buffer supported as of now
|
||||
*/
|
||||
#define EMAC_MAX_RX_BUFFERS 10
|
||||
|
||||
|
||||
/***********************************************
|
||||
******** Internally used macros ***************
|
||||
***********************************************/
|
||||
|
||||
#define EMAC_CH_TX 1
|
||||
#define EMAC_CH_RX 0
|
||||
|
||||
/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
|
||||
* reserve space for 64 descriptors max
|
||||
*/
|
||||
#define EMAC_RX_DESC_BASE 0x0
|
||||
#define EMAC_TX_DESC_BASE 0x1000
|
||||
|
||||
/* EMAC Teardown value */
|
||||
#define EMAC_TEARDOWN_VALUE 0xfffffffc
|
||||
|
||||
/* MII Status Register */
|
||||
#define MII_STATUS_REG 1
|
||||
|
||||
/* Number of statistics registers */
|
||||
#define EMAC_NUM_STATS 36
|
||||
|
||||
|
||||
/* EMAC Descriptor */
|
||||
typedef volatile struct _emac_desc
|
||||
{
|
||||
u_int32_t next; /* Pointer to next descriptor
|
||||
in chain */
|
||||
u_int8_t *buffer; /* Pointer to data buffer */
|
||||
u_int32_t buff_off_len; /* Buffer Offset(MSW) and Length(LSW) */
|
||||
u_int32_t pkt_flag_len; /* Packet Flags(MSW) and Length(LSW) */
|
||||
} emac_desc;
|
||||
|
||||
/* CPPI bit positions */
|
||||
#define EMAC_CPPI_SOP_BIT (0x80000000)
|
||||
#define EMAC_CPPI_EOP_BIT (0x40000000)
|
||||
#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000)
|
||||
#define EMAC_CPPI_EOQ_BIT (0x10000000)
|
||||
#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000)
|
||||
#define EMAC_CPPI_PASS_CRC_BIT (0x04000000)
|
||||
|
||||
#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000)
|
||||
|
||||
#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20)
|
||||
#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1)
|
||||
#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7)
|
||||
#define EMAC_MACCONTROL_GIGFORCE (1 << 17)
|
||||
#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15)
|
||||
|
||||
#define EMAC_MAC_ADDR_MATCH (1 << 19)
|
||||
#define EMAC_MAC_ADDR_IS_VALID (1 << 20)
|
||||
|
||||
#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000)
|
||||
#define EMAC_RXMBPENABLE_RXBROADEN (0x2000)
|
||||
|
||||
|
||||
#define MDIO_CONTROL_IDLE (0x80000000)
|
||||
#define MDIO_CONTROL_ENABLE (0x40000000)
|
||||
#define MDIO_CONTROL_FAULT_ENABLE (0x40000)
|
||||
#define MDIO_CONTROL_FAULT (0x80000)
|
||||
#define MDIO_USERACCESS0_GO (0x80000000)
|
||||
#define MDIO_USERACCESS0_WRITE_READ (0x0)
|
||||
#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000)
|
||||
#define MDIO_USERACCESS0_ACK (0x20000000)
|
||||
|
||||
/* Ethernet MAC Registers Structure */
|
||||
typedef struct {
|
||||
dv_reg TXIDVER;
|
||||
dv_reg TXCONTROL;
|
||||
dv_reg TXTEARDOWN;
|
||||
u_int8_t RSVD0[4];
|
||||
dv_reg RXIDVER;
|
||||
dv_reg RXCONTROL;
|
||||
dv_reg RXTEARDOWN;
|
||||
u_int8_t RSVD1[100];
|
||||
dv_reg TXINTSTATRAW;
|
||||
dv_reg TXINTSTATMASKED;
|
||||
dv_reg TXINTMASKSET;
|
||||
dv_reg TXINTMASKCLEAR;
|
||||
dv_reg MACINVECTOR;
|
||||
u_int8_t RSVD2[12];
|
||||
dv_reg RXINTSTATRAW;
|
||||
dv_reg RXINTSTATMASKED;
|
||||
dv_reg RXINTMASKSET;
|
||||
dv_reg RXINTMASKCLEAR;
|
||||
dv_reg MACINTSTATRAW;
|
||||
dv_reg MACINTSTATMASKED;
|
||||
dv_reg MACINTMASKSET;
|
||||
dv_reg MACINTMASKCLEAR;
|
||||
u_int8_t RSVD3[64];
|
||||
dv_reg RXMBPENABLE;
|
||||
dv_reg RXUNICASTSET;
|
||||
dv_reg RXUNICASTCLEAR;
|
||||
dv_reg RXMAXLEN;
|
||||
dv_reg RXBUFFEROFFSET;
|
||||
dv_reg RXFILTERLOWTHRESH;
|
||||
u_int8_t RSVD4[8];
|
||||
dv_reg RX0FLOWTHRESH;
|
||||
dv_reg RX1FLOWTHRESH;
|
||||
dv_reg RX2FLOWTHRESH;
|
||||
dv_reg RX3FLOWTHRESH;
|
||||
dv_reg RX4FLOWTHRESH;
|
||||
dv_reg RX5FLOWTHRESH;
|
||||
dv_reg RX6FLOWTHRESH;
|
||||
dv_reg RX7FLOWTHRESH;
|
||||
dv_reg RX0FREEBUFFER;
|
||||
dv_reg RX1FREEBUFFER;
|
||||
dv_reg RX2FREEBUFFER;
|
||||
dv_reg RX3FREEBUFFER;
|
||||
dv_reg RX4FREEBUFFER;
|
||||
dv_reg RX5FREEBUFFER;
|
||||
dv_reg RX6FREEBUFFER;
|
||||
dv_reg RX7FREEBUFFER;
|
||||
dv_reg MACCONTROL;
|
||||
dv_reg MACSTATUS;
|
||||
dv_reg EMCONTROL;
|
||||
dv_reg FIFOCONTROL;
|
||||
dv_reg MACCONFIG;
|
||||
dv_reg SOFTRESET;
|
||||
u_int8_t RSVD5[88];
|
||||
dv_reg MACSRCADDRLO;
|
||||
dv_reg MACSRCADDRHI;
|
||||
dv_reg MACHASH1;
|
||||
dv_reg MACHASH2;
|
||||
dv_reg BOFFTEST;
|
||||
dv_reg TPACETEST;
|
||||
dv_reg RXPAUSE;
|
||||
dv_reg TXPAUSE;
|
||||
u_int8_t RSVD6[16];
|
||||
dv_reg RXGOODFRAMES;
|
||||
dv_reg RXBCASTFRAMES;
|
||||
dv_reg RXMCASTFRAMES;
|
||||
dv_reg RXPAUSEFRAMES;
|
||||
dv_reg RXCRCERRORS;
|
||||
dv_reg RXALIGNCODEERRORS;
|
||||
dv_reg RXOVERSIZED;
|
||||
dv_reg RXJABBER;
|
||||
dv_reg RXUNDERSIZED;
|
||||
dv_reg RXFRAGMENTS;
|
||||
dv_reg RXFILTERED;
|
||||
dv_reg RXQOSFILTERED;
|
||||
dv_reg RXOCTETS;
|
||||
dv_reg TXGOODFRAMES;
|
||||
dv_reg TXBCASTFRAMES;
|
||||
dv_reg TXMCASTFRAMES;
|
||||
dv_reg TXPAUSEFRAMES;
|
||||
dv_reg TXDEFERRED;
|
||||
dv_reg TXCOLLISION;
|
||||
dv_reg TXSINGLECOLL;
|
||||
dv_reg TXMULTICOLL;
|
||||
dv_reg TXEXCESSIVECOLL;
|
||||
dv_reg TXLATECOLL;
|
||||
dv_reg TXUNDERRUN;
|
||||
dv_reg TXCARRIERSENSE;
|
||||
dv_reg TXOCTETS;
|
||||
dv_reg FRAME64;
|
||||
dv_reg FRAME65T127;
|
||||
dv_reg FRAME128T255;
|
||||
dv_reg FRAME256T511;
|
||||
dv_reg FRAME512T1023;
|
||||
dv_reg FRAME1024TUP;
|
||||
dv_reg NETOCTETS;
|
||||
dv_reg RXSOFOVERRUNS;
|
||||
dv_reg RXMOFOVERRUNS;
|
||||
dv_reg RXDMAOVERRUNS;
|
||||
u_int8_t RSVD7[624];
|
||||
dv_reg MACADDRLO;
|
||||
dv_reg MACADDRHI;
|
||||
dv_reg MACINDEX;
|
||||
u_int8_t RSVD8[244];
|
||||
dv_reg TX0HDP;
|
||||
dv_reg TX1HDP;
|
||||
dv_reg TX2HDP;
|
||||
dv_reg TX3HDP;
|
||||
dv_reg TX4HDP;
|
||||
dv_reg TX5HDP;
|
||||
dv_reg TX6HDP;
|
||||
dv_reg TX7HDP;
|
||||
dv_reg RX0HDP;
|
||||
dv_reg RX1HDP;
|
||||
dv_reg RX2HDP;
|
||||
dv_reg RX3HDP;
|
||||
dv_reg RX4HDP;
|
||||
dv_reg RX5HDP;
|
||||
dv_reg RX6HDP;
|
||||
dv_reg RX7HDP;
|
||||
dv_reg TX0CP;
|
||||
dv_reg TX1CP;
|
||||
dv_reg TX2CP;
|
||||
dv_reg TX3CP;
|
||||
dv_reg TX4CP;
|
||||
dv_reg TX5CP;
|
||||
dv_reg TX6CP;
|
||||
dv_reg TX7CP;
|
||||
dv_reg RX0CP;
|
||||
dv_reg RX1CP;
|
||||
dv_reg RX2CP;
|
||||
dv_reg RX3CP;
|
||||
dv_reg RX4CP;
|
||||
dv_reg RX5CP;
|
||||
dv_reg RX6CP;
|
||||
dv_reg RX7CP;
|
||||
} emac_regs;
|
||||
|
||||
/* EMAC Wrapper Registers Structure */
|
||||
typedef struct {
|
||||
#ifdef DAVINCI_EMAC_VERSION2
|
||||
dv_reg idver;
|
||||
dv_reg softrst;
|
||||
dv_reg emctrl;
|
||||
dv_reg c0rxthreshen;
|
||||
dv_reg c0rxen;
|
||||
dv_reg c0txen;
|
||||
dv_reg c0miscen;
|
||||
dv_reg c1rxthreshen;
|
||||
dv_reg c1rxen;
|
||||
dv_reg c1txen;
|
||||
dv_reg c1miscen;
|
||||
dv_reg c2rxthreshen;
|
||||
dv_reg c2rxen;
|
||||
dv_reg c2txen;
|
||||
dv_reg c2miscen;
|
||||
dv_reg c0rxthreshstat;
|
||||
dv_reg c0rxstat;
|
||||
dv_reg c0txstat;
|
||||
dv_reg c0miscstat;
|
||||
dv_reg c1rxthreshstat;
|
||||
dv_reg c1rxstat;
|
||||
dv_reg c1txstat;
|
||||
dv_reg c1miscstat;
|
||||
dv_reg c2rxthreshstat;
|
||||
dv_reg c2rxstat;
|
||||
dv_reg c2txstat;
|
||||
dv_reg c2miscstat;
|
||||
dv_reg c0rximax;
|
||||
dv_reg c0tximax;
|
||||
dv_reg c1rximax;
|
||||
dv_reg c1tximax;
|
||||
dv_reg c2rximax;
|
||||
dv_reg c2tximax;
|
||||
#else
|
||||
u_int8_t RSVD0[4100];
|
||||
dv_reg EWCTL;
|
||||
dv_reg EWINTTCNT;
|
||||
#endif
|
||||
} ewrap_regs;
|
||||
|
||||
/* EMAC MDIO Registers Structure */
|
||||
typedef struct {
|
||||
dv_reg VERSION;
|
||||
dv_reg CONTROL;
|
||||
dv_reg ALIVE;
|
||||
dv_reg LINK;
|
||||
dv_reg LINKINTRAW;
|
||||
dv_reg LINKINTMASKED;
|
||||
u_int8_t RSVD0[8];
|
||||
dv_reg USERINTRAW;
|
||||
dv_reg USERINTMASKED;
|
||||
dv_reg USERINTMASKSET;
|
||||
dv_reg USERINTMASKCLEAR;
|
||||
u_int8_t RSVD1[80];
|
||||
dv_reg USERACCESS0;
|
||||
dv_reg USERPHYSEL0;
|
||||
dv_reg USERACCESS1;
|
||||
dv_reg USERPHYSEL1;
|
||||
} mdio_regs;
|
||||
|
||||
int davinci_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data);
|
||||
int davinci_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data);
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
int (*init)(int phy_addr);
|
||||
int (*is_phy_connected)(int phy_addr);
|
||||
int (*get_link_speed)(int phy_addr);
|
||||
int (*auto_negotiate)(int phy_addr);
|
||||
} phy_t;
|
||||
|
||||
#endif /* _DAVINCI_EMAC_H_ */
|
||||
763
sources/uboot-be550/drivers/net/dc2114x.c
Normal file
763
sources/uboot-be550/drivers/net/dc2114x.c
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <netdev.h>
|
||||
#include <pci.h>
|
||||
|
||||
#undef DEBUG_SROM
|
||||
#undef DEBUG_SROM2
|
||||
|
||||
#undef UPDATE_SROM
|
||||
|
||||
/* PCI Registers.
|
||||
*/
|
||||
#define PCI_CFDA_PSM 0x43
|
||||
|
||||
#define CFRV_RN 0x000000f0 /* Revision Number */
|
||||
|
||||
#define WAKEUP 0x00 /* Power Saving Wakeup */
|
||||
#define SLEEP 0x80 /* Power Saving Sleep Mode */
|
||||
|
||||
#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */
|
||||
|
||||
/* Ethernet chip registers.
|
||||
*/
|
||||
#define DE4X5_BMR 0x000 /* Bus Mode Register */
|
||||
#define DE4X5_TPD 0x008 /* Transmit Poll Demand Reg */
|
||||
#define DE4X5_RRBA 0x018 /* RX Ring Base Address Reg */
|
||||
#define DE4X5_TRBA 0x020 /* TX Ring Base Address Reg */
|
||||
#define DE4X5_STS 0x028 /* Status Register */
|
||||
#define DE4X5_OMR 0x030 /* Operation Mode Register */
|
||||
#define DE4X5_SICR 0x068 /* SIA Connectivity Register */
|
||||
#define DE4X5_APROM 0x048 /* Ethernet Address PROM */
|
||||
|
||||
/* Register bits.
|
||||
*/
|
||||
#define BMR_SWR 0x00000001 /* Software Reset */
|
||||
#define STS_TS 0x00700000 /* Transmit Process State */
|
||||
#define STS_RS 0x000e0000 /* Receive Process State */
|
||||
#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */
|
||||
#define OMR_SR 0x00000002 /* Start/Stop Receive */
|
||||
#define OMR_PS 0x00040000 /* Port Select */
|
||||
#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */
|
||||
#define OMR_PM 0x00000080 /* Pass All Multicast */
|
||||
|
||||
/* Descriptor bits.
|
||||
*/
|
||||
#define R_OWN 0x80000000 /* Own Bit */
|
||||
#define RD_RER 0x02000000 /* Receive End Of Ring */
|
||||
#define RD_LS 0x00000100 /* Last Descriptor */
|
||||
#define RD_ES 0x00008000 /* Error Summary */
|
||||
#define TD_TER 0x02000000 /* Transmit End Of Ring */
|
||||
#define T_OWN 0x80000000 /* Own Bit */
|
||||
#define TD_LS 0x40000000 /* Last Segment */
|
||||
#define TD_FS 0x20000000 /* First Segment */
|
||||
#define TD_ES 0x00008000 /* Error Summary */
|
||||
#define TD_SET 0x08000000 /* Setup Packet */
|
||||
|
||||
/* The EEPROM commands include the alway-set leading bit. */
|
||||
#define SROM_WRITE_CMD 5
|
||||
#define SROM_READ_CMD 6
|
||||
#define SROM_ERASE_CMD 7
|
||||
|
||||
#define SROM_HWADD 0x0014 /* Hardware Address offset in SROM */
|
||||
#define SROM_RD 0x00004000 /* Read from Boot ROM */
|
||||
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
|
||||
#define EE_WRITE_0 0x4801
|
||||
#define EE_WRITE_1 0x4805
|
||||
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
|
||||
#define SROM_SR 0x00000800 /* Select Serial ROM when set */
|
||||
|
||||
#define DT_IN 0x00000004 /* Serial Data In */
|
||||
#define DT_CLK 0x00000002 /* Serial ROM Clock */
|
||||
#define DT_CS 0x00000001 /* Serial ROM Chip Select */
|
||||
|
||||
#define POLL_DEMAND 1
|
||||
|
||||
#ifdef CONFIG_TULIP_FIX_DAVICOM
|
||||
#define RESET_DM9102(dev) {\
|
||||
unsigned long i;\
|
||||
i=INL(dev, 0x0);\
|
||||
udelay(1000);\
|
||||
OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
|
||||
udelay(1000);\
|
||||
}
|
||||
#else
|
||||
#define RESET_DE4X5(dev) {\
|
||||
int i;\
|
||||
i=INL(dev, DE4X5_BMR);\
|
||||
udelay(1000);\
|
||||
OUTL(dev, i | BMR_SWR, DE4X5_BMR);\
|
||||
udelay(1000);\
|
||||
OUTL(dev, i, DE4X5_BMR);\
|
||||
udelay(1000);\
|
||||
for (i=0;i<5;i++) {INL(dev, DE4X5_BMR); udelay(10000);}\
|
||||
udelay(1000);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define START_DE4X5(dev) {\
|
||||
s32 omr; \
|
||||
omr = INL(dev, DE4X5_OMR);\
|
||||
omr |= OMR_ST | OMR_SR;\
|
||||
OUTL(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */\
|
||||
}
|
||||
|
||||
#define STOP_DE4X5(dev) {\
|
||||
s32 omr; \
|
||||
omr = INL(dev, DE4X5_OMR);\
|
||||
omr &= ~(OMR_ST|OMR_SR);\
|
||||
OUTL(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ \
|
||||
}
|
||||
|
||||
#define NUM_RX_DESC PKTBUFSRX
|
||||
#ifndef CONFIG_TULIP_FIX_DAVICOM
|
||||
#define NUM_TX_DESC 1 /* Number of TX descriptors */
|
||||
#else
|
||||
#define NUM_TX_DESC 4
|
||||
#endif
|
||||
#define RX_BUFF_SZ PKTSIZE_ALIGN
|
||||
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
#define SETUP_FRAME_LEN 192
|
||||
#define ETH_ALEN 6
|
||||
|
||||
struct de4x5_desc {
|
||||
volatile s32 status;
|
||||
u32 des1;
|
||||
u32 buf;
|
||||
u32 next;
|
||||
};
|
||||
|
||||
static struct de4x5_desc rx_ring[NUM_RX_DESC] __attribute__ ((aligned(32))); /* RX descriptor ring */
|
||||
static struct de4x5_desc tx_ring[NUM_TX_DESC] __attribute__ ((aligned(32))); /* TX descriptor ring */
|
||||
static int rx_new; /* RX descriptor ring pointer */
|
||||
static int tx_new; /* TX descriptor ring pointer */
|
||||
|
||||
static char rxRingSize;
|
||||
static char txRingSize;
|
||||
|
||||
#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
|
||||
static void sendto_srom(struct eth_device* dev, u_int command, u_long addr);
|
||||
static int getfrom_srom(struct eth_device* dev, u_long addr);
|
||||
static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr,int cmd,int cmd_len);
|
||||
static int do_read_eeprom(struct eth_device *dev,u_long ioaddr,int location,int addr_len);
|
||||
#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
|
||||
#ifdef UPDATE_SROM
|
||||
static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value);
|
||||
static void update_srom(struct eth_device *dev, bd_t *bis);
|
||||
#endif
|
||||
#ifndef CONFIG_TULIP_FIX_DAVICOM
|
||||
static int read_srom(struct eth_device *dev, u_long ioaddr, int index);
|
||||
static void read_hw_addr(struct eth_device* dev, bd_t * bis);
|
||||
#endif /* CONFIG_TULIP_FIX_DAVICOM */
|
||||
static void send_setup_frame(struct eth_device* dev, bd_t * bis);
|
||||
|
||||
static int dc21x4x_init(struct eth_device* dev, bd_t* bis);
|
||||
static int dc21x4x_send(struct eth_device *dev, void *packet, int length);
|
||||
static int dc21x4x_recv(struct eth_device* dev);
|
||||
static void dc21x4x_halt(struct eth_device* dev);
|
||||
#ifdef CONFIG_TULIP_SELECT_MEDIA
|
||||
extern void dc21x4x_select_media(struct eth_device* dev);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_E500)
|
||||
#define phys_to_bus(a) (a)
|
||||
#else
|
||||
#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
|
||||
#endif
|
||||
|
||||
static int INL(struct eth_device* dev, u_long addr)
|
||||
{
|
||||
return le32_to_cpu(*(volatile u_long *)(addr + dev->iobase));
|
||||
}
|
||||
|
||||
static void OUTL(struct eth_device* dev, int command, u_long addr)
|
||||
{
|
||||
*(volatile u_long *)(addr + dev->iobase) = cpu_to_le32(command);
|
||||
}
|
||||
|
||||
static struct pci_device_id supported[] = {
|
||||
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST },
|
||||
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 },
|
||||
#ifdef CONFIG_TULIP_FIX_DAVICOM
|
||||
{ PCI_VENDOR_ID_DAVICOM, PCI_DEVICE_ID_DAVICOM_DM9102A },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
int dc21x4x_initialize(bd_t *bis)
|
||||
{
|
||||
int idx=0;
|
||||
int card_number = 0;
|
||||
unsigned int cfrv;
|
||||
unsigned char timer;
|
||||
pci_dev_t devbusfn;
|
||||
unsigned int iobase;
|
||||
unsigned short status;
|
||||
struct eth_device* dev;
|
||||
|
||||
while(1) {
|
||||
devbusfn = pci_find_devices(supported, idx++);
|
||||
if (devbusfn == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the chip configuration revision register. */
|
||||
pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv);
|
||||
|
||||
#ifndef CONFIG_TULIP_FIX_DAVICOM
|
||||
if ((cfrv & CFRV_RN) < DC2114x_BRK ) {
|
||||
printf("Error: The chip is not DC21143.\n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
pci_read_config_word(devbusfn, PCI_COMMAND, &status);
|
||||
status |=
|
||||
#ifdef CONFIG_TULIP_USE_IO
|
||||
PCI_COMMAND_IO |
|
||||
#else
|
||||
PCI_COMMAND_MEMORY |
|
||||
#endif
|
||||
PCI_COMMAND_MASTER;
|
||||
pci_write_config_word(devbusfn, PCI_COMMAND, status);
|
||||
|
||||
pci_read_config_word(devbusfn, PCI_COMMAND, &status);
|
||||
#ifdef CONFIG_TULIP_USE_IO
|
||||
if (!(status & PCI_COMMAND_IO)) {
|
||||
printf("Error: Can not enable I/O access.\n");
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
if (!(status & PCI_COMMAND_MEMORY)) {
|
||||
printf("Error: Can not enable MEMORY access.\n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(status & PCI_COMMAND_MASTER)) {
|
||||
printf("Error: Can not enable Bus Mastering.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check the latency timer for values >= 0x60. */
|
||||
pci_read_config_byte(devbusfn, PCI_LATENCY_TIMER, &timer);
|
||||
|
||||
if (timer < 0x60) {
|
||||
pci_write_config_byte(devbusfn, PCI_LATENCY_TIMER, 0x60);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TULIP_USE_IO
|
||||
/* read BAR for memory space access */
|
||||
pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &iobase);
|
||||
iobase &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
#else
|
||||
/* read BAR for memory space access */
|
||||
pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_1, &iobase);
|
||||
iobase &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||
#endif
|
||||
debug ("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase);
|
||||
|
||||
dev = (struct eth_device*) malloc(sizeof *dev);
|
||||
|
||||
if (!dev) {
|
||||
printf("Can not allocalte memory of dc21x4x\n");
|
||||
break;
|
||||
}
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
#ifdef CONFIG_TULIP_FIX_DAVICOM
|
||||
sprintf(dev->name, "Davicom#%d", card_number);
|
||||
#else
|
||||
sprintf(dev->name, "dc21x4x#%d", card_number);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TULIP_USE_IO
|
||||
dev->iobase = pci_io_to_phys(devbusfn, iobase);
|
||||
#else
|
||||
dev->iobase = pci_mem_to_phys(devbusfn, iobase);
|
||||
#endif
|
||||
dev->priv = (void*) devbusfn;
|
||||
dev->init = dc21x4x_init;
|
||||
dev->halt = dc21x4x_halt;
|
||||
dev->send = dc21x4x_send;
|
||||
dev->recv = dc21x4x_recv;
|
||||
|
||||
/* Ensure we're not sleeping. */
|
||||
pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
|
||||
|
||||
udelay(10 * 1000);
|
||||
|
||||
#ifndef CONFIG_TULIP_FIX_DAVICOM
|
||||
read_hw_addr(dev, bis);
|
||||
#endif
|
||||
eth_register(dev);
|
||||
|
||||
card_number++;
|
||||
}
|
||||
|
||||
return card_number;
|
||||
}
|
||||
|
||||
static int dc21x4x_init(struct eth_device* dev, bd_t* bis)
|
||||
{
|
||||
int i;
|
||||
int devbusfn = (int) dev->priv;
|
||||
|
||||
/* Ensure we're not sleeping. */
|
||||
pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP);
|
||||
|
||||
#ifdef CONFIG_TULIP_FIX_DAVICOM
|
||||
RESET_DM9102(dev);
|
||||
#else
|
||||
RESET_DE4X5(dev);
|
||||
#endif
|
||||
|
||||
if ((INL(dev, DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
|
||||
printf("Error: Cannot reset ethernet controller.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TULIP_SELECT_MEDIA
|
||||
dc21x4x_select_media(dev);
|
||||
#else
|
||||
OUTL(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NUM_RX_DESC; i++) {
|
||||
rx_ring[i].status = cpu_to_le32(R_OWN);
|
||||
rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
|
||||
rx_ring[i].buf = cpu_to_le32(
|
||||
phys_to_bus((u32)net_rx_packets[i]));
|
||||
#ifdef CONFIG_TULIP_FIX_DAVICOM
|
||||
rx_ring[i].next = cpu_to_le32(
|
||||
phys_to_bus((u32)&rx_ring[(i + 1) % NUM_RX_DESC]));
|
||||
#else
|
||||
rx_ring[i].next = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i=0; i < NUM_TX_DESC; i++) {
|
||||
tx_ring[i].status = 0;
|
||||
tx_ring[i].des1 = 0;
|
||||
tx_ring[i].buf = 0;
|
||||
|
||||
#ifdef CONFIG_TULIP_FIX_DAVICOM
|
||||
tx_ring[i].next = cpu_to_le32(phys_to_bus((u32) &tx_ring[(i+1) % NUM_TX_DESC]));
|
||||
#else
|
||||
tx_ring[i].next = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
rxRingSize = NUM_RX_DESC;
|
||||
txRingSize = NUM_TX_DESC;
|
||||
|
||||
/* Write the end of list marker to the descriptor lists. */
|
||||
rx_ring[rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
|
||||
tx_ring[txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
|
||||
|
||||
/* Tell the adapter where the TX/RX rings are located. */
|
||||
OUTL(dev, phys_to_bus((u32) &rx_ring), DE4X5_RRBA);
|
||||
OUTL(dev, phys_to_bus((u32) &tx_ring), DE4X5_TRBA);
|
||||
|
||||
START_DE4X5(dev);
|
||||
|
||||
tx_new = 0;
|
||||
rx_new = 0;
|
||||
|
||||
send_setup_frame(dev, bis);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dc21x4x_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
int status = -1;
|
||||
int i;
|
||||
|
||||
if (length <= 0) {
|
||||
printf("%s: bad packet size: %d\n", dev->name, length);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf("%s: tx error buffer not ready\n", dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) packet));
|
||||
tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
|
||||
tx_ring[tx_new].status = cpu_to_le32(T_OWN);
|
||||
|
||||
OUTL(dev, POLL_DEMAND, DE4X5_TPD);
|
||||
|
||||
for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf(".%s: tx buffer not ready\n", dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) {
|
||||
#if 0 /* test-only */
|
||||
printf("TX error status = 0x%08X\n",
|
||||
le32_to_cpu(tx_ring[tx_new].status));
|
||||
#endif
|
||||
tx_ring[tx_new].status = 0x0;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = length;
|
||||
|
||||
Done:
|
||||
tx_new = (tx_new+1) % NUM_TX_DESC;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int dc21x4x_recv(struct eth_device* dev)
|
||||
{
|
||||
s32 status;
|
||||
int length = 0;
|
||||
|
||||
for ( ; ; ) {
|
||||
status = (s32)le32_to_cpu(rx_ring[rx_new].status);
|
||||
|
||||
if (status & R_OWN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (status & RD_LS) {
|
||||
/* Valid frame status.
|
||||
*/
|
||||
if (status & RD_ES) {
|
||||
|
||||
/* There was an error.
|
||||
*/
|
||||
printf("RX error status = 0x%08X\n", status);
|
||||
} else {
|
||||
/* A valid frame received.
|
||||
*/
|
||||
length = (le32_to_cpu(rx_ring[rx_new].status) >> 16);
|
||||
|
||||
/* Pass the packet up to the protocol
|
||||
* layers.
|
||||
*/
|
||||
net_process_received_packet(
|
||||
net_rx_packets[rx_new], length - 4);
|
||||
}
|
||||
|
||||
/* Change buffer ownership for this frame, back
|
||||
* to the adapter.
|
||||
*/
|
||||
rx_ring[rx_new].status = cpu_to_le32(R_OWN);
|
||||
}
|
||||
|
||||
/* Update entry information.
|
||||
*/
|
||||
rx_new = (rx_new + 1) % rxRingSize;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static void dc21x4x_halt(struct eth_device* dev)
|
||||
{
|
||||
int devbusfn = (int) dev->priv;
|
||||
|
||||
STOP_DE4X5(dev);
|
||||
OUTL(dev, 0, DE4X5_SICR);
|
||||
|
||||
pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP);
|
||||
}
|
||||
|
||||
static void send_setup_frame(struct eth_device* dev, bd_t *bis)
|
||||
{
|
||||
int i;
|
||||
char setup_frame[SETUP_FRAME_LEN];
|
||||
char *pa = &setup_frame[0];
|
||||
|
||||
memset(pa, 0xff, SETUP_FRAME_LEN);
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
*(pa + (i & 1)) = dev->enetaddr[i];
|
||||
if (i & 0x01) {
|
||||
pa += 4;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf("%s: tx error buffer not ready\n", dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32) &setup_frame[0]));
|
||||
tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET| SETUP_FRAME_LEN);
|
||||
tx_ring[tx_new].status = cpu_to_le32(T_OWN);
|
||||
|
||||
OUTL(dev, POLL_DEMAND, DE4X5_TPD);
|
||||
|
||||
for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf("%s: tx buffer not ready\n", dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) {
|
||||
printf("TX error status2 = 0x%08X\n", le32_to_cpu(tx_ring[tx_new].status));
|
||||
}
|
||||
tx_new = (tx_new+1) % NUM_TX_DESC;
|
||||
|
||||
Done:
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
|
||||
/* SROM Read and write routines.
|
||||
*/
|
||||
static void
|
||||
sendto_srom(struct eth_device* dev, u_int command, u_long addr)
|
||||
{
|
||||
OUTL(dev, command, addr);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static int
|
||||
getfrom_srom(struct eth_device* dev, u_long addr)
|
||||
{
|
||||
s32 tmp;
|
||||
|
||||
tmp = INL(dev, addr);
|
||||
udelay(1);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Note: this routine returns extra data bits for size detection. */
|
||||
static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, int addr_len)
|
||||
{
|
||||
int i;
|
||||
unsigned retval = 0;
|
||||
int read_cmd = location | (SROM_READ_CMD << addr_len);
|
||||
|
||||
sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
|
||||
|
||||
#ifdef DEBUG_SROM
|
||||
printf(" EEPROM read at %d ", location);
|
||||
#endif
|
||||
|
||||
/* Shift the read command bits out. */
|
||||
for (i = 4 + addr_len; i >= 0; i--) {
|
||||
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval, ioaddr);
|
||||
udelay(10);
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK, ioaddr);
|
||||
udelay(10);
|
||||
#ifdef DEBUG_SROM2
|
||||
printf("%X", getfrom_srom(dev, ioaddr) & 15);
|
||||
#endif
|
||||
retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
|
||||
}
|
||||
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
|
||||
|
||||
#ifdef DEBUG_SROM2
|
||||
printf(" :%X:", getfrom_srom(dev, ioaddr) & 15);
|
||||
#endif
|
||||
|
||||
for (i = 16; i > 0; i--) {
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
|
||||
udelay(10);
|
||||
#ifdef DEBUG_SROM2
|
||||
printf("%X", getfrom_srom(dev, ioaddr) & 15);
|
||||
#endif
|
||||
retval = (retval << 1) | ((getfrom_srom(dev, ioaddr) & EE_DATA_READ) ? 1 : 0);
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/* Terminate the EEPROM access. */
|
||||
sendto_srom(dev, SROM_RD | SROM_SR, ioaddr);
|
||||
|
||||
#ifdef DEBUG_SROM2
|
||||
printf(" EEPROM value at %d is %5.5x.\n", location, retval);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
|
||||
|
||||
/* This executes a generic EEPROM command, typically a write or write
|
||||
* enable. It returns the data output from the EEPROM, and thus may
|
||||
* also be used for reads.
|
||||
*/
|
||||
#if defined(UPDATE_SROM) || !defined(CONFIG_TULIP_FIX_DAVICOM)
|
||||
static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, int cmd_len)
|
||||
{
|
||||
unsigned retval = 0;
|
||||
|
||||
#ifdef DEBUG_SROM
|
||||
printf(" EEPROM op 0x%x: ", cmd);
|
||||
#endif
|
||||
|
||||
sendto_srom(dev,SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr);
|
||||
|
||||
/* Shift the command bits out. */
|
||||
do {
|
||||
short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
|
||||
sendto_srom(dev,dataval, ioaddr);
|
||||
udelay(10);
|
||||
|
||||
#ifdef DEBUG_SROM2
|
||||
printf("%X", getfrom_srom(dev,ioaddr) & 15);
|
||||
#endif
|
||||
|
||||
sendto_srom(dev,dataval | DT_CLK, ioaddr);
|
||||
udelay(10);
|
||||
retval = (retval << 1) | ((getfrom_srom(dev,ioaddr) & EE_DATA_READ) ? 1 : 0);
|
||||
} while (--cmd_len >= 0);
|
||||
sendto_srom(dev,SROM_RD | SROM_SR | DT_CS, ioaddr);
|
||||
|
||||
/* Terminate the EEPROM access. */
|
||||
sendto_srom(dev,SROM_RD | SROM_SR, ioaddr);
|
||||
|
||||
#ifdef DEBUG_SROM
|
||||
printf(" EEPROM result is 0x%5.5x.\n", retval);
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* UPDATE_SROM || !CONFIG_TULIP_FIX_DAVICOM */
|
||||
|
||||
#ifndef CONFIG_TULIP_FIX_DAVICOM
|
||||
static int read_srom(struct eth_device *dev, u_long ioaddr, int index)
|
||||
{
|
||||
int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
|
||||
|
||||
return do_eeprom_cmd(dev, ioaddr,
|
||||
(((SROM_READ_CMD << ee_addr_size) | index) << 16)
|
||||
| 0xffff, 3 + ee_addr_size + 16);
|
||||
}
|
||||
#endif /* CONFIG_TULIP_FIX_DAVICOM */
|
||||
|
||||
#ifdef UPDATE_SROM
|
||||
static int write_srom(struct eth_device *dev, u_long ioaddr, int index, int new_value)
|
||||
{
|
||||
int ee_addr_size = do_read_eeprom(dev, ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
|
||||
int i;
|
||||
unsigned short newval;
|
||||
|
||||
udelay(10*1000); /* test-only */
|
||||
|
||||
#ifdef DEBUG_SROM
|
||||
printf("ee_addr_size=%d.\n", ee_addr_size);
|
||||
printf("Writing new entry 0x%4.4x to offset %d.\n", new_value, index);
|
||||
#endif
|
||||
|
||||
/* Enable programming modes. */
|
||||
do_eeprom_cmd(dev, ioaddr, (0x4f << (ee_addr_size-4)), 3+ee_addr_size);
|
||||
|
||||
/* Do the actual write. */
|
||||
do_eeprom_cmd(dev, ioaddr,
|
||||
(((SROM_WRITE_CMD<<ee_addr_size)|index) << 16) | new_value,
|
||||
3 + ee_addr_size + 16);
|
||||
|
||||
/* Poll for write finished. */
|
||||
sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr);
|
||||
for (i = 0; i < 10000; i++) /* Typical 2000 ticks */
|
||||
if (getfrom_srom(dev, ioaddr) & EE_DATA_READ)
|
||||
break;
|
||||
|
||||
#ifdef DEBUG_SROM
|
||||
printf(" Write finished after %d ticks.\n", i);
|
||||
#endif
|
||||
|
||||
/* Disable programming. */
|
||||
do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size-4)), 3 + ee_addr_size);
|
||||
|
||||
/* And read the result. */
|
||||
newval = do_eeprom_cmd(dev, ioaddr,
|
||||
(((SROM_READ_CMD<<ee_addr_size)|index) << 16)
|
||||
| 0xffff, 3 + ee_addr_size + 16);
|
||||
#ifdef DEBUG_SROM
|
||||
printf(" New value at offset %d is %4.4x.\n", index, newval);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TULIP_FIX_DAVICOM
|
||||
static void read_hw_addr(struct eth_device *dev, bd_t *bis)
|
||||
{
|
||||
u_short tmp, *p = (u_short *)(&dev->enetaddr[0]);
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; i < (ETH_ALEN >> 1); i++) {
|
||||
tmp = read_srom(dev, DE4X5_APROM, ((SROM_HWADD >> 1) + i));
|
||||
*p = le16_to_cpu(tmp);
|
||||
j += *p++;
|
||||
}
|
||||
|
||||
if ((j == 0) || (j == 0x2fffd)) {
|
||||
memset (dev->enetaddr, 0, ETH_ALEN);
|
||||
debug ("Warning: can't read HW address from SROM.\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
Done:
|
||||
#ifdef UPDATE_SROM
|
||||
update_srom(dev, bis);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_TULIP_FIX_DAVICOM */
|
||||
|
||||
#ifdef UPDATE_SROM
|
||||
static void update_srom(struct eth_device *dev, bd_t *bis)
|
||||
{
|
||||
int i;
|
||||
static unsigned short eeprom[0x40] = {
|
||||
0x140b, 0x6610, 0x0000, 0x0000, /* 00 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 04 */
|
||||
0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */
|
||||
0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */
|
||||
0x0108, 0x038d, 0x0000, 0x0000, /* 10 */
|
||||
0xe078, 0x0001, 0x0040, 0x0018, /* 14 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 18 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 1c */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 20 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 24 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 28 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 2c */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 30 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 34 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 38 */
|
||||
0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */
|
||||
};
|
||||
uchar enetaddr[6];
|
||||
|
||||
/* Ethernet Addr... */
|
||||
if (!eth_getenv_enetaddr("ethaddr", enetaddr))
|
||||
return;
|
||||
eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0];
|
||||
eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2];
|
||||
eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4];
|
||||
|
||||
for (i=0; i<0x40; i++) {
|
||||
write_srom(dev, DE4X5_APROM, i, eeprom[i]);
|
||||
}
|
||||
}
|
||||
#endif /* UPDATE_SROM */
|
||||
676
sources/uboot-be550/drivers/net/designware.c
Normal file
676
sources/uboot-be550/drivers/net/designware.c
Normal file
|
|
@ -0,0 +1,676 @@
|
|||
/*
|
||||
* (C) Copyright 2010
|
||||
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Designware ethernet IP driver for U-Boot
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <miiphy.h>
|
||||
#include <malloc.h>
|
||||
#include <pci.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/io.h>
|
||||
#include "designware.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct eth_mac_regs *mac_p = bus->priv;
|
||||
ulong start;
|
||||
u16 miiaddr;
|
||||
int timeout = CONFIG_MDIO_TIMEOUT;
|
||||
|
||||
miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
|
||||
((reg << MIIREGSHIFT) & MII_REGMSK);
|
||||
|
||||
writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
|
||||
|
||||
start = get_timer(0);
|
||||
while (get_timer(start) < timeout) {
|
||||
if (!(readl(&mac_p->miiaddr) & MII_BUSY))
|
||||
return readl(&mac_p->miidata);
|
||||
udelay(10);
|
||||
};
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
||||
u16 val)
|
||||
{
|
||||
struct eth_mac_regs *mac_p = bus->priv;
|
||||
ulong start;
|
||||
u16 miiaddr;
|
||||
int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT;
|
||||
|
||||
writel(val, &mac_p->miidata);
|
||||
miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
|
||||
((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
|
||||
|
||||
writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
|
||||
|
||||
start = get_timer(0);
|
||||
while (get_timer(start) < timeout) {
|
||||
if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
udelay(10);
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
|
||||
{
|
||||
struct mii_dev *bus = mdio_alloc();
|
||||
|
||||
if (!bus) {
|
||||
printf("Failed to allocate MDIO bus\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus->read = dw_mdio_read;
|
||||
bus->write = dw_mdio_write;
|
||||
snprintf(bus->name, sizeof(bus->name), name);
|
||||
|
||||
bus->priv = (void *)mac_regs_p;
|
||||
|
||||
return mdio_register(bus);
|
||||
}
|
||||
|
||||
static void tx_descs_init(struct dw_eth_dev *priv)
|
||||
{
|
||||
struct eth_dma_regs *dma_p = priv->dma_regs_p;
|
||||
struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
|
||||
char *txbuffs = &priv->txbuffs[0];
|
||||
struct dmamacdescr *desc_p;
|
||||
u32 idx;
|
||||
|
||||
for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
|
||||
desc_p = &desc_table_p[idx];
|
||||
desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
|
||||
desc_p->dmamac_next = &desc_table_p[idx + 1];
|
||||
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
|
||||
DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS |
|
||||
DESC_TXSTS_TXCHECKINSCTRL |
|
||||
DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
|
||||
|
||||
desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
|
||||
desc_p->dmamac_cntl = 0;
|
||||
desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
|
||||
#else
|
||||
desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
|
||||
desc_p->txrx_status = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Correcting the last pointer of the chain */
|
||||
desc_p->dmamac_next = &desc_table_p[0];
|
||||
|
||||
/* Flush all Tx buffer descriptors at once */
|
||||
flush_dcache_range((unsigned int)priv->tx_mac_descrtable,
|
||||
(unsigned int)priv->tx_mac_descrtable +
|
||||
sizeof(priv->tx_mac_descrtable));
|
||||
|
||||
writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
|
||||
priv->tx_currdescnum = 0;
|
||||
}
|
||||
|
||||
static void rx_descs_init(struct dw_eth_dev *priv)
|
||||
{
|
||||
struct eth_dma_regs *dma_p = priv->dma_regs_p;
|
||||
struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
|
||||
char *rxbuffs = &priv->rxbuffs[0];
|
||||
struct dmamacdescr *desc_p;
|
||||
u32 idx;
|
||||
|
||||
/* Before passing buffers to GMAC we need to make sure zeros
|
||||
* written there right after "priv" structure allocation were
|
||||
* flushed into RAM.
|
||||
* Otherwise there's a chance to get some of them flushed in RAM when
|
||||
* GMAC is already pushing data to RAM via DMA. This way incoming from
|
||||
* GMAC data will be corrupted. */
|
||||
flush_dcache_range((unsigned int)rxbuffs, (unsigned int)rxbuffs +
|
||||
RX_TOTAL_BUFSIZE);
|
||||
|
||||
for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
|
||||
desc_p = &desc_table_p[idx];
|
||||
desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
|
||||
desc_p->dmamac_next = &desc_table_p[idx + 1];
|
||||
|
||||
desc_p->dmamac_cntl =
|
||||
(MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) |
|
||||
DESC_RXCTRL_RXCHAIN;
|
||||
|
||||
desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
|
||||
}
|
||||
|
||||
/* Correcting the last pointer of the chain */
|
||||
desc_p->dmamac_next = &desc_table_p[0];
|
||||
|
||||
/* Flush all Rx buffer descriptors at once */
|
||||
flush_dcache_range((unsigned int)priv->rx_mac_descrtable,
|
||||
(unsigned int)priv->rx_mac_descrtable +
|
||||
sizeof(priv->rx_mac_descrtable));
|
||||
|
||||
writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
|
||||
priv->rx_currdescnum = 0;
|
||||
}
|
||||
|
||||
static int _dw_write_hwaddr(struct dw_eth_dev *priv, u8 *mac_id)
|
||||
{
|
||||
struct eth_mac_regs *mac_p = priv->mac_regs_p;
|
||||
u32 macid_lo, macid_hi;
|
||||
|
||||
macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
|
||||
(mac_id[3] << 24);
|
||||
macid_hi = mac_id[4] + (mac_id[5] << 8);
|
||||
|
||||
writel(macid_hi, &mac_p->macaddr0hi);
|
||||
writel(macid_lo, &mac_p->macaddr0lo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_adjust_link(struct eth_mac_regs *mac_p,
|
||||
struct phy_device *phydev)
|
||||
{
|
||||
u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
|
||||
|
||||
if (!phydev->link) {
|
||||
printf("%s: No link.\n", phydev->dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (phydev->speed != 1000)
|
||||
conf |= MII_PORTSELECT;
|
||||
|
||||
if (phydev->speed == 100)
|
||||
conf |= FES_100;
|
||||
|
||||
if (phydev->duplex)
|
||||
conf |= FULLDPLXMODE;
|
||||
|
||||
writel(conf, &mac_p->conf);
|
||||
|
||||
printf("Speed: %d, %s duplex%s\n", phydev->speed,
|
||||
(phydev->duplex) ? "full" : "half",
|
||||
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
|
||||
}
|
||||
|
||||
static void _dw_eth_halt(struct dw_eth_dev *priv)
|
||||
{
|
||||
struct eth_mac_regs *mac_p = priv->mac_regs_p;
|
||||
struct eth_dma_regs *dma_p = priv->dma_regs_p;
|
||||
|
||||
writel(readl(&mac_p->conf) & ~(RXENABLE | TXENABLE), &mac_p->conf);
|
||||
writel(readl(&dma_p->opmode) & ~(RXSTART | TXSTART), &dma_p->opmode);
|
||||
|
||||
phy_shutdown(priv->phydev);
|
||||
}
|
||||
|
||||
static int _dw_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
|
||||
{
|
||||
struct eth_mac_regs *mac_p = priv->mac_regs_p;
|
||||
struct eth_dma_regs *dma_p = priv->dma_regs_p;
|
||||
unsigned int start;
|
||||
int ret;
|
||||
|
||||
writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
|
||||
|
||||
start = get_timer(0);
|
||||
while (readl(&dma_p->busmode) & DMAMAC_SRST) {
|
||||
if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT) {
|
||||
printf("DMA reset timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
mdelay(100);
|
||||
};
|
||||
|
||||
/*
|
||||
* Soft reset above clears HW address registers.
|
||||
* So we have to set it here once again.
|
||||
*/
|
||||
_dw_write_hwaddr(priv, enetaddr);
|
||||
|
||||
rx_descs_init(priv);
|
||||
tx_descs_init(priv);
|
||||
|
||||
writel(FIXEDBURST | PRIORXTX_41 | DMA_PBL, &dma_p->busmode);
|
||||
|
||||
#ifndef CONFIG_DW_MAC_FORCE_THRESHOLD_MODE
|
||||
writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD,
|
||||
&dma_p->opmode);
|
||||
#else
|
||||
writel(readl(&dma_p->opmode) | FLUSHTXFIFO,
|
||||
&dma_p->opmode);
|
||||
#endif
|
||||
|
||||
writel(readl(&dma_p->opmode) | RXSTART | TXSTART, &dma_p->opmode);
|
||||
|
||||
#ifdef CONFIG_DW_AXI_BURST_LEN
|
||||
writel((CONFIG_DW_AXI_BURST_LEN & 0x1FF >> 1), &dma_p->axibus);
|
||||
#endif
|
||||
|
||||
/* Start up the PHY */
|
||||
ret = phy_startup(priv->phydev);
|
||||
if (ret) {
|
||||
printf("Could not initialize PHY %s\n",
|
||||
priv->phydev->dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dw_adjust_link(mac_p, priv->phydev);
|
||||
|
||||
if (!priv->phydev->link)
|
||||
return -EIO;
|
||||
|
||||
writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
|
||||
{
|
||||
struct eth_dma_regs *dma_p = priv->dma_regs_p;
|
||||
u32 desc_num = priv->tx_currdescnum;
|
||||
struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
|
||||
uint32_t desc_start = (uint32_t)desc_p;
|
||||
uint32_t desc_end = desc_start +
|
||||
roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
|
||||
uint32_t data_start = (uint32_t)desc_p->dmamac_addr;
|
||||
uint32_t data_end = data_start +
|
||||
roundup(length, ARCH_DMA_MINALIGN);
|
||||
/*
|
||||
* Strictly we only need to invalidate the "txrx_status" field
|
||||
* for the following check, but on some platforms we cannot
|
||||
* invalidate only 4 bytes, so we flush the entire descriptor,
|
||||
* which is 16 bytes in total. This is safe because the
|
||||
* individual descriptors in the array are each aligned to
|
||||
* ARCH_DMA_MINALIGN and padded appropriately.
|
||||
*/
|
||||
invalidate_dcache_range(desc_start, desc_end);
|
||||
|
||||
/* Check if the descriptor is owned by CPU */
|
||||
if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
|
||||
printf("CPU not owner of tx frame\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
memcpy(desc_p->dmamac_addr, packet, length);
|
||||
|
||||
/* Flush data to be sent */
|
||||
flush_dcache_range(data_start, data_end);
|
||||
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
|
||||
desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) &
|
||||
DESC_TXCTRL_SIZE1MASK;
|
||||
|
||||
desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
|
||||
desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
|
||||
#else
|
||||
desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) &
|
||||
DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST |
|
||||
DESC_TXCTRL_TXFIRST;
|
||||
|
||||
desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
|
||||
#endif
|
||||
|
||||
/* Flush modified buffer descriptor */
|
||||
flush_dcache_range(desc_start, desc_end);
|
||||
|
||||
/* Test the wrap-around condition. */
|
||||
if (++desc_num >= CONFIG_TX_DESCR_NUM)
|
||||
desc_num = 0;
|
||||
|
||||
priv->tx_currdescnum = desc_num;
|
||||
|
||||
/* Start the transmission */
|
||||
writel(POLL_DATA, &dma_p->txpolldemand);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
|
||||
{
|
||||
u32 status, desc_num = priv->rx_currdescnum;
|
||||
struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
|
||||
int length = -EAGAIN;
|
||||
uint32_t desc_start = (uint32_t)desc_p;
|
||||
uint32_t desc_end = desc_start +
|
||||
roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
|
||||
uint32_t data_start = (uint32_t)desc_p->dmamac_addr;
|
||||
uint32_t data_end;
|
||||
|
||||
/* Invalidate entire buffer descriptor */
|
||||
invalidate_dcache_range(desc_start, desc_end);
|
||||
|
||||
status = desc_p->txrx_status;
|
||||
|
||||
/* Check if the owner is the CPU */
|
||||
if (!(status & DESC_RXSTS_OWNBYDMA)) {
|
||||
|
||||
length = (status & DESC_RXSTS_FRMLENMSK) >>
|
||||
DESC_RXSTS_FRMLENSHFT;
|
||||
|
||||
/* Invalidate received data */
|
||||
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
|
||||
invalidate_dcache_range(data_start, data_end);
|
||||
*packetp = desc_p->dmamac_addr;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int _dw_free_pkt(struct dw_eth_dev *priv)
|
||||
{
|
||||
u32 desc_num = priv->rx_currdescnum;
|
||||
struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
|
||||
uint32_t desc_start = (uint32_t)desc_p;
|
||||
uint32_t desc_end = desc_start +
|
||||
roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
|
||||
|
||||
/*
|
||||
* Make the current descriptor valid again and go to
|
||||
* the next one
|
||||
*/
|
||||
desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
|
||||
|
||||
/* Flush only status field - others weren't changed */
|
||||
flush_dcache_range(desc_start, desc_end);
|
||||
|
||||
/* Test the wrap-around condition. */
|
||||
if (++desc_num >= CONFIG_RX_DESCR_NUM)
|
||||
desc_num = 0;
|
||||
priv->rx_currdescnum = desc_num;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
|
||||
{
|
||||
struct phy_device *phydev;
|
||||
int mask = 0xffffffff;
|
||||
|
||||
#ifdef CONFIG_PHY_ADDR
|
||||
mask = 1 << CONFIG_PHY_ADDR;
|
||||
#endif
|
||||
|
||||
phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
|
||||
if (!phydev)
|
||||
return -ENODEV;
|
||||
|
||||
phy_connect_dev(phydev, dev);
|
||||
|
||||
phydev->supported &= PHY_GBIT_FEATURES;
|
||||
phydev->advertising = phydev->supported;
|
||||
|
||||
priv->phydev = phydev;
|
||||
phy_config(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_ETH
|
||||
static int dw_eth_init(struct eth_device *dev, bd_t *bis)
|
||||
{
|
||||
return _dw_eth_init(dev->priv, dev->enetaddr);
|
||||
}
|
||||
|
||||
static int dw_eth_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
return _dw_eth_send(dev->priv, packet, length);
|
||||
}
|
||||
|
||||
static int dw_eth_recv(struct eth_device *dev)
|
||||
{
|
||||
uchar *packet;
|
||||
int length;
|
||||
|
||||
length = _dw_eth_recv(dev->priv, &packet);
|
||||
if (length == -EAGAIN)
|
||||
return 0;
|
||||
net_process_received_packet(packet, length);
|
||||
|
||||
_dw_free_pkt(dev->priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_eth_halt(struct eth_device *dev)
|
||||
{
|
||||
return _dw_eth_halt(dev->priv);
|
||||
}
|
||||
|
||||
static int dw_write_hwaddr(struct eth_device *dev)
|
||||
{
|
||||
return _dw_write_hwaddr(dev->priv, dev->enetaddr);
|
||||
}
|
||||
|
||||
int designware_initialize(ulong base_addr, u32 interface)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct dw_eth_dev *priv;
|
||||
|
||||
dev = (struct eth_device *) malloc(sizeof(struct eth_device));
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Since the priv structure contains the descriptors which need a strict
|
||||
* buswidth alignment, memalign is used to allocate memory
|
||||
*/
|
||||
priv = (struct dw_eth_dev *) memalign(ARCH_DMA_MINALIGN,
|
||||
sizeof(struct dw_eth_dev));
|
||||
if (!priv) {
|
||||
free(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(struct eth_device));
|
||||
memset(priv, 0, sizeof(struct dw_eth_dev));
|
||||
|
||||
sprintf(dev->name, "dwmac.%lx", base_addr);
|
||||
dev->iobase = (int)base_addr;
|
||||
dev->priv = priv;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
|
||||
priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
|
||||
DW_DMA_BASE_OFFSET);
|
||||
|
||||
dev->init = dw_eth_init;
|
||||
dev->send = dw_eth_send;
|
||||
dev->recv = dw_eth_recv;
|
||||
dev->halt = dw_eth_halt;
|
||||
dev->write_hwaddr = dw_write_hwaddr;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
priv->interface = interface;
|
||||
|
||||
dw_mdio_init(dev->name, priv->mac_regs_p);
|
||||
priv->bus = miiphy_get_dev_by_name(dev->name);
|
||||
|
||||
return dw_phy_init(priv, dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
static int designware_eth_start(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
|
||||
return _dw_eth_init(dev->priv, pdata->enetaddr);
|
||||
}
|
||||
|
||||
static int designware_eth_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
return _dw_eth_send(priv, packet, length);
|
||||
}
|
||||
|
||||
static int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
{
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
return _dw_eth_recv(priv, packetp);
|
||||
}
|
||||
|
||||
static int designware_eth_free_pkt(struct udevice *dev, uchar *packet,
|
||||
int length)
|
||||
{
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
return _dw_free_pkt(priv);
|
||||
}
|
||||
|
||||
static void designware_eth_stop(struct udevice *dev)
|
||||
{
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
return _dw_eth_halt(priv);
|
||||
}
|
||||
|
||||
static int designware_eth_write_hwaddr(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
return _dw_write_hwaddr(priv, pdata->enetaddr);
|
||||
}
|
||||
|
||||
static int designware_eth_bind(struct udevice *dev)
|
||||
{
|
||||
#ifdef CONFIG_DM_PCI
|
||||
static int num_cards;
|
||||
char name[20];
|
||||
|
||||
/* Create a unique device name for PCI type devices */
|
||||
if (device_is_on_pci_bus(dev)) {
|
||||
sprintf(name, "eth_designware#%u", num_cards++);
|
||||
device_set_name(dev, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int designware_eth_probe(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
u32 iobase = pdata->iobase;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_DM_PCI
|
||||
/*
|
||||
* If we are on PCI bus, either directly attached to a PCI root port,
|
||||
* or via a PCI bridge, fill in platdata before we probe the hardware.
|
||||
*/
|
||||
if (device_is_on_pci_bus(dev)) {
|
||||
pci_dev_t bdf = pci_get_bdf(dev);
|
||||
|
||||
dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase);
|
||||
iobase &= PCI_BASE_ADDRESS_MEM_MASK;
|
||||
iobase = pci_mem_to_phys(bdf, iobase);
|
||||
|
||||
pdata->iobase = iobase;
|
||||
pdata->phy_interface = PHY_INTERFACE_MODE_RMII;
|
||||
}
|
||||
#endif
|
||||
|
||||
debug("%s, iobase=%x, priv=%p\n", __func__, iobase, priv);
|
||||
priv->mac_regs_p = (struct eth_mac_regs *)iobase;
|
||||
priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
|
||||
priv->interface = pdata->phy_interface;
|
||||
|
||||
dw_mdio_init(dev->name, priv->mac_regs_p);
|
||||
priv->bus = miiphy_get_dev_by_name(dev->name);
|
||||
|
||||
ret = dw_phy_init(priv, dev);
|
||||
debug("%s, ret=%d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int designware_eth_remove(struct udevice *dev)
|
||||
{
|
||||
struct dw_eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
free(priv->phydev);
|
||||
mdio_unregister(priv->bus);
|
||||
mdio_free(priv->bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_ops designware_eth_ops = {
|
||||
.start = designware_eth_start,
|
||||
.send = designware_eth_send,
|
||||
.recv = designware_eth_recv,
|
||||
.free_pkt = designware_eth_free_pkt,
|
||||
.stop = designware_eth_stop,
|
||||
.write_hwaddr = designware_eth_write_hwaddr,
|
||||
};
|
||||
|
||||
static int designware_eth_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
const char *phy_mode;
|
||||
|
||||
pdata->iobase = dev_get_addr(dev);
|
||||
pdata->phy_interface = -1;
|
||||
phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
|
||||
if (phy_mode)
|
||||
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
|
||||
if (pdata->phy_interface == -1) {
|
||||
debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id designware_eth_ids[] = {
|
||||
{ .compatible = "allwinner,sun7i-a20-gmac" },
|
||||
{ .compatible = "altr,socfpga-stmmac" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(eth_designware) = {
|
||||
.name = "eth_designware",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = designware_eth_ids,
|
||||
.ofdata_to_platdata = designware_eth_ofdata_to_platdata,
|
||||
.bind = designware_eth_bind,
|
||||
.probe = designware_eth_probe,
|
||||
.remove = designware_eth_remove,
|
||||
.ops = &designware_eth_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct dw_eth_dev),
|
||||
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
|
||||
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
||||
};
|
||||
|
||||
static struct pci_device_id supported[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_EMAC) },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_PCI_DEVICE(eth_designware, supported);
|
||||
#endif
|
||||
238
sources/uboot-be550/drivers/net/designware.h
Normal file
238
sources/uboot-be550/drivers/net/designware.h
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* (C) Copyright 2010
|
||||
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _DW_ETH_H
|
||||
#define _DW_ETH_H
|
||||
|
||||
#define CONFIG_TX_DESCR_NUM 16
|
||||
#define CONFIG_RX_DESCR_NUM 16
|
||||
#define CONFIG_ETH_BUFSIZE 2048
|
||||
#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
|
||||
#define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
|
||||
|
||||
#define CONFIG_MACRESET_TIMEOUT (3 * CONFIG_SYS_HZ)
|
||||
#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ)
|
||||
|
||||
struct eth_mac_regs {
|
||||
u32 conf; /* 0x00 */
|
||||
u32 framefilt; /* 0x04 */
|
||||
u32 hashtablehigh; /* 0x08 */
|
||||
u32 hashtablelow; /* 0x0c */
|
||||
u32 miiaddr; /* 0x10 */
|
||||
u32 miidata; /* 0x14 */
|
||||
u32 flowcontrol; /* 0x18 */
|
||||
u32 vlantag; /* 0x1c */
|
||||
u32 version; /* 0x20 */
|
||||
u8 reserved_1[20];
|
||||
u32 intreg; /* 0x38 */
|
||||
u32 intmask; /* 0x3c */
|
||||
u32 macaddr0hi; /* 0x40 */
|
||||
u32 macaddr0lo; /* 0x44 */
|
||||
};
|
||||
|
||||
/* MAC configuration register definitions */
|
||||
#define FRAMEBURSTENABLE (1 << 21)
|
||||
#define MII_PORTSELECT (1 << 15)
|
||||
#define FES_100 (1 << 14)
|
||||
#define DISABLERXOWN (1 << 13)
|
||||
#define FULLDPLXMODE (1 << 11)
|
||||
#define RXENABLE (1 << 2)
|
||||
#define TXENABLE (1 << 3)
|
||||
|
||||
/* MII address register definitions */
|
||||
#define MII_BUSY (1 << 0)
|
||||
#define MII_WRITE (1 << 1)
|
||||
#define MII_CLKRANGE_60_100M (0)
|
||||
#define MII_CLKRANGE_100_150M (0x4)
|
||||
#define MII_CLKRANGE_20_35M (0x8)
|
||||
#define MII_CLKRANGE_35_60M (0xC)
|
||||
#define MII_CLKRANGE_150_250M (0x10)
|
||||
#define MII_CLKRANGE_250_300M (0x14)
|
||||
|
||||
#define MIIADDRSHIFT (11)
|
||||
#define MIIREGSHIFT (6)
|
||||
#define MII_REGMSK (0x1F << 6)
|
||||
#define MII_ADDRMSK (0x1F << 11)
|
||||
|
||||
|
||||
struct eth_dma_regs {
|
||||
u32 busmode; /* 0x00 */
|
||||
u32 txpolldemand; /* 0x04 */
|
||||
u32 rxpolldemand; /* 0x08 */
|
||||
u32 rxdesclistaddr; /* 0x0c */
|
||||
u32 txdesclistaddr; /* 0x10 */
|
||||
u32 status; /* 0x14 */
|
||||
u32 opmode; /* 0x18 */
|
||||
u32 intenable; /* 0x1c */
|
||||
u32 reserved1[2];
|
||||
u32 axibus; /* 0x28 */
|
||||
u32 reserved2[7];
|
||||
u32 currhosttxdesc; /* 0x48 */
|
||||
u32 currhostrxdesc; /* 0x4c */
|
||||
u32 currhosttxbuffaddr; /* 0x50 */
|
||||
u32 currhostrxbuffaddr; /* 0x54 */
|
||||
};
|
||||
|
||||
#define DW_DMA_BASE_OFFSET (0x1000)
|
||||
|
||||
/* Default DMA Burst length */
|
||||
#ifndef CONFIG_DW_GMAC_DEFAULT_DMA_PBL
|
||||
#define CONFIG_DW_GMAC_DEFAULT_DMA_PBL 8
|
||||
#endif
|
||||
|
||||
/* Bus mode register definitions */
|
||||
#define FIXEDBURST (1 << 16)
|
||||
#define PRIORXTX_41 (3 << 14)
|
||||
#define PRIORXTX_31 (2 << 14)
|
||||
#define PRIORXTX_21 (1 << 14)
|
||||
#define PRIORXTX_11 (0 << 14)
|
||||
#define DMA_PBL (CONFIG_DW_GMAC_DEFAULT_DMA_PBL<<8)
|
||||
#define RXHIGHPRIO (1 << 1)
|
||||
#define DMAMAC_SRST (1 << 0)
|
||||
|
||||
/* Poll demand definitions */
|
||||
#define POLL_DATA (0xFFFFFFFF)
|
||||
|
||||
/* Operation mode definitions */
|
||||
#define STOREFORWARD (1 << 21)
|
||||
#define FLUSHTXFIFO (1 << 20)
|
||||
#define TXSTART (1 << 13)
|
||||
#define TXSECONDFRAME (1 << 2)
|
||||
#define RXSTART (1 << 1)
|
||||
|
||||
/* Descriptior related definitions */
|
||||
#define MAC_MAX_FRAME_SZ (1600)
|
||||
|
||||
struct dmamacdescr {
|
||||
u32 txrx_status;
|
||||
u32 dmamac_cntl;
|
||||
void *dmamac_addr;
|
||||
struct dmamacdescr *dmamac_next;
|
||||
} __aligned(ARCH_DMA_MINALIGN);
|
||||
|
||||
/*
|
||||
* txrx_status definitions
|
||||
*/
|
||||
|
||||
/* tx status bits definitions */
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
|
||||
#define DESC_TXSTS_OWNBYDMA (1 << 31)
|
||||
#define DESC_TXSTS_TXINT (1 << 30)
|
||||
#define DESC_TXSTS_TXLAST (1 << 29)
|
||||
#define DESC_TXSTS_TXFIRST (1 << 28)
|
||||
#define DESC_TXSTS_TXCRCDIS (1 << 27)
|
||||
|
||||
#define DESC_TXSTS_TXPADDIS (1 << 26)
|
||||
#define DESC_TXSTS_TXCHECKINSCTRL (3 << 22)
|
||||
#define DESC_TXSTS_TXRINGEND (1 << 21)
|
||||
#define DESC_TXSTS_TXCHAIN (1 << 20)
|
||||
#define DESC_TXSTS_MSK (0x1FFFF << 0)
|
||||
|
||||
#else
|
||||
|
||||
#define DESC_TXSTS_OWNBYDMA (1 << 31)
|
||||
#define DESC_TXSTS_MSK (0x1FFFF << 0)
|
||||
|
||||
#endif
|
||||
|
||||
/* rx status bits definitions */
|
||||
#define DESC_RXSTS_OWNBYDMA (1 << 31)
|
||||
#define DESC_RXSTS_DAFILTERFAIL (1 << 30)
|
||||
#define DESC_RXSTS_FRMLENMSK (0x3FFF << 16)
|
||||
#define DESC_RXSTS_FRMLENSHFT (16)
|
||||
|
||||
#define DESC_RXSTS_ERROR (1 << 15)
|
||||
#define DESC_RXSTS_RXTRUNCATED (1 << 14)
|
||||
#define DESC_RXSTS_SAFILTERFAIL (1 << 13)
|
||||
#define DESC_RXSTS_RXIPC_GIANTFRAME (1 << 12)
|
||||
#define DESC_RXSTS_RXDAMAGED (1 << 11)
|
||||
#define DESC_RXSTS_RXVLANTAG (1 << 10)
|
||||
#define DESC_RXSTS_RXFIRST (1 << 9)
|
||||
#define DESC_RXSTS_RXLAST (1 << 8)
|
||||
#define DESC_RXSTS_RXIPC_GIANT (1 << 7)
|
||||
#define DESC_RXSTS_RXCOLLISION (1 << 6)
|
||||
#define DESC_RXSTS_RXFRAMEETHER (1 << 5)
|
||||
#define DESC_RXSTS_RXWATCHDOG (1 << 4)
|
||||
#define DESC_RXSTS_RXMIIERROR (1 << 3)
|
||||
#define DESC_RXSTS_RXDRIBBLING (1 << 2)
|
||||
#define DESC_RXSTS_RXCRC (1 << 1)
|
||||
|
||||
/*
|
||||
* dmamac_cntl definitions
|
||||
*/
|
||||
|
||||
/* tx control bits definitions */
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
|
||||
#define DESC_TXCTRL_SIZE1MASK (0x1FFF << 0)
|
||||
#define DESC_TXCTRL_SIZE1SHFT (0)
|
||||
#define DESC_TXCTRL_SIZE2MASK (0x1FFF << 16)
|
||||
#define DESC_TXCTRL_SIZE2SHFT (16)
|
||||
|
||||
#else
|
||||
|
||||
#define DESC_TXCTRL_TXINT (1 << 31)
|
||||
#define DESC_TXCTRL_TXLAST (1 << 30)
|
||||
#define DESC_TXCTRL_TXFIRST (1 << 29)
|
||||
#define DESC_TXCTRL_TXCHECKINSCTRL (3 << 27)
|
||||
#define DESC_TXCTRL_TXCRCDIS (1 << 26)
|
||||
#define DESC_TXCTRL_TXRINGEND (1 << 25)
|
||||
#define DESC_TXCTRL_TXCHAIN (1 << 24)
|
||||
|
||||
#define DESC_TXCTRL_SIZE1MASK (0x7FF << 0)
|
||||
#define DESC_TXCTRL_SIZE1SHFT (0)
|
||||
#define DESC_TXCTRL_SIZE2MASK (0x7FF << 11)
|
||||
#define DESC_TXCTRL_SIZE2SHFT (11)
|
||||
|
||||
#endif
|
||||
|
||||
/* rx control bits definitions */
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
|
||||
#define DESC_RXCTRL_RXINTDIS (1 << 31)
|
||||
#define DESC_RXCTRL_RXRINGEND (1 << 15)
|
||||
#define DESC_RXCTRL_RXCHAIN (1 << 14)
|
||||
|
||||
#define DESC_RXCTRL_SIZE1MASK (0x1FFF << 0)
|
||||
#define DESC_RXCTRL_SIZE1SHFT (0)
|
||||
#define DESC_RXCTRL_SIZE2MASK (0x1FFF << 16)
|
||||
#define DESC_RXCTRL_SIZE2SHFT (16)
|
||||
|
||||
#else
|
||||
|
||||
#define DESC_RXCTRL_RXINTDIS (1 << 31)
|
||||
#define DESC_RXCTRL_RXRINGEND (1 << 25)
|
||||
#define DESC_RXCTRL_RXCHAIN (1 << 24)
|
||||
|
||||
#define DESC_RXCTRL_SIZE1MASK (0x7FF << 0)
|
||||
#define DESC_RXCTRL_SIZE1SHFT (0)
|
||||
#define DESC_RXCTRL_SIZE2MASK (0x7FF << 11)
|
||||
#define DESC_RXCTRL_SIZE2SHFT (11)
|
||||
|
||||
#endif
|
||||
|
||||
struct dw_eth_dev {
|
||||
struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];
|
||||
struct dmamacdescr rx_mac_descrtable[CONFIG_RX_DESCR_NUM];
|
||||
char txbuffs[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
|
||||
char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
|
||||
|
||||
u32 interface;
|
||||
u32 tx_currdescnum;
|
||||
u32 rx_currdescnum;
|
||||
|
||||
struct eth_mac_regs *mac_regs_p;
|
||||
struct eth_dma_regs *dma_regs_p;
|
||||
#ifndef CONFIG_DM_ETH
|
||||
struct eth_device *dev;
|
||||
#endif
|
||||
struct phy_device *phydev;
|
||||
struct mii_dev *bus;
|
||||
};
|
||||
|
||||
#endif
|
||||
638
sources/uboot-be550/drivers/net/dm9000x.c
Normal file
638
sources/uboot-be550/drivers/net/dm9000x.c
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
dm9000.c: Version 1.2 12/15/2003
|
||||
|
||||
A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
|
||||
Copyright (C) 1997 Sten Wang
|
||||
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
(C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
|
||||
|
||||
V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match
|
||||
06/22/2001 Support DM9801 progrmming
|
||||
E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
|
||||
E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
|
||||
R17 = (R17 & 0xfff0) | NF + 3
|
||||
E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
|
||||
R17 = (R17 & 0xfff0) | NF
|
||||
|
||||
v1.00 modify by simon 2001.9.5
|
||||
change for kernel 2.4.x
|
||||
|
||||
v1.1 11/09/2001 fix force mode bug
|
||||
|
||||
v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>:
|
||||
Fixed phy reset.
|
||||
Added tx/rx 32 bit mode.
|
||||
Cleaned up for kernel merge.
|
||||
|
||||
--------------------------------------
|
||||
|
||||
12/15/2003 Initial port to u-boot by
|
||||
Sascha Hauer <saschahauer@web.de>
|
||||
|
||||
06/03/2008 Remy Bohmer <linux@bohmer.net>
|
||||
- Fixed the driver to work with DM9000A.
|
||||
(check on ISR receive status bit before reading the
|
||||
FIFO as described in DM9000 programming guide and
|
||||
application notes)
|
||||
- Added autodetect of databus width.
|
||||
- Made debug code compile again.
|
||||
- Adapt eth_send such that it matches the DM9000*
|
||||
application notes. Needed to make it work properly
|
||||
for DM9000A.
|
||||
- Adapted reset procedure to match DM9000 application
|
||||
notes (i.e. double reset)
|
||||
- some minor code cleanups
|
||||
These changes are tested with DM9000{A,EP,E} together
|
||||
with a 200MHz Atmel AT91SAM9261 core
|
||||
|
||||
TODO: external MII is not functional, only internal at the moment.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm9000.h>
|
||||
|
||||
#include "dm9000x.h"
|
||||
|
||||
/* Board/System/Debug information/definition ---------------- */
|
||||
|
||||
/* #define CONFIG_DM9000_DEBUG */
|
||||
|
||||
#ifdef CONFIG_DM9000_DEBUG
|
||||
#define DM9000_DBG(fmt,args...) printf(fmt, ##args)
|
||||
#define DM9000_DMP_PACKET(func,packet,length) \
|
||||
do { \
|
||||
int i; \
|
||||
printf("%s: length: %d\n", func, length); \
|
||||
for (i = 0; i < length; i++) { \
|
||||
if (i % 8 == 0) \
|
||||
printf("\n%s: %02x: ", func, i); \
|
||||
printf("%02x ", ((unsigned char *) packet)[i]); \
|
||||
} printf("\n"); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DM9000_DBG(fmt,args...)
|
||||
#define DM9000_DMP_PACKET(func,packet,length)
|
||||
#endif
|
||||
|
||||
/* Structure/enum declaration ------------------------------- */
|
||||
typedef struct board_info {
|
||||
u32 runt_length_counter; /* counter: RX length < 64byte */
|
||||
u32 long_length_counter; /* counter: RX length > 1514byte */
|
||||
u32 reset_counter; /* counter: RESET */
|
||||
u32 reset_tx_timeout; /* RESET caused by TX Timeout */
|
||||
u32 reset_rx_status; /* RESET caused by RX Statsus wrong */
|
||||
u16 tx_pkt_cnt;
|
||||
u16 queue_start_addr;
|
||||
u16 dbug_cnt;
|
||||
u8 phy_addr;
|
||||
u8 device_wait_reset; /* device state */
|
||||
unsigned char srom[128];
|
||||
void (*outblk)(volatile void *data_ptr, int count);
|
||||
void (*inblk)(void *data_ptr, int count);
|
||||
void (*rx_status)(u16 *RxStatus, u16 *RxLen);
|
||||
struct eth_device netdev;
|
||||
} board_info_t;
|
||||
static board_info_t dm9000_info;
|
||||
|
||||
|
||||
/* function declaration ------------------------------------- */
|
||||
static int dm9000_probe(void);
|
||||
static u16 dm9000_phy_read(int);
|
||||
static void dm9000_phy_write(int, u16);
|
||||
static u8 DM9000_ior(int);
|
||||
static void DM9000_iow(int reg, u8 value);
|
||||
|
||||
/* DM9000 network board routine ---------------------------- */
|
||||
#ifndef CONFIG_DM9000_BYTE_SWAPPED
|
||||
#define DM9000_outb(d,r) writeb(d, (volatile u8 *)(r))
|
||||
#define DM9000_outw(d,r) writew(d, (volatile u16 *)(r))
|
||||
#define DM9000_outl(d,r) writel(d, (volatile u32 *)(r))
|
||||
#define DM9000_inb(r) readb((volatile u8 *)(r))
|
||||
#define DM9000_inw(r) readw((volatile u16 *)(r))
|
||||
#define DM9000_inl(r) readl((volatile u32 *)(r))
|
||||
#else
|
||||
#define DM9000_outb(d, r) __raw_writeb(d, r)
|
||||
#define DM9000_outw(d, r) __raw_writew(d, r)
|
||||
#define DM9000_outl(d, r) __raw_writel(d, r)
|
||||
#define DM9000_inb(r) __raw_readb(r)
|
||||
#define DM9000_inw(r) __raw_readw(r)
|
||||
#define DM9000_inl(r) __raw_readl(r)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM9000_DEBUG
|
||||
static void
|
||||
dump_regs(void)
|
||||
{
|
||||
DM9000_DBG("\n");
|
||||
DM9000_DBG("NCR (0x00): %02x\n", DM9000_ior(0));
|
||||
DM9000_DBG("NSR (0x01): %02x\n", DM9000_ior(1));
|
||||
DM9000_DBG("TCR (0x02): %02x\n", DM9000_ior(2));
|
||||
DM9000_DBG("TSRI (0x03): %02x\n", DM9000_ior(3));
|
||||
DM9000_DBG("TSRII (0x04): %02x\n", DM9000_ior(4));
|
||||
DM9000_DBG("RCR (0x05): %02x\n", DM9000_ior(5));
|
||||
DM9000_DBG("RSR (0x06): %02x\n", DM9000_ior(6));
|
||||
DM9000_DBG("ISR (0xFE): %02x\n", DM9000_ior(DM9000_ISR));
|
||||
DM9000_DBG("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dm9000_outblk_8bit(volatile void *data_ptr, int count)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < count; i++)
|
||||
DM9000_outb((((u8 *) data_ptr)[i] & 0xff), DM9000_DATA);
|
||||
}
|
||||
|
||||
static void dm9000_outblk_16bit(volatile void *data_ptr, int count)
|
||||
{
|
||||
int i;
|
||||
u32 tmplen = (count + 1) / 2;
|
||||
|
||||
for (i = 0; i < tmplen; i++)
|
||||
DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
|
||||
}
|
||||
static void dm9000_outblk_32bit(volatile void *data_ptr, int count)
|
||||
{
|
||||
int i;
|
||||
u32 tmplen = (count + 3) / 4;
|
||||
|
||||
for (i = 0; i < tmplen; i++)
|
||||
DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);
|
||||
}
|
||||
|
||||
static void dm9000_inblk_8bit(void *data_ptr, int count)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < count; i++)
|
||||
((u8 *) data_ptr)[i] = DM9000_inb(DM9000_DATA);
|
||||
}
|
||||
|
||||
static void dm9000_inblk_16bit(void *data_ptr, int count)
|
||||
{
|
||||
int i;
|
||||
u32 tmplen = (count + 1) / 2;
|
||||
|
||||
for (i = 0; i < tmplen; i++)
|
||||
((u16 *) data_ptr)[i] = DM9000_inw(DM9000_DATA);
|
||||
}
|
||||
static void dm9000_inblk_32bit(void *data_ptr, int count)
|
||||
{
|
||||
int i;
|
||||
u32 tmplen = (count + 3) / 4;
|
||||
|
||||
for (i = 0; i < tmplen; i++)
|
||||
((u32 *) data_ptr)[i] = DM9000_inl(DM9000_DATA);
|
||||
}
|
||||
|
||||
static void dm9000_rx_status_32bit(u16 *RxStatus, u16 *RxLen)
|
||||
{
|
||||
u32 tmpdata;
|
||||
|
||||
DM9000_outb(DM9000_MRCMD, DM9000_IO);
|
||||
|
||||
tmpdata = DM9000_inl(DM9000_DATA);
|
||||
*RxStatus = __le16_to_cpu(tmpdata);
|
||||
*RxLen = __le16_to_cpu(tmpdata >> 16);
|
||||
}
|
||||
|
||||
static void dm9000_rx_status_16bit(u16 *RxStatus, u16 *RxLen)
|
||||
{
|
||||
DM9000_outb(DM9000_MRCMD, DM9000_IO);
|
||||
|
||||
*RxStatus = __le16_to_cpu(DM9000_inw(DM9000_DATA));
|
||||
*RxLen = __le16_to_cpu(DM9000_inw(DM9000_DATA));
|
||||
}
|
||||
|
||||
static void dm9000_rx_status_8bit(u16 *RxStatus, u16 *RxLen)
|
||||
{
|
||||
DM9000_outb(DM9000_MRCMD, DM9000_IO);
|
||||
|
||||
*RxStatus =
|
||||
__le16_to_cpu(DM9000_inb(DM9000_DATA) +
|
||||
(DM9000_inb(DM9000_DATA) << 8));
|
||||
*RxLen =
|
||||
__le16_to_cpu(DM9000_inb(DM9000_DATA) +
|
||||
(DM9000_inb(DM9000_DATA) << 8));
|
||||
}
|
||||
|
||||
/*
|
||||
Search DM9000 board, allocate space and register it
|
||||
*/
|
||||
int
|
||||
dm9000_probe(void)
|
||||
{
|
||||
u32 id_val;
|
||||
id_val = DM9000_ior(DM9000_VIDL);
|
||||
id_val |= DM9000_ior(DM9000_VIDH) << 8;
|
||||
id_val |= DM9000_ior(DM9000_PIDL) << 16;
|
||||
id_val |= DM9000_ior(DM9000_PIDH) << 24;
|
||||
if (id_val == DM9000_ID) {
|
||||
printf("dm9000 i/o: 0x%x, id: 0x%x \n", CONFIG_DM9000_BASE,
|
||||
id_val);
|
||||
return 0;
|
||||
} else {
|
||||
printf("dm9000 not found at 0x%08x id: 0x%08x\n",
|
||||
CONFIG_DM9000_BASE, id_val);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* General Purpose dm9000 reset routine */
|
||||
static void
|
||||
dm9000_reset(void)
|
||||
{
|
||||
DM9000_DBG("resetting DM9000\n");
|
||||
|
||||
/* Reset DM9000,
|
||||
see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 */
|
||||
|
||||
/* DEBUG: Make all GPIO0 outputs, all others inputs */
|
||||
DM9000_iow(DM9000_GPCR, GPCR_GPIO0_OUT);
|
||||
/* Step 1: Power internal PHY by writing 0 to GPIO0 pin */
|
||||
DM9000_iow(DM9000_GPR, 0);
|
||||
/* Step 2: Software reset */
|
||||
DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST));
|
||||
|
||||
do {
|
||||
DM9000_DBG("resetting the DM9000, 1st reset\n");
|
||||
udelay(25); /* Wait at least 20 us */
|
||||
} while (DM9000_ior(DM9000_NCR) & 1);
|
||||
|
||||
DM9000_iow(DM9000_NCR, 0);
|
||||
DM9000_iow(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); /* Issue a second reset */
|
||||
|
||||
do {
|
||||
DM9000_DBG("resetting the DM9000, 2nd reset\n");
|
||||
udelay(25); /* Wait at least 20 us */
|
||||
} while (DM9000_ior(DM9000_NCR) & 1);
|
||||
|
||||
/* Check whether the ethernet controller is present */
|
||||
if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
|
||||
(DM9000_ior(DM9000_PIDH) != 0x90))
|
||||
printf("ERROR: resetting DM9000 -> not responding\n");
|
||||
}
|
||||
|
||||
/* Initialize dm9000 board
|
||||
*/
|
||||
static int dm9000_init(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
int i, oft, lnk;
|
||||
u8 io_mode;
|
||||
struct board_info *db = &dm9000_info;
|
||||
|
||||
DM9000_DBG("%s\n", __func__);
|
||||
|
||||
/* RESET device */
|
||||
dm9000_reset();
|
||||
|
||||
if (dm9000_probe() < 0)
|
||||
return -1;
|
||||
|
||||
/* Auto-detect 8/16/32 bit mode, ISR Bit 6+7 indicate bus width */
|
||||
io_mode = DM9000_ior(DM9000_ISR) >> 6;
|
||||
|
||||
switch (io_mode) {
|
||||
case 0x0: /* 16-bit mode */
|
||||
printf("DM9000: running in 16 bit mode\n");
|
||||
db->outblk = dm9000_outblk_16bit;
|
||||
db->inblk = dm9000_inblk_16bit;
|
||||
db->rx_status = dm9000_rx_status_16bit;
|
||||
break;
|
||||
case 0x01: /* 32-bit mode */
|
||||
printf("DM9000: running in 32 bit mode\n");
|
||||
db->outblk = dm9000_outblk_32bit;
|
||||
db->inblk = dm9000_inblk_32bit;
|
||||
db->rx_status = dm9000_rx_status_32bit;
|
||||
break;
|
||||
case 0x02: /* 8 bit mode */
|
||||
printf("DM9000: running in 8 bit mode\n");
|
||||
db->outblk = dm9000_outblk_8bit;
|
||||
db->inblk = dm9000_inblk_8bit;
|
||||
db->rx_status = dm9000_rx_status_8bit;
|
||||
break;
|
||||
default:
|
||||
/* Assume 8 bit mode, will probably not work anyway */
|
||||
printf("DM9000: Undefined IO-mode:0x%x\n", io_mode);
|
||||
db->outblk = dm9000_outblk_8bit;
|
||||
db->inblk = dm9000_inblk_8bit;
|
||||
db->rx_status = dm9000_rx_status_8bit;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Program operating register, only internal phy supported */
|
||||
DM9000_iow(DM9000_NCR, 0x0);
|
||||
/* TX Polling clear */
|
||||
DM9000_iow(DM9000_TCR, 0);
|
||||
/* Less 3Kb, 200us */
|
||||
DM9000_iow(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US);
|
||||
/* Flow Control : High/Low Water */
|
||||
DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
|
||||
/* SH FIXME: This looks strange! Flow Control */
|
||||
DM9000_iow(DM9000_FCR, 0x0);
|
||||
/* Special Mode */
|
||||
DM9000_iow(DM9000_SMCR, 0);
|
||||
/* clear TX status */
|
||||
DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
|
||||
/* Clear interrupt status */
|
||||
DM9000_iow(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS);
|
||||
|
||||
printf("MAC: %pM\n", dev->enetaddr);
|
||||
if (!is_valid_ethaddr(dev->enetaddr)) {
|
||||
printf("WARNING: Bad MAC address (uninitialized EEPROM?)\n");
|
||||
}
|
||||
|
||||
/* fill device MAC address registers */
|
||||
for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
|
||||
DM9000_iow(oft, dev->enetaddr[i]);
|
||||
for (i = 0, oft = 0x16; i < 8; i++, oft++)
|
||||
DM9000_iow(oft, 0xff);
|
||||
|
||||
/* read back mac, just to be sure */
|
||||
for (i = 0, oft = 0x10; i < 6; i++, oft++)
|
||||
DM9000_DBG("%02x:", DM9000_ior(oft));
|
||||
DM9000_DBG("\n");
|
||||
|
||||
/* Activate DM9000 */
|
||||
/* RX enable */
|
||||
DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
|
||||
/* Enable TX/RX interrupt mask */
|
||||
DM9000_iow(DM9000_IMR, IMR_PAR);
|
||||
|
||||
i = 0;
|
||||
while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */
|
||||
udelay(1000);
|
||||
i++;
|
||||
if (i == 10000) {
|
||||
printf("could not establish link\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* see what we've got */
|
||||
lnk = dm9000_phy_read(17) >> 12;
|
||||
printf("operating at ");
|
||||
switch (lnk) {
|
||||
case 1:
|
||||
printf("10M half duplex ");
|
||||
break;
|
||||
case 2:
|
||||
printf("10M full duplex ");
|
||||
break;
|
||||
case 4:
|
||||
printf("100M half duplex ");
|
||||
break;
|
||||
case 8:
|
||||
printf("100M full duplex ");
|
||||
break;
|
||||
default:
|
||||
printf("unknown: %d ", lnk);
|
||||
break;
|
||||
}
|
||||
printf("mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Hardware start transmission.
|
||||
Send a packet to media from the upper layer.
|
||||
*/
|
||||
static int dm9000_send(struct eth_device *netdev, void *packet, int length)
|
||||
{
|
||||
int tmo;
|
||||
struct board_info *db = &dm9000_info;
|
||||
|
||||
DM9000_DMP_PACKET(__func__ , packet, length);
|
||||
|
||||
DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
|
||||
|
||||
/* Move data to DM9000 TX RAM */
|
||||
DM9000_outb(DM9000_MWCMD, DM9000_IO); /* Prepare for TX-data */
|
||||
|
||||
/* push the data to the TX-fifo */
|
||||
(db->outblk)(packet, length);
|
||||
|
||||
/* Set TX length to DM9000 */
|
||||
DM9000_iow(DM9000_TXPLL, length & 0xff);
|
||||
DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
|
||||
|
||||
/* Issue TX polling command */
|
||||
DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
|
||||
|
||||
/* wait for end of transmission */
|
||||
tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
|
||||
while ( !(DM9000_ior(DM9000_NSR) & (NSR_TX1END | NSR_TX2END)) ||
|
||||
!(DM9000_ior(DM9000_ISR) & IMR_PTM) ) {
|
||||
if (get_timer(0) >= tmo) {
|
||||
printf("transmission timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
DM9000_iow(DM9000_ISR, IMR_PTM); /* Clear Tx bit in ISR */
|
||||
|
||||
DM9000_DBG("transmit done\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Stop the interface.
|
||||
The interface is stopped when it is brought.
|
||||
*/
|
||||
static void dm9000_halt(struct eth_device *netdev)
|
||||
{
|
||||
DM9000_DBG("%s\n", __func__);
|
||||
|
||||
/* RESET devie */
|
||||
dm9000_phy_write(0, 0x8000); /* PHY RESET */
|
||||
DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
|
||||
DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
|
||||
DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
|
||||
}
|
||||
|
||||
/*
|
||||
Received a packet and pass to upper layer
|
||||
*/
|
||||
static int dm9000_rx(struct eth_device *netdev)
|
||||
{
|
||||
u8 rxbyte;
|
||||
u8 *rdptr = (u8 *)net_rx_packets[0];
|
||||
u16 RxStatus, RxLen = 0;
|
||||
struct board_info *db = &dm9000_info;
|
||||
|
||||
/* Check packet ready or not, we must check
|
||||
the ISR status first for DM9000A */
|
||||
if (!(DM9000_ior(DM9000_ISR) & 0x01)) /* Rx-ISR bit must be set. */
|
||||
return 0;
|
||||
|
||||
DM9000_iow(DM9000_ISR, 0x01); /* clear PR status latched in bit 0 */
|
||||
|
||||
/* There is _at least_ 1 package in the fifo, read them all */
|
||||
for (;;) {
|
||||
DM9000_ior(DM9000_MRCMDX); /* Dummy read */
|
||||
|
||||
/* Get most updated data,
|
||||
only look at bits 0:1, See application notes DM9000 */
|
||||
rxbyte = DM9000_inb(DM9000_DATA) & 0x03;
|
||||
|
||||
/* Status check: this byte must be 0 or 1 */
|
||||
if (rxbyte > DM9000_PKT_RDY) {
|
||||
DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
|
||||
DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
|
||||
printf("DM9000 error: status check fail: 0x%x\n",
|
||||
rxbyte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rxbyte != DM9000_PKT_RDY)
|
||||
return 0; /* No packet received, ignore */
|
||||
|
||||
DM9000_DBG("receiving packet\n");
|
||||
|
||||
/* A packet ready now & Get status/length */
|
||||
(db->rx_status)(&RxStatus, &RxLen);
|
||||
|
||||
DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);
|
||||
|
||||
/* Move data from DM9000 */
|
||||
/* Read received packet from RX SRAM */
|
||||
(db->inblk)(rdptr, RxLen);
|
||||
|
||||
if ((RxStatus & 0xbf00) || (RxLen < 0x40)
|
||||
|| (RxLen > DM9000_PKT_MAX)) {
|
||||
if (RxStatus & 0x100) {
|
||||
printf("rx fifo error\n");
|
||||
}
|
||||
if (RxStatus & 0x200) {
|
||||
printf("rx crc error\n");
|
||||
}
|
||||
if (RxStatus & 0x8000) {
|
||||
printf("rx length error\n");
|
||||
}
|
||||
if (RxLen > DM9000_PKT_MAX) {
|
||||
printf("rx length too big\n");
|
||||
dm9000_reset();
|
||||
}
|
||||
} else {
|
||||
DM9000_DMP_PACKET(__func__ , rdptr, RxLen);
|
||||
|
||||
DM9000_DBG("passing packet to upper layer\n");
|
||||
net_process_received_packet(net_rx_packets[0], RxLen);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Read a word data from SROM
|
||||
*/
|
||||
#if !defined(CONFIG_DM9000_NO_SROM)
|
||||
void dm9000_read_srom_word(int offset, u8 *to)
|
||||
{
|
||||
DM9000_iow(DM9000_EPAR, offset);
|
||||
DM9000_iow(DM9000_EPCR, 0x4);
|
||||
udelay(8000);
|
||||
DM9000_iow(DM9000_EPCR, 0x0);
|
||||
to[0] = DM9000_ior(DM9000_EPDRL);
|
||||
to[1] = DM9000_ior(DM9000_EPDRH);
|
||||
}
|
||||
|
||||
void dm9000_write_srom_word(int offset, u16 val)
|
||||
{
|
||||
DM9000_iow(DM9000_EPAR, offset);
|
||||
DM9000_iow(DM9000_EPDRH, ((val >> 8) & 0xff));
|
||||
DM9000_iow(DM9000_EPDRL, (val & 0xff));
|
||||
DM9000_iow(DM9000_EPCR, 0x12);
|
||||
udelay(8000);
|
||||
DM9000_iow(DM9000_EPCR, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dm9000_get_enetaddr(struct eth_device *dev)
|
||||
{
|
||||
#if !defined(CONFIG_DM9000_NO_SROM)
|
||||
int i;
|
||||
for (i = 0; i < 3; i++)
|
||||
dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Read a byte from I/O port
|
||||
*/
|
||||
static u8
|
||||
DM9000_ior(int reg)
|
||||
{
|
||||
DM9000_outb(reg, DM9000_IO);
|
||||
return DM9000_inb(DM9000_DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
Write a byte to I/O port
|
||||
*/
|
||||
static void
|
||||
DM9000_iow(int reg, u8 value)
|
||||
{
|
||||
DM9000_outb(reg, DM9000_IO);
|
||||
DM9000_outb(value, DM9000_DATA);
|
||||
}
|
||||
|
||||
/*
|
||||
Read a word from phyxcer
|
||||
*/
|
||||
static u16
|
||||
dm9000_phy_read(int reg)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
/* Fill the phyxcer register into REG_0C */
|
||||
DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
|
||||
DM9000_iow(DM9000_EPCR, 0xc); /* Issue phyxcer read command */
|
||||
udelay(100); /* Wait read complete */
|
||||
DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer read command */
|
||||
val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
|
||||
|
||||
/* The read data keeps on REG_0D & REG_0E */
|
||||
DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
Write a word to phyxcer
|
||||
*/
|
||||
static void
|
||||
dm9000_phy_write(int reg, u16 value)
|
||||
{
|
||||
|
||||
/* Fill the phyxcer register into REG_0C */
|
||||
DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
|
||||
|
||||
/* Fill the written data into REG_0D & REG_0E */
|
||||
DM9000_iow(DM9000_EPDRL, (value & 0xff));
|
||||
DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
|
||||
DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */
|
||||
udelay(500); /* Wait write complete */
|
||||
DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */
|
||||
DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value);
|
||||
}
|
||||
|
||||
int dm9000_initialize(bd_t *bis)
|
||||
{
|
||||
struct eth_device *dev = &(dm9000_info.netdev);
|
||||
|
||||
/* Load MAC address from EEPROM */
|
||||
dm9000_get_enetaddr(dev);
|
||||
|
||||
dev->init = dm9000_init;
|
||||
dev->halt = dm9000_halt;
|
||||
dev->send = dm9000_send;
|
||||
dev->recv = dm9000_rx;
|
||||
sprintf(dev->name, "dm9000");
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
140
sources/uboot-be550/drivers/net/dm9000x.h
Normal file
140
sources/uboot-be550/drivers/net/dm9000x.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* dm9000 Ethernet
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DRIVER_DM9000
|
||||
|
||||
#define DM9000_ID 0x90000A46
|
||||
#define DM9000_PKT_MAX 1536 /* Received packet max size */
|
||||
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
|
||||
|
||||
/* although the registers are 16 bit, they are 32-bit aligned.
|
||||
*/
|
||||
|
||||
#define DM9000_NCR 0x00
|
||||
#define DM9000_NSR 0x01
|
||||
#define DM9000_TCR 0x02
|
||||
#define DM9000_TSR1 0x03
|
||||
#define DM9000_TSR2 0x04
|
||||
#define DM9000_RCR 0x05
|
||||
#define DM9000_RSR 0x06
|
||||
#define DM9000_ROCR 0x07
|
||||
#define DM9000_BPTR 0x08
|
||||
#define DM9000_FCTR 0x09
|
||||
#define DM9000_FCR 0x0A
|
||||
#define DM9000_EPCR 0x0B
|
||||
#define DM9000_EPAR 0x0C
|
||||
#define DM9000_EPDRL 0x0D
|
||||
#define DM9000_EPDRH 0x0E
|
||||
#define DM9000_WCR 0x0F
|
||||
|
||||
#define DM9000_PAR 0x10
|
||||
#define DM9000_MAR 0x16
|
||||
|
||||
#define DM9000_GPCR 0x1e
|
||||
#define DM9000_GPR 0x1f
|
||||
#define DM9000_TRPAL 0x22
|
||||
#define DM9000_TRPAH 0x23
|
||||
#define DM9000_RWPAL 0x24
|
||||
#define DM9000_RWPAH 0x25
|
||||
|
||||
#define DM9000_VIDL 0x28
|
||||
#define DM9000_VIDH 0x29
|
||||
#define DM9000_PIDL 0x2A
|
||||
#define DM9000_PIDH 0x2B
|
||||
|
||||
#define DM9000_CHIPR 0x2C
|
||||
#define DM9000_SMCR 0x2F
|
||||
|
||||
#define DM9000_PHY 0x40 /* PHY address 0x01 */
|
||||
|
||||
#define DM9000_MRCMDX 0xF0
|
||||
#define DM9000_MRCMD 0xF2
|
||||
#define DM9000_MRRL 0xF4
|
||||
#define DM9000_MRRH 0xF5
|
||||
#define DM9000_MWCMDX 0xF6
|
||||
#define DM9000_MWCMD 0xF8
|
||||
#define DM9000_MWRL 0xFA
|
||||
#define DM9000_MWRH 0xFB
|
||||
#define DM9000_TXPLL 0xFC
|
||||
#define DM9000_TXPLH 0xFD
|
||||
#define DM9000_ISR 0xFE
|
||||
#define DM9000_IMR 0xFF
|
||||
|
||||
#define NCR_EXT_PHY (1<<7)
|
||||
#define NCR_WAKEEN (1<<6)
|
||||
#define NCR_FCOL (1<<4)
|
||||
#define NCR_FDX (1<<3)
|
||||
#define NCR_LBK (3<<1)
|
||||
#define NCR_LBK_INT_MAC (1<<1)
|
||||
#define NCR_LBK_INT_PHY (2<<1)
|
||||
#define NCR_RST (1<<0)
|
||||
|
||||
#define NSR_SPEED (1<<7)
|
||||
#define NSR_LINKST (1<<6)
|
||||
#define NSR_WAKEST (1<<5)
|
||||
#define NSR_TX2END (1<<3)
|
||||
#define NSR_TX1END (1<<2)
|
||||
#define NSR_RXOV (1<<1)
|
||||
|
||||
#define TCR_TJDIS (1<<6)
|
||||
#define TCR_EXCECM (1<<5)
|
||||
#define TCR_PAD_DIS2 (1<<4)
|
||||
#define TCR_CRC_DIS2 (1<<3)
|
||||
#define TCR_PAD_DIS1 (1<<2)
|
||||
#define TCR_CRC_DIS1 (1<<1)
|
||||
#define TCR_TXREQ (1<<0)
|
||||
|
||||
#define TSR_TJTO (1<<7)
|
||||
#define TSR_LC (1<<6)
|
||||
#define TSR_NC (1<<5)
|
||||
#define TSR_LCOL (1<<4)
|
||||
#define TSR_COL (1<<3)
|
||||
#define TSR_EC (1<<2)
|
||||
|
||||
#define RCR_WTDIS (1<<6)
|
||||
#define RCR_DIS_LONG (1<<5)
|
||||
#define RCR_DIS_CRC (1<<4)
|
||||
#define RCR_ALL (1<<3)
|
||||
#define RCR_RUNT (1<<2)
|
||||
#define RCR_PRMSC (1<<1)
|
||||
#define RCR_RXEN (1<<0)
|
||||
|
||||
#define RSR_RF (1<<7)
|
||||
#define RSR_MF (1<<6)
|
||||
#define RSR_LCS (1<<5)
|
||||
#define RSR_RWTO (1<<4)
|
||||
#define RSR_PLE (1<<3)
|
||||
#define RSR_AE (1<<2)
|
||||
#define RSR_CE (1<<1)
|
||||
#define RSR_FOE (1<<0)
|
||||
|
||||
#define EPCR_EPOS_PHY (1<<3)
|
||||
#define EPCR_EPOS_EE (0<<3)
|
||||
#define EPCR_ERPRR (1<<2)
|
||||
#define EPCR_ERPRW (1<<1)
|
||||
#define EPCR_ERRE (1<<0)
|
||||
|
||||
#define FCTR_HWOT(ot) (( ot & 0xf ) << 4 )
|
||||
#define FCTR_LWOT(ot) ( ot & 0xf )
|
||||
|
||||
#define BPTR_BPHW(x) ((x) << 4)
|
||||
#define BPTR_JPT_200US (0x07)
|
||||
#define BPTR_JPT_600US (0x0f)
|
||||
|
||||
#define IMR_PAR (1<<7)
|
||||
#define IMR_ROOM (1<<3)
|
||||
#define IMR_ROM (1<<2)
|
||||
#define IMR_PTM (1<<1)
|
||||
#define IMR_PRM (1<<0)
|
||||
|
||||
#define ISR_ROOS (1<<3)
|
||||
#define ISR_ROS (1<<2)
|
||||
#define ISR_PTS (1<<1)
|
||||
#define ISR_PRS (1<<0)
|
||||
|
||||
#define GPCR_GPIO0_OUT (1<<0)
|
||||
|
||||
#define GPR_PHY_PWROFF (1<<0)
|
||||
|
||||
#endif
|
||||
393
sources/uboot-be550/drivers/net/dnet.c
Normal file
393
sources/uboot-be550/drivers/net/dnet.c
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Dave Ethernet Controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#ifndef CONFIG_DNET_AUTONEG_TIMEOUT
|
||||
#define CONFIG_DNET_AUTONEG_TIMEOUT 5000000 /* default value */
|
||||
#endif
|
||||
|
||||
#include <net.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/mii.h>
|
||||
|
||||
#include <miiphy.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "dnet.h"
|
||||
|
||||
struct dnet_device {
|
||||
struct dnet_registers *regs;
|
||||
const struct device *dev;
|
||||
struct eth_device netdev;
|
||||
unsigned short phy_addr;
|
||||
};
|
||||
|
||||
/* get struct dnet_device from given struct netdev */
|
||||
#define to_dnet(_nd) container_of(_nd, struct dnet_device, netdev)
|
||||
|
||||
/* function for reading internal MAC register */
|
||||
u16 dnet_readw_mac(struct dnet_device *dnet, u16 reg)
|
||||
{
|
||||
u16 data_read;
|
||||
|
||||
/* issue a read */
|
||||
writel(reg, &dnet->regs->MACREG_ADDR);
|
||||
|
||||
/* since a read/write op to the MAC is very slow,
|
||||
* we must wait before reading the data */
|
||||
udelay(1);
|
||||
|
||||
/* read data read from the MAC register */
|
||||
data_read = readl(&dnet->regs->MACREG_DATA);
|
||||
|
||||
/* all done */
|
||||
return data_read;
|
||||
}
|
||||
|
||||
/* function for writing internal MAC register */
|
||||
void dnet_writew_mac(struct dnet_device *dnet, u16 reg, u16 val)
|
||||
{
|
||||
/* load data to write */
|
||||
writel(val, &dnet->regs->MACREG_DATA);
|
||||
|
||||
/* issue a write */
|
||||
writel(reg | DNET_INTERNAL_WRITE, &dnet->regs->MACREG_ADDR);
|
||||
|
||||
/* since a read/write op to the MAC is very slow,
|
||||
* we must wait before exiting */
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static void dnet_mdio_write(struct dnet_device *dnet, u8 reg, u16 value)
|
||||
{
|
||||
u16 tmp;
|
||||
|
||||
debug(DRIVERNAME "dnet_mdio_write %02x:%02x <- %04x\n",
|
||||
dnet->phy_addr, reg, value);
|
||||
|
||||
while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
|
||||
DNET_INTERNAL_GMII_MNG_CMD_FIN))
|
||||
;
|
||||
|
||||
/* prepare for a write operation */
|
||||
tmp = (1 << 13);
|
||||
|
||||
/* only 5 bits allowed for register offset */
|
||||
reg &= 0x1f;
|
||||
|
||||
/* prepare reg_value for a write */
|
||||
tmp |= (dnet->phy_addr << 8);
|
||||
tmp |= reg;
|
||||
|
||||
/* write data to write first */
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG, value);
|
||||
|
||||
/* write control word */
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp);
|
||||
|
||||
while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
|
||||
DNET_INTERNAL_GMII_MNG_CMD_FIN))
|
||||
;
|
||||
}
|
||||
|
||||
static u16 dnet_mdio_read(struct dnet_device *dnet, u8 reg)
|
||||
{
|
||||
u16 value;
|
||||
|
||||
while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
|
||||
DNET_INTERNAL_GMII_MNG_CMD_FIN))
|
||||
;
|
||||
|
||||
/* only 5 bits allowed for register offset*/
|
||||
reg &= 0x1f;
|
||||
|
||||
/* prepare reg_value for a read */
|
||||
value = (dnet->phy_addr << 8);
|
||||
value |= reg;
|
||||
|
||||
/* write control word */
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG, value);
|
||||
|
||||
/* wait for end of transfer */
|
||||
while (!(dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_CTL_REG) &
|
||||
DNET_INTERNAL_GMII_MNG_CMD_FIN))
|
||||
;
|
||||
|
||||
value = dnet_readw_mac(dnet, DNET_INTERNAL_GMII_MNG_DAT_REG);
|
||||
|
||||
debug(DRIVERNAME "dnet_mdio_read %02x:%02x <- %04x\n",
|
||||
dnet->phy_addr, reg, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int dnet_send(struct eth_device *netdev, void *packet, int length)
|
||||
{
|
||||
struct dnet_device *dnet = to_dnet(netdev);
|
||||
int i, wrsz;
|
||||
unsigned int *bufp;
|
||||
unsigned int tx_cmd;
|
||||
|
||||
debug(DRIVERNAME "[%s] Sending %u bytes\n", __func__, length);
|
||||
|
||||
bufp = (unsigned int *) (((u32)packet) & 0xFFFFFFFC);
|
||||
wrsz = (u32)length + 3;
|
||||
wrsz += ((u32)packet) & 0x3;
|
||||
wrsz >>= 2;
|
||||
tx_cmd = ((((unsigned int)(packet)) & 0x03) << 16) | (u32)length;
|
||||
|
||||
/* check if there is enough room for the current frame */
|
||||
if (wrsz < (DNET_FIFO_SIZE - readl(&dnet->regs->TX_FIFO_WCNT))) {
|
||||
for (i = 0; i < wrsz; i++)
|
||||
writel(*bufp++, &dnet->regs->TX_DATA_FIFO);
|
||||
/*
|
||||
* inform MAC that a packet's written and ready
|
||||
* to be shipped out
|
||||
*/
|
||||
writel(tx_cmd, &dnet->regs->TX_LEN_FIFO);
|
||||
} else {
|
||||
printf(DRIVERNAME "No free space (actual %d, required %d "
|
||||
"(words))\n", DNET_FIFO_SIZE -
|
||||
readl(&dnet->regs->TX_FIFO_WCNT), wrsz);
|
||||
}
|
||||
|
||||
/* No one cares anyway */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int dnet_recv(struct eth_device *netdev)
|
||||
{
|
||||
struct dnet_device *dnet = to_dnet(netdev);
|
||||
unsigned int *data_ptr;
|
||||
int pkt_len, poll, i;
|
||||
u32 cmd_word;
|
||||
|
||||
debug("Waiting for pkt (polling)\n");
|
||||
poll = 50;
|
||||
while ((readl(&dnet->regs->RX_FIFO_WCNT) >> 16) == 0) {
|
||||
udelay(10); /* wait 10 usec */
|
||||
if (--poll == 0)
|
||||
return 0; /* no pkt available */
|
||||
}
|
||||
|
||||
cmd_word = readl(&dnet->regs->RX_LEN_FIFO);
|
||||
pkt_len = cmd_word & 0xFFFF;
|
||||
|
||||
debug("Got pkt with size %d bytes\n", pkt_len);
|
||||
|
||||
if (cmd_word & 0xDF180000)
|
||||
printf("%s packet receive error %x\n", __func__, cmd_word);
|
||||
|
||||
data_ptr = (unsigned int *)net_rx_packets[0];
|
||||
|
||||
for (i = 0; i < (pkt_len + 3) >> 2; i++)
|
||||
*data_ptr++ = readl(&dnet->regs->RX_DATA_FIFO);
|
||||
|
||||
/* ok + 5 ?? */
|
||||
net_process_received_packet(net_rx_packets[0], pkt_len + 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dnet_set_hwaddr(struct eth_device *netdev)
|
||||
{
|
||||
struct dnet_device *dnet = to_dnet(netdev);
|
||||
u16 tmp;
|
||||
|
||||
tmp = get_unaligned_be16(netdev->enetaddr);
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_0_REG, tmp);
|
||||
tmp = get_unaligned_be16(&netdev->enetaddr[2]);
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_1_REG, tmp);
|
||||
tmp = get_unaligned_be16(&netdev->enetaddr[4]);
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_MAC_ADDR_2_REG, tmp);
|
||||
}
|
||||
|
||||
static void dnet_phy_reset(struct dnet_device *dnet)
|
||||
{
|
||||
struct eth_device *netdev = &dnet->netdev;
|
||||
int i;
|
||||
u16 status, adv;
|
||||
|
||||
adv = ADVERTISE_CSMA | ADVERTISE_ALL;
|
||||
dnet_mdio_write(dnet, MII_ADVERTISE, adv);
|
||||
printf("%s: Starting autonegotiation...\n", netdev->name);
|
||||
dnet_mdio_write(dnet, MII_BMCR, (BMCR_ANENABLE
|
||||
| BMCR_ANRESTART));
|
||||
|
||||
for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) {
|
||||
status = dnet_mdio_read(dnet, MII_BMSR);
|
||||
if (status & BMSR_ANEGCOMPLETE)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (status & BMSR_ANEGCOMPLETE)
|
||||
printf("%s: Autonegotiation complete\n", netdev->name);
|
||||
else
|
||||
printf("%s: Autonegotiation timed out (status=0x%04x)\n",
|
||||
netdev->name, status);
|
||||
}
|
||||
|
||||
static int dnet_phy_init(struct dnet_device *dnet)
|
||||
{
|
||||
struct eth_device *netdev = &dnet->netdev;
|
||||
u16 phy_id, status, adv, lpa;
|
||||
int media, speed, duplex;
|
||||
int i;
|
||||
u32 ctl_reg;
|
||||
|
||||
/* Find a PHY */
|
||||
for (i = 0; i < 32; i++) {
|
||||
dnet->phy_addr = i;
|
||||
phy_id = dnet_mdio_read(dnet, MII_PHYSID1);
|
||||
if (phy_id != 0xffff) {
|
||||
/* ok we found it */
|
||||
printf("Found PHY at address %d PHYID (%04x:%04x)\n",
|
||||
i, phy_id,
|
||||
dnet_mdio_read(dnet, MII_PHYSID2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the PHY is up to snuff... */
|
||||
phy_id = dnet_mdio_read(dnet, MII_PHYSID1);
|
||||
if (phy_id == 0xffff) {
|
||||
printf("%s: No PHY present\n", netdev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = dnet_mdio_read(dnet, MII_BMSR);
|
||||
if (!(status & BMSR_LSTATUS)) {
|
||||
/* Try to re-negotiate if we don't have link already. */
|
||||
dnet_phy_reset(dnet);
|
||||
|
||||
for (i = 0; i < CONFIG_DNET_AUTONEG_TIMEOUT / 100; i++) {
|
||||
status = dnet_mdio_read(dnet, MII_BMSR);
|
||||
if (status & BMSR_LSTATUS)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(status & BMSR_LSTATUS)) {
|
||||
printf("%s: link down (status: 0x%04x)\n",
|
||||
netdev->name, status);
|
||||
return -1;
|
||||
} else {
|
||||
adv = dnet_mdio_read(dnet, MII_ADVERTISE);
|
||||
lpa = dnet_mdio_read(dnet, MII_LPA);
|
||||
media = mii_nway_result(lpa & adv);
|
||||
speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
|
||||
? 1 : 0);
|
||||
duplex = (media & ADVERTISE_FULL) ? 1 : 0;
|
||||
/* 1000BaseT ethernet is not supported */
|
||||
printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
|
||||
netdev->name,
|
||||
speed ? "100" : "10",
|
||||
duplex ? "full" : "half",
|
||||
lpa);
|
||||
|
||||
ctl_reg = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG);
|
||||
|
||||
if (duplex)
|
||||
ctl_reg &= ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP);
|
||||
else
|
||||
ctl_reg |= DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP;
|
||||
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int dnet_init(struct eth_device *netdev, bd_t *bd)
|
||||
{
|
||||
struct dnet_device *dnet = to_dnet(netdev);
|
||||
u32 config;
|
||||
|
||||
/*
|
||||
* dnet_halt should have been called at some point before now,
|
||||
* so we'll assume the controller is idle.
|
||||
*/
|
||||
|
||||
/* set hardware address */
|
||||
dnet_set_hwaddr(netdev);
|
||||
|
||||
if (dnet_phy_init(dnet) < 0)
|
||||
return -1;
|
||||
|
||||
/* flush rx/tx fifos */
|
||||
writel(DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH,
|
||||
&dnet->regs->SYS_CTL);
|
||||
udelay(1000);
|
||||
writel(0, &dnet->regs->SYS_CTL);
|
||||
|
||||
config = dnet_readw_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG);
|
||||
|
||||
config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE |
|
||||
DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST |
|
||||
DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL |
|
||||
DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS;
|
||||
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_RXTX_CONTROL_REG, config);
|
||||
|
||||
/* Enable TX and RX */
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG,
|
||||
DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dnet_halt(struct eth_device *netdev)
|
||||
{
|
||||
struct dnet_device *dnet = to_dnet(netdev);
|
||||
|
||||
/* Disable TX and RX */
|
||||
dnet_writew_mac(dnet, DNET_INTERNAL_MODE_REG, 0);
|
||||
}
|
||||
|
||||
int dnet_eth_initialize(int id, void *regs, unsigned int phy_addr)
|
||||
{
|
||||
struct dnet_device *dnet;
|
||||
struct eth_device *netdev;
|
||||
unsigned int dev_capa;
|
||||
|
||||
dnet = malloc(sizeof(struct dnet_device));
|
||||
if (!dnet) {
|
||||
printf("Error: Failed to allocate memory for DNET%d\n", id);
|
||||
return -1;
|
||||
}
|
||||
memset(dnet, 0, sizeof(struct dnet_device));
|
||||
|
||||
netdev = &dnet->netdev;
|
||||
|
||||
dnet->regs = (struct dnet_registers *)regs;
|
||||
dnet->phy_addr = phy_addr;
|
||||
|
||||
sprintf(netdev->name, "dnet%d", id);
|
||||
netdev->init = dnet_init;
|
||||
netdev->halt = dnet_halt;
|
||||
netdev->send = dnet_send;
|
||||
netdev->recv = dnet_recv;
|
||||
|
||||
dev_capa = readl(&dnet->regs->VERCAPS) & 0xFFFF;
|
||||
debug("%s: has %smdio, %sirq, %sgigabit, %sdma \n", netdev->name,
|
||||
(dev_capa & DNET_HAS_MDIO) ? "" : "no ",
|
||||
(dev_capa & DNET_HAS_IRQ) ? "" : "no ",
|
||||
(dev_capa & DNET_HAS_GIGABIT) ? "" : "no ",
|
||||
(dev_capa & DNET_HAS_DMA) ? "" : "no ");
|
||||
|
||||
eth_register(netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
166
sources/uboot-be550/drivers/net/dnet.h
Normal file
166
sources/uboot-be550/drivers/net/dnet.h
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Dave Ethernet Controller driver
|
||||
*
|
||||
* Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_DNET_H__
|
||||
#define __DRIVERS_DNET_H__
|
||||
|
||||
#define DRIVERNAME "dnet"
|
||||
|
||||
struct dnet_registers {
|
||||
/* ALL DNET FIFO REGISTERS */
|
||||
u32 RX_LEN_FIFO;
|
||||
u32 RX_DATA_FIFO;
|
||||
u32 TX_LEN_FIFO;
|
||||
u32 TX_DATA_FIFO;
|
||||
u32 pad1[0x3c];
|
||||
/* ALL DNET CONTROL/STATUS REGISTERS */
|
||||
u32 VERCAPS;
|
||||
u32 INTR_SRC;
|
||||
u32 INTR_ENB;
|
||||
u32 RX_STATUS;
|
||||
u32 TX_STATUS;
|
||||
u32 RX_FRAMES_CNT;
|
||||
u32 TX_FRAMES_CNT;
|
||||
u32 RX_FIFO_TH;
|
||||
u32 TX_FIFO_TH;
|
||||
u32 SYS_CTL;
|
||||
u32 PAUSE_TMR;
|
||||
u32 RX_FIFO_WCNT;
|
||||
u32 TX_FIFO_WCNT;
|
||||
u32 pad2[0x33];
|
||||
/* ALL DNET MAC REGISTERS */
|
||||
u32 MACREG_DATA; /* Mac-Reg Data */
|
||||
u32 MACREG_ADDR; /* Mac-Reg Addr */
|
||||
u32 pad3[0x3e];
|
||||
/* ALL DNET RX STATISTICS COUNTERS */
|
||||
u32 RX_PKT_IGNR_CNT;
|
||||
u32 RX_LEN_CHK_ERR_CNT;
|
||||
u32 RX_LNG_FRM_CNT;
|
||||
u32 RX_SHRT_FRM_CNT;
|
||||
u32 RX_IPG_VIOL_CNT;
|
||||
u32 RX_CRC_ERR_CNT;
|
||||
u32 RX_OK_PKT_CNT;
|
||||
u32 RX_CTL_FRM_CNT;
|
||||
u32 RX_PAUSE_FRM_CNT;
|
||||
u32 RX_MULTICAST_CNT;
|
||||
u32 RX_BROADCAST_CNT;
|
||||
u32 RX_VLAN_TAG_CNT;
|
||||
u32 RX_PRE_SHRINK_CNT;
|
||||
u32 RX_DRIB_NIB_CNT;
|
||||
u32 RX_UNSUP_OPCD_CNT;
|
||||
u32 RX_BYTE_CNT;
|
||||
u32 pad4[0x30];
|
||||
/* DNET TX STATISTICS COUNTERS */
|
||||
u32 TX_UNICAST_CNT;
|
||||
u32 TX_PAUSE_FRM_CNT;
|
||||
u32 TX_MULTICAST_CNT;
|
||||
u32 TX_BRDCAST_CNT;
|
||||
u32 TX_VLAN_TAG_CNT;
|
||||
u32 TX_BAD_FCS_CNT;
|
||||
u32 TX_JUMBO_CNT;
|
||||
u32 TX_BYTE_CNT;
|
||||
};
|
||||
|
||||
/* SOME INTERNAL MAC-CORE REGISTER */
|
||||
#define DNET_INTERNAL_MODE_REG 0x0
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2
|
||||
#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4
|
||||
#define DNET_INTERNAL_IGP_REG 0x8
|
||||
#define DNET_INTERNAL_MAC_ADDR_0_REG 0xa
|
||||
#define DNET_INTERNAL_MAC_ADDR_1_REG 0xc
|
||||
#define DNET_INTERNAL_MAC_ADDR_2_REG 0xe
|
||||
#define DNET_INTERNAL_TX_RX_STS_REG 0x12
|
||||
#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14
|
||||
#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16
|
||||
|
||||
#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14)
|
||||
|
||||
#define DNET_INTERNAL_WRITE (1 << 31)
|
||||
|
||||
/* MAC-CORE REGISTER FIELDS */
|
||||
|
||||
/* MAC-CORE MODE REGISTER FIELDS */
|
||||
#define DNET_INTERNAL_MODE_GBITEN (1 << 0)
|
||||
#define DNET_INTERNAL_MODE_FCEN (1 << 1)
|
||||
#define DNET_INTERNAL_MODE_RXEN (1 << 2)
|
||||
#define DNET_INTERNAL_MODE_TXEN (1 << 3)
|
||||
|
||||
/* MAC-CORE RXTX CONTROL REGISTER FIELDS */
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME (1 << 8)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST (1 << 7)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST (1 << 4)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE (1 << 3)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS (1 << 2)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS (1 << 1)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC (1 << 0)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL (1 << 6)
|
||||
#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP (1 << 5)
|
||||
|
||||
/* SYSTEM CONTROL REGISTER FIELDS */
|
||||
#define DNET_SYS_CTL_IGNORENEXTPKT (1 << 0)
|
||||
#define DNET_SYS_CTL_SENDPAUSE (1 << 2)
|
||||
#define DNET_SYS_CTL_RXFIFOFLUSH (1 << 3)
|
||||
#define DNET_SYS_CTL_TXFIFOFLUSH (1 << 4)
|
||||
|
||||
/* TX STATUS REGISTER FIELDS */
|
||||
#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY (1 << 2)
|
||||
#define DNET_TX_STATUS_FIFO_ALMOST_FULL (1 << 1)
|
||||
|
||||
/* INTERRUPT SOURCE REGISTER FIELDS */
|
||||
#define DNET_INTR_SRC_TX_PKTSENT (1 << 0)
|
||||
#define DNET_INTR_SRC_TX_FIFOAF (1 << 1)
|
||||
#define DNET_INTR_SRC_TX_FIFOAE (1 << 2)
|
||||
#define DNET_INTR_SRC_TX_DISCFRM (1 << 3)
|
||||
#define DNET_INTR_SRC_TX_FIFOFULL (1 << 4)
|
||||
#define DNET_INTR_SRC_RX_CMDFIFOAF (1 << 8)
|
||||
#define DNET_INTR_SRC_RX_CMDFIFOFF (1 << 9)
|
||||
#define DNET_INTR_SRC_RX_DATAFIFOFF (1 << 10)
|
||||
#define DNET_INTR_SRC_TX_SUMMARY (1 << 16)
|
||||
#define DNET_INTR_SRC_RX_SUMMARY (1 << 17)
|
||||
#define DNET_INTR_SRC_PHY (1 << 19)
|
||||
|
||||
/* INTERRUPT ENABLE REGISTER FIELDS */
|
||||
#define DNET_INTR_ENB_TX_PKTSENT (1 << 0)
|
||||
#define DNET_INTR_ENB_TX_FIFOAF (1 << 1)
|
||||
#define DNET_INTR_ENB_TX_FIFOAE (1 << 2)
|
||||
#define DNET_INTR_ENB_TX_DISCFRM (1 << 3)
|
||||
#define DNET_INTR_ENB_TX_FIFOFULL (1 << 4)
|
||||
#define DNET_INTR_ENB_RX_PKTRDY (1 << 8)
|
||||
#define DNET_INTR_ENB_RX_FIFOAF (1 << 9)
|
||||
#define DNET_INTR_ENB_RX_FIFOERR (1 << 10)
|
||||
#define DNET_INTR_ENB_RX_ERROR (1 << 11)
|
||||
#define DNET_INTR_ENB_RX_FIFOFULL (1 << 12)
|
||||
#define DNET_INTR_ENB_RX_FIFOAE (1 << 13)
|
||||
#define DNET_INTR_ENB_TX_SUMMARY (1 << 16)
|
||||
#define DNET_INTR_ENB_RX_SUMMARY (1 << 17)
|
||||
#define DNET_INTR_ENB_GLOBAL_ENABLE (1 << 18)
|
||||
|
||||
/*
|
||||
* Capabilities. Used by the driver to know the capabilities that
|
||||
* the ethernet controller inside the FPGA have.
|
||||
*/
|
||||
|
||||
#define DNET_HAS_MDIO (1 << 0)
|
||||
#define DNET_HAS_IRQ (1 << 1)
|
||||
#define DNET_HAS_GIGABIT (1 << 2)
|
||||
#define DNET_HAS_DMA (1 << 3)
|
||||
|
||||
#define DNET_HAS_MII (1 << 4) /* or GMII */
|
||||
#define DNET_HAS_RMII (1 << 5) /* or RGMII */
|
||||
|
||||
#define DNET_CAPS_MASK 0xFFFF
|
||||
|
||||
#define DNET_FIFO_SIZE 2048 /* 2K x 32 bit */
|
||||
#define DNET_FIFO_TX_DATA_AF_TH (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */
|
||||
#define DNET_FIFO_TX_DATA_AE_TH (384)
|
||||
|
||||
#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */
|
||||
|
||||
#endif
|
||||
5681
sources/uboot-be550/drivers/net/e1000.c
Normal file
5681
sources/uboot-be550/drivers/net/e1000.c
Normal file
File diff suppressed because it is too large
Load diff
2617
sources/uboot-be550/drivers/net/e1000.h
Normal file
2617
sources/uboot-be550/drivers/net/e1000.h
Normal file
File diff suppressed because it is too large
Load diff
579
sources/uboot-be550/drivers/net/e1000_spi.c
Normal file
579
sources/uboot-be550/drivers/net/e1000_spi.c
Normal file
|
|
@ -0,0 +1,579 @@
|
|||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include "e1000.h"
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* SPI transfer
|
||||
*
|
||||
* This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
|
||||
* "bitlen" bits in the SPI MISO port. That's just the way SPI works.
|
||||
*
|
||||
* The source of the outgoing bits is the "dout" parameter and the
|
||||
* destination of the input bits is the "din" parameter. Note that "dout"
|
||||
* and "din" can point to the same memory location, in which case the
|
||||
* input data overwrites the output data (since both are buffered by
|
||||
* temporary variables, this is OK).
|
||||
*
|
||||
* This may be interrupted with Ctrl-C if "intr" is true, otherwise it will
|
||||
* never return an error.
|
||||
*/
|
||||
static int e1000_spi_xfer(struct e1000_hw *hw, unsigned int bitlen,
|
||||
const void *dout_mem, void *din_mem, bool intr)
|
||||
{
|
||||
const uint8_t *dout = dout_mem;
|
||||
uint8_t *din = din_mem;
|
||||
|
||||
uint8_t mask = 0;
|
||||
uint32_t eecd;
|
||||
unsigned long i;
|
||||
|
||||
/* Pre-read the control register */
|
||||
eecd = E1000_READ_REG(hw, EECD);
|
||||
|
||||
/* Iterate over each bit */
|
||||
for (i = 0, mask = 0x80; i < bitlen; i++, mask = (mask >> 1)?:0x80) {
|
||||
/* Check for interrupt */
|
||||
if (intr && ctrlc())
|
||||
return -1;
|
||||
|
||||
/* Determine the output bit */
|
||||
if (dout && dout[i >> 3] & mask)
|
||||
eecd |= E1000_EECD_DI;
|
||||
else
|
||||
eecd &= ~E1000_EECD_DI;
|
||||
|
||||
/* Write the output bit and wait 50us */
|
||||
E1000_WRITE_REG(hw, EECD, eecd);
|
||||
E1000_WRITE_FLUSH(hw);
|
||||
udelay(50);
|
||||
|
||||
/* Poke the clock (waits 50us) */
|
||||
e1000_raise_ee_clk(hw, &eecd);
|
||||
|
||||
/* Now read the input bit */
|
||||
eecd = E1000_READ_REG(hw, EECD);
|
||||
if (din) {
|
||||
if (eecd & E1000_EECD_DO)
|
||||
din[i >> 3] |= mask;
|
||||
else
|
||||
din[i >> 3] &= ~mask;
|
||||
}
|
||||
|
||||
/* Poke the clock again (waits 50us) */
|
||||
e1000_lower_ee_clk(hw, &eecd);
|
||||
}
|
||||
|
||||
/* Now clear any remaining bits of the input */
|
||||
if (din && (i & 7))
|
||||
din[i >> 3] &= ~((mask << 1) - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_E1000_SPI_GENERIC
|
||||
static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi)
|
||||
{
|
||||
return container_of(spi, struct e1000_hw, spi);
|
||||
}
|
||||
|
||||
/* Not sure why all of these are necessary */
|
||||
void spi_init_r(void) { /* Nothing to do */ }
|
||||
void spi_init_f(void) { /* Nothing to do */ }
|
||||
void spi_init(void) { /* Nothing to do */ }
|
||||
|
||||
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
/* Find the right PCI device */
|
||||
struct e1000_hw *hw = e1000_find_card(bus);
|
||||
if (!hw) {
|
||||
printf("ERROR: No such e1000 device: e1000#%u\n", bus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure it has an SPI chip */
|
||||
if (hw->eeprom.type != e1000_eeprom_spi) {
|
||||
E1000_ERR(hw->nic, "No attached SPI EEPROM found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Argument sanity checks */
|
||||
if (cs != 0) {
|
||||
E1000_ERR(hw->nic, "No such SPI chip: %u\n", cs);
|
||||
return NULL;
|
||||
}
|
||||
if (mode != SPI_MODE_0) {
|
||||
E1000_ERR(hw->nic, "Only SPI MODE-0 is supported!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO: Use max_hz somehow */
|
||||
E1000_DBG(hw->nic, "EEPROM SPI access requested\n");
|
||||
return &hw->spi;
|
||||
}
|
||||
|
||||
void spi_free_slave(struct spi_slave *spi)
|
||||
{
|
||||
__maybe_unused struct e1000_hw *hw = e1000_hw_from_spi(spi);
|
||||
E1000_DBG(hw->nic, "EEPROM SPI access released\n");
|
||||
}
|
||||
|
||||
int spi_claim_bus(struct spi_slave *spi)
|
||||
{
|
||||
struct e1000_hw *hw = e1000_hw_from_spi(spi);
|
||||
|
||||
if (e1000_acquire_eeprom(hw)) {
|
||||
E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(struct spi_slave *spi)
|
||||
{
|
||||
struct e1000_hw *hw = e1000_hw_from_spi(spi);
|
||||
e1000_release_eeprom(hw);
|
||||
}
|
||||
|
||||
/* Skinny wrapper around e1000_spi_xfer */
|
||||
int spi_xfer(struct spi_slave *spi, unsigned int bitlen,
|
||||
const void *dout_mem, void *din_mem, unsigned long flags)
|
||||
{
|
||||
struct e1000_hw *hw = e1000_hw_from_spi(spi);
|
||||
int ret;
|
||||
|
||||
if (flags & SPI_XFER_BEGIN)
|
||||
e1000_standby_eeprom(hw);
|
||||
|
||||
ret = e1000_spi_xfer(hw, bitlen, dout_mem, din_mem, true);
|
||||
|
||||
if (flags & SPI_XFER_END)
|
||||
e1000_standby_eeprom(hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* not CONFIG_E1000_SPI_GENERIC */
|
||||
|
||||
#ifdef CONFIG_CMD_E1000
|
||||
|
||||
/* The EEPROM opcodes */
|
||||
#define SPI_EEPROM_ENABLE_WR 0x06
|
||||
#define SPI_EEPROM_DISABLE_WR 0x04
|
||||
#define SPI_EEPROM_WRITE_STATUS 0x01
|
||||
#define SPI_EEPROM_READ_STATUS 0x05
|
||||
#define SPI_EEPROM_WRITE_PAGE 0x02
|
||||
#define SPI_EEPROM_READ_PAGE 0x03
|
||||
|
||||
/* The EEPROM status bits */
|
||||
#define SPI_EEPROM_STATUS_BUSY 0x01
|
||||
#define SPI_EEPROM_STATUS_WREN 0x02
|
||||
|
||||
static int e1000_spi_eeprom_enable_wr(struct e1000_hw *hw, bool intr)
|
||||
{
|
||||
u8 op[] = { SPI_EEPROM_ENABLE_WR };
|
||||
e1000_standby_eeprom(hw);
|
||||
return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
|
||||
}
|
||||
|
||||
/*
|
||||
* These have been tested to perform correctly, but they are not used by any
|
||||
* of the EEPROM commands at this time.
|
||||
*/
|
||||
#if 0
|
||||
static int e1000_spi_eeprom_disable_wr(struct e1000_hw *hw, bool intr)
|
||||
{
|
||||
u8 op[] = { SPI_EEPROM_DISABLE_WR };
|
||||
e1000_standby_eeprom(hw);
|
||||
return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
|
||||
}
|
||||
|
||||
static int e1000_spi_eeprom_write_status(struct e1000_hw *hw,
|
||||
u8 status, bool intr)
|
||||
{
|
||||
u8 op[] = { SPI_EEPROM_WRITE_STATUS, status };
|
||||
e1000_standby_eeprom(hw);
|
||||
return e1000_spi_xfer(hw, 8*sizeof(op), op, NULL, intr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int e1000_spi_eeprom_read_status(struct e1000_hw *hw, bool intr)
|
||||
{
|
||||
u8 op[] = { SPI_EEPROM_READ_STATUS, 0 };
|
||||
e1000_standby_eeprom(hw);
|
||||
if (e1000_spi_xfer(hw, 8*sizeof(op), op, op, intr))
|
||||
return -1;
|
||||
return op[1];
|
||||
}
|
||||
|
||||
static int e1000_spi_eeprom_write_page(struct e1000_hw *hw,
|
||||
const void *data, u16 off, u16 len, bool intr)
|
||||
{
|
||||
u8 op[] = {
|
||||
SPI_EEPROM_WRITE_PAGE,
|
||||
(off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff
|
||||
};
|
||||
|
||||
e1000_standby_eeprom(hw);
|
||||
|
||||
if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr))
|
||||
return -1;
|
||||
if (e1000_spi_xfer(hw, len << 3, data, NULL, intr))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e1000_spi_eeprom_read_page(struct e1000_hw *hw,
|
||||
void *data, u16 off, u16 len, bool intr)
|
||||
{
|
||||
u8 op[] = {
|
||||
SPI_EEPROM_READ_PAGE,
|
||||
(off >> (hw->eeprom.address_bits - 8)) & 0xff, off & 0xff
|
||||
};
|
||||
|
||||
e1000_standby_eeprom(hw);
|
||||
|
||||
if (e1000_spi_xfer(hw, 8 + hw->eeprom.address_bits, op, NULL, intr))
|
||||
return -1;
|
||||
if (e1000_spi_xfer(hw, len << 3, NULL, data, intr))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e1000_spi_eeprom_poll_ready(struct e1000_hw *hw, bool intr)
|
||||
{
|
||||
int status;
|
||||
while ((status = e1000_spi_eeprom_read_status(hw, intr)) >= 0) {
|
||||
if (!(status & SPI_EEPROM_STATUS_BUSY))
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int e1000_spi_eeprom_dump(struct e1000_hw *hw,
|
||||
void *data, u16 off, unsigned int len, bool intr)
|
||||
{
|
||||
/* Interruptibly wait for the EEPROM to be ready */
|
||||
if (e1000_spi_eeprom_poll_ready(hw, intr))
|
||||
return -1;
|
||||
|
||||
/* Dump each page in sequence */
|
||||
while (len) {
|
||||
/* Calculate the data bytes on this page */
|
||||
u16 pg_off = off & (hw->eeprom.page_size - 1);
|
||||
u16 pg_len = hw->eeprom.page_size - pg_off;
|
||||
if (pg_len > len)
|
||||
pg_len = len;
|
||||
|
||||
/* Now dump the page */
|
||||
if (e1000_spi_eeprom_read_page(hw, data, off, pg_len, intr))
|
||||
return -1;
|
||||
|
||||
/* Otherwise go on to the next page */
|
||||
len -= pg_len;
|
||||
off += pg_len;
|
||||
data += pg_len;
|
||||
}
|
||||
|
||||
/* We're done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e1000_spi_eeprom_program(struct e1000_hw *hw,
|
||||
const void *data, u16 off, u16 len, bool intr)
|
||||
{
|
||||
/* Program each page in sequence */
|
||||
while (len) {
|
||||
/* Calculate the data bytes on this page */
|
||||
u16 pg_off = off & (hw->eeprom.page_size - 1);
|
||||
u16 pg_len = hw->eeprom.page_size - pg_off;
|
||||
if (pg_len > len)
|
||||
pg_len = len;
|
||||
|
||||
/* Interruptibly wait for the EEPROM to be ready */
|
||||
if (e1000_spi_eeprom_poll_ready(hw, intr))
|
||||
return -1;
|
||||
|
||||
/* Enable write access */
|
||||
if (e1000_spi_eeprom_enable_wr(hw, intr))
|
||||
return -1;
|
||||
|
||||
/* Now program the page */
|
||||
if (e1000_spi_eeprom_write_page(hw, data, off, pg_len, intr))
|
||||
return -1;
|
||||
|
||||
/* Otherwise go on to the next page */
|
||||
len -= pg_len;
|
||||
off += pg_len;
|
||||
data += pg_len;
|
||||
}
|
||||
|
||||
/* Wait for the last write to complete */
|
||||
if (e1000_spi_eeprom_poll_ready(hw, intr))
|
||||
return -1;
|
||||
|
||||
/* We're done! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_e1000_spi_show(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
unsigned int length = 0;
|
||||
u16 i, offset = 0;
|
||||
u8 *buffer;
|
||||
int err;
|
||||
|
||||
if (argc > 2) {
|
||||
cmd_usage(cmdtp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the offset and length */
|
||||
if (argc >= 1)
|
||||
offset = simple_strtoul(argv[0], NULL, 0);
|
||||
if (argc == 2)
|
||||
length = simple_strtoul(argv[1], NULL, 0);
|
||||
else if (offset < (hw->eeprom.word_size << 1))
|
||||
length = (hw->eeprom.word_size << 1) - offset;
|
||||
|
||||
/* Extra sanity checks */
|
||||
if (!length) {
|
||||
E1000_ERR(hw->nic, "Requested zero-sized dump!\n");
|
||||
return 1;
|
||||
}
|
||||
if ((0x10000 < length) || (0x10000 - length < offset)) {
|
||||
E1000_ERR(hw->nic, "Can't dump past 0xFFFF!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allocate a buffer to hold stuff */
|
||||
buffer = malloc(length);
|
||||
if (!buffer) {
|
||||
E1000_ERR(hw->nic, "Out of Memory!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Acquire the EEPROM and perform the dump */
|
||||
if (e1000_acquire_eeprom(hw)) {
|
||||
E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
err = e1000_spi_eeprom_dump(hw, buffer, offset, length, true);
|
||||
e1000_release_eeprom(hw);
|
||||
if (err) {
|
||||
E1000_ERR(hw->nic, "Interrupted!\n");
|
||||
free(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Now hexdump the result */
|
||||
printf("%s: ===== Intel e1000 EEPROM (0x%04hX - 0x%04hX) =====",
|
||||
hw->nic->name, offset, offset + length - 1);
|
||||
for (i = 0; i < length; i++) {
|
||||
if ((i & 0xF) == 0)
|
||||
printf("\n%s: %04hX: ", hw->nic->name, offset + i);
|
||||
else if ((i & 0xF) == 0x8)
|
||||
printf(" ");
|
||||
printf(" %02hx", buffer[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* Success! */
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_e1000_spi_dump(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
unsigned int length;
|
||||
u16 offset;
|
||||
void *dest;
|
||||
|
||||
if (argc != 3) {
|
||||
cmd_usage(cmdtp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the arguments */
|
||||
dest = (void *)simple_strtoul(argv[0], NULL, 16);
|
||||
offset = simple_strtoul(argv[1], NULL, 0);
|
||||
length = simple_strtoul(argv[2], NULL, 0);
|
||||
|
||||
/* Extra sanity checks */
|
||||
if (!length) {
|
||||
E1000_ERR(hw->nic, "Requested zero-sized dump!\n");
|
||||
return 1;
|
||||
}
|
||||
if ((0x10000 < length) || (0x10000 - length < offset)) {
|
||||
E1000_ERR(hw->nic, "Can't dump past 0xFFFF!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Acquire the EEPROM */
|
||||
if (e1000_acquire_eeprom(hw)) {
|
||||
E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform the programming operation */
|
||||
if (e1000_spi_eeprom_dump(hw, dest, offset, length, true) < 0) {
|
||||
E1000_ERR(hw->nic, "Interrupted!\n");
|
||||
e1000_release_eeprom(hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
e1000_release_eeprom(hw);
|
||||
printf("%s: ===== EEPROM DUMP COMPLETE =====\n", hw->nic->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_e1000_spi_program(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
unsigned int length;
|
||||
const void *source;
|
||||
u16 offset;
|
||||
|
||||
if (argc != 3) {
|
||||
cmd_usage(cmdtp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the arguments */
|
||||
source = (const void *)simple_strtoul(argv[0], NULL, 16);
|
||||
offset = simple_strtoul(argv[1], NULL, 0);
|
||||
length = simple_strtoul(argv[2], NULL, 0);
|
||||
|
||||
/* Acquire the EEPROM */
|
||||
if (e1000_acquire_eeprom(hw)) {
|
||||
E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform the programming operation */
|
||||
if (e1000_spi_eeprom_program(hw, source, offset, length, true) < 0) {
|
||||
E1000_ERR(hw->nic, "Interrupted!\n");
|
||||
e1000_release_eeprom(hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
e1000_release_eeprom(hw);
|
||||
printf("%s: ===== EEPROM PROGRAMMED =====\n", hw->nic->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_e1000_spi_checksum(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
uint16_t i, length, checksum = 0, checksum_reg;
|
||||
uint16_t *buffer;
|
||||
bool upd;
|
||||
|
||||
if (argc == 0)
|
||||
upd = 0;
|
||||
else if ((argc == 1) && !strcmp(argv[0], "update"))
|
||||
upd = 1;
|
||||
else {
|
||||
cmd_usage(cmdtp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allocate a temporary buffer */
|
||||
length = sizeof(uint16_t) * (EEPROM_CHECKSUM_REG + 1);
|
||||
buffer = malloc(length);
|
||||
if (!buffer) {
|
||||
E1000_ERR(hw->nic, "Unable to allocate EEPROM buffer!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Acquire the EEPROM */
|
||||
if (e1000_acquire_eeprom(hw)) {
|
||||
E1000_ERR(hw->nic, "EEPROM SPI cannot be acquired!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read the EEPROM */
|
||||
if (e1000_spi_eeprom_dump(hw, buffer, 0, length, true) < 0) {
|
||||
E1000_ERR(hw->nic, "Interrupted!\n");
|
||||
e1000_release_eeprom(hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the checksum and read the expected value */
|
||||
for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
|
||||
checksum += le16_to_cpu(buffer[i]);
|
||||
checksum = ((uint16_t)EEPROM_SUM) - checksum;
|
||||
checksum_reg = le16_to_cpu(buffer[i]);
|
||||
|
||||
/* Verify it! */
|
||||
if (checksum_reg == checksum) {
|
||||
printf("%s: INFO: EEPROM checksum is correct! (0x%04hx)\n",
|
||||
hw->nic->name, checksum);
|
||||
e1000_release_eeprom(hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Hrm, verification failed, print an error */
|
||||
E1000_ERR(hw->nic, "EEPROM checksum is incorrect!\n");
|
||||
E1000_ERR(hw->nic, " ...register was 0x%04hx, calculated 0x%04hx\n",
|
||||
checksum_reg, checksum);
|
||||
|
||||
/* If they didn't ask us to update it, just return an error */
|
||||
if (!upd) {
|
||||
e1000_release_eeprom(hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Ok, correct it! */
|
||||
printf("%s: Reprogramming the EEPROM checksum...\n", hw->nic->name);
|
||||
buffer[i] = cpu_to_le16(checksum);
|
||||
if (e1000_spi_eeprom_program(hw, &buffer[i], i * sizeof(uint16_t),
|
||||
sizeof(uint16_t), true)) {
|
||||
E1000_ERR(hw->nic, "Interrupted!\n");
|
||||
e1000_release_eeprom(hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
e1000_release_eeprom(hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_e1000_spi(cmd_tbl_t *cmdtp, struct e1000_hw *hw,
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
if (argc < 1) {
|
||||
cmd_usage(cmdtp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make sure it has an SPI chip */
|
||||
if (hw->eeprom.type != e1000_eeprom_spi) {
|
||||
E1000_ERR(hw->nic, "No attached SPI EEPROM found!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check the eeprom sub-sub-command arguments */
|
||||
if (!strcmp(argv[0], "show"))
|
||||
return do_e1000_spi_show(cmdtp, hw, argc - 1, argv + 1);
|
||||
|
||||
if (!strcmp(argv[0], "dump"))
|
||||
return do_e1000_spi_dump(cmdtp, hw, argc - 1, argv + 1);
|
||||
|
||||
if (!strcmp(argv[0], "program"))
|
||||
return do_e1000_spi_program(cmdtp, hw, argc - 1, argv + 1);
|
||||
|
||||
if (!strcmp(argv[0], "checksum"))
|
||||
return do_e1000_spi_checksum(cmdtp, hw, argc - 1, argv + 1);
|
||||
|
||||
cmd_usage(cmdtp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* not CONFIG_CMD_E1000 */
|
||||
932
sources/uboot-be550/drivers/net/eepro100.c
Normal file
932
sources/uboot-be550/drivers/net/eepro100.c
Normal file
|
|
@ -0,0 +1,932 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <netdev.h>
|
||||
#include <asm/io.h>
|
||||
#include <pci.h>
|
||||
#include <miiphy.h>
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/* Ethernet chip registers.
|
||||
*/
|
||||
#define SCBStatus 0 /* Rx/Command Unit Status *Word* */
|
||||
#define SCBIntAckByte 1 /* Rx/Command Unit STAT/ACK byte */
|
||||
#define SCBCmd 2 /* Rx/Command Unit Command *Word* */
|
||||
#define SCBIntrCtlByte 3 /* Rx/Command Unit Intr.Control Byte */
|
||||
#define SCBPointer 4 /* General purpose pointer. */
|
||||
#define SCBPort 8 /* Misc. commands and operands. */
|
||||
#define SCBflash 12 /* Flash memory control. */
|
||||
#define SCBeeprom 14 /* EEPROM memory control. */
|
||||
#define SCBCtrlMDI 16 /* MDI interface control. */
|
||||
#define SCBEarlyRx 20 /* Early receive byte count. */
|
||||
#define SCBGenControl 28 /* 82559 General Control Register */
|
||||
#define SCBGenStatus 29 /* 82559 General Status register */
|
||||
|
||||
/* 82559 SCB status word defnitions
|
||||
*/
|
||||
#define SCB_STATUS_CX 0x8000 /* CU finished command (transmit) */
|
||||
#define SCB_STATUS_FR 0x4000 /* frame received */
|
||||
#define SCB_STATUS_CNA 0x2000 /* CU left active state */
|
||||
#define SCB_STATUS_RNR 0x1000 /* receiver left ready state */
|
||||
#define SCB_STATUS_MDI 0x0800 /* MDI read/write cycle done */
|
||||
#define SCB_STATUS_SWI 0x0400 /* software generated interrupt */
|
||||
#define SCB_STATUS_FCP 0x0100 /* flow control pause interrupt */
|
||||
|
||||
#define SCB_INTACK_MASK 0xFD00 /* all the above */
|
||||
|
||||
#define SCB_INTACK_TX (SCB_STATUS_CX | SCB_STATUS_CNA)
|
||||
#define SCB_INTACK_RX (SCB_STATUS_FR | SCB_STATUS_RNR)
|
||||
|
||||
/* System control block commands
|
||||
*/
|
||||
/* CU Commands */
|
||||
#define CU_NOP 0x0000
|
||||
#define CU_START 0x0010
|
||||
#define CU_RESUME 0x0020
|
||||
#define CU_STATSADDR 0x0040 /* Load Dump Statistics ctrs addr */
|
||||
#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */
|
||||
#define CU_ADDR_LOAD 0x0060 /* Base address to add to CU commands */
|
||||
#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */
|
||||
|
||||
/* RUC Commands */
|
||||
#define RUC_NOP 0x0000
|
||||
#define RUC_START 0x0001
|
||||
#define RUC_RESUME 0x0002
|
||||
#define RUC_ABORT 0x0004
|
||||
#define RUC_ADDR_LOAD 0x0006 /* (seems not to clear on acceptance) */
|
||||
#define RUC_RESUMENR 0x0007
|
||||
|
||||
#define CU_CMD_MASK 0x00f0
|
||||
#define RU_CMD_MASK 0x0007
|
||||
|
||||
#define SCB_M 0x0100 /* 0 = enable interrupt, 1 = disable */
|
||||
#define SCB_SWI 0x0200 /* 1 - cause device to interrupt */
|
||||
|
||||
#define CU_STATUS_MASK 0x00C0
|
||||
#define RU_STATUS_MASK 0x003C
|
||||
|
||||
#define RU_STATUS_IDLE (0<<2)
|
||||
#define RU_STATUS_SUS (1<<2)
|
||||
#define RU_STATUS_NORES (2<<2)
|
||||
#define RU_STATUS_READY (4<<2)
|
||||
#define RU_STATUS_NO_RBDS_SUS ((1<<2)|(8<<2))
|
||||
#define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2))
|
||||
#define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2))
|
||||
|
||||
/* 82559 Port interface commands.
|
||||
*/
|
||||
#define I82559_RESET 0x00000000 /* Software reset */
|
||||
#define I82559_SELFTEST 0x00000001 /* 82559 Selftest command */
|
||||
#define I82559_SELECTIVE_RESET 0x00000002
|
||||
#define I82559_DUMP 0x00000003
|
||||
#define I82559_DUMP_WAKEUP 0x00000007
|
||||
|
||||
/* 82559 Eeprom interface.
|
||||
*/
|
||||
#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
|
||||
#define EE_CS 0x02 /* EEPROM chip select. */
|
||||
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
|
||||
#define EE_WRITE_0 0x01
|
||||
#define EE_WRITE_1 0x05
|
||||
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
|
||||
#define EE_ENB (0x4800 | EE_CS)
|
||||
#define EE_CMD_BITS 3
|
||||
#define EE_DATA_BITS 16
|
||||
|
||||
/* The EEPROM commands include the alway-set leading bit.
|
||||
*/
|
||||
#define EE_EWENB_CMD (4 << addr_len)
|
||||
#define EE_WRITE_CMD (5 << addr_len)
|
||||
#define EE_READ_CMD (6 << addr_len)
|
||||
#define EE_ERASE_CMD (7 << addr_len)
|
||||
|
||||
/* Receive frame descriptors.
|
||||
*/
|
||||
struct RxFD {
|
||||
volatile u16 status;
|
||||
volatile u16 control;
|
||||
volatile u32 link; /* struct RxFD * */
|
||||
volatile u32 rx_buf_addr; /* void * */
|
||||
volatile u32 count;
|
||||
|
||||
volatile u8 data[PKTSIZE_ALIGN];
|
||||
};
|
||||
|
||||
#define RFD_STATUS_C 0x8000 /* completion of received frame */
|
||||
#define RFD_STATUS_OK 0x2000 /* frame received with no errors */
|
||||
|
||||
#define RFD_CONTROL_EL 0x8000 /* 1=last RFD in RFA */
|
||||
#define RFD_CONTROL_S 0x4000 /* 1=suspend RU after receiving frame */
|
||||
#define RFD_CONTROL_H 0x0010 /* 1=RFD is a header RFD */
|
||||
#define RFD_CONTROL_SF 0x0008 /* 0=simplified, 1=flexible mode */
|
||||
|
||||
#define RFD_COUNT_MASK 0x3fff
|
||||
#define RFD_COUNT_F 0x4000
|
||||
#define RFD_COUNT_EOF 0x8000
|
||||
|
||||
#define RFD_RX_CRC 0x0800 /* crc error */
|
||||
#define RFD_RX_ALIGNMENT 0x0400 /* alignment error */
|
||||
#define RFD_RX_RESOURCE 0x0200 /* out of space, no resources */
|
||||
#define RFD_RX_DMA_OVER 0x0100 /* DMA overrun */
|
||||
#define RFD_RX_SHORT 0x0080 /* short frame error */
|
||||
#define RFD_RX_LENGTH 0x0020
|
||||
#define RFD_RX_ERROR 0x0010 /* receive error */
|
||||
#define RFD_RX_NO_ADR_MATCH 0x0004 /* no address match */
|
||||
#define RFD_RX_IA_MATCH 0x0002 /* individual address does not match */
|
||||
#define RFD_RX_TCO 0x0001 /* TCO indication */
|
||||
|
||||
/* Transmit frame descriptors
|
||||
*/
|
||||
struct TxFD { /* Transmit frame descriptor set. */
|
||||
volatile u16 status;
|
||||
volatile u16 command;
|
||||
volatile u32 link; /* void * */
|
||||
volatile u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
|
||||
volatile s32 count;
|
||||
|
||||
volatile u32 tx_buf_addr0; /* void *, frame to be transmitted. */
|
||||
volatile s32 tx_buf_size0; /* Length of Tx frame. */
|
||||
volatile u32 tx_buf_addr1; /* void *, frame to be transmitted. */
|
||||
volatile s32 tx_buf_size1; /* Length of Tx frame. */
|
||||
};
|
||||
|
||||
#define TxCB_CMD_TRANSMIT 0x0004 /* transmit command */
|
||||
#define TxCB_CMD_SF 0x0008 /* 0=simplified, 1=flexible mode */
|
||||
#define TxCB_CMD_NC 0x0010 /* 0=CRC insert by controller */
|
||||
#define TxCB_CMD_I 0x2000 /* generate interrupt on completion */
|
||||
#define TxCB_CMD_S 0x4000 /* suspend on completion */
|
||||
#define TxCB_CMD_EL 0x8000 /* last command block in CBL */
|
||||
|
||||
#define TxCB_COUNT_MASK 0x3fff
|
||||
#define TxCB_COUNT_EOF 0x8000
|
||||
|
||||
/* The Speedo3 Rx and Tx frame/buffer descriptors.
|
||||
*/
|
||||
struct descriptor { /* A generic descriptor. */
|
||||
volatile u16 status;
|
||||
volatile u16 command;
|
||||
volatile u32 link; /* struct descriptor * */
|
||||
|
||||
unsigned char params[0];
|
||||
};
|
||||
|
||||
#define CONFIG_SYS_CMD_EL 0x8000
|
||||
#define CONFIG_SYS_CMD_SUSPEND 0x4000
|
||||
#define CONFIG_SYS_CMD_INT 0x2000
|
||||
#define CONFIG_SYS_CMD_IAS 0x0001 /* individual address setup */
|
||||
#define CONFIG_SYS_CMD_CONFIGURE 0x0002 /* configure */
|
||||
|
||||
#define CONFIG_SYS_STATUS_C 0x8000
|
||||
#define CONFIG_SYS_STATUS_OK 0x2000
|
||||
|
||||
/* Misc.
|
||||
*/
|
||||
#define NUM_RX_DESC PKTBUFSRX
|
||||
#define NUM_TX_DESC 1 /* Number of TX descriptors */
|
||||
|
||||
#define TOUT_LOOP 1000000
|
||||
|
||||
#define ETH_ALEN 6
|
||||
|
||||
static struct RxFD rx_ring[NUM_RX_DESC]; /* RX descriptor ring */
|
||||
static struct TxFD tx_ring[NUM_TX_DESC]; /* TX descriptor ring */
|
||||
static int rx_next; /* RX descriptor ring pointer */
|
||||
static int tx_next; /* TX descriptor ring pointer */
|
||||
static int tx_threshold;
|
||||
|
||||
/*
|
||||
* The parameters for a CmdConfigure operation.
|
||||
* There are so many options that it would be difficult to document
|
||||
* each bit. We mostly use the default or recommended settings.
|
||||
*/
|
||||
static const char i82557_config_cmd[] = {
|
||||
22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
|
||||
0, 0x2E, 0, 0x60, 0,
|
||||
0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
|
||||
0x3f, 0x05,
|
||||
};
|
||||
static const char i82558_config_cmd[] = {
|
||||
22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
|
||||
0, 0x2E, 0, 0x60, 0x08, 0x88,
|
||||
0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */
|
||||
0x31, 0x05,
|
||||
};
|
||||
|
||||
static void init_rx_ring (struct eth_device *dev);
|
||||
static void purge_tx_ring (struct eth_device *dev);
|
||||
|
||||
static void read_hw_addr (struct eth_device *dev, bd_t * bis);
|
||||
|
||||
static int eepro100_init (struct eth_device *dev, bd_t * bis);
|
||||
static int eepro100_send(struct eth_device *dev, void *packet, int length);
|
||||
static int eepro100_recv (struct eth_device *dev);
|
||||
static void eepro100_halt (struct eth_device *dev);
|
||||
|
||||
#if defined(CONFIG_E500)
|
||||
#define bus_to_phys(a) (a)
|
||||
#define phys_to_bus(a) (a)
|
||||
#else
|
||||
#define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)dev->priv, a)
|
||||
#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a)
|
||||
#endif
|
||||
|
||||
static inline int INW (struct eth_device *dev, u_long addr)
|
||||
{
|
||||
return le16_to_cpu (*(volatile u16 *) (addr + dev->iobase));
|
||||
}
|
||||
|
||||
static inline void OUTW (struct eth_device *dev, int command, u_long addr)
|
||||
{
|
||||
*(volatile u16 *) ((addr + dev->iobase)) = cpu_to_le16 (command);
|
||||
}
|
||||
|
||||
static inline void OUTL (struct eth_device *dev, int command, u_long addr)
|
||||
{
|
||||
*(volatile u32 *) ((addr + dev->iobase)) = cpu_to_le32 (command);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
static inline int INL (struct eth_device *dev, u_long addr)
|
||||
{
|
||||
return le32_to_cpu (*(volatile u32 *) (addr + dev->iobase));
|
||||
}
|
||||
|
||||
static int get_phyreg (struct eth_device *dev, unsigned char addr,
|
||||
unsigned char reg, unsigned short *value)
|
||||
{
|
||||
int cmd;
|
||||
int timeout = 50;
|
||||
|
||||
/* read requested data */
|
||||
cmd = (2 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
|
||||
OUTL (dev, cmd, SCBCtrlMDI);
|
||||
|
||||
do {
|
||||
udelay(1000);
|
||||
cmd = INL (dev, SCBCtrlMDI);
|
||||
} while (!(cmd & (1 << 28)) && (--timeout));
|
||||
|
||||
if (timeout == 0)
|
||||
return -1;
|
||||
|
||||
*value = (unsigned short) (cmd & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_phyreg (struct eth_device *dev, unsigned char addr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
int cmd;
|
||||
int timeout = 50;
|
||||
|
||||
/* write requested data */
|
||||
cmd = (1 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16);
|
||||
OUTL (dev, cmd | value, SCBCtrlMDI);
|
||||
|
||||
while (!(INL (dev, SCBCtrlMDI) & (1 << 28)) && (--timeout))
|
||||
udelay(1000);
|
||||
|
||||
if (timeout == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if given phyaddr is valid, i.e. there is a PHY connected.
|
||||
* Do this by checking model value field from ID2 register.
|
||||
*/
|
||||
static struct eth_device* verify_phyaddr (const char *devname,
|
||||
unsigned char addr)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
unsigned short value;
|
||||
unsigned char model;
|
||||
|
||||
dev = eth_get_dev_by_name(devname);
|
||||
if (dev == NULL) {
|
||||
printf("%s: no such device\n", devname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read id2 register */
|
||||
if (get_phyreg(dev, addr, MII_PHYSID2, &value) != 0) {
|
||||
printf("%s: mii read timeout!\n", devname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get model */
|
||||
model = (unsigned char)((value >> 4) & 0x003f);
|
||||
|
||||
if (model == 0) {
|
||||
printf("%s: no PHY at address %d\n", devname, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int eepro100_miiphy_read(const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short *value)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
|
||||
dev = verify_phyaddr(devname, addr);
|
||||
if (dev == NULL)
|
||||
return -1;
|
||||
|
||||
if (get_phyreg(dev, addr, reg, value) != 0) {
|
||||
printf("%s: mii read timeout!\n", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eepro100_miiphy_write(const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
|
||||
dev = verify_phyaddr(devname, addr);
|
||||
if (dev == NULL)
|
||||
return -1;
|
||||
|
||||
if (set_phyreg(dev, addr, reg, value) != 0) {
|
||||
printf("%s: mii write timeout!\n", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Wait for the chip get the command.
|
||||
*/
|
||||
static int wait_for_eepro100 (struct eth_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; INW (dev, SCBCmd) & (CU_CMD_MASK | RU_CMD_MASK); i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct pci_device_id supported[] = {
|
||||
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557},
|
||||
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559},
|
||||
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER},
|
||||
{}
|
||||
};
|
||||
|
||||
int eepro100_initialize (bd_t * bis)
|
||||
{
|
||||
pci_dev_t devno;
|
||||
int card_number = 0;
|
||||
struct eth_device *dev;
|
||||
u32 iobase, status;
|
||||
int idx = 0;
|
||||
|
||||
while (1) {
|
||||
/* Find PCI device
|
||||
*/
|
||||
if ((devno = pci_find_devices (supported, idx++)) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase);
|
||||
iobase &= ~0xf;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("eepro100: Intel i82559 PCI EtherExpressPro @0x%x\n",
|
||||
iobase);
|
||||
#endif
|
||||
|
||||
pci_write_config_dword (devno,
|
||||
PCI_COMMAND,
|
||||
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
||||
|
||||
/* Check if I/O accesses and Bus Mastering are enabled.
|
||||
*/
|
||||
pci_read_config_dword (devno, PCI_COMMAND, &status);
|
||||
if (!(status & PCI_COMMAND_MEMORY)) {
|
||||
printf ("Error: Can not enable MEM access.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(status & PCI_COMMAND_MASTER)) {
|
||||
printf ("Error: Can not enable Bus Mastering.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
dev = (struct eth_device *) malloc (sizeof *dev);
|
||||
if (!dev) {
|
||||
printf("eepro100: Can not allocate memory\n");
|
||||
break;
|
||||
}
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
sprintf (dev->name, "i82559#%d", card_number);
|
||||
dev->priv = (void *) devno; /* this have to come before bus_to_phys() */
|
||||
dev->iobase = bus_to_phys (iobase);
|
||||
dev->init = eepro100_init;
|
||||
dev->halt = eepro100_halt;
|
||||
dev->send = eepro100_send;
|
||||
dev->recv = eepro100_recv;
|
||||
|
||||
eth_register (dev);
|
||||
|
||||
#if defined (CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
/* register mii command access routines */
|
||||
miiphy_register(dev->name,
|
||||
eepro100_miiphy_read, eepro100_miiphy_write);
|
||||
#endif
|
||||
|
||||
card_number++;
|
||||
|
||||
/* Set the latency timer for value.
|
||||
*/
|
||||
pci_write_config_byte (devno, PCI_LATENCY_TIMER, 0x20);
|
||||
|
||||
udelay (10 * 1000);
|
||||
|
||||
read_hw_addr (dev, bis);
|
||||
}
|
||||
|
||||
return card_number;
|
||||
}
|
||||
|
||||
|
||||
static int eepro100_init (struct eth_device *dev, bd_t * bis)
|
||||
{
|
||||
int i, status = -1;
|
||||
int tx_cur;
|
||||
struct descriptor *ias_cmd, *cfg_cmd;
|
||||
|
||||
/* Reset the ethernet controller
|
||||
*/
|
||||
OUTL (dev, I82559_SELECTIVE_RESET, SCBPort);
|
||||
udelay (20);
|
||||
|
||||
OUTL (dev, I82559_RESET, SCBPort);
|
||||
udelay (20);
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
OUTL (dev, 0, SCBPointer);
|
||||
OUTW (dev, SCB_M | RUC_ADDR_LOAD, SCBCmd);
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
OUTL (dev, 0, SCBPointer);
|
||||
OUTW (dev, SCB_M | CU_ADDR_LOAD, SCBCmd);
|
||||
|
||||
/* Initialize Rx and Tx rings.
|
||||
*/
|
||||
init_rx_ring (dev);
|
||||
purge_tx_ring (dev);
|
||||
|
||||
/* Tell the adapter where the RX ring is located.
|
||||
*/
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
OUTL (dev, phys_to_bus ((u32) & rx_ring[rx_next]), SCBPointer);
|
||||
OUTW (dev, SCB_M | RUC_START, SCBCmd);
|
||||
|
||||
/* Send the Configure frame */
|
||||
tx_cur = tx_next;
|
||||
tx_next = ((tx_next + 1) % NUM_TX_DESC);
|
||||
|
||||
cfg_cmd = (struct descriptor *) &tx_ring[tx_cur];
|
||||
cfg_cmd->command = cpu_to_le16 ((CONFIG_SYS_CMD_SUSPEND | CONFIG_SYS_CMD_CONFIGURE));
|
||||
cfg_cmd->status = 0;
|
||||
cfg_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
|
||||
|
||||
memcpy (cfg_cmd->params, i82558_config_cmd,
|
||||
sizeof (i82558_config_cmd));
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error---CONFIG_SYS_CMD_CONFIGURE: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
|
||||
OUTW (dev, SCB_M | CU_START, SCBCmd);
|
||||
|
||||
for (i = 0;
|
||||
!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
|
||||
i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf ("%s: Tx error buffer not ready\n", dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
|
||||
printf ("TX error status = 0x%08X\n",
|
||||
le16_to_cpu (tx_ring[tx_cur].status));
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Send the Individual Address Setup frame
|
||||
*/
|
||||
tx_cur = tx_next;
|
||||
tx_next = ((tx_next + 1) % NUM_TX_DESC);
|
||||
|
||||
ias_cmd = (struct descriptor *) &tx_ring[tx_cur];
|
||||
ias_cmd->command = cpu_to_le16 ((CONFIG_SYS_CMD_SUSPEND | CONFIG_SYS_CMD_IAS));
|
||||
ias_cmd->status = 0;
|
||||
ias_cmd->link = cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
|
||||
|
||||
memcpy (ias_cmd->params, dev->enetaddr, 6);
|
||||
|
||||
/* Tell the adapter where the TX ring is located.
|
||||
*/
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
|
||||
OUTW (dev, SCB_M | CU_START, SCBCmd);
|
||||
|
||||
for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
|
||||
i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf ("%s: Tx error buffer not ready\n",
|
||||
dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
|
||||
printf ("TX error status = 0x%08X\n",
|
||||
le16_to_cpu (tx_ring[tx_cur].status));
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
|
||||
Done:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int eepro100_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
int i, status = -1;
|
||||
int tx_cur;
|
||||
|
||||
if (length <= 0) {
|
||||
printf ("%s: bad packet size: %d\n", dev->name, length);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
tx_cur = tx_next;
|
||||
tx_next = (tx_next + 1) % NUM_TX_DESC;
|
||||
|
||||
tx_ring[tx_cur].command = cpu_to_le16 ( TxCB_CMD_TRANSMIT |
|
||||
TxCB_CMD_SF |
|
||||
TxCB_CMD_S |
|
||||
TxCB_CMD_EL );
|
||||
tx_ring[tx_cur].status = 0;
|
||||
tx_ring[tx_cur].count = cpu_to_le32 (tx_threshold);
|
||||
tx_ring[tx_cur].link =
|
||||
cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_next]));
|
||||
tx_ring[tx_cur].tx_desc_addr =
|
||||
cpu_to_le32 (phys_to_bus ((u32) & tx_ring[tx_cur].tx_buf_addr0));
|
||||
tx_ring[tx_cur].tx_buf_addr0 =
|
||||
cpu_to_le32 (phys_to_bus ((u_long) packet));
|
||||
tx_ring[tx_cur].tx_buf_size0 = cpu_to_le32 (length);
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("%s: Tx error ethernet controller not ready.\n",
|
||||
dev->name);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/* Send the packet.
|
||||
*/
|
||||
OUTL (dev, phys_to_bus ((u32) & tx_ring[tx_cur]), SCBPointer);
|
||||
OUTW (dev, SCB_M | CU_START, SCBCmd);
|
||||
|
||||
for (i = 0; !(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_C);
|
||||
i++) {
|
||||
if (i >= TOUT_LOOP) {
|
||||
printf ("%s: Tx error buffer not ready\n", dev->name);
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(le16_to_cpu (tx_ring[tx_cur].status) & CONFIG_SYS_STATUS_OK)) {
|
||||
printf ("TX error status = 0x%08X\n",
|
||||
le16_to_cpu (tx_ring[tx_cur].status));
|
||||
goto Done;
|
||||
}
|
||||
|
||||
status = length;
|
||||
|
||||
Done:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int eepro100_recv (struct eth_device *dev)
|
||||
{
|
||||
u16 status, stat;
|
||||
int rx_prev, length = 0;
|
||||
|
||||
stat = INW (dev, SCBStatus);
|
||||
OUTW (dev, stat & SCB_STATUS_RNR, SCBStatus);
|
||||
|
||||
for (;;) {
|
||||
status = le16_to_cpu (rx_ring[rx_next].status);
|
||||
|
||||
if (!(status & RFD_STATUS_C)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Valid frame status.
|
||||
*/
|
||||
if ((status & RFD_STATUS_OK)) {
|
||||
/* A valid frame received.
|
||||
*/
|
||||
length = le32_to_cpu (rx_ring[rx_next].count) & 0x3fff;
|
||||
|
||||
/* Pass the packet up to the protocol
|
||||
* layers.
|
||||
*/
|
||||
net_process_received_packet((u8 *)rx_ring[rx_next].data,
|
||||
length);
|
||||
} else {
|
||||
/* There was an error.
|
||||
*/
|
||||
printf ("RX error status = 0x%08X\n", status);
|
||||
}
|
||||
|
||||
rx_ring[rx_next].control = cpu_to_le16 (RFD_CONTROL_S);
|
||||
rx_ring[rx_next].status = 0;
|
||||
rx_ring[rx_next].count = cpu_to_le32 (PKTSIZE_ALIGN << 16);
|
||||
|
||||
rx_prev = (rx_next + NUM_RX_DESC - 1) % NUM_RX_DESC;
|
||||
rx_ring[rx_prev].control = 0;
|
||||
|
||||
/* Update entry information.
|
||||
*/
|
||||
rx_next = (rx_next + 1) % NUM_RX_DESC;
|
||||
}
|
||||
|
||||
if (stat & SCB_STATUS_RNR) {
|
||||
|
||||
printf ("%s: Receiver is not ready, restart it !\n", dev->name);
|
||||
|
||||
/* Reinitialize Rx ring.
|
||||
*/
|
||||
init_rx_ring (dev);
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not restart ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
OUTL (dev, phys_to_bus ((u32) & rx_ring[rx_next]), SCBPointer);
|
||||
OUTW (dev, SCB_M | RUC_START, SCBCmd);
|
||||
}
|
||||
|
||||
Done:
|
||||
return length;
|
||||
}
|
||||
|
||||
static void eepro100_halt (struct eth_device *dev)
|
||||
{
|
||||
/* Reset the ethernet controller
|
||||
*/
|
||||
OUTL (dev, I82559_SELECTIVE_RESET, SCBPort);
|
||||
udelay (20);
|
||||
|
||||
OUTL (dev, I82559_RESET, SCBPort);
|
||||
udelay (20);
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
OUTL (dev, 0, SCBPointer);
|
||||
OUTW (dev, SCB_M | RUC_ADDR_LOAD, SCBCmd);
|
||||
|
||||
if (!wait_for_eepro100 (dev)) {
|
||||
printf ("Error: Can not reset ethernet controller.\n");
|
||||
goto Done;
|
||||
}
|
||||
OUTL (dev, 0, SCBPointer);
|
||||
OUTW (dev, SCB_M | CU_ADDR_LOAD, SCBCmd);
|
||||
|
||||
Done:
|
||||
return;
|
||||
}
|
||||
|
||||
/* SROM Read.
|
||||
*/
|
||||
static int read_eeprom (struct eth_device *dev, int location, int addr_len)
|
||||
{
|
||||
unsigned short retval = 0;
|
||||
int read_cmd = location | EE_READ_CMD;
|
||||
int i;
|
||||
|
||||
OUTW (dev, EE_ENB & ~EE_CS, SCBeeprom);
|
||||
OUTW (dev, EE_ENB, SCBeeprom);
|
||||
|
||||
/* Shift the read command bits out. */
|
||||
for (i = 12; i >= 0; i--) {
|
||||
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
|
||||
|
||||
OUTW (dev, EE_ENB | dataval, SCBeeprom);
|
||||
udelay (1);
|
||||
OUTW (dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
|
||||
udelay (1);
|
||||
}
|
||||
OUTW (dev, EE_ENB, SCBeeprom);
|
||||
|
||||
for (i = 15; i >= 0; i--) {
|
||||
OUTW (dev, EE_ENB | EE_SHIFT_CLK, SCBeeprom);
|
||||
udelay (1);
|
||||
retval = (retval << 1) |
|
||||
((INW (dev, SCBeeprom) & EE_DATA_READ) ? 1 : 0);
|
||||
OUTW (dev, EE_ENB, SCBeeprom);
|
||||
udelay (1);
|
||||
}
|
||||
|
||||
/* Terminate the EEPROM access. */
|
||||
OUTW (dev, EE_ENB & ~EE_CS, SCBeeprom);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EEPRO100_SROM_WRITE
|
||||
int eepro100_write_eeprom (struct eth_device* dev, int location, int addr_len, unsigned short data)
|
||||
{
|
||||
unsigned short dataval;
|
||||
int enable_cmd = 0x3f | EE_EWENB_CMD;
|
||||
int write_cmd = location | EE_WRITE_CMD;
|
||||
int i;
|
||||
unsigned long datalong, tmplong;
|
||||
|
||||
OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB, SCBeeprom);
|
||||
|
||||
/* Shift the enable command bits out. */
|
||||
for (i = (addr_len+EE_CMD_BITS-1); i >= 0; i--)
|
||||
{
|
||||
dataval = (enable_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
|
||||
OUTW(dev, EE_ENB | dataval, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
OUTW(dev, EE_ENB, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB, SCBeeprom);
|
||||
|
||||
|
||||
/* Shift the write command bits out. */
|
||||
for (i = (addr_len+EE_CMD_BITS-1); i >= 0; i--)
|
||||
{
|
||||
dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
|
||||
OUTW(dev, EE_ENB | dataval, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* Write the data */
|
||||
datalong= (unsigned long) ((((data) & 0x00ff) << 8) | ( (data) >> 8));
|
||||
|
||||
for (i = 0; i< EE_DATA_BITS; i++)
|
||||
{
|
||||
/* Extract and move data bit to bit DI */
|
||||
dataval = ((datalong & 0x8000)>>13) ? EE_DATA_WRITE : 0;
|
||||
|
||||
OUTW(dev, EE_ENB | dataval, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB | dataval | EE_SHIFT_CLK, SCBeeprom);
|
||||
udelay(1);
|
||||
OUTW(dev, EE_ENB | dataval, SCBeeprom);
|
||||
udelay(1);
|
||||
|
||||
datalong = datalong << 1; /* Adjust significant data bit*/
|
||||
}
|
||||
|
||||
/* Finish up command (toggle CS) */
|
||||
OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
|
||||
udelay(1); /* delay for more than 250 ns */
|
||||
OUTW(dev, EE_ENB, SCBeeprom);
|
||||
|
||||
/* Wait for programming ready (D0 = 1) */
|
||||
tmplong = 10;
|
||||
do
|
||||
{
|
||||
dataval = INW(dev, SCBeeprom);
|
||||
if (dataval & EE_DATA_READ)
|
||||
break;
|
||||
udelay(10000);
|
||||
}
|
||||
while (-- tmplong);
|
||||
|
||||
if (tmplong == 0)
|
||||
{
|
||||
printf ("Write i82559 eeprom timed out (100 ms waiting for data ready.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Terminate the EEPROM access. */
|
||||
OUTW(dev, EE_ENB & ~EE_CS, SCBeeprom);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void init_rx_ring (struct eth_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_RX_DESC; i++) {
|
||||
rx_ring[i].status = 0;
|
||||
rx_ring[i].control =
|
||||
(i == NUM_RX_DESC - 1) ? cpu_to_le16 (RFD_CONTROL_S) : 0;
|
||||
rx_ring[i].link =
|
||||
cpu_to_le32 (phys_to_bus
|
||||
((u32) & rx_ring[(i + 1) % NUM_RX_DESC]));
|
||||
rx_ring[i].rx_buf_addr = 0xffffffff;
|
||||
rx_ring[i].count = cpu_to_le32 (PKTSIZE_ALIGN << 16);
|
||||
}
|
||||
|
||||
rx_next = 0;
|
||||
}
|
||||
|
||||
static void purge_tx_ring (struct eth_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
tx_next = 0;
|
||||
tx_threshold = 0x01208000;
|
||||
|
||||
for (i = 0; i < NUM_TX_DESC; i++) {
|
||||
tx_ring[i].status = 0;
|
||||
tx_ring[i].command = 0;
|
||||
tx_ring[i].link = 0;
|
||||
tx_ring[i].tx_desc_addr = 0;
|
||||
tx_ring[i].count = 0;
|
||||
|
||||
tx_ring[i].tx_buf_addr0 = 0;
|
||||
tx_ring[i].tx_buf_size0 = 0;
|
||||
tx_ring[i].tx_buf_addr1 = 0;
|
||||
tx_ring[i].tx_buf_size1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_hw_addr (struct eth_device *dev, bd_t * bis)
|
||||
{
|
||||
u16 sum = 0;
|
||||
int i, j;
|
||||
int addr_len = read_eeprom (dev, 0, 6) == 0xffff ? 8 : 6;
|
||||
|
||||
for (j = 0, i = 0; i < 0x40; i++) {
|
||||
u16 value = read_eeprom (dev, i, addr_len);
|
||||
|
||||
sum += value;
|
||||
if (i < 3) {
|
||||
dev->enetaddr[j++] = value;
|
||||
dev->enetaddr[j++] = value >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (sum != 0xBABA) {
|
||||
memset (dev->enetaddr, 0, ETH_ALEN);
|
||||
#ifdef DEBUG
|
||||
printf ("%s: Invalid EEPROM checksum %#4.4x, "
|
||||
"check settings before activating this device!\n",
|
||||
dev->name, sum);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
964
sources/uboot-be550/drivers/net/enc28j60.c
Normal file
964
sources/uboot-be550/drivers/net/enc28j60.c
Normal file
|
|
@ -0,0 +1,964 @@
|
|||
/*
|
||||
* (C) Copyright 2010
|
||||
* Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
|
||||
* Martin Krause, Martin.Krause@tqs.de
|
||||
* reworked original enc28j60.c
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <net.h>
|
||||
#include <spi.h>
|
||||
#include <malloc.h>
|
||||
#include <netdev.h>
|
||||
#include <miiphy.h>
|
||||
#include "enc28j60.h"
|
||||
|
||||
/*
|
||||
* IMPORTANT: spi_claim_bus() and spi_release_bus()
|
||||
* are called at begin and end of each of the following functions:
|
||||
* enc_miiphy_read(), enc_miiphy_write(), enc_write_hwaddr(),
|
||||
* enc_init(), enc_recv(), enc_send(), enc_halt()
|
||||
* ALL other functions assume that the bus has already been claimed!
|
||||
* Since net_process_received_packet() might call enc_send() in return, the bus
|
||||
* must be released, net_process_received_packet() called and claimed again.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Controller memory layout.
|
||||
* We only allow 1 frame for transmission and reserve the rest
|
||||
* for reception to handle as many broadcast packets as possible.
|
||||
* Also use the memory from 0x0000 for receiver buffer. See errata pt. 5
|
||||
* 0x0000 - 0x19ff 6656 bytes receive buffer
|
||||
* 0x1a00 - 0x1fff 1536 bytes transmit buffer =
|
||||
* control(1)+frame(1518)+status(7)+reserve(10).
|
||||
*/
|
||||
#define ENC_RX_BUF_START 0x0000
|
||||
#define ENC_RX_BUF_END 0x19ff
|
||||
#define ENC_TX_BUF_START 0x1a00
|
||||
#define ENC_TX_BUF_END 0x1fff
|
||||
#define ENC_MAX_FRM_LEN 1518
|
||||
#define RX_RESET_COUNTER 1000
|
||||
|
||||
/*
|
||||
* For non data transfer functions, like phy read/write, set hwaddr, init
|
||||
* we do not need a full, time consuming init including link ready wait.
|
||||
* This enum helps to bring the chip through the minimum necessary inits.
|
||||
*/
|
||||
enum enc_initstate {none=0, setupdone, linkready};
|
||||
typedef struct enc_device {
|
||||
struct eth_device *dev; /* back pointer */
|
||||
struct spi_slave *slave;
|
||||
int rx_reset_counter;
|
||||
u16 next_pointer;
|
||||
u8 bank; /* current bank in enc28j60 */
|
||||
enum enc_initstate initstate;
|
||||
} enc_dev_t;
|
||||
|
||||
/*
|
||||
* enc_bset: set bits in a common register
|
||||
* enc_bclr: clear bits in a common register
|
||||
*
|
||||
* making the reg parameter u8 will give a compile time warning if the
|
||||
* functions are called with a register not accessible in all Banks
|
||||
*/
|
||||
static void enc_bset(enc_dev_t *enc, const u8 reg, const u8 data)
|
||||
{
|
||||
u8 dout[2];
|
||||
|
||||
dout[0] = CMD_BFS(reg);
|
||||
dout[1] = data;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
}
|
||||
|
||||
static void enc_bclr(enc_dev_t *enc, const u8 reg, const u8 data)
|
||||
{
|
||||
u8 dout[2];
|
||||
|
||||
dout[0] = CMD_BFC(reg);
|
||||
dout[1] = data;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
}
|
||||
|
||||
/*
|
||||
* high byte of the register contains bank number:
|
||||
* 0: no bank switch necessary
|
||||
* 1: switch to bank 0
|
||||
* 2: switch to bank 1
|
||||
* 3: switch to bank 2
|
||||
* 4: switch to bank 3
|
||||
*/
|
||||
static void enc_set_bank(enc_dev_t *enc, const u16 reg)
|
||||
{
|
||||
u8 newbank = reg >> 8;
|
||||
|
||||
if (newbank == 0 || newbank == enc->bank)
|
||||
return;
|
||||
switch (newbank) {
|
||||
case 1:
|
||||
enc_bclr(enc, CTL_REG_ECON1,
|
||||
ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
|
||||
break;
|
||||
case 2:
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
|
||||
enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
|
||||
break;
|
||||
case 3:
|
||||
enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_BSEL0);
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_BSEL1);
|
||||
break;
|
||||
case 4:
|
||||
enc_bset(enc, CTL_REG_ECON1,
|
||||
ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1);
|
||||
break;
|
||||
}
|
||||
enc->bank = newbank;
|
||||
}
|
||||
|
||||
/*
|
||||
* local functions to access SPI
|
||||
*
|
||||
* reg: register inside ENC28J60
|
||||
* data: 8/16 bits to write
|
||||
* c: number of retries
|
||||
*
|
||||
* enc_r8: read 8 bits
|
||||
* enc_r16: read 16 bits
|
||||
* enc_w8: write 8 bits
|
||||
* enc_w16: write 16 bits
|
||||
* enc_w8_retry: write 8 bits, verify and retry
|
||||
* enc_rbuf: read from ENC28J60 into buffer
|
||||
* enc_wbuf: write from buffer into ENC28J60
|
||||
*/
|
||||
|
||||
/*
|
||||
* MAC and MII registers need a 3 byte SPI transfer to read,
|
||||
* all other registers need a 2 byte SPI transfer.
|
||||
*/
|
||||
static int enc_reg2nbytes(const u16 reg)
|
||||
{
|
||||
/* check if MAC or MII register */
|
||||
return ((reg >= CTL_REG_MACON1 && reg <= CTL_REG_MIRDH) ||
|
||||
(reg >= CTL_REG_MAADR1 && reg <= CTL_REG_MAADR4) ||
|
||||
(reg == CTL_REG_MISTAT)) ? 3 : 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a byte register
|
||||
*/
|
||||
static u8 enc_r8(enc_dev_t *enc, const u16 reg)
|
||||
{
|
||||
u8 dout[3];
|
||||
u8 din[3];
|
||||
int nbytes = enc_reg2nbytes(reg);
|
||||
|
||||
enc_set_bank(enc, reg);
|
||||
dout[0] = CMD_RCR(reg);
|
||||
spi_xfer(enc->slave, nbytes * 8, dout, din,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
return din[nbytes-1];
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a L/H register pair and return a word.
|
||||
* Must be called with the L register's address.
|
||||
*/
|
||||
static u16 enc_r16(enc_dev_t *enc, const u16 reg)
|
||||
{
|
||||
u8 dout[3];
|
||||
u8 din[3];
|
||||
u16 result;
|
||||
int nbytes = enc_reg2nbytes(reg);
|
||||
|
||||
enc_set_bank(enc, reg);
|
||||
dout[0] = CMD_RCR(reg);
|
||||
spi_xfer(enc->slave, nbytes * 8, dout, din,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
result = din[nbytes-1];
|
||||
dout[0]++; /* next register */
|
||||
spi_xfer(enc->slave, nbytes * 8, dout, din,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
result |= din[nbytes-1] << 8;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a byte register
|
||||
*/
|
||||
static void enc_w8(enc_dev_t *enc, const u16 reg, const u8 data)
|
||||
{
|
||||
u8 dout[2];
|
||||
|
||||
enc_set_bank(enc, reg);
|
||||
dout[0] = CMD_WCR(reg);
|
||||
dout[1] = data;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a L/H register pair.
|
||||
* Must be called with the L register's address.
|
||||
*/
|
||||
static void enc_w16(enc_dev_t *enc, const u16 reg, const u16 data)
|
||||
{
|
||||
u8 dout[2];
|
||||
|
||||
enc_set_bank(enc, reg);
|
||||
dout[0] = CMD_WCR(reg);
|
||||
dout[1] = data;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
dout[0]++; /* next register */
|
||||
dout[1] = data >> 8;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a byte register, verify and retry
|
||||
*/
|
||||
static void enc_w8_retry(enc_dev_t *enc, const u16 reg, const u8 data, const int c)
|
||||
{
|
||||
u8 dout[2];
|
||||
u8 readback;
|
||||
int i;
|
||||
|
||||
enc_set_bank(enc, reg);
|
||||
for (i = 0; i < c; i++) {
|
||||
dout[0] = CMD_WCR(reg);
|
||||
dout[1] = data;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
readback = enc_r8(enc, reg);
|
||||
if (readback == data)
|
||||
break;
|
||||
/* wait 1ms */
|
||||
udelay(1000);
|
||||
}
|
||||
if (i == c) {
|
||||
printf("%s: write reg 0x%03x failed\n", enc->dev->name, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read ENC RAM into buffer
|
||||
*/
|
||||
static void enc_rbuf(enc_dev_t *enc, const u16 length, u8 *buf)
|
||||
{
|
||||
u8 dout[1];
|
||||
|
||||
dout[0] = CMD_RBM;
|
||||
spi_xfer(enc->slave, 8, dout, NULL, SPI_XFER_BEGIN);
|
||||
spi_xfer(enc->slave, length * 8, NULL, buf, SPI_XFER_END);
|
||||
#ifdef DEBUG
|
||||
puts("Rx:\n");
|
||||
print_buffer(0, buf, 1, length, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write buffer into ENC RAM
|
||||
*/
|
||||
static void enc_wbuf(enc_dev_t *enc, const u16 length, const u8 *buf, const u8 control)
|
||||
{
|
||||
u8 dout[2];
|
||||
dout[0] = CMD_WBM;
|
||||
dout[1] = control;
|
||||
spi_xfer(enc->slave, 2 * 8, dout, NULL, SPI_XFER_BEGIN);
|
||||
spi_xfer(enc->slave, length * 8, buf, NULL, SPI_XFER_END);
|
||||
#ifdef DEBUG
|
||||
puts("Tx:\n");
|
||||
print_buffer(0, buf, 1, length, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to claim the SPI bus.
|
||||
* Print error message on failure.
|
||||
*/
|
||||
static int enc_claim_bus(enc_dev_t *enc)
|
||||
{
|
||||
int rc = spi_claim_bus(enc->slave);
|
||||
if (rc)
|
||||
printf("%s: failed to claim SPI bus\n", enc->dev->name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release previously claimed SPI bus.
|
||||
* This function is mainly for symmetry to enc_claim_bus().
|
||||
* Let the toolchain decide to inline it...
|
||||
*/
|
||||
static void enc_release_bus(enc_dev_t *enc)
|
||||
{
|
||||
spi_release_bus(enc->slave);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read PHY register
|
||||
*/
|
||||
static u16 enc_phy_read(enc_dev_t *enc, const u8 addr)
|
||||
{
|
||||
uint64_t etime;
|
||||
u8 status;
|
||||
|
||||
enc_w8(enc, CTL_REG_MIREGADR, addr);
|
||||
enc_w8(enc, CTL_REG_MICMD, ENC_MICMD_MIIRD);
|
||||
/* 1 second timeout - only happens on hardware problem */
|
||||
etime = get_ticks() + get_tbclk();
|
||||
/* poll MISTAT.BUSY bit until operation is complete */
|
||||
do
|
||||
{
|
||||
status = enc_r8(enc, CTL_REG_MISTAT);
|
||||
} while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
|
||||
if (status & ENC_MISTAT_BUSY) {
|
||||
printf("%s: timeout reading phy\n", enc->dev->name);
|
||||
return 0;
|
||||
}
|
||||
enc_w8(enc, CTL_REG_MICMD, 0);
|
||||
return enc_r16(enc, CTL_REG_MIRDL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write PHY register
|
||||
*/
|
||||
static void enc_phy_write(enc_dev_t *enc, const u8 addr, const u16 data)
|
||||
{
|
||||
uint64_t etime;
|
||||
u8 status;
|
||||
|
||||
enc_w8(enc, CTL_REG_MIREGADR, addr);
|
||||
enc_w16(enc, CTL_REG_MIWRL, data);
|
||||
/* 1 second timeout - only happens on hardware problem */
|
||||
etime = get_ticks() + get_tbclk();
|
||||
/* poll MISTAT.BUSY bit until operation is complete */
|
||||
do
|
||||
{
|
||||
status = enc_r8(enc, CTL_REG_MISTAT);
|
||||
} while (get_ticks() <= etime && (status & ENC_MISTAT_BUSY));
|
||||
if (status & ENC_MISTAT_BUSY) {
|
||||
printf("%s: timeout writing phy\n", enc->dev->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify link status, wait if necessary
|
||||
*
|
||||
* Note: with a 10 MBit/s only PHY there is no autonegotiation possible,
|
||||
* half/full duplex is a pure setup matter. For the time being, this driver
|
||||
* will setup in half duplex mode only.
|
||||
*/
|
||||
static int enc_phy_link_wait(enc_dev_t *enc)
|
||||
{
|
||||
u16 status;
|
||||
int duplex;
|
||||
uint64_t etime;
|
||||
|
||||
#ifdef CONFIG_ENC_SILENTLINK
|
||||
/* check if we have a link, then just return */
|
||||
status = enc_phy_read(enc, PHY_REG_PHSTAT1);
|
||||
if (status & ENC_PHSTAT1_LLSTAT)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/* wait for link with 1 second timeout */
|
||||
etime = get_ticks() + get_tbclk();
|
||||
while (get_ticks() <= etime) {
|
||||
status = enc_phy_read(enc, PHY_REG_PHSTAT1);
|
||||
if (status & ENC_PHSTAT1_LLSTAT) {
|
||||
/* now we have a link */
|
||||
status = enc_phy_read(enc, PHY_REG_PHSTAT2);
|
||||
duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0;
|
||||
printf("%s: link up, 10Mbps %s-duplex\n",
|
||||
enc->dev->name, duplex ? "full" : "half");
|
||||
return 0;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
/* timeout occured */
|
||||
printf("%s: link down\n", enc->dev->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function resets the receiver only.
|
||||
*/
|
||||
static void enc_reset_rx(enc_dev_t *enc)
|
||||
{
|
||||
u8 econ1;
|
||||
|
||||
econ1 = enc_r8(enc, CTL_REG_ECON1);
|
||||
if ((econ1 & ENC_ECON1_RXRST) == 0) {
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
|
||||
enc->rx_reset_counter = RX_RESET_COUNTER;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset receiver and reenable it.
|
||||
*/
|
||||
static void enc_reset_rx_call(enc_dev_t *enc)
|
||||
{
|
||||
enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXRST);
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a packet from the receive ring and forward it to
|
||||
* the protocol stack.
|
||||
*/
|
||||
static void enc_receive(enc_dev_t *enc)
|
||||
{
|
||||
u8 *packet = (u8 *)net_rx_packets[0];
|
||||
u16 pkt_len;
|
||||
u16 copy_len;
|
||||
u16 status;
|
||||
u8 pkt_cnt = 0;
|
||||
u16 rxbuf_rdpt;
|
||||
u8 hbuf[6];
|
||||
|
||||
enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
|
||||
do {
|
||||
enc_rbuf(enc, 6, hbuf);
|
||||
enc->next_pointer = hbuf[0] | (hbuf[1] << 8);
|
||||
pkt_len = hbuf[2] | (hbuf[3] << 8);
|
||||
status = hbuf[4] | (hbuf[5] << 8);
|
||||
debug("next_pointer=$%04x pkt_len=%u status=$%04x\n",
|
||||
enc->next_pointer, pkt_len, status);
|
||||
if (pkt_len <= ENC_MAX_FRM_LEN)
|
||||
copy_len = pkt_len;
|
||||
else
|
||||
copy_len = 0;
|
||||
if ((status & (1L << 7)) == 0) /* check Received Ok bit */
|
||||
copy_len = 0;
|
||||
/* check if next pointer is resonable */
|
||||
if (enc->next_pointer >= ENC_TX_BUF_START)
|
||||
copy_len = 0;
|
||||
if (copy_len > 0) {
|
||||
enc_rbuf(enc, copy_len, packet);
|
||||
}
|
||||
/* advance read pointer to next pointer */
|
||||
enc_w16(enc, CTL_REG_ERDPTL, enc->next_pointer);
|
||||
/* decrease packet counter */
|
||||
enc_bset(enc, CTL_REG_ECON2, ENC_ECON2_PKTDEC);
|
||||
/*
|
||||
* Only odd values should be written to ERXRDPTL,
|
||||
* see errata B4 pt.13
|
||||
*/
|
||||
rxbuf_rdpt = enc->next_pointer - 1;
|
||||
if ((rxbuf_rdpt < enc_r16(enc, CTL_REG_ERXSTL)) ||
|
||||
(rxbuf_rdpt > enc_r16(enc, CTL_REG_ERXNDL))) {
|
||||
enc_w16(enc, CTL_REG_ERXRDPTL,
|
||||
enc_r16(enc, CTL_REG_ERXNDL));
|
||||
} else {
|
||||
enc_w16(enc, CTL_REG_ERXRDPTL, rxbuf_rdpt);
|
||||
}
|
||||
/* read pktcnt */
|
||||
pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
|
||||
if (copy_len == 0) {
|
||||
(void)enc_r8(enc, CTL_REG_EIR);
|
||||
enc_reset_rx(enc);
|
||||
printf("%s: receive copy_len=0\n", enc->dev->name);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Because net_process_received_packet() might call enc_send(),
|
||||
* we need to release the SPI bus, call
|
||||
* net_process_received_packet(), reclaim the bus.
|
||||
*/
|
||||
enc_release_bus(enc);
|
||||
net_process_received_packet(packet, pkt_len);
|
||||
if (enc_claim_bus(enc))
|
||||
return;
|
||||
(void)enc_r8(enc, CTL_REG_EIR);
|
||||
} while (pkt_cnt);
|
||||
/* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll for completely received packets.
|
||||
*/
|
||||
static void enc_poll(enc_dev_t *enc)
|
||||
{
|
||||
u8 eir_reg;
|
||||
u8 pkt_cnt;
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* clear global interrupt enable bit in enc28j60 */
|
||||
enc_bclr(enc, CTL_REG_EIE, ENC_EIE_INTIE);
|
||||
#endif
|
||||
(void)enc_r8(enc, CTL_REG_ESTAT);
|
||||
eir_reg = enc_r8(enc, CTL_REG_EIR);
|
||||
if (eir_reg & ENC_EIR_TXIF) {
|
||||
/* clear TXIF bit in EIR */
|
||||
enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXIF);
|
||||
}
|
||||
/* We have to use pktcnt and not pktif bit, see errata pt. 6 */
|
||||
pkt_cnt = enc_r8(enc, CTL_REG_EPKTCNT);
|
||||
if (pkt_cnt > 0) {
|
||||
if ((eir_reg & ENC_EIR_PKTIF) == 0) {
|
||||
debug("enc_poll: pkt cnt > 0, but pktif not set\n");
|
||||
}
|
||||
enc_receive(enc);
|
||||
/*
|
||||
* clear PKTIF bit in EIR, this should not need to be done
|
||||
* but it seems like we get problems if we do not
|
||||
*/
|
||||
enc_bclr(enc, CTL_REG_EIR, ENC_EIR_PKTIF);
|
||||
}
|
||||
if (eir_reg & ENC_EIR_RXERIF) {
|
||||
printf("%s: rx error\n", enc->dev->name);
|
||||
enc_bclr(enc, CTL_REG_EIR, ENC_EIR_RXERIF);
|
||||
}
|
||||
if (eir_reg & ENC_EIR_TXERIF) {
|
||||
printf("%s: tx error\n", enc->dev->name);
|
||||
enc_bclr(enc, CTL_REG_EIR, ENC_EIR_TXERIF);
|
||||
}
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* set global interrupt enable bit in enc28j60 */
|
||||
enc_bset(enc, CTL_REG_EIE, ENC_EIE_INTIE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Completely Reset the ENC
|
||||
*/
|
||||
static void enc_reset(enc_dev_t *enc)
|
||||
{
|
||||
u8 dout[1];
|
||||
|
||||
dout[0] = CMD_SRC;
|
||||
spi_xfer(enc->slave, 8, dout, NULL,
|
||||
SPI_XFER_BEGIN | SPI_XFER_END);
|
||||
/* sleep 1 ms. See errata pt. 2 */
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialisation data for most of the ENC registers
|
||||
*/
|
||||
static const u16 enc_initdata[] = {
|
||||
/*
|
||||
* Setup the buffer space. The reset values are valid for the
|
||||
* other pointers.
|
||||
*
|
||||
* We shall not write to ERXST, see errata pt. 5. Instead we
|
||||
* have to make sure that ENC_RX_BUS_START is 0.
|
||||
*/
|
||||
CTL_REG_ERXSTL, ENC_RX_BUF_START,
|
||||
CTL_REG_ERXSTH, ENC_RX_BUF_START >> 8,
|
||||
CTL_REG_ERXNDL, ENC_RX_BUF_END,
|
||||
CTL_REG_ERXNDH, ENC_RX_BUF_END >> 8,
|
||||
CTL_REG_ERDPTL, ENC_RX_BUF_START,
|
||||
CTL_REG_ERDPTH, ENC_RX_BUF_START >> 8,
|
||||
/*
|
||||
* Set the filter to receive only good-CRC, unicast and broadcast
|
||||
* frames.
|
||||
* Note: some DHCP servers return their answers as broadcasts!
|
||||
* So its unwise to remove broadcast from this. This driver
|
||||
* might incur receiver overruns with packet loss on a broadcast
|
||||
* flooded network.
|
||||
*/
|
||||
CTL_REG_ERXFCON, ENC_RFR_BCEN | ENC_RFR_UCEN | ENC_RFR_CRCEN,
|
||||
|
||||
/* enable MAC to receive frames */
|
||||
CTL_REG_MACON1,
|
||||
ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS,
|
||||
|
||||
/* configure pad, tx-crc and duplex */
|
||||
CTL_REG_MACON3,
|
||||
ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN |
|
||||
ENC_MACON3_FRMLNEN,
|
||||
|
||||
/* Allow infinite deferals if the medium is continously busy */
|
||||
CTL_REG_MACON4, ENC_MACON4_DEFER,
|
||||
|
||||
/* Late collisions occur beyond 63 bytes */
|
||||
CTL_REG_MACLCON2, 63,
|
||||
|
||||
/*
|
||||
* Set (low byte) Non-Back-to_Back Inter-Packet Gap.
|
||||
* Recommended 0x12
|
||||
*/
|
||||
CTL_REG_MAIPGL, 0x12,
|
||||
|
||||
/*
|
||||
* Set (high byte) Non-Back-to_Back Inter-Packet Gap.
|
||||
* Recommended 0x0c for half-duplex. Nothing for full-duplex
|
||||
*/
|
||||
CTL_REG_MAIPGH, 0x0C,
|
||||
|
||||
/* set maximum frame length */
|
||||
CTL_REG_MAMXFLL, ENC_MAX_FRM_LEN,
|
||||
CTL_REG_MAMXFLH, ENC_MAX_FRM_LEN >> 8,
|
||||
|
||||
/*
|
||||
* Set MAC back-to-back inter-packet gap.
|
||||
* Recommended 0x12 for half duplex
|
||||
* and 0x15 for full duplex.
|
||||
*/
|
||||
CTL_REG_MABBIPG, 0x12,
|
||||
|
||||
/* end of table */
|
||||
0xffff
|
||||
};
|
||||
|
||||
/*
|
||||
* Wait for the XTAL oscillator to become ready
|
||||
*/
|
||||
static int enc_clock_wait(enc_dev_t *enc)
|
||||
{
|
||||
uint64_t etime;
|
||||
|
||||
/* one second timeout */
|
||||
etime = get_ticks() + get_tbclk();
|
||||
|
||||
/*
|
||||
* Wait for CLKRDY to become set (i.e., check that we can
|
||||
* communicate with the ENC)
|
||||
*/
|
||||
do
|
||||
{
|
||||
if (enc_r8(enc, CTL_REG_ESTAT) & ENC_ESTAT_CLKRDY)
|
||||
return 0;
|
||||
} while (get_ticks() <= etime);
|
||||
|
||||
printf("%s: timeout waiting for CLKRDY\n", enc->dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the MAC address into the ENC
|
||||
*/
|
||||
static int enc_write_macaddr(enc_dev_t *enc)
|
||||
{
|
||||
unsigned char *p = enc->dev->enetaddr;
|
||||
|
||||
enc_w8_retry(enc, CTL_REG_MAADR5, *p++, 5);
|
||||
enc_w8_retry(enc, CTL_REG_MAADR4, *p++, 5);
|
||||
enc_w8_retry(enc, CTL_REG_MAADR3, *p++, 5);
|
||||
enc_w8_retry(enc, CTL_REG_MAADR2, *p++, 5);
|
||||
enc_w8_retry(enc, CTL_REG_MAADR1, *p++, 5);
|
||||
enc_w8_retry(enc, CTL_REG_MAADR0, *p, 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup most of the ENC registers
|
||||
*/
|
||||
static int enc_setup(enc_dev_t *enc)
|
||||
{
|
||||
u16 phid1 = 0;
|
||||
u16 phid2 = 0;
|
||||
const u16 *tp;
|
||||
|
||||
/* reset enc struct values */
|
||||
enc->next_pointer = ENC_RX_BUF_START;
|
||||
enc->rx_reset_counter = RX_RESET_COUNTER;
|
||||
enc->bank = 0xff; /* invalidate current bank in enc28j60 */
|
||||
|
||||
/* verify PHY identification */
|
||||
phid1 = enc_phy_read(enc, PHY_REG_PHID1);
|
||||
phid2 = enc_phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK;
|
||||
if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) {
|
||||
printf("%s: failed to identify PHY. Found %04x:%04x\n",
|
||||
enc->dev->name, phid1, phid2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now program registers */
|
||||
for (tp = enc_initdata; *tp != 0xffff; tp += 2)
|
||||
enc_w8_retry(enc, tp[0], tp[1], 10);
|
||||
|
||||
/*
|
||||
* Prevent automatic loopback of data beeing transmitted by setting
|
||||
* ENC_PHCON2_HDLDIS
|
||||
*/
|
||||
enc_phy_write(enc, PHY_REG_PHCON2, (1<<8));
|
||||
|
||||
/*
|
||||
* LEDs configuration
|
||||
* LEDA: LACFG = 0100 -> display link status
|
||||
* LEDB: LBCFG = 0111 -> display TX & RX activity
|
||||
* STRCH = 1 -> LED pulses
|
||||
*/
|
||||
enc_phy_write(enc, PHY_REG_PHLCON, 0x0472);
|
||||
|
||||
/* Reset PDPXMD-bit => half duplex */
|
||||
enc_phy_write(enc, PHY_REG_PHCON1, 0);
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* enable interrupts */
|
||||
enc_bset(enc, CTL_REG_EIE, ENC_EIE_PKTIE);
|
||||
enc_bset(enc, CTL_REG_EIE, ENC_EIE_TXIE);
|
||||
enc_bset(enc, CTL_REG_EIE, ENC_EIE_RXERIE);
|
||||
enc_bset(enc, CTL_REG_EIE, ENC_EIE_TXERIE);
|
||||
enc_bset(enc, CTL_REG_EIE, ENC_EIE_INTIE);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if ENC has been initialized.
|
||||
* If not, try to initialize it.
|
||||
* Remember initialized state in struct.
|
||||
*/
|
||||
static int enc_initcheck(enc_dev_t *enc, const enum enc_initstate requiredstate)
|
||||
{
|
||||
if (enc->initstate >= requiredstate)
|
||||
return 0;
|
||||
|
||||
if (enc->initstate < setupdone) {
|
||||
/* Initialize the ENC only */
|
||||
enc_reset(enc);
|
||||
/* if any of functions fails, skip the rest and return an error */
|
||||
if (enc_clock_wait(enc) || enc_setup(enc) || enc_write_macaddr(enc)) {
|
||||
return -1;
|
||||
}
|
||||
enc->initstate = setupdone;
|
||||
}
|
||||
/* if that's all we need, return here */
|
||||
if (enc->initstate >= requiredstate)
|
||||
return 0;
|
||||
|
||||
/* now wait for link ready condition */
|
||||
if (enc_phy_link_wait(enc)) {
|
||||
return -1;
|
||||
}
|
||||
enc->initstate = linkready;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_CMD_MII)
|
||||
/*
|
||||
* Read a PHY register.
|
||||
*
|
||||
* This function is registered with miiphy_register().
|
||||
*/
|
||||
int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
|
||||
{
|
||||
struct eth_device *dev = eth_get_dev_by_name(devname);
|
||||
enc_dev_t *enc;
|
||||
|
||||
if (!dev || phy_adr != 0)
|
||||
return -1;
|
||||
|
||||
enc = dev->priv;
|
||||
if (enc_claim_bus(enc))
|
||||
return -1;
|
||||
if (enc_initcheck(enc, setupdone)) {
|
||||
enc_release_bus(enc);
|
||||
return -1;
|
||||
}
|
||||
*value = enc_phy_read(enc, reg);
|
||||
enc_release_bus(enc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a PHY register.
|
||||
*
|
||||
* This function is registered with miiphy_register().
|
||||
*/
|
||||
int enc_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
|
||||
{
|
||||
struct eth_device *dev = eth_get_dev_by_name(devname);
|
||||
enc_dev_t *enc;
|
||||
|
||||
if (!dev || phy_adr != 0)
|
||||
return -1;
|
||||
|
||||
enc = dev->priv;
|
||||
if (enc_claim_bus(enc))
|
||||
return -1;
|
||||
if (enc_initcheck(enc, setupdone)) {
|
||||
enc_release_bus(enc);
|
||||
return -1;
|
||||
}
|
||||
enc_phy_write(enc, reg, value);
|
||||
enc_release_bus(enc);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Write hardware (MAC) address.
|
||||
*
|
||||
* This function entered into eth_device structure.
|
||||
*/
|
||||
static int enc_write_hwaddr(struct eth_device *dev)
|
||||
{
|
||||
enc_dev_t *enc = dev->priv;
|
||||
|
||||
if (enc_claim_bus(enc))
|
||||
return -1;
|
||||
if (enc_initcheck(enc, setupdone)) {
|
||||
enc_release_bus(enc);
|
||||
return -1;
|
||||
}
|
||||
enc_release_bus(enc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize ENC28J60 for use.
|
||||
*
|
||||
* This function entered into eth_device structure.
|
||||
*/
|
||||
static int enc_init(struct eth_device *dev, bd_t *bis)
|
||||
{
|
||||
enc_dev_t *enc = dev->priv;
|
||||
|
||||
if (enc_claim_bus(enc))
|
||||
return -1;
|
||||
if (enc_initcheck(enc, linkready)) {
|
||||
enc_release_bus(enc);
|
||||
return -1;
|
||||
}
|
||||
/* enable receive */
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
|
||||
enc_release_bus(enc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for received packets.
|
||||
*
|
||||
* This function entered into eth_device structure.
|
||||
*/
|
||||
static int enc_recv(struct eth_device *dev)
|
||||
{
|
||||
enc_dev_t *enc = dev->priv;
|
||||
|
||||
if (enc_claim_bus(enc))
|
||||
return -1;
|
||||
if (enc_initcheck(enc, linkready)) {
|
||||
enc_release_bus(enc);
|
||||
return -1;
|
||||
}
|
||||
/* Check for dead receiver */
|
||||
if (enc->rx_reset_counter > 0)
|
||||
enc->rx_reset_counter--;
|
||||
else
|
||||
enc_reset_rx_call(enc);
|
||||
enc_poll(enc);
|
||||
enc_release_bus(enc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a packet.
|
||||
*
|
||||
* This function entered into eth_device structure.
|
||||
*
|
||||
* Should we wait here until we have a Link? Or shall we leave that to
|
||||
* protocol retries?
|
||||
*/
|
||||
static int enc_send(
|
||||
struct eth_device *dev,
|
||||
void *packet,
|
||||
int length)
|
||||
{
|
||||
enc_dev_t *enc = dev->priv;
|
||||
|
||||
if (enc_claim_bus(enc))
|
||||
return -1;
|
||||
if (enc_initcheck(enc, linkready)) {
|
||||
enc_release_bus(enc);
|
||||
return -1;
|
||||
}
|
||||
/* setup transmit pointers */
|
||||
enc_w16(enc, CTL_REG_EWRPTL, ENC_TX_BUF_START);
|
||||
enc_w16(enc, CTL_REG_ETXNDL, length + ENC_TX_BUF_START);
|
||||
enc_w16(enc, CTL_REG_ETXSTL, ENC_TX_BUF_START);
|
||||
/* write packet to ENC */
|
||||
enc_wbuf(enc, length, (u8 *) packet, 0x00);
|
||||
/*
|
||||
* Check that the internal transmit logic has not been altered
|
||||
* by excessive collisions. Reset transmitter if so.
|
||||
* See Errata B4 12 and 14.
|
||||
*/
|
||||
if (enc_r8(enc, CTL_REG_EIR) & ENC_EIR_TXERIF) {
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
|
||||
enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_TXRST);
|
||||
}
|
||||
enc_bclr(enc, CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
|
||||
/* start transmitting */
|
||||
enc_bset(enc, CTL_REG_ECON1, ENC_ECON1_TXRTS);
|
||||
enc_release_bus(enc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish use of ENC.
|
||||
*
|
||||
* This function entered into eth_device structure.
|
||||
*/
|
||||
static void enc_halt(struct eth_device *dev)
|
||||
{
|
||||
enc_dev_t *enc = dev->priv;
|
||||
|
||||
if (enc_claim_bus(enc))
|
||||
return;
|
||||
/* Just disable receiver */
|
||||
enc_bclr(enc, CTL_REG_ECON1, ENC_ECON1_RXEN);
|
||||
enc_release_bus(enc);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the only exported function.
|
||||
*
|
||||
* It may be called several times with different bus:cs combinations.
|
||||
*/
|
||||
int enc28j60_initialize(unsigned int bus, unsigned int cs,
|
||||
unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
enc_dev_t *enc;
|
||||
|
||||
/* try to allocate, check and clear eth_device object */
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev) {
|
||||
return -1;
|
||||
}
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
|
||||
/* try to allocate, check and clear enc_dev_t object */
|
||||
enc = malloc(sizeof(*enc));
|
||||
if (!enc) {
|
||||
free(dev);
|
||||
return -1;
|
||||
}
|
||||
memset(enc, 0, sizeof(*enc));
|
||||
|
||||
/* try to setup the SPI slave */
|
||||
enc->slave = spi_setup_slave(bus, cs, max_hz, mode);
|
||||
if (!enc->slave) {
|
||||
printf("enc28j60: invalid SPI device %i:%i\n", bus, cs);
|
||||
free(enc);
|
||||
free(dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
enc->dev = dev;
|
||||
/* now fill the eth_device object */
|
||||
dev->priv = enc;
|
||||
dev->init = enc_init;
|
||||
dev->halt = enc_halt;
|
||||
dev->send = enc_send;
|
||||
dev->recv = enc_recv;
|
||||
dev->write_hwaddr = enc_write_hwaddr;
|
||||
sprintf(dev->name, "enc%i.%i", bus, cs);
|
||||
eth_register(dev);
|
||||
#if defined(CONFIG_CMD_MII)
|
||||
miiphy_register(dev->name, enc_miiphy_read, enc_miiphy_write);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
238
sources/uboot-be550/drivers/net/enc28j60.h
Normal file
238
sources/uboot-be550/drivers/net/enc28j60.h
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* (X) extracted from enc28j60.c
|
||||
* Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _enc28j60_h
|
||||
#define _enc28j60_h
|
||||
|
||||
/*
|
||||
* SPI Commands
|
||||
*
|
||||
* Bits 7-5: Command
|
||||
* Bits 4-0: Register
|
||||
*/
|
||||
#define CMD_RCR(x) (0x00+((x)&0x1f)) /* Read Control Register */
|
||||
#define CMD_RBM 0x3a /* Read Buffer Memory */
|
||||
#define CMD_WCR(x) (0x40+((x)&0x1f)) /* Write Control Register */
|
||||
#define CMD_WBM 0x7a /* Write Buffer Memory */
|
||||
#define CMD_BFS(x) (0x80+((x)&0x1f)) /* Bit Field Set */
|
||||
#define CMD_BFC(x) (0xa0+((x)&0x1f)) /* Bit Field Clear */
|
||||
#define CMD_SRC 0xff /* System Reset Command */
|
||||
|
||||
/* NEW: encode (bank number+1) in upper byte */
|
||||
|
||||
/* Common Control Registers accessible in all Banks */
|
||||
#define CTL_REG_EIE 0x01B
|
||||
#define CTL_REG_EIR 0x01C
|
||||
#define CTL_REG_ESTAT 0x01D
|
||||
#define CTL_REG_ECON2 0x01E
|
||||
#define CTL_REG_ECON1 0x01F
|
||||
|
||||
/* Control Registers accessible in Bank 0 */
|
||||
#define CTL_REG_ERDPTL 0x100
|
||||
#define CTL_REG_ERDPTH 0x101
|
||||
#define CTL_REG_EWRPTL 0x102
|
||||
#define CTL_REG_EWRPTH 0x103
|
||||
#define CTL_REG_ETXSTL 0x104
|
||||
#define CTL_REG_ETXSTH 0x105
|
||||
#define CTL_REG_ETXNDL 0x106
|
||||
#define CTL_REG_ETXNDH 0x107
|
||||
#define CTL_REG_ERXSTL 0x108
|
||||
#define CTL_REG_ERXSTH 0x109
|
||||
#define CTL_REG_ERXNDL 0x10A
|
||||
#define CTL_REG_ERXNDH 0x10B
|
||||
#define CTL_REG_ERXRDPTL 0x10C
|
||||
#define CTL_REG_ERXRDPTH 0x10D
|
||||
#define CTL_REG_ERXWRPTL 0x10E
|
||||
#define CTL_REG_ERXWRPTH 0x10F
|
||||
#define CTL_REG_EDMASTL 0x110
|
||||
#define CTL_REG_EDMASTH 0x111
|
||||
#define CTL_REG_EDMANDL 0x112
|
||||
#define CTL_REG_EDMANDH 0x113
|
||||
#define CTL_REG_EDMADSTL 0x114
|
||||
#define CTL_REG_EDMADSTH 0x115
|
||||
#define CTL_REG_EDMACSL 0x116
|
||||
#define CTL_REG_EDMACSH 0x117
|
||||
|
||||
/* Control Registers accessible in Bank 1 */
|
||||
#define CTL_REG_EHT0 0x200
|
||||
#define CTL_REG_EHT1 0x201
|
||||
#define CTL_REG_EHT2 0x202
|
||||
#define CTL_REG_EHT3 0x203
|
||||
#define CTL_REG_EHT4 0x204
|
||||
#define CTL_REG_EHT5 0x205
|
||||
#define CTL_REG_EHT6 0x206
|
||||
#define CTL_REG_EHT7 0x207
|
||||
#define CTL_REG_EPMM0 0x208
|
||||
#define CTL_REG_EPMM1 0x209
|
||||
#define CTL_REG_EPMM2 0x20A
|
||||
#define CTL_REG_EPMM3 0x20B
|
||||
#define CTL_REG_EPMM4 0x20C
|
||||
#define CTL_REG_EPMM5 0x20D
|
||||
#define CTL_REG_EPMM6 0x20E
|
||||
#define CTL_REG_EPMM7 0x20F
|
||||
#define CTL_REG_EPMCSL 0x210
|
||||
#define CTL_REG_EPMCSH 0x211
|
||||
#define CTL_REG_EPMOL 0x214
|
||||
#define CTL_REG_EPMOH 0x215
|
||||
#define CTL_REG_EWOLIE 0x216
|
||||
#define CTL_REG_EWOLIR 0x217
|
||||
#define CTL_REG_ERXFCON 0x218
|
||||
#define CTL_REG_EPKTCNT 0x219
|
||||
|
||||
/* Control Registers accessible in Bank 2 */
|
||||
#define CTL_REG_MACON1 0x300
|
||||
#define CTL_REG_MACON2 0x301
|
||||
#define CTL_REG_MACON3 0x302
|
||||
#define CTL_REG_MACON4 0x303
|
||||
#define CTL_REG_MABBIPG 0x304
|
||||
#define CTL_REG_MAIPGL 0x306
|
||||
#define CTL_REG_MAIPGH 0x307
|
||||
#define CTL_REG_MACLCON1 0x308
|
||||
#define CTL_REG_MACLCON2 0x309
|
||||
#define CTL_REG_MAMXFLL 0x30A
|
||||
#define CTL_REG_MAMXFLH 0x30B
|
||||
#define CTL_REG_MAPHSUP 0x30D
|
||||
#define CTL_REG_MICON 0x311
|
||||
#define CTL_REG_MICMD 0x312
|
||||
#define CTL_REG_MIREGADR 0x314
|
||||
#define CTL_REG_MIWRL 0x316
|
||||
#define CTL_REG_MIWRH 0x317
|
||||
#define CTL_REG_MIRDL 0x318
|
||||
#define CTL_REG_MIRDH 0x319
|
||||
|
||||
/* Control Registers accessible in Bank 3 */
|
||||
#define CTL_REG_MAADR1 0x400
|
||||
#define CTL_REG_MAADR0 0x401
|
||||
#define CTL_REG_MAADR3 0x402
|
||||
#define CTL_REG_MAADR2 0x403
|
||||
#define CTL_REG_MAADR5 0x404
|
||||
#define CTL_REG_MAADR4 0x405
|
||||
#define CTL_REG_EBSTSD 0x406
|
||||
#define CTL_REG_EBSTCON 0x407
|
||||
#define CTL_REG_EBSTCSL 0x408
|
||||
#define CTL_REG_EBSTCSH 0x409
|
||||
#define CTL_REG_MISTAT 0x40A
|
||||
#define CTL_REG_EREVID 0x412
|
||||
#define CTL_REG_ECOCON 0x415
|
||||
#define CTL_REG_EFLOCON 0x417
|
||||
#define CTL_REG_EPAUSL 0x418
|
||||
#define CTL_REG_EPAUSH 0x419
|
||||
|
||||
/* PHY Register */
|
||||
#define PHY_REG_PHCON1 0x00
|
||||
#define PHY_REG_PHSTAT1 0x01
|
||||
#define PHY_REG_PHID1 0x02
|
||||
#define PHY_REG_PHID2 0x03
|
||||
#define PHY_REG_PHCON2 0x10
|
||||
#define PHY_REG_PHSTAT2 0x11
|
||||
#define PHY_REG_PHLCON 0x14
|
||||
|
||||
/* Receive Filter Register (ERXFCON) bits */
|
||||
#define ENC_RFR_UCEN 0x80
|
||||
#define ENC_RFR_ANDOR 0x40
|
||||
#define ENC_RFR_CRCEN 0x20
|
||||
#define ENC_RFR_PMEN 0x10
|
||||
#define ENC_RFR_MPEN 0x08
|
||||
#define ENC_RFR_HTEN 0x04
|
||||
#define ENC_RFR_MCEN 0x02
|
||||
#define ENC_RFR_BCEN 0x01
|
||||
|
||||
/* ECON1 Register Bits */
|
||||
#define ENC_ECON1_TXRST 0x80
|
||||
#define ENC_ECON1_RXRST 0x40
|
||||
#define ENC_ECON1_DMAST 0x20
|
||||
#define ENC_ECON1_CSUMEN 0x10
|
||||
#define ENC_ECON1_TXRTS 0x08
|
||||
#define ENC_ECON1_RXEN 0x04
|
||||
#define ENC_ECON1_BSEL1 0x02
|
||||
#define ENC_ECON1_BSEL0 0x01
|
||||
|
||||
/* ECON2 Register Bits */
|
||||
#define ENC_ECON2_AUTOINC 0x80
|
||||
#define ENC_ECON2_PKTDEC 0x40
|
||||
#define ENC_ECON2_PWRSV 0x20
|
||||
#define ENC_ECON2_VRPS 0x08
|
||||
|
||||
/* EIR Register Bits */
|
||||
#define ENC_EIR_PKTIF 0x40
|
||||
#define ENC_EIR_DMAIF 0x20
|
||||
#define ENC_EIR_LINKIF 0x10
|
||||
#define ENC_EIR_TXIF 0x08
|
||||
#define ENC_EIR_WOLIF 0x04
|
||||
#define ENC_EIR_TXERIF 0x02
|
||||
#define ENC_EIR_RXERIF 0x01
|
||||
|
||||
/* ESTAT Register Bits */
|
||||
#define ENC_ESTAT_INT 0x80
|
||||
#define ENC_ESTAT_LATECOL 0x10
|
||||
#define ENC_ESTAT_RXBUSY 0x04
|
||||
#define ENC_ESTAT_TXABRT 0x02
|
||||
#define ENC_ESTAT_CLKRDY 0x01
|
||||
|
||||
/* EIE Register Bits */
|
||||
#define ENC_EIE_INTIE 0x80
|
||||
#define ENC_EIE_PKTIE 0x40
|
||||
#define ENC_EIE_DMAIE 0x20
|
||||
#define ENC_EIE_LINKIE 0x10
|
||||
#define ENC_EIE_TXIE 0x08
|
||||
#define ENC_EIE_WOLIE 0x04
|
||||
#define ENC_EIE_TXERIE 0x02
|
||||
#define ENC_EIE_RXERIE 0x01
|
||||
|
||||
/* MACON1 Register Bits */
|
||||
#define ENC_MACON1_LOOPBK 0x10
|
||||
#define ENC_MACON1_TXPAUS 0x08
|
||||
#define ENC_MACON1_RXPAUS 0x04
|
||||
#define ENC_MACON1_PASSALL 0x02
|
||||
#define ENC_MACON1_MARXEN 0x01
|
||||
|
||||
/* MACON2 Register Bits */
|
||||
#define ENC_MACON2_MARST 0x80
|
||||
#define ENC_MACON2_RNDRST 0x40
|
||||
#define ENC_MACON2_MARXRST 0x08
|
||||
#define ENC_MACON2_RFUNRST 0x04
|
||||
#define ENC_MACON2_MATXRST 0x02
|
||||
#define ENC_MACON2_TFUNRST 0x01
|
||||
|
||||
/* MACON3 Register Bits */
|
||||
#define ENC_MACON3_PADCFG2 0x80
|
||||
#define ENC_MACON3_PADCFG1 0x40
|
||||
#define ENC_MACON3_PADCFG0 0x20
|
||||
#define ENC_MACON3_TXCRCEN 0x10
|
||||
#define ENC_MACON3_PHDRLEN 0x08
|
||||
#define ENC_MACON3_HFRMEN 0x04
|
||||
#define ENC_MACON3_FRMLNEN 0x02
|
||||
#define ENC_MACON3_FULDPX 0x01
|
||||
|
||||
/* MACON4 Register Bits */
|
||||
#define ENC_MACON4_DEFER 0x40
|
||||
|
||||
/* MICMD Register Bits */
|
||||
#define ENC_MICMD_MIISCAN 0x02
|
||||
#define ENC_MICMD_MIIRD 0x01
|
||||
|
||||
/* MISTAT Register Bits */
|
||||
#define ENC_MISTAT_NVALID 0x04
|
||||
#define ENC_MISTAT_SCAN 0x02
|
||||
#define ENC_MISTAT_BUSY 0x01
|
||||
|
||||
/* PHID1 and PHID2 values */
|
||||
#define ENC_PHID1_VALUE 0x0083
|
||||
#define ENC_PHID2_VALUE 0x1400
|
||||
#define ENC_PHID2_MASK 0xFC00
|
||||
|
||||
/* PHCON1 values */
|
||||
#define ENC_PHCON1_PDPXMD 0x0100
|
||||
|
||||
/* PHSTAT1 values */
|
||||
#define ENC_PHSTAT1_LLSTAT 0x0004
|
||||
|
||||
/* PHSTAT2 values */
|
||||
#define ENC_PHSTAT2_LSTAT 0x0400
|
||||
#define ENC_PHSTAT2_DPXSTAT 0x0200
|
||||
|
||||
#endif
|
||||
640
sources/uboot-be550/drivers/net/ep93xx_eth.c
Normal file
640
sources/uboot-be550/drivers/net/ep93xx_eth.c
Normal file
|
|
@ -0,0 +1,640 @@
|
|||
/*
|
||||
* Cirrus Logic EP93xx ethernet MAC / MII driver.
|
||||
*
|
||||
* Copyright (C) 2010, 2009
|
||||
* Matthias Kaehlcke <matthias@kaehlcke.net>
|
||||
*
|
||||
* Copyright (C) 2004, 2005
|
||||
* Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
|
||||
*
|
||||
* Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver,
|
||||
* which is
|
||||
*
|
||||
* (C) Copyright 2002 2003
|
||||
* Adam Bezanson, Network Audio Technologies, Inc.
|
||||
* <bezanson@netaudiotech.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <command.h>
|
||||
#include <common.h>
|
||||
#include <asm/arch/ep93xx.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <miiphy.h>
|
||||
#include <linux/types.h>
|
||||
#include "ep93xx_eth.h"
|
||||
|
||||
#define GET_PRIV(eth_dev) ((struct ep93xx_priv *)(eth_dev)->priv)
|
||||
#define GET_REGS(eth_dev) (GET_PRIV(eth_dev)->regs)
|
||||
|
||||
/* ep93xx_miiphy ops forward declarations */
|
||||
static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
|
||||
unsigned char const reg, unsigned short * const value);
|
||||
static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
|
||||
unsigned char const reg, unsigned short const value);
|
||||
|
||||
#if defined(EP93XX_MAC_DEBUG)
|
||||
/**
|
||||
* Dump ep93xx_mac values to the terminal.
|
||||
*/
|
||||
static void dump_dev(struct eth_device *dev)
|
||||
{
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int i;
|
||||
|
||||
printf("\ndump_dev()\n");
|
||||
printf(" rx_dq.base %p\n", priv->rx_dq.base);
|
||||
printf(" rx_dq.current %p\n", priv->rx_dq.current);
|
||||
printf(" rx_dq.end %p\n", priv->rx_dq.end);
|
||||
printf(" rx_sq.base %p\n", priv->rx_sq.base);
|
||||
printf(" rx_sq.current %p\n", priv->rx_sq.current);
|
||||
printf(" rx_sq.end %p\n", priv->rx_sq.end);
|
||||
|
||||
for (i = 0; i < NUMRXDESC; i++)
|
||||
printf(" rx_buffer[%2.d] %p\n", i, net_rx_packets[i]);
|
||||
|
||||
printf(" tx_dq.base %p\n", priv->tx_dq.base);
|
||||
printf(" tx_dq.current %p\n", priv->tx_dq.current);
|
||||
printf(" tx_dq.end %p\n", priv->tx_dq.end);
|
||||
printf(" tx_sq.base %p\n", priv->tx_sq.base);
|
||||
printf(" tx_sq.current %p\n", priv->tx_sq.current);
|
||||
printf(" tx_sq.end %p\n", priv->tx_sq.end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all RX status queue entries to the terminal.
|
||||
*/
|
||||
static void dump_rx_status_queue(struct eth_device *dev)
|
||||
{
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int i;
|
||||
|
||||
printf("\ndump_rx_status_queue()\n");
|
||||
printf(" descriptor address word1 word2\n");
|
||||
for (i = 0; i < NUMRXDESC; i++) {
|
||||
printf(" [ %p ] %08X %08X\n",
|
||||
priv->rx_sq.base + i,
|
||||
(priv->rx_sq.base + i)->word1,
|
||||
(priv->rx_sq.base + i)->word2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all RX descriptor queue entries to the terminal.
|
||||
*/
|
||||
static void dump_rx_descriptor_queue(struct eth_device *dev)
|
||||
{
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int i;
|
||||
|
||||
printf("\ndump_rx_descriptor_queue()\n");
|
||||
printf(" descriptor address word1 word2\n");
|
||||
for (i = 0; i < NUMRXDESC; i++) {
|
||||
printf(" [ %p ] %08X %08X\n",
|
||||
priv->rx_dq.base + i,
|
||||
(priv->rx_dq.base + i)->word1,
|
||||
(priv->rx_dq.base + i)->word2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all TX descriptor queue entries to the terminal.
|
||||
*/
|
||||
static void dump_tx_descriptor_queue(struct eth_device *dev)
|
||||
{
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int i;
|
||||
|
||||
printf("\ndump_tx_descriptor_queue()\n");
|
||||
printf(" descriptor address word1 word2\n");
|
||||
for (i = 0; i < NUMTXDESC; i++) {
|
||||
printf(" [ %p ] %08X %08X\n",
|
||||
priv->tx_dq.base + i,
|
||||
(priv->tx_dq.base + i)->word1,
|
||||
(priv->tx_dq.base + i)->word2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all TX status queue entries to the terminal.
|
||||
*/
|
||||
static void dump_tx_status_queue(struct eth_device *dev)
|
||||
{
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int i;
|
||||
|
||||
printf("\ndump_tx_status_queue()\n");
|
||||
printf(" descriptor address word1\n");
|
||||
for (i = 0; i < NUMTXDESC; i++) {
|
||||
printf(" [ %p ] %08X\n",
|
||||
priv->rx_sq.base + i,
|
||||
(priv->rx_sq.base + i)->word1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define dump_dev(x)
|
||||
#define dump_rx_descriptor_queue(x)
|
||||
#define dump_rx_status_queue(x)
|
||||
#define dump_tx_descriptor_queue(x)
|
||||
#define dump_tx_status_queue(x)
|
||||
#endif /* defined(EP93XX_MAC_DEBUG) */
|
||||
|
||||
/**
|
||||
* Reset the EP93xx MAC by twiddling the soft reset bit and spinning until
|
||||
* it's cleared.
|
||||
*/
|
||||
static void ep93xx_mac_reset(struct eth_device *dev)
|
||||
{
|
||||
struct mac_regs *mac = GET_REGS(dev);
|
||||
uint32_t value;
|
||||
|
||||
debug("+ep93xx_mac_reset");
|
||||
|
||||
value = readl(&mac->selfctl);
|
||||
value |= SELFCTL_RESET;
|
||||
writel(value, &mac->selfctl);
|
||||
|
||||
while (readl(&mac->selfctl) & SELFCTL_RESET)
|
||||
; /* noop */
|
||||
|
||||
debug("-ep93xx_mac_reset");
|
||||
}
|
||||
|
||||
/* Eth device open */
|
||||
static int ep93xx_eth_open(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
struct mac_regs *mac = GET_REGS(dev);
|
||||
uchar *mac_addr = dev->enetaddr;
|
||||
int i;
|
||||
|
||||
debug("+ep93xx_eth_open");
|
||||
|
||||
/* Reset the MAC */
|
||||
ep93xx_mac_reset(dev);
|
||||
|
||||
/* Reset the descriptor queues' current and end address values */
|
||||
priv->tx_dq.current = priv->tx_dq.base;
|
||||
priv->tx_dq.end = (priv->tx_dq.base + NUMTXDESC);
|
||||
|
||||
priv->tx_sq.current = priv->tx_sq.base;
|
||||
priv->tx_sq.end = (priv->tx_sq.base + NUMTXDESC);
|
||||
|
||||
priv->rx_dq.current = priv->rx_dq.base;
|
||||
priv->rx_dq.end = (priv->rx_dq.base + NUMRXDESC);
|
||||
|
||||
priv->rx_sq.current = priv->rx_sq.base;
|
||||
priv->rx_sq.end = (priv->rx_sq.base + NUMRXDESC);
|
||||
|
||||
/*
|
||||
* Set the transmit descriptor and status queues' base address,
|
||||
* current address, and length registers. Set the maximum frame
|
||||
* length and threshold. Enable the transmit descriptor processor.
|
||||
*/
|
||||
writel((uint32_t)priv->tx_dq.base, &mac->txdq.badd);
|
||||
writel((uint32_t)priv->tx_dq.base, &mac->txdq.curadd);
|
||||
writel(sizeof(struct tx_descriptor) * NUMTXDESC, &mac->txdq.blen);
|
||||
|
||||
writel((uint32_t)priv->tx_sq.base, &mac->txstsq.badd);
|
||||
writel((uint32_t)priv->tx_sq.base, &mac->txstsq.curadd);
|
||||
writel(sizeof(struct tx_status) * NUMTXDESC, &mac->txstsq.blen);
|
||||
|
||||
writel(0x00040000, &mac->txdthrshld);
|
||||
writel(0x00040000, &mac->txststhrshld);
|
||||
|
||||
writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), &mac->maxfrmlen);
|
||||
writel(BMCTL_TXEN, &mac->bmctl);
|
||||
|
||||
/*
|
||||
* Set the receive descriptor and status queues' base address,
|
||||
* current address, and length registers. Enable the receive
|
||||
* descriptor processor.
|
||||
*/
|
||||
writel((uint32_t)priv->rx_dq.base, &mac->rxdq.badd);
|
||||
writel((uint32_t)priv->rx_dq.base, &mac->rxdq.curadd);
|
||||
writel(sizeof(struct rx_descriptor) * NUMRXDESC, &mac->rxdq.blen);
|
||||
|
||||
writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.badd);
|
||||
writel((uint32_t)priv->rx_sq.base, &mac->rxstsq.curadd);
|
||||
writel(sizeof(struct rx_status) * NUMRXDESC, &mac->rxstsq.blen);
|
||||
|
||||
writel(0x00040000, &mac->rxdthrshld);
|
||||
|
||||
writel(BMCTL_RXEN, &mac->bmctl);
|
||||
|
||||
writel(0x00040000, &mac->rxststhrshld);
|
||||
|
||||
/* Wait until the receive descriptor processor is active */
|
||||
while (!(readl(&mac->bmsts) & BMSTS_RXACT))
|
||||
; /* noop */
|
||||
|
||||
/*
|
||||
* Initialize the RX descriptor queue. Clear the TX descriptor queue.
|
||||
* Clear the RX and TX status queues. Enqueue the RX descriptor and
|
||||
* status entries to the MAC.
|
||||
*/
|
||||
for (i = 0; i < NUMRXDESC; i++) {
|
||||
/* set buffer address */
|
||||
(priv->rx_dq.base + i)->word1 = (uint32_t)net_rx_packets[i];
|
||||
|
||||
/* set buffer length, clear buffer index and NSOF */
|
||||
(priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN;
|
||||
}
|
||||
|
||||
memset(priv->tx_dq.base, 0,
|
||||
(sizeof(struct tx_descriptor) * NUMTXDESC));
|
||||
memset(priv->rx_sq.base, 0,
|
||||
(sizeof(struct rx_status) * NUMRXDESC));
|
||||
memset(priv->tx_sq.base, 0,
|
||||
(sizeof(struct tx_status) * NUMTXDESC));
|
||||
|
||||
writel(NUMRXDESC, &mac->rxdqenq);
|
||||
writel(NUMRXDESC, &mac->rxstsqenq);
|
||||
|
||||
/* Set the primary MAC address */
|
||||
writel(AFP_IAPRIMARY, &mac->afp);
|
||||
writel(mac_addr[0] | (mac_addr[1] << 8) |
|
||||
(mac_addr[2] << 16) | (mac_addr[3] << 24),
|
||||
&mac->indad);
|
||||
writel(mac_addr[4] | (mac_addr[5] << 8), &mac->indad_upper);
|
||||
|
||||
/* Turn on RX and TX */
|
||||
writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON |
|
||||
RXCTL_RCRCA | RXCTL_MA, &mac->rxctl);
|
||||
writel(TXCTL_STXON, &mac->txctl);
|
||||
|
||||
/* Dump data structures if we're debugging */
|
||||
dump_dev(dev);
|
||||
dump_rx_descriptor_queue(dev);
|
||||
dump_rx_status_queue(dev);
|
||||
dump_tx_descriptor_queue(dev);
|
||||
dump_tx_status_queue(dev);
|
||||
|
||||
debug("-ep93xx_eth_open");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL
|
||||
* registers.
|
||||
*/
|
||||
static void ep93xx_eth_close(struct eth_device *dev)
|
||||
{
|
||||
struct mac_regs *mac = GET_REGS(dev);
|
||||
|
||||
debug("+ep93xx_eth_close");
|
||||
|
||||
writel(0x00000000, &mac->rxctl);
|
||||
writel(0x00000000, &mac->txctl);
|
||||
|
||||
debug("-ep93xx_eth_close");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a frame of data from the MAC into the protocol layer for further
|
||||
* processing.
|
||||
*/
|
||||
static int ep93xx_eth_rcv_packet(struct eth_device *dev)
|
||||
{
|
||||
struct mac_regs *mac = GET_REGS(dev);
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int len = -1;
|
||||
|
||||
debug("+ep93xx_eth_rcv_packet");
|
||||
|
||||
if (RX_STATUS_RFP(priv->rx_sq.current)) {
|
||||
if (RX_STATUS_RWE(priv->rx_sq.current)) {
|
||||
/*
|
||||
* We have a good frame. Extract the frame's length
|
||||
* from the current rx_status_queue entry, and copy
|
||||
* the frame's data into net_rx_packets[] of the
|
||||
* protocol stack. We track the total number of
|
||||
* bytes in the frame (nbytes_frame) which will be
|
||||
* used when we pass the data off to the protocol
|
||||
* layer via net_process_received_packet().
|
||||
*/
|
||||
len = RX_STATUS_FRAME_LEN(priv->rx_sq.current);
|
||||
|
||||
net_process_received_packet(
|
||||
(uchar *)priv->rx_dq.current->word1, len);
|
||||
|
||||
debug("reporting %d bytes...\n", len);
|
||||
} else {
|
||||
/* Do we have an erroneous packet? */
|
||||
error("packet rx error, status %08X %08X",
|
||||
priv->rx_sq.current->word1,
|
||||
priv->rx_sq.current->word2);
|
||||
dump_rx_descriptor_queue(dev);
|
||||
dump_rx_status_queue(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the associated status queue entry, and
|
||||
* increment our current pointers to the next RX
|
||||
* descriptor and status queue entries (making sure
|
||||
* we wrap properly).
|
||||
*/
|
||||
memset((void *)priv->rx_sq.current, 0,
|
||||
sizeof(struct rx_status));
|
||||
|
||||
priv->rx_sq.current++;
|
||||
if (priv->rx_sq.current >= priv->rx_sq.end)
|
||||
priv->rx_sq.current = priv->rx_sq.base;
|
||||
|
||||
priv->rx_dq.current++;
|
||||
if (priv->rx_dq.current >= priv->rx_dq.end)
|
||||
priv->rx_dq.current = priv->rx_dq.base;
|
||||
|
||||
/*
|
||||
* Finally, return the RX descriptor and status entries
|
||||
* back to the MAC engine, and loop again, checking for
|
||||
* more descriptors to process.
|
||||
*/
|
||||
writel(1, &mac->rxdqenq);
|
||||
writel(1, &mac->rxstsqenq);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
debug("-ep93xx_eth_rcv_packet %d", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a block of data via ethernet.
|
||||
*/
|
||||
static int ep93xx_eth_send_packet(struct eth_device *dev,
|
||||
void * const packet, int const length)
|
||||
{
|
||||
struct mac_regs *mac = GET_REGS(dev);
|
||||
struct ep93xx_priv *priv = GET_PRIV(dev);
|
||||
int ret = -1;
|
||||
|
||||
debug("+ep93xx_eth_send_packet");
|
||||
|
||||
/* Parameter check */
|
||||
BUG_ON(packet == NULL);
|
||||
|
||||
/*
|
||||
* Initialize the TX descriptor queue with the new packet's info.
|
||||
* Clear the associated status queue entry. Enqueue the packet
|
||||
* to the MAC for transmission.
|
||||
*/
|
||||
|
||||
/* set buffer address */
|
||||
priv->tx_dq.current->word1 = (uint32_t)packet;
|
||||
|
||||
/* set buffer length and EOF bit */
|
||||
priv->tx_dq.current->word2 = length | TX_DESC_EOF;
|
||||
|
||||
/* clear tx status */
|
||||
priv->tx_sq.current->word1 = 0;
|
||||
|
||||
/* enqueue the TX descriptor */
|
||||
writel(1, &mac->txdqenq);
|
||||
|
||||
/* wait for the frame to become processed */
|
||||
while (!TX_STATUS_TXFP(priv->tx_sq.current))
|
||||
; /* noop */
|
||||
|
||||
if (!TX_STATUS_TXWE(priv->tx_sq.current)) {
|
||||
error("packet tx error, status %08X",
|
||||
priv->tx_sq.current->word1);
|
||||
dump_tx_descriptor_queue(dev);
|
||||
dump_tx_status_queue(dev);
|
||||
|
||||
/* TODO: Add better error handling? */
|
||||
goto eth_send_out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
/* Fall through */
|
||||
|
||||
eth_send_out:
|
||||
debug("-ep93xx_eth_send_packet %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MII)
|
||||
int ep93xx_miiphy_initialize(bd_t * const bd)
|
||||
{
|
||||
miiphy_register("ep93xx_eth0", ep93xx_miiphy_read, ep93xx_miiphy_write);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the EP93xx MAC. The MAC hardware is reset. Buffers are
|
||||
* allocated, if necessary, for the TX and RX descriptor and status queues,
|
||||
* as well as for received packets. The EP93XX MAC hardware is initialized.
|
||||
* Transmit and receive operations are enabled.
|
||||
*/
|
||||
int ep93xx_eth_initialize(u8 dev_num, int base_addr)
|
||||
{
|
||||
int ret = -1;
|
||||
struct eth_device *dev;
|
||||
struct ep93xx_priv *priv;
|
||||
|
||||
debug("+ep93xx_eth_initialize");
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (!priv) {
|
||||
error("malloc() failed");
|
||||
goto eth_init_failed_0;
|
||||
}
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
priv->regs = (struct mac_regs *)base_addr;
|
||||
|
||||
priv->tx_dq.base = calloc(NUMTXDESC,
|
||||
sizeof(struct tx_descriptor));
|
||||
if (priv->tx_dq.base == NULL) {
|
||||
error("calloc() failed");
|
||||
goto eth_init_failed_1;
|
||||
}
|
||||
|
||||
priv->tx_sq.base = calloc(NUMTXDESC,
|
||||
sizeof(struct tx_status));
|
||||
if (priv->tx_sq.base == NULL) {
|
||||
error("calloc() failed");
|
||||
goto eth_init_failed_2;
|
||||
}
|
||||
|
||||
priv->rx_dq.base = calloc(NUMRXDESC,
|
||||
sizeof(struct rx_descriptor));
|
||||
if (priv->rx_dq.base == NULL) {
|
||||
error("calloc() failed");
|
||||
goto eth_init_failed_3;
|
||||
}
|
||||
|
||||
priv->rx_sq.base = calloc(NUMRXDESC,
|
||||
sizeof(struct rx_status));
|
||||
if (priv->rx_sq.base == NULL) {
|
||||
error("calloc() failed");
|
||||
goto eth_init_failed_4;
|
||||
}
|
||||
|
||||
dev = malloc(sizeof *dev);
|
||||
if (dev == NULL) {
|
||||
error("malloc() failed");
|
||||
goto eth_init_failed_5;
|
||||
}
|
||||
memset(dev, 0, sizeof *dev);
|
||||
|
||||
dev->iobase = base_addr;
|
||||
dev->priv = priv;
|
||||
dev->init = ep93xx_eth_open;
|
||||
dev->halt = ep93xx_eth_close;
|
||||
dev->send = ep93xx_eth_send_packet;
|
||||
dev->recv = ep93xx_eth_rcv_packet;
|
||||
|
||||
sprintf(dev->name, "ep93xx_eth-%hu", dev_num);
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
/* Done! */
|
||||
ret = 1;
|
||||
goto eth_init_done;
|
||||
|
||||
eth_init_failed_5:
|
||||
free(priv->rx_sq.base);
|
||||
/* Fall through */
|
||||
|
||||
eth_init_failed_4:
|
||||
free(priv->rx_dq.base);
|
||||
/* Fall through */
|
||||
|
||||
eth_init_failed_3:
|
||||
free(priv->tx_sq.base);
|
||||
/* Fall through */
|
||||
|
||||
eth_init_failed_2:
|
||||
free(priv->tx_dq.base);
|
||||
/* Fall through */
|
||||
|
||||
eth_init_failed_1:
|
||||
free(priv);
|
||||
/* Fall through */
|
||||
|
||||
eth_init_failed_0:
|
||||
/* Fall through */
|
||||
|
||||
eth_init_done:
|
||||
debug("-ep93xx_eth_initialize %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MII)
|
||||
|
||||
/**
|
||||
* Maximum MII address we support
|
||||
*/
|
||||
#define MII_ADDRESS_MAX 31
|
||||
|
||||
/**
|
||||
* Maximum MII register address we support
|
||||
*/
|
||||
#define MII_REGISTER_MAX 31
|
||||
|
||||
/**
|
||||
* Read a 16-bit value from an MII register.
|
||||
*/
|
||||
static int ep93xx_miiphy_read(const char * const dev, unsigned char const addr,
|
||||
unsigned char const reg, unsigned short * const value)
|
||||
{
|
||||
struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
|
||||
int ret = -1;
|
||||
uint32_t self_ctl;
|
||||
|
||||
debug("+ep93xx_miiphy_read");
|
||||
|
||||
/* Parameter checks */
|
||||
BUG_ON(dev == NULL);
|
||||
BUG_ON(addr > MII_ADDRESS_MAX);
|
||||
BUG_ON(reg > MII_REGISTER_MAX);
|
||||
BUG_ON(value == NULL);
|
||||
|
||||
/*
|
||||
* Save the current SelfCTL register value. Set MAC to suppress
|
||||
* preamble bits. Wait for any previous MII command to complete
|
||||
* before issuing the new command.
|
||||
*/
|
||||
self_ctl = readl(&mac->selfctl);
|
||||
#if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
|
||||
writel(self_ctl & ~(1 << 8), &mac->selfctl);
|
||||
#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
|
||||
|
||||
while (readl(&mac->miists) & MIISTS_BUSY)
|
||||
; /* noop */
|
||||
|
||||
/*
|
||||
* Issue the MII 'read' command. Wait for the command to complete.
|
||||
* Read the MII data value.
|
||||
*/
|
||||
writel(MIICMD_OPCODE_READ | ((uint32_t)addr << 5) | (uint32_t)reg,
|
||||
&mac->miicmd);
|
||||
while (readl(&mac->miists) & MIISTS_BUSY)
|
||||
; /* noop */
|
||||
|
||||
*value = (unsigned short)readl(&mac->miidata);
|
||||
|
||||
/* Restore the saved SelfCTL value and return. */
|
||||
writel(self_ctl, &mac->selfctl);
|
||||
|
||||
ret = 0;
|
||||
/* Fall through */
|
||||
|
||||
debug("-ep93xx_miiphy_read");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 16-bit value to an MII register.
|
||||
*/
|
||||
static int ep93xx_miiphy_write(const char * const dev, unsigned char const addr,
|
||||
unsigned char const reg, unsigned short const value)
|
||||
{
|
||||
struct mac_regs *mac = (struct mac_regs *)MAC_BASE;
|
||||
int ret = -1;
|
||||
uint32_t self_ctl;
|
||||
|
||||
debug("+ep93xx_miiphy_write");
|
||||
|
||||
/* Parameter checks */
|
||||
BUG_ON(dev == NULL);
|
||||
BUG_ON(addr > MII_ADDRESS_MAX);
|
||||
BUG_ON(reg > MII_REGISTER_MAX);
|
||||
|
||||
/*
|
||||
* Save the current SelfCTL register value. Set MAC to suppress
|
||||
* preamble bits. Wait for any previous MII command to complete
|
||||
* before issuing the new command.
|
||||
*/
|
||||
self_ctl = readl(&mac->selfctl);
|
||||
#if defined(CONFIG_MII_SUPPRESS_PREAMBLE)
|
||||
writel(self_ctl & ~(1 << 8), &mac->selfctl);
|
||||
#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */
|
||||
|
||||
while (readl(&mac->miists) & MIISTS_BUSY)
|
||||
; /* noop */
|
||||
|
||||
/* Issue the MII 'write' command. Wait for the command to complete. */
|
||||
writel((uint32_t)value, &mac->miidata);
|
||||
writel(MIICMD_OPCODE_WRITE | ((uint32_t)addr << 5) | (uint32_t)reg,
|
||||
&mac->miicmd);
|
||||
while (readl(&mac->miists) & MIISTS_BUSY)
|
||||
; /* noop */
|
||||
|
||||
/* Restore the saved SelfCTL value and return. */
|
||||
writel(self_ctl, &mac->selfctl);
|
||||
|
||||
ret = 0;
|
||||
/* Fall through */
|
||||
|
||||
debug("-ep93xx_miiphy_write");
|
||||
return ret;
|
||||
}
|
||||
#endif /* defined(CONFIG_MII) */
|
||||
127
sources/uboot-be550/drivers/net/ep93xx_eth.h
Normal file
127
sources/uboot-be550/drivers/net/ep93xx_eth.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Matthias Kaehlcke <matthias@kaehlcke.net>
|
||||
*
|
||||
* Copyright (C) 2004, 2005
|
||||
* Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef _EP93XX_ETH_H
|
||||
#define _EP93XX_ETH_H
|
||||
|
||||
#include <net.h>
|
||||
|
||||
/**
|
||||
* #define this to dump device status and queue info during initialization and
|
||||
* following errors.
|
||||
*/
|
||||
#undef EP93XX_MAC_DEBUG
|
||||
|
||||
/**
|
||||
* Number of descriptor and status entries in our RX queues.
|
||||
* It must be power of 2 !
|
||||
*/
|
||||
#define NUMRXDESC PKTBUFSRX
|
||||
|
||||
/**
|
||||
* Number of descriptor and status entries in our TX queues.
|
||||
*/
|
||||
#define NUMTXDESC 1
|
||||
|
||||
/**
|
||||
* 944 = (1024 - 64) - 16, Fifo size - Minframesize - 16 (Chip FACT)
|
||||
*/
|
||||
#define TXSTARTMAX 944
|
||||
|
||||
/**
|
||||
* Receive descriptor queue entry
|
||||
*/
|
||||
struct rx_descriptor {
|
||||
uint32_t word1;
|
||||
uint32_t word2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Receive status queue entry
|
||||
*/
|
||||
struct rx_status {
|
||||
uint32_t word1;
|
||||
uint32_t word2;
|
||||
};
|
||||
|
||||
#define RX_STATUS_RWE(rx_status) ((rx_status->word1 >> 30) & 0x01)
|
||||
#define RX_STATUS_RFP(rx_status) ((rx_status->word1 >> 31) & 0x01)
|
||||
#define RX_STATUS_FRAME_LEN(rx_status) (rx_status->word2 & 0xFFFF)
|
||||
|
||||
/**
|
||||
* Transmit descriptor queue entry
|
||||
*/
|
||||
struct tx_descriptor {
|
||||
uint32_t word1;
|
||||
uint32_t word2;
|
||||
};
|
||||
|
||||
#define TX_DESC_EOF (1 << 31)
|
||||
|
||||
/**
|
||||
* Transmit status queue entry
|
||||
*/
|
||||
struct tx_status {
|
||||
uint32_t word1;
|
||||
};
|
||||
|
||||
#define TX_STATUS_TXWE(tx_status) (((tx_status)->word1 >> 30) & 0x01)
|
||||
#define TX_STATUS_TXFP(tx_status) (((tx_status)->word1 >> 31) & 0x01)
|
||||
|
||||
/**
|
||||
* Transmit descriptor queue
|
||||
*/
|
||||
struct tx_descriptor_queue {
|
||||
struct tx_descriptor *base;
|
||||
struct tx_descriptor *current;
|
||||
struct tx_descriptor *end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transmit status queue
|
||||
*/
|
||||
struct tx_status_queue {
|
||||
struct tx_status *base;
|
||||
volatile struct tx_status *current;
|
||||
struct tx_status *end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Receive descriptor queue
|
||||
*/
|
||||
struct rx_descriptor_queue {
|
||||
struct rx_descriptor *base;
|
||||
struct rx_descriptor *current;
|
||||
struct rx_descriptor *end;
|
||||
};
|
||||
|
||||
/**
|
||||
* Receive status queue
|
||||
*/
|
||||
struct rx_status_queue {
|
||||
struct rx_status *base;
|
||||
volatile struct rx_status *current;
|
||||
struct rx_status *end;
|
||||
};
|
||||
|
||||
/**
|
||||
* EP93xx MAC private data structure
|
||||
*/
|
||||
struct ep93xx_priv {
|
||||
struct rx_descriptor_queue rx_dq;
|
||||
struct rx_status_queue rx_sq;
|
||||
void *rx_buffer[NUMRXDESC];
|
||||
|
||||
struct tx_descriptor_queue tx_dq;
|
||||
struct tx_status_queue tx_sq;
|
||||
|
||||
struct mac_regs *regs;
|
||||
};
|
||||
|
||||
#endif
|
||||
511
sources/uboot-be550/drivers/net/ethoc.c
Normal file
511
sources/uboot-be550/drivers/net/ethoc.c
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Opencore 10/100 ethernet mac driver
|
||||
*
|
||||
* Copyright (C) 2007-2008 Avionic Design Development GmbH
|
||||
* Copyright (C) 2008-2009 Avionic Design GmbH
|
||||
* Thierry Reding <thierry.reding@avionic-design.de>
|
||||
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <miiphy.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
/* register offsets */
|
||||
#define MODER 0x00
|
||||
#define INT_SOURCE 0x04
|
||||
#define INT_MASK 0x08
|
||||
#define IPGT 0x0c
|
||||
#define IPGR1 0x10
|
||||
#define IPGR2 0x14
|
||||
#define PACKETLEN 0x18
|
||||
#define COLLCONF 0x1c
|
||||
#define TX_BD_NUM 0x20
|
||||
#define CTRLMODER 0x24
|
||||
#define MIIMODER 0x28
|
||||
#define MIICOMMAND 0x2c
|
||||
#define MIIADDRESS 0x30
|
||||
#define MIITX_DATA 0x34
|
||||
#define MIIRX_DATA 0x38
|
||||
#define MIISTATUS 0x3c
|
||||
#define MAC_ADDR0 0x40
|
||||
#define MAC_ADDR1 0x44
|
||||
#define ETH_HASH0 0x48
|
||||
#define ETH_HASH1 0x4c
|
||||
#define ETH_TXCTRL 0x50
|
||||
|
||||
/* mode register */
|
||||
#define MODER_RXEN (1 << 0) /* receive enable */
|
||||
#define MODER_TXEN (1 << 1) /* transmit enable */
|
||||
#define MODER_NOPRE (1 << 2) /* no preamble */
|
||||
#define MODER_BRO (1 << 3) /* broadcast address */
|
||||
#define MODER_IAM (1 << 4) /* individual address mode */
|
||||
#define MODER_PRO (1 << 5) /* promiscuous mode */
|
||||
#define MODER_IFG (1 << 6) /* interframe gap for incoming frames */
|
||||
#define MODER_LOOP (1 << 7) /* loopback */
|
||||
#define MODER_NBO (1 << 8) /* no back-off */
|
||||
#define MODER_EDE (1 << 9) /* excess defer enable */
|
||||
#define MODER_FULLD (1 << 10) /* full duplex */
|
||||
#define MODER_RESET (1 << 11) /* FIXME: reset (undocumented) */
|
||||
#define MODER_DCRC (1 << 12) /* delayed CRC enable */
|
||||
#define MODER_CRC (1 << 13) /* CRC enable */
|
||||
#define MODER_HUGE (1 << 14) /* huge packets enable */
|
||||
#define MODER_PAD (1 << 15) /* padding enabled */
|
||||
#define MODER_RSM (1 << 16) /* receive small packets */
|
||||
|
||||
/* interrupt source and mask registers */
|
||||
#define INT_MASK_TXF (1 << 0) /* transmit frame */
|
||||
#define INT_MASK_TXE (1 << 1) /* transmit error */
|
||||
#define INT_MASK_RXF (1 << 2) /* receive frame */
|
||||
#define INT_MASK_RXE (1 << 3) /* receive error */
|
||||
#define INT_MASK_BUSY (1 << 4)
|
||||
#define INT_MASK_TXC (1 << 5) /* transmit control frame */
|
||||
#define INT_MASK_RXC (1 << 6) /* receive control frame */
|
||||
|
||||
#define INT_MASK_TX (INT_MASK_TXF | INT_MASK_TXE)
|
||||
#define INT_MASK_RX (INT_MASK_RXF | INT_MASK_RXE)
|
||||
|
||||
#define INT_MASK_ALL ( \
|
||||
INT_MASK_TXF | INT_MASK_TXE | \
|
||||
INT_MASK_RXF | INT_MASK_RXE | \
|
||||
INT_MASK_TXC | INT_MASK_RXC | \
|
||||
INT_MASK_BUSY \
|
||||
)
|
||||
|
||||
/* packet length register */
|
||||
#define PACKETLEN_MIN(min) (((min) & 0xffff) << 16)
|
||||
#define PACKETLEN_MAX(max) (((max) & 0xffff) << 0)
|
||||
#define PACKETLEN_MIN_MAX(min, max) (PACKETLEN_MIN(min) | \
|
||||
PACKETLEN_MAX(max))
|
||||
|
||||
/* transmit buffer number register */
|
||||
#define TX_BD_NUM_VAL(x) (((x) <= 0x80) ? (x) : 0x80)
|
||||
|
||||
/* control module mode register */
|
||||
#define CTRLMODER_PASSALL (1 << 0) /* pass all receive frames */
|
||||
#define CTRLMODER_RXFLOW (1 << 1) /* receive control flow */
|
||||
#define CTRLMODER_TXFLOW (1 << 2) /* transmit control flow */
|
||||
|
||||
/* MII mode register */
|
||||
#define MIIMODER_CLKDIV(x) ((x) & 0xfe) /* needs to be an even number */
|
||||
#define MIIMODER_NOPRE (1 << 8) /* no preamble */
|
||||
|
||||
/* MII command register */
|
||||
#define MIICOMMAND_SCAN (1 << 0) /* scan status */
|
||||
#define MIICOMMAND_READ (1 << 1) /* read status */
|
||||
#define MIICOMMAND_WRITE (1 << 2) /* write control data */
|
||||
|
||||
/* MII address register */
|
||||
#define MIIADDRESS_FIAD(x) (((x) & 0x1f) << 0)
|
||||
#define MIIADDRESS_RGAD(x) (((x) & 0x1f) << 8)
|
||||
#define MIIADDRESS_ADDR(phy, reg) (MIIADDRESS_FIAD(phy) | \
|
||||
MIIADDRESS_RGAD(reg))
|
||||
|
||||
/* MII transmit data register */
|
||||
#define MIITX_DATA_VAL(x) ((x) & 0xffff)
|
||||
|
||||
/* MII receive data register */
|
||||
#define MIIRX_DATA_VAL(x) ((x) & 0xffff)
|
||||
|
||||
/* MII status register */
|
||||
#define MIISTATUS_LINKFAIL (1 << 0)
|
||||
#define MIISTATUS_BUSY (1 << 1)
|
||||
#define MIISTATUS_INVALID (1 << 2)
|
||||
|
||||
/* TX buffer descriptor */
|
||||
#define TX_BD_CS (1 << 0) /* carrier sense lost */
|
||||
#define TX_BD_DF (1 << 1) /* defer indication */
|
||||
#define TX_BD_LC (1 << 2) /* late collision */
|
||||
#define TX_BD_RL (1 << 3) /* retransmission limit */
|
||||
#define TX_BD_RETRY_MASK (0x00f0)
|
||||
#define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4)
|
||||
#define TX_BD_UR (1 << 8) /* transmitter underrun */
|
||||
#define TX_BD_CRC (1 << 11) /* TX CRC enable */
|
||||
#define TX_BD_PAD (1 << 12) /* pad enable */
|
||||
#define TX_BD_WRAP (1 << 13)
|
||||
#define TX_BD_IRQ (1 << 14) /* interrupt request enable */
|
||||
#define TX_BD_READY (1 << 15) /* TX buffer ready */
|
||||
#define TX_BD_LEN(x) (((x) & 0xffff) << 16)
|
||||
#define TX_BD_LEN_MASK (0xffff << 16)
|
||||
|
||||
#define TX_BD_STATS (TX_BD_CS | TX_BD_DF | TX_BD_LC | \
|
||||
TX_BD_RL | TX_BD_RETRY_MASK | TX_BD_UR)
|
||||
|
||||
/* RX buffer descriptor */
|
||||
#define RX_BD_LC (1 << 0) /* late collision */
|
||||
#define RX_BD_CRC (1 << 1) /* RX CRC error */
|
||||
#define RX_BD_SF (1 << 2) /* short frame */
|
||||
#define RX_BD_TL (1 << 3) /* too long */
|
||||
#define RX_BD_DN (1 << 4) /* dribble nibble */
|
||||
#define RX_BD_IS (1 << 5) /* invalid symbol */
|
||||
#define RX_BD_OR (1 << 6) /* receiver overrun */
|
||||
#define RX_BD_MISS (1 << 7)
|
||||
#define RX_BD_CF (1 << 8) /* control frame */
|
||||
#define RX_BD_WRAP (1 << 13)
|
||||
#define RX_BD_IRQ (1 << 14) /* interrupt request enable */
|
||||
#define RX_BD_EMPTY (1 << 15)
|
||||
#define RX_BD_LEN(x) (((x) & 0xffff) << 16)
|
||||
|
||||
#define RX_BD_STATS (RX_BD_LC | RX_BD_CRC | RX_BD_SF | RX_BD_TL | \
|
||||
RX_BD_DN | RX_BD_IS | RX_BD_OR | RX_BD_MISS)
|
||||
|
||||
#define ETHOC_BUFSIZ 1536
|
||||
#define ETHOC_ZLEN 64
|
||||
#define ETHOC_BD_BASE 0x400
|
||||
#define ETHOC_TIMEOUT (HZ / 2)
|
||||
#define ETHOC_MII_TIMEOUT (1 + (HZ / 5))
|
||||
|
||||
/**
|
||||
* struct ethoc - driver-private device structure
|
||||
* @num_tx: number of send buffers
|
||||
* @cur_tx: last send buffer written
|
||||
* @dty_tx: last buffer actually sent
|
||||
* @num_rx: number of receive buffers
|
||||
* @cur_rx: current receive buffer
|
||||
*/
|
||||
struct ethoc {
|
||||
u32 num_tx;
|
||||
u32 cur_tx;
|
||||
u32 dty_tx;
|
||||
u32 num_rx;
|
||||
u32 cur_rx;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ethoc_bd - buffer descriptor
|
||||
* @stat: buffer statistics
|
||||
* @addr: physical memory address
|
||||
*/
|
||||
struct ethoc_bd {
|
||||
u32 stat;
|
||||
u32 addr;
|
||||
};
|
||||
|
||||
static inline u32 ethoc_read(struct eth_device *dev, size_t offset)
|
||||
{
|
||||
return readl(dev->iobase + offset);
|
||||
}
|
||||
|
||||
static inline void ethoc_write(struct eth_device *dev, size_t offset, u32 data)
|
||||
{
|
||||
writel(data, dev->iobase + offset);
|
||||
}
|
||||
|
||||
static inline void ethoc_read_bd(struct eth_device *dev, int index,
|
||||
struct ethoc_bd *bd)
|
||||
{
|
||||
size_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
|
||||
bd->stat = ethoc_read(dev, offset + 0);
|
||||
bd->addr = ethoc_read(dev, offset + 4);
|
||||
}
|
||||
|
||||
static inline void ethoc_write_bd(struct eth_device *dev, int index,
|
||||
const struct ethoc_bd *bd)
|
||||
{
|
||||
size_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
|
||||
ethoc_write(dev, offset + 0, bd->stat);
|
||||
ethoc_write(dev, offset + 4, bd->addr);
|
||||
}
|
||||
|
||||
static int ethoc_set_mac_address(struct eth_device *dev)
|
||||
{
|
||||
u8 *mac = dev->enetaddr;
|
||||
|
||||
ethoc_write(dev, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
|
||||
(mac[4] << 8) | (mac[5] << 0));
|
||||
ethoc_write(dev, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ethoc_ack_irq(struct eth_device *dev, u32 mask)
|
||||
{
|
||||
ethoc_write(dev, INT_SOURCE, mask);
|
||||
}
|
||||
|
||||
static inline void ethoc_enable_rx_and_tx(struct eth_device *dev)
|
||||
{
|
||||
u32 mode = ethoc_read(dev, MODER);
|
||||
mode |= MODER_RXEN | MODER_TXEN;
|
||||
ethoc_write(dev, MODER, mode);
|
||||
}
|
||||
|
||||
static inline void ethoc_disable_rx_and_tx(struct eth_device *dev)
|
||||
{
|
||||
u32 mode = ethoc_read(dev, MODER);
|
||||
mode &= ~(MODER_RXEN | MODER_TXEN);
|
||||
ethoc_write(dev, MODER, mode);
|
||||
}
|
||||
|
||||
static int ethoc_init_ring(struct eth_device *dev)
|
||||
{
|
||||
struct ethoc *priv = (struct ethoc *)dev->priv;
|
||||
struct ethoc_bd bd;
|
||||
int i;
|
||||
|
||||
priv->cur_tx = 0;
|
||||
priv->dty_tx = 0;
|
||||
priv->cur_rx = 0;
|
||||
|
||||
/* setup transmission buffers */
|
||||
bd.stat = TX_BD_IRQ | TX_BD_CRC;
|
||||
|
||||
for (i = 0; i < priv->num_tx; i++) {
|
||||
if (i == priv->num_tx - 1)
|
||||
bd.stat |= TX_BD_WRAP;
|
||||
|
||||
ethoc_write_bd(dev, i, &bd);
|
||||
}
|
||||
|
||||
bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
|
||||
|
||||
for (i = 0; i < priv->num_rx; i++) {
|
||||
bd.addr = (u32)net_rx_packets[i];
|
||||
if (i == priv->num_rx - 1)
|
||||
bd.stat |= RX_BD_WRAP;
|
||||
|
||||
flush_dcache_range(bd.addr, bd.addr + PKTSIZE_ALIGN);
|
||||
ethoc_write_bd(dev, priv->num_tx + i, &bd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethoc_reset(struct eth_device *dev)
|
||||
{
|
||||
u32 mode;
|
||||
|
||||
/* TODO: reset controller? */
|
||||
|
||||
ethoc_disable_rx_and_tx(dev);
|
||||
|
||||
/* TODO: setup registers */
|
||||
|
||||
/* enable FCS generation and automatic padding */
|
||||
mode = ethoc_read(dev, MODER);
|
||||
mode |= MODER_CRC | MODER_PAD;
|
||||
ethoc_write(dev, MODER, mode);
|
||||
|
||||
/* set full-duplex mode */
|
||||
mode = ethoc_read(dev, MODER);
|
||||
mode |= MODER_FULLD;
|
||||
ethoc_write(dev, MODER, mode);
|
||||
ethoc_write(dev, IPGT, 0x15);
|
||||
|
||||
ethoc_ack_irq(dev, INT_MASK_ALL);
|
||||
ethoc_enable_rx_and_tx(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethoc_init(struct eth_device *dev, bd_t * bd)
|
||||
{
|
||||
struct ethoc *priv = (struct ethoc *)dev->priv;
|
||||
printf("ethoc\n");
|
||||
|
||||
priv->num_tx = 1;
|
||||
priv->num_rx = PKTBUFSRX;
|
||||
ethoc_write(dev, TX_BD_NUM, priv->num_tx);
|
||||
ethoc_init_ring(dev);
|
||||
ethoc_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethoc_update_rx_stats(struct ethoc_bd *bd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (bd->stat & RX_BD_TL) {
|
||||
debug("ETHOC: " "RX: frame too long\n");
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (bd->stat & RX_BD_SF) {
|
||||
debug("ETHOC: " "RX: frame too short\n");
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (bd->stat & RX_BD_DN)
|
||||
debug("ETHOC: " "RX: dribble nibble\n");
|
||||
|
||||
if (bd->stat & RX_BD_CRC) {
|
||||
debug("ETHOC: " "RX: wrong CRC\n");
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (bd->stat & RX_BD_OR) {
|
||||
debug("ETHOC: " "RX: overrun\n");
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (bd->stat & RX_BD_LC) {
|
||||
debug("ETHOC: " "RX: late collision\n");
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethoc_rx(struct eth_device *dev, int limit)
|
||||
{
|
||||
struct ethoc *priv = (struct ethoc *)dev->priv;
|
||||
int count;
|
||||
|
||||
for (count = 0; count < limit; ++count) {
|
||||
u32 entry;
|
||||
struct ethoc_bd bd;
|
||||
|
||||
entry = priv->num_tx + (priv->cur_rx % priv->num_rx);
|
||||
ethoc_read_bd(dev, entry, &bd);
|
||||
if (bd.stat & RX_BD_EMPTY)
|
||||
break;
|
||||
|
||||
debug("%s(): RX buffer %d, %x received\n",
|
||||
__func__, priv->cur_rx, bd.stat);
|
||||
if (ethoc_update_rx_stats(&bd) == 0) {
|
||||
int size = bd.stat >> 16;
|
||||
size -= 4; /* strip the CRC */
|
||||
net_process_received_packet((void *)bd.addr, size);
|
||||
}
|
||||
|
||||
/* clear the buffer descriptor so it can be reused */
|
||||
flush_dcache_range(bd.addr, bd.addr + PKTSIZE_ALIGN);
|
||||
bd.stat &= ~RX_BD_STATS;
|
||||
bd.stat |= RX_BD_EMPTY;
|
||||
ethoc_write_bd(dev, entry, &bd);
|
||||
priv->cur_rx++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int ethoc_update_tx_stats(struct ethoc_bd *bd)
|
||||
{
|
||||
if (bd->stat & TX_BD_LC)
|
||||
debug("ETHOC: " "TX: late collision\n");
|
||||
|
||||
if (bd->stat & TX_BD_RL)
|
||||
debug("ETHOC: " "TX: retransmit limit\n");
|
||||
|
||||
if (bd->stat & TX_BD_UR)
|
||||
debug("ETHOC: " "TX: underrun\n");
|
||||
|
||||
if (bd->stat & TX_BD_CS)
|
||||
debug("ETHOC: " "TX: carrier sense lost\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ethoc_tx(struct eth_device *dev)
|
||||
{
|
||||
struct ethoc *priv = (struct ethoc *)dev->priv;
|
||||
u32 entry = priv->dty_tx % priv->num_tx;
|
||||
struct ethoc_bd bd;
|
||||
|
||||
ethoc_read_bd(dev, entry, &bd);
|
||||
if ((bd.stat & TX_BD_READY) == 0)
|
||||
(void)ethoc_update_tx_stats(&bd);
|
||||
}
|
||||
|
||||
static int ethoc_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
struct ethoc *priv = (struct ethoc *)dev->priv;
|
||||
struct ethoc_bd bd;
|
||||
u32 entry;
|
||||
u32 pending;
|
||||
int tmo;
|
||||
|
||||
entry = priv->cur_tx % priv->num_tx;
|
||||
ethoc_read_bd(dev, entry, &bd);
|
||||
if (unlikely(length < ETHOC_ZLEN))
|
||||
bd.stat |= TX_BD_PAD;
|
||||
else
|
||||
bd.stat &= ~TX_BD_PAD;
|
||||
bd.addr = (u32)packet;
|
||||
|
||||
flush_dcache_range(bd.addr, bd.addr + length);
|
||||
bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
|
||||
bd.stat |= TX_BD_LEN(length);
|
||||
ethoc_write_bd(dev, entry, &bd);
|
||||
|
||||
/* start transmit */
|
||||
bd.stat |= TX_BD_READY;
|
||||
ethoc_write_bd(dev, entry, &bd);
|
||||
|
||||
/* wait for transfer to succeed */
|
||||
tmo = get_timer(0) + 5 * CONFIG_SYS_HZ;
|
||||
while (1) {
|
||||
pending = ethoc_read(dev, INT_SOURCE);
|
||||
ethoc_ack_irq(dev, pending & ~INT_MASK_RX);
|
||||
if (pending & INT_MASK_BUSY)
|
||||
debug("%s(): packet dropped\n", __func__);
|
||||
|
||||
if (pending & INT_MASK_TX) {
|
||||
ethoc_tx(dev);
|
||||
break;
|
||||
}
|
||||
if (get_timer(0) >= tmo) {
|
||||
debug("%s(): timed out\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s(): packet sent\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ethoc_halt(struct eth_device *dev)
|
||||
{
|
||||
ethoc_disable_rx_and_tx(dev);
|
||||
}
|
||||
|
||||
static int ethoc_recv(struct eth_device *dev)
|
||||
{
|
||||
u32 pending;
|
||||
|
||||
pending = ethoc_read(dev, INT_SOURCE);
|
||||
ethoc_ack_irq(dev, pending);
|
||||
if (pending & INT_MASK_BUSY)
|
||||
debug("%s(): packet dropped\n", __func__);
|
||||
if (pending & INT_MASK_RX) {
|
||||
debug("%s(): rx irq\n", __func__);
|
||||
ethoc_rx(dev, PKTBUFSRX);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ethoc_initialize(u8 dev_num, int base_addr)
|
||||
{
|
||||
struct ethoc *priv;
|
||||
struct eth_device *dev;
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (!priv)
|
||||
return 0;
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev) {
|
||||
free(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->priv = priv;
|
||||
dev->iobase = base_addr;
|
||||
dev->init = ethoc_init;
|
||||
dev->halt = ethoc_halt;
|
||||
dev->send = ethoc_send;
|
||||
dev->recv = ethoc_recv;
|
||||
dev->write_hwaddr = ethoc_set_mac_address;
|
||||
sprintf(dev->name, "%s-%hu", "ETHOC", dev_num);
|
||||
|
||||
eth_register(dev);
|
||||
return 1;
|
||||
}
|
||||
1145
sources/uboot-be550/drivers/net/fec_mxc.c
Normal file
1145
sources/uboot-be550/drivers/net/fec_mxc.c
Normal file
File diff suppressed because it is too large
Load diff
323
sources/uboot-be550/drivers/net/fec_mxc.h
Normal file
323
sources/uboot-be550/drivers/net/fec_mxc.h
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
|
||||
* (C) Copyright 2008 Armadeus Systems, nc
|
||||
* (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
|
||||
* (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
|
||||
* (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
|
||||
*
|
||||
* (C) Copyright 2003
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* This file is based on mpc4200fec.h
|
||||
* (C) Copyright Motorola, Inc., 2000
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __FEC_MXC_H
|
||||
#define __FEC_MXC_H
|
||||
|
||||
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac);
|
||||
|
||||
/**
|
||||
* Layout description of the FEC
|
||||
*/
|
||||
struct ethernet_regs {
|
||||
|
||||
/* [10:2]addr = 00 */
|
||||
|
||||
/* Control and status Registers (offset 000-1FF) */
|
||||
|
||||
uint32_t res0[1]; /* MBAR_ETH + 0x000 */
|
||||
uint32_t ievent; /* MBAR_ETH + 0x004 */
|
||||
uint32_t imask; /* MBAR_ETH + 0x008 */
|
||||
|
||||
uint32_t res1[1]; /* MBAR_ETH + 0x00C */
|
||||
uint32_t r_des_active; /* MBAR_ETH + 0x010 */
|
||||
uint32_t x_des_active; /* MBAR_ETH + 0x014 */
|
||||
uint32_t res2[3]; /* MBAR_ETH + 0x018-20 */
|
||||
uint32_t ecntrl; /* MBAR_ETH + 0x024 */
|
||||
|
||||
uint32_t res3[6]; /* MBAR_ETH + 0x028-03C */
|
||||
uint32_t mii_data; /* MBAR_ETH + 0x040 */
|
||||
uint32_t mii_speed; /* MBAR_ETH + 0x044 */
|
||||
uint32_t res4[7]; /* MBAR_ETH + 0x048-60 */
|
||||
uint32_t mib_control; /* MBAR_ETH + 0x064 */
|
||||
|
||||
uint32_t res5[7]; /* MBAR_ETH + 0x068-80 */
|
||||
uint32_t r_cntrl; /* MBAR_ETH + 0x084 */
|
||||
uint32_t res6[15]; /* MBAR_ETH + 0x088-C0 */
|
||||
uint32_t x_cntrl; /* MBAR_ETH + 0x0C4 */
|
||||
uint32_t res7[7]; /* MBAR_ETH + 0x0C8-E0 */
|
||||
uint32_t paddr1; /* MBAR_ETH + 0x0E4 */
|
||||
uint32_t paddr2; /* MBAR_ETH + 0x0E8 */
|
||||
uint32_t op_pause; /* MBAR_ETH + 0x0EC */
|
||||
|
||||
uint32_t res8[10]; /* MBAR_ETH + 0x0F0-114 */
|
||||
uint32_t iaddr1; /* MBAR_ETH + 0x118 */
|
||||
uint32_t iaddr2; /* MBAR_ETH + 0x11C */
|
||||
uint32_t gaddr1; /* MBAR_ETH + 0x120 */
|
||||
uint32_t gaddr2; /* MBAR_ETH + 0x124 */
|
||||
uint32_t res9[7]; /* MBAR_ETH + 0x128-140 */
|
||||
|
||||
uint32_t x_wmrk; /* MBAR_ETH + 0x144 */
|
||||
uint32_t res10[1]; /* MBAR_ETH + 0x148 */
|
||||
uint32_t r_bound; /* MBAR_ETH + 0x14C */
|
||||
uint32_t r_fstart; /* MBAR_ETH + 0x150 */
|
||||
uint32_t res11[11]; /* MBAR_ETH + 0x154-17C */
|
||||
uint32_t erdsr; /* MBAR_ETH + 0x180 */
|
||||
uint32_t etdsr; /* MBAR_ETH + 0x184 */
|
||||
uint32_t emrbr; /* MBAR_ETH + 0x188 */
|
||||
uint32_t res12[29]; /* MBAR_ETH + 0x18C-1FC */
|
||||
|
||||
/* MIB COUNTERS (Offset 200-2FF) */
|
||||
|
||||
uint32_t rmon_t_drop; /* MBAR_ETH + 0x200 */
|
||||
uint32_t rmon_t_packets; /* MBAR_ETH + 0x204 */
|
||||
uint32_t rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */
|
||||
uint32_t rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */
|
||||
uint32_t rmon_t_crc_align; /* MBAR_ETH + 0x210 */
|
||||
uint32_t rmon_t_undersize; /* MBAR_ETH + 0x214 */
|
||||
uint32_t rmon_t_oversize; /* MBAR_ETH + 0x218 */
|
||||
uint32_t rmon_t_frag; /* MBAR_ETH + 0x21C */
|
||||
uint32_t rmon_t_jab; /* MBAR_ETH + 0x220 */
|
||||
uint32_t rmon_t_col; /* MBAR_ETH + 0x224 */
|
||||
uint32_t rmon_t_p64; /* MBAR_ETH + 0x228 */
|
||||
uint32_t rmon_t_p65to127; /* MBAR_ETH + 0x22C */
|
||||
uint32_t rmon_t_p128to255; /* MBAR_ETH + 0x230 */
|
||||
uint32_t rmon_t_p256to511; /* MBAR_ETH + 0x234 */
|
||||
uint32_t rmon_t_p512to1023; /* MBAR_ETH + 0x238 */
|
||||
uint32_t rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */
|
||||
uint32_t rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */
|
||||
uint32_t rmon_t_octets; /* MBAR_ETH + 0x244 */
|
||||
uint32_t ieee_t_drop; /* MBAR_ETH + 0x248 */
|
||||
uint32_t ieee_t_frame_ok; /* MBAR_ETH + 0x24C */
|
||||
uint32_t ieee_t_1col; /* MBAR_ETH + 0x250 */
|
||||
uint32_t ieee_t_mcol; /* MBAR_ETH + 0x254 */
|
||||
uint32_t ieee_t_def; /* MBAR_ETH + 0x258 */
|
||||
uint32_t ieee_t_lcol; /* MBAR_ETH + 0x25C */
|
||||
uint32_t ieee_t_excol; /* MBAR_ETH + 0x260 */
|
||||
uint32_t ieee_t_macerr; /* MBAR_ETH + 0x264 */
|
||||
uint32_t ieee_t_cserr; /* MBAR_ETH + 0x268 */
|
||||
uint32_t ieee_t_sqe; /* MBAR_ETH + 0x26C */
|
||||
uint32_t t_fdxfc; /* MBAR_ETH + 0x270 */
|
||||
uint32_t ieee_t_octets_ok; /* MBAR_ETH + 0x274 */
|
||||
|
||||
uint32_t res13[2]; /* MBAR_ETH + 0x278-27C */
|
||||
uint32_t rmon_r_drop; /* MBAR_ETH + 0x280 */
|
||||
uint32_t rmon_r_packets; /* MBAR_ETH + 0x284 */
|
||||
uint32_t rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */
|
||||
uint32_t rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */
|
||||
uint32_t rmon_r_crc_align; /* MBAR_ETH + 0x290 */
|
||||
uint32_t rmon_r_undersize; /* MBAR_ETH + 0x294 */
|
||||
uint32_t rmon_r_oversize; /* MBAR_ETH + 0x298 */
|
||||
uint32_t rmon_r_frag; /* MBAR_ETH + 0x29C */
|
||||
uint32_t rmon_r_jab; /* MBAR_ETH + 0x2A0 */
|
||||
|
||||
uint32_t rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */
|
||||
|
||||
uint32_t rmon_r_p64; /* MBAR_ETH + 0x2A8 */
|
||||
uint32_t rmon_r_p65to127; /* MBAR_ETH + 0x2AC */
|
||||
uint32_t rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */
|
||||
uint32_t rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */
|
||||
uint32_t rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */
|
||||
uint32_t rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */
|
||||
uint32_t rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */
|
||||
uint32_t rmon_r_octets; /* MBAR_ETH + 0x2C4 */
|
||||
uint32_t ieee_r_drop; /* MBAR_ETH + 0x2C8 */
|
||||
uint32_t ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */
|
||||
uint32_t ieee_r_crc; /* MBAR_ETH + 0x2D0 */
|
||||
uint32_t ieee_r_align; /* MBAR_ETH + 0x2D4 */
|
||||
uint32_t r_macerr; /* MBAR_ETH + 0x2D8 */
|
||||
uint32_t r_fdxfc; /* MBAR_ETH + 0x2DC */
|
||||
uint32_t ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */
|
||||
|
||||
uint32_t res14[7]; /* MBAR_ETH + 0x2E4-2FC */
|
||||
|
||||
#if defined(CONFIG_MX25) || defined(CONFIG_MX53) || defined(CONFIG_MX6SL)
|
||||
uint16_t miigsk_cfgr; /* MBAR_ETH + 0x300 */
|
||||
uint16_t res15[3]; /* MBAR_ETH + 0x302-306 */
|
||||
uint16_t miigsk_enr; /* MBAR_ETH + 0x308 */
|
||||
uint16_t res16[3]; /* MBAR_ETH + 0x30a-30e */
|
||||
uint32_t res17[60]; /* MBAR_ETH + 0x300-3FF */
|
||||
#else
|
||||
uint32_t res15[64]; /* MBAR_ETH + 0x300-3FF */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define FEC_IEVENT_HBERR 0x80000000
|
||||
#define FEC_IEVENT_BABR 0x40000000
|
||||
#define FEC_IEVENT_BABT 0x20000000
|
||||
#define FEC_IEVENT_GRA 0x10000000
|
||||
#define FEC_IEVENT_TXF 0x08000000
|
||||
#define FEC_IEVENT_TXB 0x04000000
|
||||
#define FEC_IEVENT_RXF 0x02000000
|
||||
#define FEC_IEVENT_RXB 0x01000000
|
||||
#define FEC_IEVENT_MII 0x00800000
|
||||
#define FEC_IEVENT_EBERR 0x00400000
|
||||
#define FEC_IEVENT_LC 0x00200000
|
||||
#define FEC_IEVENT_RL 0x00100000
|
||||
#define FEC_IEVENT_UN 0x00080000
|
||||
|
||||
#define FEC_IMASK_HBERR 0x80000000
|
||||
#define FEC_IMASK_BABR 0x40000000
|
||||
#define FEC_IMASKT_BABT 0x20000000
|
||||
#define FEC_IMASK_GRA 0x10000000
|
||||
#define FEC_IMASKT_TXF 0x08000000
|
||||
#define FEC_IMASK_TXB 0x04000000
|
||||
#define FEC_IMASKT_RXF 0x02000000
|
||||
#define FEC_IMASK_RXB 0x01000000
|
||||
#define FEC_IMASK_MII 0x00800000
|
||||
#define FEC_IMASK_EBERR 0x00400000
|
||||
#define FEC_IMASK_LC 0x00200000
|
||||
#define FEC_IMASKT_RL 0x00100000
|
||||
#define FEC_IMASK_UN 0x00080000
|
||||
|
||||
|
||||
#define FEC_RCNTRL_MAX_FL_SHIFT 16
|
||||
#define FEC_RCNTRL_LOOP 0x00000001
|
||||
#define FEC_RCNTRL_DRT 0x00000002
|
||||
#define FEC_RCNTRL_MII_MODE 0x00000004
|
||||
#define FEC_RCNTRL_PROM 0x00000008
|
||||
#define FEC_RCNTRL_BC_REJ 0x00000010
|
||||
#define FEC_RCNTRL_FCE 0x00000020
|
||||
#define FEC_RCNTRL_RGMII 0x00000040
|
||||
#define FEC_RCNTRL_RMII 0x00000100
|
||||
#define FEC_RCNTRL_RMII_10T 0x00000200
|
||||
|
||||
#define FEC_TCNTRL_GTS 0x00000001
|
||||
#define FEC_TCNTRL_HBC 0x00000002
|
||||
#define FEC_TCNTRL_FDEN 0x00000004
|
||||
#define FEC_TCNTRL_TFC_PAUSE 0x00000008
|
||||
#define FEC_TCNTRL_RFC_PAUSE 0x00000010
|
||||
|
||||
#define FEC_ECNTRL_RESET 0x00000001 /* reset the FEC */
|
||||
#define FEC_ECNTRL_ETHER_EN 0x00000002 /* enable the FEC */
|
||||
#define FEC_ECNTRL_SPEED 0x00000020
|
||||
#define FEC_ECNTRL_DBSWAP 0x00000100
|
||||
|
||||
#define FEC_X_WMRK_STRFWD 0x00000100
|
||||
|
||||
#define FEC_X_DES_ACTIVE_TDAR 0x01000000
|
||||
#define FEC_R_DES_ACTIVE_RDAR 0x01000000
|
||||
|
||||
#if defined(CONFIG_MX25) || defined(CONFIG_MX53) || defined(CONFIG_MX6SL)
|
||||
/* defines for MIIGSK */
|
||||
/* RMII frequency control: 0=50MHz, 1=5MHz */
|
||||
#define MIIGSK_CFGR_FRCONT (1 << 6)
|
||||
/* loopback mode */
|
||||
#define MIIGSK_CFGR_LBMODE (1 << 4)
|
||||
/* echo mode */
|
||||
#define MIIGSK_CFGR_EMODE (1 << 3)
|
||||
/* MII gasket mode field */
|
||||
#define MIIGSK_CFGR_IF_MODE_MASK (3 << 0)
|
||||
/* MMI/7-Wire mode */
|
||||
#define MIIGSK_CFGR_IF_MODE_MII (0 << 0)
|
||||
/* RMII mode */
|
||||
#define MIIGSK_CFGR_IF_MODE_RMII (1 << 0)
|
||||
/* reflects MIIGSK Enable bit (RO) */
|
||||
#define MIIGSK_ENR_READY (1 << 2)
|
||||
/* enable MIGSK (set by default) */
|
||||
#define MIIGSK_ENR_EN (1 << 1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Receive & Transmit Buffer Descriptor definitions
|
||||
*
|
||||
* Note: The first BD must be aligned (see DB_ALIGNMENT)
|
||||
*/
|
||||
struct fec_bd {
|
||||
uint16_t data_length; /* payload's length in bytes */
|
||||
uint16_t status; /* BD's staus (see datasheet) */
|
||||
uint32_t data_pointer; /* payload's buffer address */
|
||||
};
|
||||
|
||||
/**
|
||||
* Supported phy types on this platform
|
||||
*/
|
||||
enum xceiver_type {
|
||||
SEVENWIRE, /* 7-wire */
|
||||
MII10, /* MII 10Mbps */
|
||||
MII100, /* MII 100Mbps */
|
||||
RMII, /* RMII */
|
||||
RGMII, /* RGMII */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief i.MX27-FEC private structure
|
||||
*/
|
||||
struct fec_priv {
|
||||
struct ethernet_regs *eth; /* pointer to register'S base */
|
||||
enum xceiver_type xcv_type; /* transceiver type */
|
||||
struct fec_bd *rbd_base; /* RBD ring */
|
||||
int rbd_index; /* next receive BD to read */
|
||||
struct fec_bd *tbd_base; /* TBD ring */
|
||||
int tbd_index; /* next transmit BD to write */
|
||||
bd_t *bd;
|
||||
uint8_t *tdb_ptr;
|
||||
int dev_id;
|
||||
struct mii_dev *bus;
|
||||
#ifdef CONFIG_PHYLIB
|
||||
struct phy_device *phydev;
|
||||
#else
|
||||
int phy_id;
|
||||
int (*mii_postcall)(int);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Numbers of buffer descriptors for receiving
|
||||
*
|
||||
* The number defines the stocked memory buffers for the receiving task.
|
||||
* Larger values makes no sense in this limited environment.
|
||||
*/
|
||||
#define FEC_RBD_NUM 64
|
||||
|
||||
/**
|
||||
* @brief Define the ethernet packet size limit in memory
|
||||
*
|
||||
* Note: Do not shrink this number. This will force the FEC to spread larger
|
||||
* frames in more than one BD. This is nothing to worry about, but the current
|
||||
* driver can't handle it.
|
||||
*/
|
||||
#define FEC_MAX_PKT_SIZE 1536
|
||||
|
||||
/* Receive BD status bits */
|
||||
#define FEC_RBD_EMPTY 0x8000 /* Receive BD status: Buffer is empty */
|
||||
#define FEC_RBD_WRAP 0x2000 /* Receive BD status: Last BD in ring */
|
||||
/* Receive BD status: Buffer is last in frame (useless here!) */
|
||||
#define FEC_RBD_LAST 0x0800
|
||||
#define FEC_RBD_MISS 0x0100 /* Receive BD status: Miss bit for prom mode */
|
||||
/* Receive BD status: The received frame is broadcast frame */
|
||||
#define FEC_RBD_BC 0x0080
|
||||
/* Receive BD status: The received frame is multicast frame */
|
||||
#define FEC_RBD_MC 0x0040
|
||||
#define FEC_RBD_LG 0x0020 /* Receive BD status: Frame length violation */
|
||||
#define FEC_RBD_NO 0x0010 /* Receive BD status: Nonoctet align frame */
|
||||
#define FEC_RBD_CR 0x0004 /* Receive BD status: CRC error */
|
||||
#define FEC_RBD_OV 0x0002 /* Receive BD status: Receive FIFO overrun */
|
||||
#define FEC_RBD_TR 0x0001 /* Receive BD status: Frame is truncated */
|
||||
#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
|
||||
FEC_RBD_OV | FEC_RBD_TR)
|
||||
|
||||
/* Transmit BD status bits */
|
||||
#define FEC_TBD_READY 0x8000 /* Tansmit BD status: Buffer is ready */
|
||||
#define FEC_TBD_WRAP 0x2000 /* Tansmit BD status: Mark as last BD in ring */
|
||||
#define FEC_TBD_LAST 0x0800 /* Tansmit BD status: Buffer is last in frame */
|
||||
#define FEC_TBD_TC 0x0400 /* Tansmit BD status: Transmit the CRC */
|
||||
#define FEC_TBD_ABC 0x0200 /* Tansmit BD status: Append bad CRC */
|
||||
|
||||
/* MII-related definitios */
|
||||
#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */
|
||||
#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */
|
||||
#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */
|
||||
#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */
|
||||
#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */
|
||||
#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
|
||||
#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */
|
||||
|
||||
#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
|
||||
#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
|
||||
|
||||
#endif /* __FEC_MXC_H */
|
||||
40
sources/uboot-be550/drivers/net/fm/Makefile
Normal file
40
sources/uboot-be550/drivers/net/fm/Makefile
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += dtsec.o
|
||||
obj-y += eth.o
|
||||
obj-y += fm.o
|
||||
obj-y += init.o
|
||||
obj-y += tgec.o
|
||||
obj-y += tgec_phy.o
|
||||
|
||||
# Soc have FMAN v3 with mEMAC
|
||||
obj-$(CONFIG_SYS_FMAN_V3) += memac_phy.o
|
||||
obj-$(CONFIG_SYS_FMAN_V3) += memac.o
|
||||
|
||||
# SoC specific SERDES support
|
||||
obj-$(CONFIG_P1017) += p1023.o
|
||||
obj-$(CONFIG_P1023) += p1023.o
|
||||
# The P204x, P304x, and P5020 are the same
|
||||
obj-$(CONFIG_PPC_P2041) += p5020.o
|
||||
obj-$(CONFIG_PPC_P3041) += p5020.o
|
||||
obj-$(CONFIG_PPC_P4080) += p4080.o
|
||||
obj-$(CONFIG_PPC_P5020) += p5020.o
|
||||
obj-$(CONFIG_PPC_P5040) += p5040.o
|
||||
obj-$(CONFIG_PPC_T1040) += t1040.o
|
||||
obj-$(CONFIG_PPC_T1042) += t1040.o
|
||||
obj-$(CONFIG_PPC_T1020) += t1040.o
|
||||
obj-$(CONFIG_PPC_T1022) += t1040.o
|
||||
obj-$(CONFIG_PPC_T1023) += t1024.o
|
||||
obj-$(CONFIG_PPC_T1024) += t1024.o
|
||||
obj-$(CONFIG_PPC_T2080) += t2080.o
|
||||
obj-$(CONFIG_PPC_T2081) += t2080.o
|
||||
obj-$(CONFIG_PPC_T4240) += t4240.o
|
||||
obj-$(CONFIG_PPC_T4160) += t4240.o
|
||||
obj-$(CONFIG_PPC_T4080) += t4240.o
|
||||
obj-$(CONFIG_PPC_B4420) += b4860.o
|
||||
obj-$(CONFIG_PPC_B4860) += b4860.o
|
||||
obj-$(CONFIG_LS1043A) += ls1043.o
|
||||
137
sources/uboot-be550/drivers/net/fm/b4860.c
Normal file
137
sources/uboot-be550/drivers/net/fm/b4860.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Roy Zang <tie-fei.zang@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
#include <hwconfig.h>
|
||||
|
||||
u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
|
||||
[FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1,
|
||||
[FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
void fman_enable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
#if defined(CONFIG_B4860QDS)
|
||||
u32 serdes2_prtcl;
|
||||
char buffer[HWCONFIG_BUFFER_SIZE];
|
||||
char *buf = NULL;
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
#endif
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
/*B4860 has two 10Gig Mac*/
|
||||
if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
|
||||
((is_serdes_configured(XAUI_FM1_MAC9)) ||
|
||||
#if !defined(CONFIG_B4860QDS)
|
||||
(is_serdes_configured(XFI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC10)) ||
|
||||
#endif
|
||||
(is_serdes_configured(XAUI_FM1_MAC10))
|
||||
))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
#if defined(CONFIG_B4860QDS)
|
||||
serdes2_prtcl = in_be32(&gur->rcwsr[4]) &
|
||||
FSL_CORENET2_RCWSR4_SRDS2_PRTCL;
|
||||
|
||||
if (serdes2_prtcl) {
|
||||
serdes2_prtcl >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT;
|
||||
switch (serdes2_prtcl) {
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x86:
|
||||
case 0x87:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8a:
|
||||
case 0x8b:
|
||||
case 0x8c:
|
||||
case 0x8d:
|
||||
case 0x8e:
|
||||
case 0xb1:
|
||||
case 0xb2:
|
||||
/*
|
||||
* Extract hwconfig from environment since environment
|
||||
* is not setup yet
|
||||
*/
|
||||
getenv_f("hwconfig", buffer, sizeof(buffer));
|
||||
buf = buffer;
|
||||
|
||||
/* check if XFI interface enable in hwconfig for 10g */
|
||||
if (hwconfig_subarg_cmp_f("fsl_b4860_serdes2",
|
||||
"sfp_amc", "sfp", buf)) {
|
||||
if ((port == FM1_10GEC1 ||
|
||||
port == FM1_10GEC2) &&
|
||||
((is_serdes_configured(XFI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC10))))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
else if ((port == FM1_DTSEC1) ||
|
||||
(port == FM1_DTSEC2) ||
|
||||
(port == FM1_DTSEC3) ||
|
||||
(port == FM1_DTSEC4))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fix me need to handle RGMII here first */
|
||||
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
case FM1_DTSEC5:
|
||||
case FM1_DTSEC6:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
167
sources/uboot-be550/drivers/net/fm/dtsec.c
Normal file
167
sources/uboot-be550/drivers/net/fm/dtsec.c
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_dtsec.h>
|
||||
#include <fsl_mdio.h>
|
||||
#include <phy.h>
|
||||
|
||||
#include "fm.h"
|
||||
|
||||
#define RCTRL_INIT (RCTRL_GRS | RCTRL_UPROM)
|
||||
#define TCTRL_INIT TCTRL_GTS
|
||||
#define MACCFG1_INIT MACCFG1_SOFT_RST
|
||||
|
||||
#define MACCFG2_INIT (MACCFG2_PRE_LEN(0x7) | MACCFG2_LEN_CHECK | \
|
||||
MACCFG2_PAD_CRC | MACCFG2_FULL_DUPLEX | \
|
||||
MACCFG2_IF_MODE_NIBBLE)
|
||||
|
||||
/* MAXFRM - maximum frame length register */
|
||||
#define MAXFRM_MASK 0x00003fff
|
||||
|
||||
static void dtsec_init_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct dtsec *regs = mac->base;
|
||||
|
||||
/* soft reset */
|
||||
out_be32(®s->maccfg1, MACCFG1_SOFT_RST);
|
||||
udelay(1000);
|
||||
|
||||
/* clear soft reset, Rx/Tx MAC disable */
|
||||
out_be32(®s->maccfg1, 0);
|
||||
|
||||
/* graceful stop rx */
|
||||
out_be32(®s->rctrl, RCTRL_INIT);
|
||||
udelay(1000);
|
||||
|
||||
/* graceful stop tx */
|
||||
out_be32(®s->tctrl, TCTRL_INIT);
|
||||
udelay(1000);
|
||||
|
||||
/* disable all interrupts */
|
||||
out_be32(®s->imask, IMASK_MASK_ALL);
|
||||
|
||||
/* clear all events */
|
||||
out_be32(®s->ievent, IEVENT_CLEAR_ALL);
|
||||
|
||||
/* set the max Rx length */
|
||||
out_be32(®s->maxfrm, mac->max_rx_len & MAXFRM_MASK);
|
||||
|
||||
/* set the ecntrl to reset value */
|
||||
out_be32(®s->ecntrl, ECNTRL_DEFAULT);
|
||||
|
||||
/*
|
||||
* Rx length check, no strip CRC for Rx, pad and append CRC for Tx,
|
||||
* full duplex
|
||||
*/
|
||||
out_be32(®s->maccfg2, MACCFG2_INIT);
|
||||
}
|
||||
|
||||
static void dtsec_enable_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct dtsec *regs = mac->base;
|
||||
|
||||
/* enable Rx/Tx MAC */
|
||||
setbits_be32(®s->maccfg1, MACCFG1_RXTX_EN);
|
||||
|
||||
/* clear the graceful Rx stop */
|
||||
clrbits_be32(®s->rctrl, RCTRL_GRS);
|
||||
|
||||
/* clear the graceful Tx stop */
|
||||
clrbits_be32(®s->tctrl, TCTRL_GTS);
|
||||
}
|
||||
|
||||
static void dtsec_disable_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct dtsec *regs = mac->base;
|
||||
|
||||
/* graceful Rx stop */
|
||||
setbits_be32(®s->rctrl, RCTRL_GRS);
|
||||
|
||||
/* graceful Tx stop */
|
||||
setbits_be32(®s->tctrl, TCTRL_GTS);
|
||||
|
||||
/* disable Rx/Tx MAC */
|
||||
clrbits_be32(®s->maccfg1, MACCFG1_RXTX_EN);
|
||||
}
|
||||
|
||||
static void dtsec_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
|
||||
{
|
||||
struct dtsec *regs = mac->base;
|
||||
u32 mac_addr1, mac_addr2;
|
||||
|
||||
/*
|
||||
* if a station address of 0x12345678ABCD, perform a write to
|
||||
* MACSTNADDR1 of 0xCDAB7856, MACSTNADDR2 of 0x34120000
|
||||
*/
|
||||
mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \
|
||||
(mac_addr[3] << 8) | (mac_addr[2]);
|
||||
out_be32(®s->macstnaddr1, mac_addr1);
|
||||
|
||||
mac_addr2 = ((mac_addr[1] << 24) | (mac_addr[0] << 16)) & 0xffff0000;
|
||||
out_be32(®s->macstnaddr2, mac_addr2);
|
||||
}
|
||||
|
||||
static void dtsec_set_interface_mode(struct fsl_enet_mac *mac,
|
||||
phy_interface_t type, int speed)
|
||||
{
|
||||
struct dtsec *regs = mac->base;
|
||||
u32 ecntrl, maccfg2;
|
||||
|
||||
/* clear all bits relative with interface mode */
|
||||
ecntrl = in_be32(®s->ecntrl);
|
||||
ecntrl &= ~(ECNTRL_TBIM | ECNTRL_GMIIM | ECNTRL_RPM |
|
||||
ECNTRL_R100M | ECNTRL_SGMIIM);
|
||||
|
||||
maccfg2 = in_be32(®s->maccfg2);
|
||||
maccfg2 &= ~MACCFG2_IF_MODE_MASK;
|
||||
|
||||
if (speed == SPEED_1000)
|
||||
maccfg2 |= MACCFG2_IF_MODE_BYTE;
|
||||
else
|
||||
maccfg2 |= MACCFG2_IF_MODE_NIBBLE;
|
||||
|
||||
/* set interface mode */
|
||||
switch (type) {
|
||||
case PHY_INTERFACE_MODE_GMII:
|
||||
ecntrl |= ECNTRL_GMIIM;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
ecntrl |= (ECNTRL_GMIIM | ECNTRL_RPM);
|
||||
if (speed == SPEED_100)
|
||||
ecntrl |= ECNTRL_R100M;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RMII:
|
||||
if (speed == SPEED_100)
|
||||
ecntrl |= ECNTRL_R100M;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
ecntrl |= (ECNTRL_SGMIIM | ECNTRL_TBIM);
|
||||
if (speed == SPEED_100)
|
||||
ecntrl |= ECNTRL_R100M;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out_be32(®s->ecntrl, ecntrl);
|
||||
out_be32(®s->maccfg2, maccfg2);
|
||||
}
|
||||
|
||||
void init_dtsec(struct fsl_enet_mac *mac, void *base,
|
||||
void *phyregs, int max_rx_len)
|
||||
{
|
||||
mac->base = base;
|
||||
mac->phyregs = phyregs;
|
||||
mac->max_rx_len = max_rx_len;
|
||||
mac->init_mac = dtsec_init_mac;
|
||||
mac->enable_mac = dtsec_enable_mac;
|
||||
mac->disable_mac = dtsec_disable_mac;
|
||||
mac->set_mac_addr = dtsec_set_mac_addr;
|
||||
mac->set_if_mode = dtsec_set_interface_mode;
|
||||
}
|
||||
783
sources/uboot-be550/drivers/net/fm/eth.c
Normal file
783
sources/uboot-be550/drivers/net/fm/eth.c
Normal file
|
|
@ -0,0 +1,783 @@
|
|||
/*
|
||||
* Copyright 2009-2012 Freescale Semiconductor, Inc.
|
||||
* Dave Liu <daveliu@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <hwconfig.h>
|
||||
#include <fm_eth.h>
|
||||
#include <fsl_mdio.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
#include <fsl_dtsec.h>
|
||||
#include <fsl_tgec.h>
|
||||
#include <fsl_memac.h>
|
||||
|
||||
#include "fm.h"
|
||||
|
||||
static struct eth_device *devlist[NUM_FM_PORTS];
|
||||
static int num_controllers;
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
|
||||
|
||||
#define TBIANA_SETTINGS (TBIANA_ASYMMETRIC_PAUSE | TBIANA_SYMMETRIC_PAUSE | \
|
||||
TBIANA_FULL_DUPLEX)
|
||||
|
||||
#define TBIANA_SGMII_ACK 0x4001
|
||||
|
||||
#define TBICR_SETTINGS (TBICR_ANEG_ENABLE | TBICR_RESTART_ANEG | \
|
||||
TBICR_FULL_DUPLEX | TBICR_SPEED1_SET)
|
||||
|
||||
/* Configure the TBI for SGMII operation */
|
||||
static void dtsec_configure_serdes(struct fm_eth *priv)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FMAN_V3
|
||||
u32 value;
|
||||
struct mii_dev bus;
|
||||
bus.priv = priv->mac->phyregs;
|
||||
bool sgmii_2500 = (priv->enet_if ==
|
||||
PHY_INTERFACE_MODE_SGMII_2500) ? true : false;
|
||||
int i = 0;
|
||||
|
||||
qsgmii_loop:
|
||||
/* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
|
||||
value = PHY_SGMII_IF_MODE_SGMII;
|
||||
if (!sgmii_2500)
|
||||
value |= PHY_SGMII_IF_MODE_AN;
|
||||
|
||||
memac_mdio_write(&bus, i, MDIO_DEVAD_NONE, 0x14, value);
|
||||
|
||||
/* Dev ability according to SGMII specification */
|
||||
value = PHY_SGMII_DEV_ABILITY_SGMII;
|
||||
memac_mdio_write(&bus, i, MDIO_DEVAD_NONE, 0x4, value);
|
||||
|
||||
/* Adjust link timer for SGMII -
|
||||
1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 */
|
||||
memac_mdio_write(&bus, i, MDIO_DEVAD_NONE, 0x13, 0x3);
|
||||
memac_mdio_write(&bus, i, MDIO_DEVAD_NONE, 0x12, 0xd40);
|
||||
|
||||
/* Restart AN */
|
||||
value = PHY_SGMII_CR_DEF_VAL;
|
||||
if (!sgmii_2500)
|
||||
value |= PHY_SGMII_CR_RESET_AN;
|
||||
memac_mdio_write(&bus, i, MDIO_DEVAD_NONE, 0, value);
|
||||
|
||||
if ((priv->enet_if == PHY_INTERFACE_MODE_QSGMII) && (i < 3)) {
|
||||
i++;
|
||||
goto qsgmii_loop;
|
||||
}
|
||||
#else
|
||||
struct dtsec *regs = priv->mac->base;
|
||||
struct tsec_mii_mng *phyregs = priv->mac->phyregs;
|
||||
|
||||
/*
|
||||
* Access TBI PHY registers at given TSEC register offset as
|
||||
* opposed to the register offset used for external PHY accesses
|
||||
*/
|
||||
tsec_local_mdio_write(phyregs, in_be32(®s->tbipa), 0, TBI_TBICON,
|
||||
TBICON_CLK_SELECT);
|
||||
tsec_local_mdio_write(phyregs, in_be32(®s->tbipa), 0, TBI_ANA,
|
||||
TBIANA_SGMII_ACK);
|
||||
tsec_local_mdio_write(phyregs, in_be32(®s->tbipa), 0,
|
||||
TBI_CR, TBICR_SETTINGS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dtsec_init_phy(struct eth_device *dev)
|
||||
{
|
||||
struct fm_eth *fm_eth = dev->priv;
|
||||
#ifndef CONFIG_SYS_FMAN_V3
|
||||
struct dtsec *regs = (struct dtsec *)CONFIG_SYS_FSL_FM1_DTSEC1_ADDR;
|
||||
|
||||
/* Assign a Physical address to the TBI */
|
||||
out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE);
|
||||
#endif
|
||||
|
||||
if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII ||
|
||||
fm_eth->enet_if == PHY_INTERFACE_MODE_QSGMII ||
|
||||
fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII_2500)
|
||||
dtsec_configure_serdes(fm_eth);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
static int tgec_is_fibre(struct eth_device *dev)
|
||||
{
|
||||
struct fm_eth *fm = dev->priv;
|
||||
char phyopt[20];
|
||||
|
||||
sprintf(phyopt, "fsl_fm%d_xaui_phy", fm->fm_index + 1);
|
||||
|
||||
return hwconfig_arg_cmp(phyopt, "xfi");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static u16 muram_readw(u16 *addr)
|
||||
{
|
||||
ulong base = (ulong)addr & ~0x3UL;
|
||||
u32 val32 = in_be32((void *)base);
|
||||
int byte_pos;
|
||||
u16 ret;
|
||||
|
||||
byte_pos = (ulong)addr & 0x3UL;
|
||||
if (byte_pos)
|
||||
ret = (u16)(val32 & 0x0000ffff);
|
||||
else
|
||||
ret = (u16)((val32 & 0xffff0000) >> 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void muram_writew(u16 *addr, u16 val)
|
||||
{
|
||||
ulong base = (ulong)addr & ~0x3UL;
|
||||
u32 org32 = in_be32((void *)base);
|
||||
u32 val32;
|
||||
int byte_pos;
|
||||
|
||||
byte_pos = (ulong)addr & 0x3UL;
|
||||
if (byte_pos)
|
||||
val32 = (org32 & 0xffff0000) | val;
|
||||
else
|
||||
val32 = (org32 & 0x0000ffff) | ((u32)val << 16);
|
||||
|
||||
out_be32((void *)base, val32);
|
||||
}
|
||||
|
||||
static void bmi_rx_port_disable(struct fm_bmi_rx_port *rx_port)
|
||||
{
|
||||
int timeout = 1000000;
|
||||
|
||||
clrbits_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_EN);
|
||||
|
||||
/* wait until the rx port is not busy */
|
||||
while ((in_be32(&rx_port->fmbm_rst) & FMBM_RST_BSY) && timeout--)
|
||||
;
|
||||
}
|
||||
|
||||
static void bmi_rx_port_init(struct fm_bmi_rx_port *rx_port)
|
||||
{
|
||||
/* set BMI to independent mode, Rx port disable */
|
||||
out_be32(&rx_port->fmbm_rcfg, FMBM_RCFG_IM);
|
||||
/* clear FOF in IM case */
|
||||
out_be32(&rx_port->fmbm_rim, 0);
|
||||
/* Rx frame next engine -RISC */
|
||||
out_be32(&rx_port->fmbm_rfne, NIA_ENG_RISC | NIA_RISC_AC_IM_RX);
|
||||
/* Rx command attribute - no order, MR[3] = 1 */
|
||||
clrbits_be32(&rx_port->fmbm_rfca, FMBM_RFCA_ORDER | FMBM_RFCA_MR_MASK);
|
||||
setbits_be32(&rx_port->fmbm_rfca, FMBM_RFCA_MR(4));
|
||||
/* enable Rx statistic counters */
|
||||
out_be32(&rx_port->fmbm_rstc, FMBM_RSTC_EN);
|
||||
/* disable Rx performance counters */
|
||||
out_be32(&rx_port->fmbm_rpc, 0);
|
||||
}
|
||||
|
||||
static void bmi_tx_port_disable(struct fm_bmi_tx_port *tx_port)
|
||||
{
|
||||
int timeout = 1000000;
|
||||
|
||||
clrbits_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_EN);
|
||||
|
||||
/* wait until the tx port is not busy */
|
||||
while ((in_be32(&tx_port->fmbm_tst) & FMBM_TST_BSY) && timeout--)
|
||||
;
|
||||
}
|
||||
|
||||
static void bmi_tx_port_init(struct fm_bmi_tx_port *tx_port)
|
||||
{
|
||||
/* set BMI to independent mode, Tx port disable */
|
||||
out_be32(&tx_port->fmbm_tcfg, FMBM_TCFG_IM);
|
||||
/* Tx frame next engine -RISC */
|
||||
out_be32(&tx_port->fmbm_tfne, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
|
||||
out_be32(&tx_port->fmbm_tfene, NIA_ENG_RISC | NIA_RISC_AC_IM_TX);
|
||||
/* Tx command attribute - no order, MR[3] = 1 */
|
||||
clrbits_be32(&tx_port->fmbm_tfca, FMBM_TFCA_ORDER | FMBM_TFCA_MR_MASK);
|
||||
setbits_be32(&tx_port->fmbm_tfca, FMBM_TFCA_MR(4));
|
||||
/* enable Tx statistic counters */
|
||||
out_be32(&tx_port->fmbm_tstc, FMBM_TSTC_EN);
|
||||
/* disable Tx performance counters */
|
||||
out_be32(&tx_port->fmbm_tpc, 0);
|
||||
}
|
||||
|
||||
static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth)
|
||||
{
|
||||
struct fm_port_global_pram *pram;
|
||||
u32 pram_page_offset;
|
||||
void *rx_bd_ring_base;
|
||||
void *rx_buf_pool;
|
||||
u32 bd_ring_base_lo, bd_ring_base_hi;
|
||||
u32 buf_lo, buf_hi;
|
||||
struct fm_port_bd *rxbd;
|
||||
struct fm_port_qd *rxqd;
|
||||
struct fm_bmi_rx_port *bmi_rx_port = fm_eth->rx_port;
|
||||
int i;
|
||||
|
||||
/* alloc global parameter ram at MURAM */
|
||||
pram = (struct fm_port_global_pram *)fm_muram_alloc(fm_eth->fm_index,
|
||||
FM_PRAM_SIZE, FM_PRAM_ALIGN);
|
||||
if (!pram) {
|
||||
printf("%s: No muram for Rx global parameter\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fm_eth->rx_pram = pram;
|
||||
|
||||
/* parameter page offset to MURAM */
|
||||
pram_page_offset = (void *)pram - fm_muram_base(fm_eth->fm_index);
|
||||
|
||||
/* enable global mode- snooping data buffers and BDs */
|
||||
out_be32(&pram->mode, PRAM_MODE_GLOBAL);
|
||||
|
||||
/* init the Rx queue descriptor pionter */
|
||||
out_be32(&pram->rxqd_ptr, pram_page_offset + 0x20);
|
||||
|
||||
/* set the max receive buffer length, power of 2 */
|
||||
muram_writew(&pram->mrblr, MAX_RXBUF_LOG2);
|
||||
|
||||
/* alloc Rx buffer descriptors from main memory */
|
||||
rx_bd_ring_base = malloc(sizeof(struct fm_port_bd)
|
||||
* RX_BD_RING_SIZE);
|
||||
if (!rx_bd_ring_base)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(rx_bd_ring_base, 0, sizeof(struct fm_port_bd)
|
||||
* RX_BD_RING_SIZE);
|
||||
|
||||
/* alloc Rx buffer from main memory */
|
||||
rx_buf_pool = malloc(MAX_RXBUF_LEN * RX_BD_RING_SIZE);
|
||||
if (!rx_buf_pool)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(rx_buf_pool, 0, MAX_RXBUF_LEN * RX_BD_RING_SIZE);
|
||||
debug("%s: rx_buf_pool = %p\n", __func__, rx_buf_pool);
|
||||
|
||||
/* save them to fm_eth */
|
||||
fm_eth->rx_bd_ring = rx_bd_ring_base;
|
||||
fm_eth->cur_rxbd = rx_bd_ring_base;
|
||||
fm_eth->rx_buf = rx_buf_pool;
|
||||
|
||||
/* init Rx BDs ring */
|
||||
rxbd = (struct fm_port_bd *)rx_bd_ring_base;
|
||||
for (i = 0; i < RX_BD_RING_SIZE; i++) {
|
||||
muram_writew(&rxbd->status, RxBD_EMPTY);
|
||||
muram_writew(&rxbd->len, 0);
|
||||
buf_hi = upper_32_bits(virt_to_phys(rx_buf_pool +
|
||||
i * MAX_RXBUF_LEN));
|
||||
buf_lo = lower_32_bits(virt_to_phys(rx_buf_pool +
|
||||
i * MAX_RXBUF_LEN));
|
||||
muram_writew(&rxbd->buf_ptr_hi, (u16)buf_hi);
|
||||
out_be32(&rxbd->buf_ptr_lo, buf_lo);
|
||||
rxbd++;
|
||||
}
|
||||
|
||||
/* set the Rx queue descriptor */
|
||||
rxqd = &pram->rxqd;
|
||||
muram_writew(&rxqd->gen, 0);
|
||||
bd_ring_base_hi = upper_32_bits(virt_to_phys(rx_bd_ring_base));
|
||||
bd_ring_base_lo = lower_32_bits(virt_to_phys(rx_bd_ring_base));
|
||||
muram_writew(&rxqd->bd_ring_base_hi, (u16)bd_ring_base_hi);
|
||||
out_be32(&rxqd->bd_ring_base_lo, bd_ring_base_lo);
|
||||
muram_writew(&rxqd->bd_ring_size, sizeof(struct fm_port_bd)
|
||||
* RX_BD_RING_SIZE);
|
||||
muram_writew(&rxqd->offset_in, 0);
|
||||
muram_writew(&rxqd->offset_out, 0);
|
||||
|
||||
/* set IM parameter ram pointer to Rx Frame Queue ID */
|
||||
out_be32(&bmi_rx_port->fmbm_rfqid, pram_page_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fm_eth_tx_port_parameter_init(struct fm_eth *fm_eth)
|
||||
{
|
||||
struct fm_port_global_pram *pram;
|
||||
u32 pram_page_offset;
|
||||
void *tx_bd_ring_base;
|
||||
u32 bd_ring_base_lo, bd_ring_base_hi;
|
||||
struct fm_port_bd *txbd;
|
||||
struct fm_port_qd *txqd;
|
||||
struct fm_bmi_tx_port *bmi_tx_port = fm_eth->tx_port;
|
||||
int i;
|
||||
|
||||
/* alloc global parameter ram at MURAM */
|
||||
pram = (struct fm_port_global_pram *)fm_muram_alloc(fm_eth->fm_index,
|
||||
FM_PRAM_SIZE, FM_PRAM_ALIGN);
|
||||
if (!pram) {
|
||||
printf("%s: No muram for Tx global parameter\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
fm_eth->tx_pram = pram;
|
||||
|
||||
/* parameter page offset to MURAM */
|
||||
pram_page_offset = (void *)pram - fm_muram_base(fm_eth->fm_index);
|
||||
|
||||
/* enable global mode- snooping data buffers and BDs */
|
||||
out_be32(&pram->mode, PRAM_MODE_GLOBAL);
|
||||
|
||||
/* init the Tx queue descriptor pionter */
|
||||
out_be32(&pram->txqd_ptr, pram_page_offset + 0x40);
|
||||
|
||||
/* alloc Tx buffer descriptors from main memory */
|
||||
tx_bd_ring_base = malloc(sizeof(struct fm_port_bd)
|
||||
* TX_BD_RING_SIZE);
|
||||
if (!tx_bd_ring_base)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(tx_bd_ring_base, 0, sizeof(struct fm_port_bd)
|
||||
* TX_BD_RING_SIZE);
|
||||
/* save it to fm_eth */
|
||||
fm_eth->tx_bd_ring = tx_bd_ring_base;
|
||||
fm_eth->cur_txbd = tx_bd_ring_base;
|
||||
|
||||
/* init Tx BDs ring */
|
||||
txbd = (struct fm_port_bd *)tx_bd_ring_base;
|
||||
for (i = 0; i < TX_BD_RING_SIZE; i++) {
|
||||
muram_writew(&txbd->status, TxBD_LAST);
|
||||
muram_writew(&txbd->len, 0);
|
||||
muram_writew(&txbd->buf_ptr_hi, 0);
|
||||
out_be32(&txbd->buf_ptr_lo, 0);
|
||||
txbd++;
|
||||
}
|
||||
|
||||
/* set the Tx queue decriptor */
|
||||
txqd = &pram->txqd;
|
||||
bd_ring_base_hi = upper_32_bits(virt_to_phys(tx_bd_ring_base));
|
||||
bd_ring_base_lo = lower_32_bits(virt_to_phys(tx_bd_ring_base));
|
||||
muram_writew(&txqd->bd_ring_base_hi, (u16)bd_ring_base_hi);
|
||||
out_be32(&txqd->bd_ring_base_lo, bd_ring_base_lo);
|
||||
muram_writew(&txqd->bd_ring_size, sizeof(struct fm_port_bd)
|
||||
* TX_BD_RING_SIZE);
|
||||
muram_writew(&txqd->offset_in, 0);
|
||||
muram_writew(&txqd->offset_out, 0);
|
||||
|
||||
/* set IM parameter ram pointer to Tx Confirmation Frame Queue ID */
|
||||
out_be32(&bmi_tx_port->fmbm_tcfqid, pram_page_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fm_eth_init(struct fm_eth *fm_eth)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fm_eth_rx_port_parameter_init(fm_eth);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = fm_eth_tx_port_parameter_init(fm_eth);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fm_eth_startup(struct fm_eth *fm_eth)
|
||||
{
|
||||
struct fsl_enet_mac *mac;
|
||||
int ret;
|
||||
|
||||
mac = fm_eth->mac;
|
||||
|
||||
/* Rx/TxBDs, Rx/TxQDs, Rx buff and parameter ram init */
|
||||
ret = fm_eth_init(fm_eth);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* setup the MAC controller */
|
||||
mac->init_mac(mac);
|
||||
|
||||
/* For some reason we need to set SPEED_100 */
|
||||
if (((fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII) ||
|
||||
(fm_eth->enet_if == PHY_INTERFACE_MODE_QSGMII)) &&
|
||||
mac->set_if_mode)
|
||||
mac->set_if_mode(mac, fm_eth->enet_if, SPEED_100);
|
||||
|
||||
/* init bmi rx port, IM mode and disable */
|
||||
bmi_rx_port_init(fm_eth->rx_port);
|
||||
/* init bmi tx port, IM mode and disable */
|
||||
bmi_tx_port_init(fm_eth->tx_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fmc_tx_port_graceful_stop_enable(struct fm_eth *fm_eth)
|
||||
{
|
||||
struct fm_port_global_pram *pram;
|
||||
|
||||
pram = fm_eth->tx_pram;
|
||||
/* graceful stop transmission of frames */
|
||||
setbits_be32(&pram->mode, PRAM_MODE_GRACEFUL_STOP);
|
||||
sync();
|
||||
}
|
||||
|
||||
static void fmc_tx_port_graceful_stop_disable(struct fm_eth *fm_eth)
|
||||
{
|
||||
struct fm_port_global_pram *pram;
|
||||
|
||||
pram = fm_eth->tx_pram;
|
||||
/* re-enable transmission of frames */
|
||||
clrbits_be32(&pram->mode, PRAM_MODE_GRACEFUL_STOP);
|
||||
sync();
|
||||
}
|
||||
|
||||
static int fm_eth_open(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
struct fm_eth *fm_eth;
|
||||
struct fsl_enet_mac *mac;
|
||||
#ifdef CONFIG_PHYLIB
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
fm_eth = (struct fm_eth *)dev->priv;
|
||||
mac = fm_eth->mac;
|
||||
|
||||
/* setup the MAC address */
|
||||
if (dev->enetaddr[0] & 0x01) {
|
||||
printf("%s: MacAddress is multcast address\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
mac->set_mac_addr(mac, dev->enetaddr);
|
||||
|
||||
/* enable bmi Rx port */
|
||||
setbits_be32(&fm_eth->rx_port->fmbm_rcfg, FMBM_RCFG_EN);
|
||||
/* enable MAC rx/tx port */
|
||||
mac->enable_mac(mac);
|
||||
/* enable bmi Tx port */
|
||||
setbits_be32(&fm_eth->tx_port->fmbm_tcfg, FMBM_TCFG_EN);
|
||||
/* re-enable transmission of frame */
|
||||
fmc_tx_port_graceful_stop_disable(fm_eth);
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
if (fm_eth->phydev) {
|
||||
ret = phy_startup(fm_eth->phydev);
|
||||
if (ret) {
|
||||
printf("%s: Could not initialize\n",
|
||||
fm_eth->phydev->dev->name);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
fm_eth->phydev->speed = SPEED_1000;
|
||||
fm_eth->phydev->link = 1;
|
||||
fm_eth->phydev->duplex = DUPLEX_FULL;
|
||||
#endif
|
||||
|
||||
/* set the MAC-PHY mode */
|
||||
mac->set_if_mode(mac, fm_eth->enet_if, fm_eth->phydev->speed);
|
||||
|
||||
if (!fm_eth->phydev->link)
|
||||
printf("%s: No link.\n", fm_eth->phydev->dev->name);
|
||||
|
||||
return fm_eth->phydev->link ? 0 : -1;
|
||||
}
|
||||
|
||||
static void fm_eth_halt(struct eth_device *dev)
|
||||
{
|
||||
struct fm_eth *fm_eth;
|
||||
struct fsl_enet_mac *mac;
|
||||
|
||||
fm_eth = (struct fm_eth *)dev->priv;
|
||||
mac = fm_eth->mac;
|
||||
|
||||
/* graceful stop the transmission of frames */
|
||||
fmc_tx_port_graceful_stop_enable(fm_eth);
|
||||
/* disable bmi Tx port */
|
||||
bmi_tx_port_disable(fm_eth->tx_port);
|
||||
/* disable MAC rx/tx port */
|
||||
mac->disable_mac(mac);
|
||||
/* disable bmi Rx port */
|
||||
bmi_rx_port_disable(fm_eth->rx_port);
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
if (fm_eth->phydev)
|
||||
phy_shutdown(fm_eth->phydev);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int fm_eth_send(struct eth_device *dev, void *buf, int len)
|
||||
{
|
||||
struct fm_eth *fm_eth;
|
||||
struct fm_port_global_pram *pram;
|
||||
struct fm_port_bd *txbd, *txbd_base;
|
||||
u16 offset_in;
|
||||
int i;
|
||||
|
||||
fm_eth = (struct fm_eth *)dev->priv;
|
||||
pram = fm_eth->tx_pram;
|
||||
txbd = fm_eth->cur_txbd;
|
||||
|
||||
/* find one empty TxBD */
|
||||
for (i = 0; muram_readw(&txbd->status) & TxBD_READY; i++) {
|
||||
udelay(100);
|
||||
if (i > 0x1000) {
|
||||
printf("%s: Tx buffer not ready, txbd->status = 0x%x\n",
|
||||
dev->name, muram_readw(&txbd->status));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* setup TxBD */
|
||||
muram_writew(&txbd->buf_ptr_hi, (u16)upper_32_bits(virt_to_phys(buf)));
|
||||
out_be32(&txbd->buf_ptr_lo, lower_32_bits(virt_to_phys(buf)));
|
||||
muram_writew(&txbd->len, len);
|
||||
sync();
|
||||
muram_writew(&txbd->status, TxBD_READY | TxBD_LAST);
|
||||
sync();
|
||||
|
||||
/* update TxQD, let RISC to send the packet */
|
||||
offset_in = muram_readw(&pram->txqd.offset_in);
|
||||
offset_in += sizeof(struct fm_port_bd);
|
||||
if (offset_in >= muram_readw(&pram->txqd.bd_ring_size))
|
||||
offset_in = 0;
|
||||
muram_writew(&pram->txqd.offset_in, offset_in);
|
||||
sync();
|
||||
|
||||
/* wait for buffer to be transmitted */
|
||||
for (i = 0; muram_readw(&txbd->status) & TxBD_READY; i++) {
|
||||
udelay(100);
|
||||
if (i > 0x10000) {
|
||||
printf("%s: Tx error, txbd->status = 0x%x\n",
|
||||
dev->name, muram_readw(&txbd->status));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* advance the TxBD */
|
||||
txbd++;
|
||||
txbd_base = (struct fm_port_bd *)fm_eth->tx_bd_ring;
|
||||
if (txbd >= (txbd_base + TX_BD_RING_SIZE))
|
||||
txbd = txbd_base;
|
||||
/* update current txbd */
|
||||
fm_eth->cur_txbd = (void *)txbd;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fm_eth_recv(struct eth_device *dev)
|
||||
{
|
||||
struct fm_eth *fm_eth;
|
||||
struct fm_port_global_pram *pram;
|
||||
struct fm_port_bd *rxbd, *rxbd_base;
|
||||
u16 status, len;
|
||||
u32 buf_lo, buf_hi;
|
||||
u8 *data;
|
||||
u16 offset_out;
|
||||
int ret = 1;
|
||||
|
||||
fm_eth = (struct fm_eth *)dev->priv;
|
||||
pram = fm_eth->rx_pram;
|
||||
rxbd = fm_eth->cur_rxbd;
|
||||
status = muram_readw(&rxbd->status);
|
||||
|
||||
while (!(status & RxBD_EMPTY)) {
|
||||
if (!(status & RxBD_ERROR)) {
|
||||
buf_hi = muram_readw(&rxbd->buf_ptr_hi);
|
||||
buf_lo = in_be32(&rxbd->buf_ptr_lo);
|
||||
data = (u8 *)((ulong)(buf_hi << 16) << 16 | buf_lo);
|
||||
len = muram_readw(&rxbd->len);
|
||||
net_process_received_packet(data, len);
|
||||
} else {
|
||||
printf("%s: Rx error\n", dev->name);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* clear the RxBDs */
|
||||
muram_writew(&rxbd->status, RxBD_EMPTY);
|
||||
muram_writew(&rxbd->len, 0);
|
||||
sync();
|
||||
|
||||
/* advance RxBD */
|
||||
rxbd++;
|
||||
rxbd_base = (struct fm_port_bd *)fm_eth->rx_bd_ring;
|
||||
if (rxbd >= (rxbd_base + RX_BD_RING_SIZE))
|
||||
rxbd = rxbd_base;
|
||||
/* read next status */
|
||||
status = muram_readw(&rxbd->status);
|
||||
|
||||
/* update RxQD */
|
||||
offset_out = muram_readw(&pram->rxqd.offset_out);
|
||||
offset_out += sizeof(struct fm_port_bd);
|
||||
if (offset_out >= muram_readw(&pram->rxqd.bd_ring_size))
|
||||
offset_out = 0;
|
||||
muram_writew(&pram->rxqd.offset_out, offset_out);
|
||||
sync();
|
||||
}
|
||||
fm_eth->cur_rxbd = (void *)rxbd;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
|
||||
{
|
||||
struct fsl_enet_mac *mac;
|
||||
int num;
|
||||
void *base, *phyregs = NULL;
|
||||
|
||||
num = fm_eth->num;
|
||||
|
||||
#ifdef CONFIG_SYS_FMAN_V3
|
||||
#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
|
||||
if (fm_eth->type == FM_ETH_10G_E) {
|
||||
/* 10GEC1/10GEC2 use mEMAC9/mEMAC10 on T2080/T4240.
|
||||
* 10GEC3/10GEC4 use mEMAC1/mEMAC2 on T2080.
|
||||
* 10GEC1 uses mEMAC1 on T1024.
|
||||
* so it needs to change the num.
|
||||
*/
|
||||
if (fm_eth->num >= 2)
|
||||
num -= 2;
|
||||
else
|
||||
num += 8;
|
||||
}
|
||||
#endif
|
||||
base = ®->memac[num].fm_memac;
|
||||
phyregs = ®->memac[num].fm_memac_mdio;
|
||||
#else
|
||||
/* Get the mac registers base address */
|
||||
if (fm_eth->type == FM_ETH_1G_E) {
|
||||
base = ®->mac_1g[num].fm_dtesc;
|
||||
phyregs = ®->mac_1g[num].fm_mdio.miimcfg;
|
||||
} else {
|
||||
base = ®->mac_10g[num].fm_10gec;
|
||||
phyregs = ®->mac_10g[num].fm_10gec_mdio;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* alloc mac controller */
|
||||
mac = malloc(sizeof(struct fsl_enet_mac));
|
||||
if (!mac)
|
||||
return -ENOMEM;
|
||||
memset(mac, 0, sizeof(struct fsl_enet_mac));
|
||||
|
||||
/* save the mac to fm_eth struct */
|
||||
fm_eth->mac = mac;
|
||||
|
||||
#ifdef CONFIG_SYS_FMAN_V3
|
||||
init_memac(mac, base, phyregs, MAX_RXBUF_LEN);
|
||||
#else
|
||||
if (fm_eth->type == FM_ETH_1G_E)
|
||||
init_dtsec(mac, base, phyregs, MAX_RXBUF_LEN);
|
||||
else
|
||||
init_tgec(mac, base, phyregs, MAX_RXBUF_LEN);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_phy(struct eth_device *dev)
|
||||
{
|
||||
struct fm_eth *fm_eth = dev->priv;
|
||||
#ifdef CONFIG_PHYLIB
|
||||
struct phy_device *phydev = NULL;
|
||||
u32 supported;
|
||||
#endif
|
||||
|
||||
if (fm_eth->type == FM_ETH_1G_E)
|
||||
dtsec_init_phy(dev);
|
||||
|
||||
#ifdef CONFIG_PHYLIB
|
||||
if (fm_eth->bus) {
|
||||
phydev = phy_connect(fm_eth->bus, fm_eth->phyaddr, dev,
|
||||
fm_eth->enet_if);
|
||||
if (!phydev) {
|
||||
printf("Failed to connect\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fm_eth->type == FM_ETH_1G_E) {
|
||||
supported = (SUPPORTED_10baseT_Half |
|
||||
SUPPORTED_10baseT_Full |
|
||||
SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_1000baseT_Full);
|
||||
} else {
|
||||
supported = SUPPORTED_10000baseT_Full;
|
||||
|
||||
if (tgec_is_fibre(dev))
|
||||
phydev->port = PORT_FIBRE;
|
||||
}
|
||||
|
||||
phydev->supported &= supported;
|
||||
phydev->advertising = phydev->supported;
|
||||
|
||||
fm_eth->phydev = phydev;
|
||||
|
||||
phy_config(phydev);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct fm_eth *fm_eth;
|
||||
int i, num = info->num;
|
||||
int ret;
|
||||
|
||||
/* alloc eth device */
|
||||
dev = (struct eth_device *)malloc(sizeof(struct eth_device));
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
memset(dev, 0, sizeof(struct eth_device));
|
||||
|
||||
/* alloc the FMan ethernet private struct */
|
||||
fm_eth = (struct fm_eth *)malloc(sizeof(struct fm_eth));
|
||||
if (!fm_eth)
|
||||
return -ENOMEM;
|
||||
memset(fm_eth, 0, sizeof(struct fm_eth));
|
||||
|
||||
/* save off some things we need from the info struct */
|
||||
fm_eth->fm_index = info->index - 1; /* keep as 0 based for muram */
|
||||
fm_eth->num = num;
|
||||
fm_eth->type = info->type;
|
||||
|
||||
fm_eth->rx_port = (void *)®->port[info->rx_port_id - 1].fm_bmi;
|
||||
fm_eth->tx_port = (void *)®->port[info->tx_port_id - 1].fm_bmi;
|
||||
|
||||
/* set the ethernet max receive length */
|
||||
fm_eth->max_rx_len = MAX_RXBUF_LEN;
|
||||
|
||||
/* init global mac structure */
|
||||
ret = fm_eth_init_mac(fm_eth, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* keep same as the manual, we call FMAN1, FMAN2, DTSEC1, DTSEC2, etc */
|
||||
if (fm_eth->type == FM_ETH_1G_E)
|
||||
sprintf(dev->name, "FM%d@DTSEC%d", info->index, num + 1);
|
||||
else
|
||||
sprintf(dev->name, "FM%d@TGEC%d", info->index, num + 1);
|
||||
|
||||
devlist[num_controllers++] = dev;
|
||||
dev->iobase = 0;
|
||||
dev->priv = (void *)fm_eth;
|
||||
dev->init = fm_eth_open;
|
||||
dev->halt = fm_eth_halt;
|
||||
dev->send = fm_eth_send;
|
||||
dev->recv = fm_eth_recv;
|
||||
fm_eth->dev = dev;
|
||||
fm_eth->bus = info->bus;
|
||||
fm_eth->phyaddr = info->phy_addr;
|
||||
fm_eth->enet_if = info->enet_if;
|
||||
|
||||
/* startup the FM im */
|
||||
ret = fm_eth_startup(fm_eth);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
init_phy(dev);
|
||||
|
||||
/* clear the ethernet address */
|
||||
for (i = 0; i < 6; i++)
|
||||
dev->enetaddr[i] = 0;
|
||||
eth_register(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
425
sources/uboot-be550/drivers/net/fm/fm.c
Normal file
425
sources/uboot-be550/drivers/net/fm/fm.c
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
* Dave Liu <daveliu@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
#include "fm.h"
|
||||
#include "../../qe/qe.h" /* For struct qe_firmware */
|
||||
|
||||
#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND
|
||||
#include <nand.h>
|
||||
#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
|
||||
#include <spi_flash.h>
|
||||
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
|
||||
#include <mmc.h>
|
||||
#endif
|
||||
|
||||
struct fm_muram muram[CONFIG_SYS_NUM_FMAN];
|
||||
|
||||
void *fm_muram_base(int fm_idx)
|
||||
{
|
||||
return muram[fm_idx].base;
|
||||
}
|
||||
|
||||
void *fm_muram_alloc(int fm_idx, size_t size, ulong align)
|
||||
{
|
||||
void *ret;
|
||||
ulong align_mask;
|
||||
size_t off;
|
||||
void *save;
|
||||
|
||||
align_mask = align - 1;
|
||||
save = muram[fm_idx].alloc;
|
||||
|
||||
off = (ulong)save & align_mask;
|
||||
if (off != 0)
|
||||
muram[fm_idx].alloc += (align - off);
|
||||
off = size & align_mask;
|
||||
if (off != 0)
|
||||
size += (align - off);
|
||||
if ((muram[fm_idx].alloc + size) >= muram[fm_idx].top) {
|
||||
muram[fm_idx].alloc = save;
|
||||
printf("%s: run out of ram.\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = muram[fm_idx].alloc;
|
||||
muram[fm_idx].alloc += size;
|
||||
memset((void *)ret, 0, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fm_init_muram(int fm_idx, void *reg)
|
||||
{
|
||||
void *base = reg;
|
||||
|
||||
muram[fm_idx].base = base;
|
||||
muram[fm_idx].size = CONFIG_SYS_FM_MURAM_SIZE;
|
||||
muram[fm_idx].alloc = base + FM_MURAM_RES_SIZE;
|
||||
muram[fm_idx].top = base + CONFIG_SYS_FM_MURAM_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* fm_upload_ucode - Fman microcode upload worker function
|
||||
*
|
||||
* This function does the actual uploading of an Fman microcode
|
||||
* to an Fman.
|
||||
*/
|
||||
static void fm_upload_ucode(int fm_idx, struct fm_imem *imem,
|
||||
u32 *ucode, unsigned int size)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int timeout = 1000000;
|
||||
|
||||
/* enable address auto increase */
|
||||
out_be32(&imem->iadd, IRAM_IADD_AIE);
|
||||
/* write microcode to IRAM */
|
||||
for (i = 0; i < size / 4; i++)
|
||||
out_be32(&imem->idata, (be32_to_cpu(ucode[i])));
|
||||
|
||||
/* verify if the writing is over */
|
||||
out_be32(&imem->iadd, 0);
|
||||
while ((in_be32(&imem->idata) != be32_to_cpu(ucode[0])) && --timeout)
|
||||
;
|
||||
if (!timeout)
|
||||
printf("Fman%u: microcode upload timeout\n", fm_idx + 1);
|
||||
|
||||
/* enable microcode from IRAM */
|
||||
out_be32(&imem->iready, IRAM_READY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload an Fman firmware
|
||||
*
|
||||
* This function is similar to qe_upload_firmware(), exception that it uploads
|
||||
* a microcode to the Fman instead of the QE.
|
||||
*
|
||||
* Because the process for uploading a microcode to the Fman is similar for
|
||||
* that of the QE, the QE firmware binary format is used for Fman microcode.
|
||||
* It should be possible to unify these two functions, but for now we keep them
|
||||
* separate.
|
||||
*/
|
||||
static int fman_upload_firmware(int fm_idx,
|
||||
struct fm_imem *fm_imem,
|
||||
const struct qe_firmware *firmware)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 crc;
|
||||
size_t calc_size = sizeof(struct qe_firmware);
|
||||
size_t length;
|
||||
const struct qe_header *hdr;
|
||||
|
||||
if (!firmware) {
|
||||
printf("Fman%u: Invalid address for firmware\n", fm_idx + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr = &firmware->header;
|
||||
length = be32_to_cpu(hdr->length);
|
||||
|
||||
/* Check the magic */
|
||||
if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
|
||||
(hdr->magic[2] != 'F')) {
|
||||
printf("Fman%u: Data at %p is not a firmware\n", fm_idx + 1,
|
||||
firmware);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Check the version */
|
||||
if (hdr->version != 1) {
|
||||
printf("Fman%u: Unsupported firmware version %u\n", fm_idx + 1,
|
||||
hdr->version);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Validate some of the fields */
|
||||
if ((firmware->count != 1)) {
|
||||
printf("Fman%u: Invalid data in firmware header\n", fm_idx + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate the length and check if there's a CRC */
|
||||
calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
|
||||
|
||||
for (i = 0; i < firmware->count; i++)
|
||||
/*
|
||||
* For situations where the second RISC uses the same microcode
|
||||
* as the first, the 'code_offset' and 'count' fields will be
|
||||
* zero, so it's okay to add those.
|
||||
*/
|
||||
calc_size += sizeof(u32) *
|
||||
be32_to_cpu(firmware->microcode[i].count);
|
||||
|
||||
/* Validate the length */
|
||||
if (length != calc_size + sizeof(u32)) {
|
||||
printf("Fman%u: Invalid length in firmware header\n",
|
||||
fm_idx + 1);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the CRC. We would normally call crc32_no_comp(), but that
|
||||
* function isn't available unless you turn on JFFS support.
|
||||
*/
|
||||
crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
|
||||
if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
|
||||
printf("Fman%u: Firmware CRC is invalid\n", fm_idx + 1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Loop through each microcode. */
|
||||
for (i = 0; i < firmware->count; i++) {
|
||||
const struct qe_microcode *ucode = &firmware->microcode[i];
|
||||
|
||||
/* Upload a microcode if it's present */
|
||||
if (be32_to_cpu(ucode->code_offset)) {
|
||||
u32 ucode_size;
|
||||
u32 *code;
|
||||
printf("Fman%u: Uploading microcode version %u.%u.%u\n",
|
||||
fm_idx + 1, ucode->major, ucode->minor,
|
||||
ucode->revision);
|
||||
code = (void *)firmware +
|
||||
be32_to_cpu(ucode->code_offset);
|
||||
ucode_size = sizeof(u32) * be32_to_cpu(ucode->count);
|
||||
fm_upload_ucode(fm_idx, fm_imem, code, ucode_size);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 fm_assign_risc(int port_id)
|
||||
{
|
||||
u32 risc_sel, val;
|
||||
risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1;
|
||||
val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK;
|
||||
val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void fm_init_fpm(struct fm_fpm *fpm)
|
||||
{
|
||||
int i, port_id;
|
||||
u32 val;
|
||||
|
||||
setbits_be32(&fpm->fmfpee, FMFPEE_EHM | FMFPEE_UEC |
|
||||
FMFPEE_CER | FMFPEE_DER);
|
||||
|
||||
/* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */
|
||||
|
||||
/* offline/parser port */
|
||||
for (i = 0; i < MAX_NUM_OH_PORT; i++) {
|
||||
port_id = OH_PORT_ID_BASE + i;
|
||||
val = fm_assign_risc(port_id);
|
||||
out_be32(&fpm->fpmprc, val);
|
||||
}
|
||||
/* Rx 1G port */
|
||||
for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
|
||||
port_id = RX_PORT_1G_BASE + i;
|
||||
val = fm_assign_risc(port_id);
|
||||
out_be32(&fpm->fpmprc, val);
|
||||
}
|
||||
/* Tx 1G port */
|
||||
for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
|
||||
port_id = TX_PORT_1G_BASE + i;
|
||||
val = fm_assign_risc(port_id);
|
||||
out_be32(&fpm->fpmprc, val);
|
||||
}
|
||||
/* Rx 10G port */
|
||||
port_id = RX_PORT_10G_BASE;
|
||||
val = fm_assign_risc(port_id);
|
||||
out_be32(&fpm->fpmprc, val);
|
||||
/* Tx 10G port */
|
||||
port_id = TX_PORT_10G_BASE;
|
||||
val = fm_assign_risc(port_id);
|
||||
out_be32(&fpm->fpmprc, val);
|
||||
|
||||
/* disable the dispatch limit in IM case */
|
||||
out_be32(&fpm->fpmflc, FMFP_FLC_DISP_LIM_NONE);
|
||||
/* clear events */
|
||||
out_be32(&fpm->fmfpee, FMFPEE_CLEAR_EVENT);
|
||||
|
||||
/* clear risc events */
|
||||
for (i = 0; i < 4; i++)
|
||||
out_be32(&fpm->fpmcev[i], 0xffffffff);
|
||||
|
||||
/* clear error */
|
||||
out_be32(&fpm->fpmrcr, FMFP_RCR_MDEC | FMFP_RCR_IDEC);
|
||||
}
|
||||
|
||||
static int fm_init_bmi(int fm_idx, struct fm_bmi_common *bmi)
|
||||
{
|
||||
int blk, i, port_id;
|
||||
u32 val;
|
||||
size_t offset;
|
||||
void *base;
|
||||
|
||||
/* alloc free buffer pool in MURAM */
|
||||
base = fm_muram_alloc(fm_idx, FM_FREE_POOL_SIZE, FM_FREE_POOL_ALIGN);
|
||||
if (!base) {
|
||||
printf("%s: no muram for free buffer pool\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
offset = base - fm_muram_base(fm_idx);
|
||||
|
||||
/* Need 128KB total free buffer pool size */
|
||||
val = offset / 256;
|
||||
blk = FM_FREE_POOL_SIZE / 256;
|
||||
/* in IM, we must not begin from offset 0 in MURAM */
|
||||
val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT);
|
||||
out_be32(&bmi->fmbm_cfg1, val);
|
||||
|
||||
/* disable all BMI interrupt */
|
||||
out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL);
|
||||
|
||||
/* clear all events */
|
||||
out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL);
|
||||
|
||||
/*
|
||||
* set port parameters - FMBM_PP_x
|
||||
* max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1
|
||||
* max dma 10G Rx/Tx=3, others is 1
|
||||
* set port FIFO size - FMBM_PFS_x
|
||||
* 4KB for all Rx and Tx ports
|
||||
*/
|
||||
/* offline/parser port */
|
||||
for (i = 0; i < MAX_NUM_OH_PORT; i++) {
|
||||
port_id = OH_PORT_ID_BASE + i - 1;
|
||||
/* max tasks=1, max dma=1, no extra */
|
||||
out_be32(&bmi->fmbm_pp[port_id], 0);
|
||||
/* port FIFO size - 256 bytes, no extra */
|
||||
out_be32(&bmi->fmbm_pfs[port_id], 0);
|
||||
}
|
||||
/* Rx 1G port */
|
||||
for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
|
||||
port_id = RX_PORT_1G_BASE + i - 1;
|
||||
/* max tasks=4, max dma=1, no extra */
|
||||
out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
|
||||
/* FIFO size - 4KB, no extra */
|
||||
out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
|
||||
}
|
||||
/* Tx 1G port FIFO size - 4KB, no extra */
|
||||
for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
|
||||
port_id = TX_PORT_1G_BASE + i - 1;
|
||||
/* max tasks=4, max dma=1, no extra */
|
||||
out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
|
||||
/* FIFO size - 4KB, no extra */
|
||||
out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
|
||||
}
|
||||
/* Rx 10G port */
|
||||
port_id = RX_PORT_10G_BASE - 1;
|
||||
/* max tasks=12, max dma=3, no extra */
|
||||
out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
|
||||
/* FIFO size - 4KB, no extra */
|
||||
out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
|
||||
|
||||
/* Tx 10G port */
|
||||
port_id = TX_PORT_10G_BASE - 1;
|
||||
/* max tasks=12, max dma=3, no extra */
|
||||
out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
|
||||
/* FIFO size - 4KB, no extra */
|
||||
out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
|
||||
|
||||
/* initialize internal buffers data base (linked list) */
|
||||
out_be32(&bmi->fmbm_init, FMBM_INIT_START);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fm_init_qmi(struct fm_qmi_common *qmi)
|
||||
{
|
||||
/* disable enqueue and dequeue of QMI */
|
||||
clrbits_be32(&qmi->fmqm_gc, FMQM_GC_ENQ_EN | FMQM_GC_DEQ_EN);
|
||||
|
||||
/* disable all error interrupts */
|
||||
out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL);
|
||||
/* clear all error events */
|
||||
out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL);
|
||||
|
||||
/* disable all interrupts */
|
||||
out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL);
|
||||
/* clear all interrupts */
|
||||
out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL);
|
||||
}
|
||||
|
||||
/* Init common part of FM, index is fm num# like fm as above */
|
||||
int fm_init_common(int index, struct ccsr_fman *reg)
|
||||
{
|
||||
int rc;
|
||||
#if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR)
|
||||
void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR;
|
||||
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND)
|
||||
size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
|
||||
void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
|
||||
|
||||
rc = nand_read(&nand_info[0], (loff_t)CONFIG_SYS_FMAN_FW_ADDR,
|
||||
&fw_length, (u_char *)addr);
|
||||
if (rc == -EUCLEAN) {
|
||||
printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
|
||||
CONFIG_SYS_FMAN_FW_ADDR, rc);
|
||||
}
|
||||
#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
|
||||
struct spi_flash *ucode_flash;
|
||||
void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
|
||||
int ret = 0;
|
||||
|
||||
ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
|
||||
CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
|
||||
if (!ucode_flash)
|
||||
printf("SF: probe for ucode failed\n");
|
||||
else {
|
||||
ret = spi_flash_read(ucode_flash, CONFIG_SYS_FMAN_FW_ADDR,
|
||||
CONFIG_SYS_QE_FMAN_FW_LENGTH, addr);
|
||||
if (ret)
|
||||
printf("SF: read for ucode failed\n");
|
||||
spi_flash_free(ucode_flash);
|
||||
}
|
||||
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
|
||||
int dev = CONFIG_SYS_MMC_ENV_DEV;
|
||||
void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
|
||||
u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
|
||||
u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512;
|
||||
struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
|
||||
|
||||
if (!mmc)
|
||||
printf("\nMMC cannot find device for ucode\n");
|
||||
else {
|
||||
printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
|
||||
dev, blk, cnt);
|
||||
mmc_init(mmc);
|
||||
(void)mmc->block_dev.block_read(dev, blk, cnt, addr);
|
||||
/* flush cache after read */
|
||||
flush_cache((ulong)addr, cnt * 512);
|
||||
}
|
||||
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_REMOTE)
|
||||
void *addr = (void *)CONFIG_SYS_FMAN_FW_ADDR;
|
||||
#else
|
||||
void *addr = NULL;
|
||||
#endif
|
||||
|
||||
/* Upload the Fman microcode if it's present */
|
||||
rc = fman_upload_firmware(index, ®->fm_imem, addr);
|
||||
if (rc)
|
||||
return rc;
|
||||
setenv_addr("fman_ucode", addr);
|
||||
|
||||
fm_init_muram(index, ®->muram);
|
||||
fm_init_qmi(®->fm_qmi_common);
|
||||
fm_init_fpm(®->fm_fpm);
|
||||
|
||||
/* clear DMA status */
|
||||
setbits_be32(®->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
|
||||
|
||||
/* set DMA mode */
|
||||
setbits_be32(®->fm_dma.fmdmmr, FMDMMR_SBER);
|
||||
|
||||
return fm_init_bmi(index, ®->fm_bmi_common);
|
||||
}
|
||||
149
sources/uboot-be550/drivers/net/fm/fm.h
Normal file
149
sources/uboot-be550/drivers/net/fm/fm.h
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __FM_H__
|
||||
#define __FM_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <fsl_fman.h>
|
||||
|
||||
/* Port ID */
|
||||
#define OH_PORT_ID_BASE 0x01
|
||||
#define MAX_NUM_OH_PORT 7
|
||||
#define RX_PORT_1G_BASE 0x08
|
||||
#define MAX_NUM_RX_PORT_1G CONFIG_SYS_NUM_FM1_DTSEC
|
||||
#define RX_PORT_10G_BASE 0x10
|
||||
#define RX_PORT_10G_BASE2 0x08
|
||||
#define TX_PORT_1G_BASE 0x28
|
||||
#define MAX_NUM_TX_PORT_1G CONFIG_SYS_NUM_FM1_DTSEC
|
||||
#define TX_PORT_10G_BASE 0x30
|
||||
#define TX_PORT_10G_BASE2 0x28
|
||||
#define MIIM_TIMEOUT 0xFFFF
|
||||
|
||||
struct fm_muram {
|
||||
void *base;
|
||||
void *top;
|
||||
size_t size;
|
||||
void *alloc;
|
||||
};
|
||||
#define FM_MURAM_RES_SIZE 0x01000
|
||||
|
||||
/* Rx/Tx buffer descriptor */
|
||||
struct fm_port_bd {
|
||||
u16 status;
|
||||
u16 len;
|
||||
u32 res0;
|
||||
u16 res1;
|
||||
u16 buf_ptr_hi;
|
||||
u32 buf_ptr_lo;
|
||||
};
|
||||
|
||||
/* Common BD flags */
|
||||
#define BD_LAST 0x0800
|
||||
|
||||
/* Rx BD status flags */
|
||||
#define RxBD_EMPTY 0x8000
|
||||
#define RxBD_LAST BD_LAST
|
||||
#define RxBD_FIRST 0x0400
|
||||
#define RxBD_PHYS_ERR 0x0008
|
||||
#define RxBD_SIZE_ERR 0x0004
|
||||
#define RxBD_ERROR (RxBD_PHYS_ERR | RxBD_SIZE_ERR)
|
||||
|
||||
/* Tx BD status flags */
|
||||
#define TxBD_READY 0x8000
|
||||
#define TxBD_LAST BD_LAST
|
||||
|
||||
/* Rx/Tx queue descriptor */
|
||||
struct fm_port_qd {
|
||||
u16 gen;
|
||||
u16 bd_ring_base_hi;
|
||||
u32 bd_ring_base_lo;
|
||||
u16 bd_ring_size;
|
||||
u16 offset_in;
|
||||
u16 offset_out;
|
||||
u16 res0;
|
||||
u32 res1[0x4];
|
||||
};
|
||||
|
||||
/* IM global parameter RAM */
|
||||
struct fm_port_global_pram {
|
||||
u32 mode; /* independent mode register */
|
||||
u32 rxqd_ptr; /* Rx queue descriptor pointer */
|
||||
u32 txqd_ptr; /* Tx queue descriptor pointer */
|
||||
u16 mrblr; /* max Rx buffer length */
|
||||
u16 rxqd_bsy_cnt; /* RxQD busy counter, should be cleared */
|
||||
u32 res0[0x4];
|
||||
struct fm_port_qd rxqd; /* Rx queue descriptor */
|
||||
struct fm_port_qd txqd; /* Tx queue descriptor */
|
||||
u32 res1[0x28];
|
||||
};
|
||||
|
||||
#define FM_PRAM_SIZE sizeof(struct fm_port_global_pram)
|
||||
#define FM_PRAM_ALIGN 256
|
||||
#define PRAM_MODE_GLOBAL 0x20000000
|
||||
#define PRAM_MODE_GRACEFUL_STOP 0x00800000
|
||||
|
||||
#if defined(CONFIG_P1017) || defined(CONFIG_P1023)
|
||||
#define FM_FREE_POOL_SIZE 0x2000 /* 8K bytes */
|
||||
#else
|
||||
#define FM_FREE_POOL_SIZE 0x20000 /* 128K bytes */
|
||||
#endif
|
||||
#define FM_FREE_POOL_ALIGN 256
|
||||
|
||||
void *fm_muram_alloc(int fm_idx, size_t size, ulong align);
|
||||
void *fm_muram_base(int fm_idx);
|
||||
int fm_init_common(int index, struct ccsr_fman *reg);
|
||||
int fm_eth_initialize(struct ccsr_fman *reg, struct fm_eth_info *info);
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port);
|
||||
void fman_disable_port(enum fm_port port);
|
||||
void fman_enable_port(enum fm_port port);
|
||||
|
||||
struct fsl_enet_mac {
|
||||
void *base; /* MAC controller registers base address */
|
||||
void *phyregs;
|
||||
int max_rx_len;
|
||||
void (*init_mac)(struct fsl_enet_mac *mac);
|
||||
void (*enable_mac)(struct fsl_enet_mac *mac);
|
||||
void (*disable_mac)(struct fsl_enet_mac *mac);
|
||||
void (*set_mac_addr)(struct fsl_enet_mac *mac, u8 *mac_addr);
|
||||
void (*set_if_mode)(struct fsl_enet_mac *mac, phy_interface_t type,
|
||||
int speed);
|
||||
};
|
||||
|
||||
/* Fman ethernet private struct */
|
||||
struct fm_eth {
|
||||
int fm_index; /* Fman index */
|
||||
u32 num; /* 0..n-1 for give type */
|
||||
struct fm_bmi_tx_port *tx_port;
|
||||
struct fm_bmi_rx_port *rx_port;
|
||||
enum fm_eth_type type; /* 1G or 10G ethernet */
|
||||
phy_interface_t enet_if;
|
||||
struct fsl_enet_mac *mac; /* MAC controller */
|
||||
struct mii_dev *bus;
|
||||
struct phy_device *phydev;
|
||||
int phyaddr;
|
||||
struct eth_device *dev;
|
||||
int max_rx_len;
|
||||
struct fm_port_global_pram *rx_pram; /* Rx parameter table */
|
||||
struct fm_port_global_pram *tx_pram; /* Tx parameter table */
|
||||
void *rx_bd_ring; /* Rx BD ring base */
|
||||
void *cur_rxbd; /* current Rx BD */
|
||||
void *rx_buf; /* Rx buffer base */
|
||||
void *tx_bd_ring; /* Tx BD ring base */
|
||||
void *cur_txbd; /* current Tx BD */
|
||||
};
|
||||
|
||||
#define RX_BD_RING_SIZE 8
|
||||
#define TX_BD_RING_SIZE 8
|
||||
#define MAX_RXBUF_LOG2 11
|
||||
#define MAX_RXBUF_LEN (1 << MAX_RXBUF_LOG2)
|
||||
|
||||
#define PORT_IS_ENABLED(port) (fm_port_to_index(port) == -1 ? \
|
||||
0 : fm_info[fm_port_to_index(port)].enabled)
|
||||
|
||||
#endif /* __FM_H__ */
|
||||
381
sources/uboot-be550/drivers/net/fm/init.c
Normal file
381
sources/uboot-be550/drivers/net/fm/init.c
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright 2011-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_mdio.h>
|
||||
#ifdef CONFIG_FSL_LAYERSCAPE
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#else
|
||||
#include <asm/fsl_serdes.h>
|
||||
#endif
|
||||
|
||||
#include "fm.h"
|
||||
|
||||
struct fm_eth_info fm_info[] = {
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 1)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 1),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 2)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 2),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 3)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 3),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 4)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 4),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 5)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 5),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 6)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 6),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 7)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 9),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_DTSEC >= 8)
|
||||
FM_DTSEC_INFO_INITIALIZER(1, 10),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 1)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 1),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 2)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 2),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 3)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 3),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 4)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 4),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 5)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 5),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 6)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 6),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 7)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 9),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 8)
|
||||
FM_DTSEC_INFO_INITIALIZER(2, 10),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_10GEC >= 1)
|
||||
FM_TGEC_INFO_INITIALIZER(1, 1),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_10GEC >= 2)
|
||||
FM_TGEC_INFO_INITIALIZER(1, 2),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_10GEC >= 3)
|
||||
FM_TGEC_INFO_INITIALIZER2(1, 3),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM1_10GEC >= 4)
|
||||
FM_TGEC_INFO_INITIALIZER2(1, 4),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_10GEC >= 1)
|
||||
FM_TGEC_INFO_INITIALIZER(2, 1),
|
||||
#endif
|
||||
#if (CONFIG_SYS_NUM_FM2_10GEC >= 2)
|
||||
FM_TGEC_INFO_INITIALIZER(2, 2),
|
||||
#endif
|
||||
};
|
||||
|
||||
int fm_standard_init(bd_t *bis)
|
||||
{
|
||||
int i;
|
||||
struct ccsr_fman *reg;
|
||||
|
||||
reg = (void *)CONFIG_SYS_FSL_FM1_ADDR;
|
||||
if (fm_init_common(0, reg))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
|
||||
if ((fm_info[i].enabled) && (fm_info[i].index == 1))
|
||||
fm_eth_initialize(reg, &fm_info[i]);
|
||||
}
|
||||
|
||||
#if (CONFIG_SYS_NUM_FMAN == 2)
|
||||
reg = (void *)CONFIG_SYS_FSL_FM2_ADDR;
|
||||
if (fm_init_common(1, reg))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
|
||||
if ((fm_info[i].enabled) && (fm_info[i].index == 2))
|
||||
fm_eth_initialize(reg, &fm_info[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* simple linear search to map from port to array index */
|
||||
static int fm_port_to_index(enum fm_port port)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
|
||||
if (fm_info[i].port == port)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if an interface is actually active based on HW config
|
||||
* we expect fman_port_enet_if() to report PHY_INTERFACE_MODE_NONE if
|
||||
* the interface is not active based on HW cfg of the SoC
|
||||
*/
|
||||
void fman_enet_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
|
||||
phy_interface_t enet_if;
|
||||
|
||||
enet_if = fman_port_enet_if(fm_info[i].port);
|
||||
if (enet_if != PHY_INTERFACE_MODE_NONE) {
|
||||
fm_info[i].enabled = 1;
|
||||
fm_info[i].enet_if = enet_if;
|
||||
} else {
|
||||
fm_info[i].enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
void fm_disable_port(enum fm_port port)
|
||||
{
|
||||
int i = fm_port_to_index(port);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
|
||||
fm_info[i].enabled = 0;
|
||||
#ifndef CONFIG_SYS_FMAN_V3
|
||||
fman_disable_port(port);
|
||||
#endif
|
||||
}
|
||||
|
||||
void fm_enable_port(enum fm_port port)
|
||||
{
|
||||
int i = fm_port_to_index(port);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
|
||||
fm_info[i].enabled = 1;
|
||||
fman_enable_port(port);
|
||||
}
|
||||
|
||||
void fm_info_set_mdio(enum fm_port port, struct mii_dev *bus)
|
||||
{
|
||||
int i = fm_port_to_index(port);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
|
||||
fm_info[i].bus = bus;
|
||||
}
|
||||
|
||||
void fm_info_set_phy_address(enum fm_port port, int address)
|
||||
{
|
||||
int i = fm_port_to_index(port);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
|
||||
fm_info[i].phy_addr = address;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the PHY address for a given Fman port
|
||||
*
|
||||
* The port must be set via a prior call to fm_info_set_phy_address().
|
||||
* A negative error code is returned if the port is invalid.
|
||||
*/
|
||||
int fm_info_get_phy_address(enum fm_port port)
|
||||
{
|
||||
int i = fm_port_to_index(port);
|
||||
|
||||
if (i == -1)
|
||||
return -1;
|
||||
|
||||
return fm_info[i].phy_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the type of the data interface between the given MAC and its PHY.
|
||||
* This is typically determined by the RCW.
|
||||
*/
|
||||
phy_interface_t fm_info_get_enet_if(enum fm_port port)
|
||||
{
|
||||
int i = fm_port_to_index(port);
|
||||
|
||||
if (i == -1)
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if (fm_info[i].enabled)
|
||||
return fm_info[i].enet_if;
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
__def_board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
|
||||
enum fm_port port, int offset)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
|
||||
enum fm_port port, int offset)
|
||||
__attribute__((weak, alias("__def_board_ft_fman_fixup_port")));
|
||||
|
||||
int ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
|
||||
{
|
||||
int off;
|
||||
uint32_t ph;
|
||||
phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset;
|
||||
#ifndef CONFIG_SYS_FMAN_V3
|
||||
u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS +
|
||||
CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET;
|
||||
#endif
|
||||
|
||||
off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
|
||||
if (off == -FDT_ERR_NOTFOUND)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->enabled) {
|
||||
fdt_fixup_phy_connection(blob, off, info->enet_if);
|
||||
board_ft_fman_fixup_port(blob, prop, paddr, info->port, off);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_FMAN_V3
|
||||
#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
|
||||
/*
|
||||
* On T2/T4 SoCs, physically FM1_DTSEC9 and FM1_10GEC1 use the same
|
||||
* dual-role MAC, when FM1_10GEC1 is enabled and FM1_DTSEC9
|
||||
* is disabled, ensure that the dual-role MAC is not disabled,
|
||||
* ditto for other dual-role MACs.
|
||||
*/
|
||||
if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
|
||||
((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
|
||||
((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC3))) ||
|
||||
((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC4))) ||
|
||||
((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) ||
|
||||
((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) ||
|
||||
((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC1))) ||
|
||||
((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC2)))
|
||||
#if (CONFIG_SYS_NUM_FMAN == 2)
|
||||
||
|
||||
((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) ||
|
||||
((info->port == FM2_DTSEC10) && (PORT_IS_ENABLED(FM2_10GEC2))) ||
|
||||
((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) ||
|
||||
((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10)))
|
||||
#endif
|
||||
#else
|
||||
/* FM1_DTSECx and FM1_10GECx use the same dual-role MAC */
|
||||
if (((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
|
||||
((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
|
||||
((info->port == FM1_DTSEC3) && (PORT_IS_ENABLED(FM1_10GEC3))) ||
|
||||
((info->port == FM1_DTSEC4) && (PORT_IS_ENABLED(FM1_10GEC4))) ||
|
||||
((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC1))) ||
|
||||
((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC2))) ||
|
||||
((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC3))) ||
|
||||
((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC4)))
|
||||
#endif
|
||||
)
|
||||
return 0;
|
||||
#endif
|
||||
/* board code might have caused offset to change */
|
||||
off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
|
||||
|
||||
#ifndef CONFIG_SYS_FMAN_V3
|
||||
/* Don't disable FM1-DTSEC1 MAC as its used for MDIO */
|
||||
if (paddr != dtsec1_addr)
|
||||
#endif
|
||||
fdt_status_disabled(blob, off); /* disable the MAC node */
|
||||
|
||||
/* disable the fsl,dpa-ethernet node that points to the MAC */
|
||||
ph = fdt_get_phandle(blob, off);
|
||||
do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph),
|
||||
"status", "disabled", strlen("disabled") + 1, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fdt_fixup_fman_ethernet(void *blob)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_SYS_FMAN_V3
|
||||
for (i = 0; i < ARRAY_SIZE(fm_info); i++)
|
||||
ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac");
|
||||
#else
|
||||
for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
|
||||
/* Try the new compatible first.
|
||||
* If the node is missing, try the old.
|
||||
*/
|
||||
if (fm_info[i].type == FM_ETH_1G_E) {
|
||||
if (ft_fixup_port(blob, &fm_info[i], "fsl,fman-dtsec"))
|
||||
ft_fixup_port(blob, &fm_info[i],
|
||||
"fsl,fman-1g-mac");
|
||||
} else {
|
||||
if (ft_fixup_port(blob, &fm_info[i], "fsl,fman-tgec"))
|
||||
ft_fixup_port(blob, &fm_info[i],
|
||||
"fsl,fman-10g-mac");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*QSGMII Riser Card can work in SGMII mode, but the PHY address is different.
|
||||
*This function scans which Riser Card being used(QSGMII or SGMII Riser Card),
|
||||
*then set the correct PHY address
|
||||
*/
|
||||
void set_sgmii_phy(struct mii_dev *bus, enum fm_port base_port,
|
||||
unsigned int port_num, int phy_base_addr)
|
||||
{
|
||||
unsigned int regnum = 0;
|
||||
int qsgmii;
|
||||
int i;
|
||||
int phy_real_addr;
|
||||
|
||||
qsgmii = is_qsgmii_riser_card(bus, phy_base_addr, port_num, regnum);
|
||||
|
||||
if (!qsgmii)
|
||||
return;
|
||||
|
||||
for (i = base_port; i < base_port + port_num; i++) {
|
||||
if (fm_info_get_enet_if(i) == PHY_INTERFACE_MODE_SGMII) {
|
||||
phy_real_addr = phy_base_addr + i - base_port;
|
||||
fm_info_set_phy_address(i, phy_real_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*to check whether qsgmii riser card is used*/
|
||||
int is_qsgmii_riser_card(struct mii_dev *bus, int phy_base_addr,
|
||||
unsigned int port_num, unsigned regnum)
|
||||
{
|
||||
int i;
|
||||
int val;
|
||||
|
||||
if (!bus)
|
||||
return 0;
|
||||
|
||||
for (i = phy_base_addr; i < phy_base_addr + port_num; i++) {
|
||||
val = bus->read(bus, i, MDIO_DEVAD_NONE, regnum);
|
||||
if (val != MIIM_TIMEOUT)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
112
sources/uboot-be550/drivers/net/fm/ls1043.c
Normal file
112
sources/uboot-be550/drivers/net/fm/ls1043.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
|
||||
#define FSL_CHASSIS2_RCWSR13_EC1 0xe0000000 /* bits 416..418 */
|
||||
#define FSL_CHASSIS2_RCWSR13_EC1_DTSEC3_RGMII 0x00000000
|
||||
#define FSL_CHASSIS2_RCWSR13_EC1_GPIO 0x20000000
|
||||
#define FSL_CHASSIS2_RCWSR13_EC1_FTM 0xa0000000
|
||||
#define FSL_CHASSIS2_RCWSR13_EC2 0x1c000000 /* bits 419..421 */
|
||||
#define FSL_CHASSIS2_RCWSR13_EC2_DTSEC4_RGMII 0x00000000
|
||||
#define FSL_CHASSIS2_RCWSR13_EC2_GPIO 0x04000000
|
||||
#define FSL_CHASSIS2_RCWSR13_EC2_1588 0x08000000
|
||||
#define FSL_CHASSIS2_RCWSR13_EC2_FTM 0x14000000
|
||||
|
||||
u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CHASSIS2_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CHASSIS2_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CHASSIS2_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CHASSIS2_DEVDISR2_DTSEC1_4,
|
||||
[FM1_DTSEC5] = FSL_CHASSIS2_DEVDISR2_DTSEC1_5,
|
||||
[FM1_DTSEC6] = FSL_CHASSIS2_DEVDISR2_DTSEC1_6,
|
||||
[FM1_DTSEC9] = FSL_CHASSIS2_DEVDISR2_DTSEC1_9,
|
||||
[FM1_DTSEC10] = FSL_CHASSIS2_DEVDISR2_DTSEC1_10,
|
||||
[FM1_10GEC1] = FSL_CHASSIS2_DEVDISR2_10GEC1_1,
|
||||
[FM1_10GEC2] = FSL_CHASSIS2_DEVDISR2_10GEC1_2,
|
||||
[FM1_10GEC3] = FSL_CHASSIS2_DEVDISR2_10GEC1_3,
|
||||
[FM1_10GEC4] = FSL_CHASSIS2_DEVDISR2_10GEC1_4,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1) && (is_serdes_configured(XFI_FM1_MAC9)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM1_DTSEC9) && (is_serdes_configured(XFI_FM1_MAC9)))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if (port == FM1_DTSEC3)
|
||||
if ((rcwsr13 & FSL_CHASSIS2_RCWSR13_EC1) ==
|
||||
FSL_CHASSIS2_RCWSR13_EC1_DTSEC3_RGMII) {
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
}
|
||||
if (port == FM1_DTSEC4)
|
||||
if ((rcwsr13 & FSL_CHASSIS2_RCWSR13_EC2) ==
|
||||
FSL_CHASSIS2_RCWSR13_EC2_DTSEC4_RGMII) {
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
}
|
||||
|
||||
/* handle SGMII */
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
if ((port == FM1_DTSEC2) &&
|
||||
is_serdes_configured(SGMII_2500_FM1_DTSEC2))
|
||||
return PHY_INTERFACE_MODE_SGMII_2500;
|
||||
case FM1_DTSEC5:
|
||||
case FM1_DTSEC6:
|
||||
case FM1_DTSEC9:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
else if ((port == FM1_DTSEC9) &&
|
||||
is_serdes_configured(SGMII_2500_FM1_DTSEC9))
|
||||
return PHY_INTERFACE_MODE_SGMII_2500;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* handle QSGMII */
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC5:
|
||||
case FM1_DTSEC6:
|
||||
/* only MAC 1,2,5,6 available for QSGMII */
|
||||
if (is_serdes_configured(QSGMII_FM1_A))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
142
sources/uboot-be550/drivers/net/fm/memac.c
Normal file
142
sources/uboot-be550/drivers/net/fm/memac.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Roy Zang <tie-fei.zang@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* MAXFRM - maximum frame length */
|
||||
#define MAXFRM_MASK 0x0000ffff
|
||||
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_memac.h>
|
||||
|
||||
#include "fm.h"
|
||||
|
||||
static void memac_init_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct memac *regs = mac->base;
|
||||
|
||||
/* mask all interrupt */
|
||||
out_be32(®s->imask, IMASK_MASK_ALL);
|
||||
|
||||
/* clear all events */
|
||||
out_be32(®s->ievent, IEVENT_CLEAR_ALL);
|
||||
|
||||
/* set the max receive length */
|
||||
out_be32(®s->maxfrm, mac->max_rx_len & MAXFRM_MASK);
|
||||
|
||||
/* multicast frame reception for the hash entry disable */
|
||||
out_be32(®s->hashtable_ctrl, 0);
|
||||
}
|
||||
|
||||
static void memac_enable_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct memac *regs = mac->base;
|
||||
|
||||
setbits_be32(®s->command_config,
|
||||
MEMAC_CMD_CFG_RXTX_EN | MEMAC_CMD_CFG_NO_LEN_CHK);
|
||||
}
|
||||
|
||||
static void memac_disable_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct memac *regs = mac->base;
|
||||
|
||||
clrbits_be32(®s->command_config, MEMAC_CMD_CFG_RXTX_EN);
|
||||
}
|
||||
|
||||
static void memac_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
|
||||
{
|
||||
struct memac *regs = mac->base;
|
||||
u32 mac_addr0, mac_addr1;
|
||||
|
||||
/*
|
||||
* if a station address of 0x12345678ABCD, perform a write to
|
||||
* MAC_ADDR0 of 0x78563412, MAC_ADDR1 of 0x0000CDAB
|
||||
*/
|
||||
mac_addr0 = (mac_addr[3] << 24) | (mac_addr[2] << 16) | \
|
||||
(mac_addr[1] << 8) | (mac_addr[0]);
|
||||
out_be32(®s->mac_addr_0, mac_addr0);
|
||||
|
||||
mac_addr1 = ((mac_addr[5] << 8) | mac_addr[4]) & 0x0000ffff;
|
||||
out_be32(®s->mac_addr_1, mac_addr1);
|
||||
}
|
||||
|
||||
static void memac_set_interface_mode(struct fsl_enet_mac *mac,
|
||||
phy_interface_t type, int speed)
|
||||
{
|
||||
/* Roy need more work here */
|
||||
|
||||
struct memac *regs = mac->base;
|
||||
u32 if_mode, if_status;
|
||||
|
||||
/* clear all bits relative with interface mode */
|
||||
if_mode = in_be32(®s->if_mode);
|
||||
if_status = in_be32(®s->if_status);
|
||||
|
||||
/* set interface mode */
|
||||
switch (type) {
|
||||
case PHY_INTERFACE_MODE_GMII:
|
||||
if_mode &= ~IF_MODE_MASK;
|
||||
if_mode |= IF_MODE_GMII;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
if_mode |= (IF_MODE_GMII | IF_MODE_RG);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RMII:
|
||||
if_mode |= (IF_MODE_GMII | IF_MODE_RM);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
||||
if_mode &= ~IF_MODE_MASK;
|
||||
if_mode |= (IF_MODE_GMII);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_XGMII:
|
||||
if_mode &= ~IF_MODE_MASK;
|
||||
if_mode |= IF_MODE_XGMII;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Enable automatic speed selection for Non-XGMII */
|
||||
if (type != PHY_INTERFACE_MODE_XGMII)
|
||||
if_mode |= IF_MODE_EN_AUTO;
|
||||
|
||||
if (type == PHY_INTERFACE_MODE_RGMII) {
|
||||
if_mode &= ~IF_MODE_EN_AUTO;
|
||||
if_mode &= ~IF_MODE_SETSP_MASK;
|
||||
switch (speed) {
|
||||
case SPEED_1000:
|
||||
if_mode |= IF_MODE_SETSP_1000M;
|
||||
break;
|
||||
case SPEED_100:
|
||||
if_mode |= IF_MODE_SETSP_100M;
|
||||
break;
|
||||
case SPEED_10:
|
||||
if_mode |= IF_MODE_SETSP_10M;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug(" %s, if_mode = %x\n", __func__, if_mode);
|
||||
debug(" %s, if_status = %x\n", __func__, if_status);
|
||||
out_be32(®s->if_mode, if_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
void init_memac(struct fsl_enet_mac *mac, void *base,
|
||||
void *phyregs, int max_rx_len)
|
||||
{
|
||||
mac->base = base;
|
||||
mac->phyregs = phyregs;
|
||||
mac->max_rx_len = max_rx_len;
|
||||
mac->init_mac = memac_init_mac;
|
||||
mac->enable_mac = memac_enable_mac;
|
||||
mac->disable_mac = memac_disable_mac;
|
||||
mac->set_mac_addr = memac_set_mac_addr;
|
||||
mac->set_if_mode = memac_set_interface_mode;
|
||||
}
|
||||
170
sources/uboot-be550/drivers/net/fm/memac_phy.c
Normal file
170
sources/uboot-be550/drivers/net/fm/memac_phy.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Andy Fleming <afleming@gmail.com>
|
||||
* Roy Zang <tie-fei.zang@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
* Some part is taken from tsec.c
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_memac.h>
|
||||
#include <fm_eth.h>
|
||||
|
||||
#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN
|
||||
#define memac_out_32(a, v) out_le32(a, v)
|
||||
#define memac_clrbits_32(a, v) clrbits_le32(a, v)
|
||||
#define memac_setbits_32(a, v) setbits_le32(a, v)
|
||||
#else
|
||||
#define memac_out_32(a, v) out_be32(a, v)
|
||||
#define memac_clrbits_32(a, v) clrbits_be32(a, v)
|
||||
#define memac_setbits_32(a, v) setbits_be32(a, v)
|
||||
#endif
|
||||
|
||||
static u32 memac_in_32(u32 *reg)
|
||||
{
|
||||
#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN
|
||||
return in_le32(reg);
|
||||
#else
|
||||
return in_be32(reg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write value to the PHY for this device to the register at regnum, waiting
|
||||
* until the write is done before it returns. All PHY configuration has to be
|
||||
* done through the TSEC1 MIIM regs
|
||||
*/
|
||||
int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
u32 mdio_ctl;
|
||||
struct memac_mdio_controller *regs = bus->priv;
|
||||
u32 c45 = 1; /* Default to 10G interface */
|
||||
|
||||
if (dev_addr == MDIO_DEVAD_NONE) {
|
||||
c45 = 0; /* clause 22 */
|
||||
dev_addr = regnum & 0x1f;
|
||||
memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
||||
} else
|
||||
memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Set the port and dev addr */
|
||||
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
|
||||
memac_out_32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Set the register address */
|
||||
if (c45)
|
||||
memac_out_32(®s->mdio_addr, regnum & 0xffff);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Write the value to the register */
|
||||
memac_out_32(®s->mdio_data, MDIO_DATA(value));
|
||||
|
||||
/* Wait till the MDIO write is complete */
|
||||
while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads from register regnum in the PHY for device dev, returning the value.
|
||||
* Clears miimcom first. All PHY configuration has to be done through the
|
||||
* TSEC1 MIIM regs
|
||||
*/
|
||||
int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
|
||||
int regnum)
|
||||
{
|
||||
u32 mdio_ctl;
|
||||
struct memac_mdio_controller *regs = bus->priv;
|
||||
u32 c45 = 1;
|
||||
|
||||
if (dev_addr == MDIO_DEVAD_NONE) {
|
||||
if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME))
|
||||
return 0xffff;
|
||||
c45 = 0; /* clause 22 */
|
||||
dev_addr = regnum & 0x1f;
|
||||
memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
||||
} else
|
||||
memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Set the Port and Device Addrs */
|
||||
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
|
||||
memac_out_32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Set the register address */
|
||||
if (c45)
|
||||
memac_out_32(®s->mdio_addr, regnum & 0xffff);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Initiate the read */
|
||||
mdio_ctl |= MDIO_CTL_READ;
|
||||
memac_out_32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Wait till the MDIO write is complete */
|
||||
while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY)
|
||||
;
|
||||
|
||||
/* Return all Fs if nothing was there */
|
||||
if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER)
|
||||
return 0xffff;
|
||||
|
||||
return memac_in_32(®s->mdio_data) & 0xffff;
|
||||
}
|
||||
|
||||
int memac_mdio_reset(struct mii_dev *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
|
||||
{
|
||||
struct mii_dev *bus = mdio_alloc();
|
||||
|
||||
if (!bus) {
|
||||
printf("Failed to allocate FM TGEC MDIO bus\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->read = memac_mdio_read;
|
||||
bus->write = memac_mdio_write;
|
||||
bus->reset = memac_mdio_reset;
|
||||
sprintf(bus->name, info->name);
|
||||
|
||||
bus->priv = info->regs;
|
||||
|
||||
/*
|
||||
* On some platforms like B4860, default value of MDIO_CLK_DIV bits
|
||||
* in mdio_stat(mdio_cfg) register generates MDIO clock too high
|
||||
* (much higher than 2.5MHz), violating the IEEE specs.
|
||||
* On other platforms like T1040, default value of MDIO_CLK_DIV bits
|
||||
* is zero, so MDIO clock is disabled.
|
||||
* So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to
|
||||
* be properly initialized.
|
||||
* NEG bit default should be '1' as per FMAN-v3 RM, but on platform
|
||||
* like T2080QDS, this bit default is '0', which leads to MDIO failure
|
||||
* on XAUI PHY, so set this bit definitely.
|
||||
*/
|
||||
memac_setbits_32(
|
||||
&((struct memac_mdio_controller *)info->regs)->mdio_stat,
|
||||
MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG);
|
||||
|
||||
return mdio_register(bus);
|
||||
}
|
||||
73
sources/uboot-be550/drivers/net/fm/p1023.c
Normal file
73
sources/uboot-be550/drivers/net/fm/p1023.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
static u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = MPC85xx_DEVDISR_TSEC1,
|
||||
[FM1_DTSEC2] = MPC85xx_DEVDISR_TSEC2,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr = in_be32(&gur->devdisr);
|
||||
|
||||
return port_to_devdisr[port] & devdisr;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
/* don't allow disabling of DTSEC1 as its needed for MDIO */
|
||||
if (port == FM1_DTSEC1)
|
||||
return;
|
||||
|
||||
setbits_be32(&gur->devdisr, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
void fman_enable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
clrbits_be32(&gur->devdisr, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 pordevsr = in_be32(&gur->pordevsr);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
/* DTSEC1 can be SGMII, RGMII or RMII */
|
||||
if (port == FM1_DTSEC1) {
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
if (pordevsr & MPC85xx_PORDEVSR_SGMII1_DIS) {
|
||||
if (pordevsr & MPC85xx_PORDEVSR_TSEC1_PRTC)
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
else
|
||||
return PHY_INTERFACE_MODE_RMII;
|
||||
}
|
||||
}
|
||||
|
||||
/* DTSEC2 only supports SGMII or RGMII */
|
||||
if (port == FM1_DTSEC2) {
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC2))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
if (pordevsr & MPC85xx_PORDEVSR_SGMII2_DIS)
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
99
sources/uboot-be550/drivers/net/fm/p4080.c
Normal file
99
sources/uboot-be550/drivers/net/fm/p4080.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
static u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1,
|
||||
[FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
|
||||
[FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
|
||||
[FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
|
||||
[FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
|
||||
[FM2_10GEC1] = FSL_CORENET_DEVDISR2_10GEC2,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
/* don't allow disabling of DTSEC1 as its needed for MDIO */
|
||||
if (port == FM1_DTSEC1)
|
||||
return;
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
void fman_enable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1) && (is_serdes_configured(XAUI_FM1)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM2_10GEC1) && (is_serdes_configured(XAUI_FM2)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
/* handle RGMII first */
|
||||
if ((port == FM1_DTSEC1) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
|
||||
FSL_CORENET_RCWSR11_EC1_FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC2) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
|
||||
FSL_CORENET_RCWSR11_EC2_FM1_DTSEC2))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM2_DTSEC1) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
|
||||
FSL_CORENET_RCWSR11_EC2_FM2_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
case FM2_DTSEC1:
|
||||
case FM2_DTSEC2:
|
||||
case FM2_DTSEC3:
|
||||
case FM2_DTSEC4:
|
||||
if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
90
sources/uboot-be550/drivers/net/fm/p5020.c
Normal file
90
sources/uboot-be550/drivers/net/fm/p5020.c
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
static u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
/* don't allow disabling of DTSEC1 as its needed for MDIO */
|
||||
if (port == FM1_DTSEC1)
|
||||
return;
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
void fman_enable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1) && (is_serdes_configured(XAUI_FM1)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
/* handle RGMII first */
|
||||
if ((port == FM1_DTSEC4) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
|
||||
FSL_CORENET_RCWSR11_EC1_FM1_DTSEC4_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC4) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
|
||||
FSL_CORENET_RCWSR11_EC1_FM1_DTSEC4_MII))
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
|
||||
if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
|
||||
FSL_CORENET_RCWSR11_EC2_FM1_DTSEC5_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
|
||||
FSL_CORENET_RCWSR11_EC2_FM1_DTSEC5_MII))
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
case FM1_DTSEC5:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
107
sources/uboot-be550/drivers/net/fm/p5040.c
Normal file
107
sources/uboot-be550/drivers/net/fm/p5040.c
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1,
|
||||
[FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
|
||||
[FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
|
||||
[FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
|
||||
[FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
|
||||
[FM2_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC2_5,
|
||||
[FM2_10GEC1] = FSL_CORENET_DEVDISR2_10GEC2,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
/* don't allow disabling of DTSEC1 as its needed for MDIO */
|
||||
if (port == FM1_DTSEC1)
|
||||
return;
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
void fman_enable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1) && (is_serdes_configured(XAUI_FM1)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM2_10GEC1) && (is_serdes_configured(XAUI_FM2)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
/* handle RGMII first */
|
||||
if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
|
||||
FSL_CORENET_RCWSR11_EC1_FM1_DTSEC5_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
|
||||
FSL_CORENET_RCWSR11_EC1_FM1_DTSEC5_MII))
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
|
||||
if ((port == FM2_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
|
||||
FSL_CORENET_RCWSR11_EC2_FM2_DTSEC5_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM2_DTSEC5) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
|
||||
FSL_CORENET_RCWSR11_EC2_FM2_DTSEC5_MII))
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
case FM1_DTSEC5:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
case FM2_DTSEC1:
|
||||
case FM2_DTSEC2:
|
||||
case FM2_DTSEC3:
|
||||
case FM2_DTSEC4:
|
||||
case FM2_DTSEC5:
|
||||
if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
88
sources/uboot-be550/drivers/net/fm/t1024.c
Normal file
88
sources/uboot-be550/drivers/net/fm/t1024.c
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Shengzhou Liu <Shengzhou.Liu@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1, /* MAC1 */
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1) && (is_serdes_configured(XFI_FM1_MAC1)))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_RGMII) &&
|
||||
(!is_serdes_configured(QSGMII_FM1_A)))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_RGMII) &&
|
||||
(!is_serdes_configured(QSGMII_FM1_A)))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
/* handle SGMII */
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
else if (is_serdes_configured(SGMII_2500_FM1_DTSEC1
|
||||
+ port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII_2500;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* handle QSGMII */
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
/* check lane A on SerDes1 */
|
||||
if (is_serdes_configured(QSGMII_FM1_A))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
67
sources/uboot-be550/drivers/net/fm/t1040.c
Normal file
67
sources/uboot-be550/drivers/net/fm/t1040.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
|
||||
|
||||
/* handle RGMII first */
|
||||
if ((port == FM1_DTSEC2) &&
|
||||
((rcwsr13 & FSL_CORENET_RCWSR13_MAC2_GMII_SEL) ==
|
||||
FSL_CORENET_RCWSR13_MAC2_GMII_SEL_ENET_PORT)) {
|
||||
if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_RGMII)
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
}
|
||||
|
||||
if ((port == FM1_DTSEC4) &&
|
||||
((rcwsr13 & FSL_CORENET_RCWSR13_MAC2_GMII_SEL) ==
|
||||
FSL_CORENET_RCWSR13_MAC2_GMII_SEL_L2_SWITCH)) {
|
||||
if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_RGMII)
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
}
|
||||
|
||||
if (port == FM1_DTSEC5) {
|
||||
if ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_RGMII)
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_MII)
|
||||
return PHY_INTERFACE_MODE_MII;
|
||||
}
|
||||
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
if (is_serdes_configured(QSGMII_SW1_A + port - FM1_DTSEC1) ||
|
||||
is_serdes_configured(SGMII_SW1_MAC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
case FM1_DTSEC5:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
93
sources/uboot-be550/drivers/net/fm/t2080.c
Normal file
93
sources/uboot-be550/drivers/net/fm/t2080.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Shengzhou Liu <Shengzhou.Liu@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
|
||||
[FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6,
|
||||
[FM1_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC1_9,
|
||||
[FM1_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC1_10,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1,
|
||||
[FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2,
|
||||
[FM1_10GEC3] = FSL_CORENET_DEVDISR2_10GEC1_3,
|
||||
[FM1_10GEC4] = FSL_CORENET_DEVDISR2_10GEC1_4,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
|
||||
((is_serdes_configured(XAUI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC10))))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM1_10GEC3 || port == FM1_10GEC4) &&
|
||||
((is_serdes_configured(XFI_FM1_MAC1)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC2))))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_DTSEC3_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_DTSEC4_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC10) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_DTSEC10_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
case FM1_DTSEC5:
|
||||
case FM1_DTSEC6:
|
||||
case FM1_DTSEC9:
|
||||
case FM1_DTSEC10:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
171
sources/uboot-be550/drivers/net/fm/t4240.c
Normal file
171
sources/uboot-be550/drivers/net/fm/t4240.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Roy Zang <tie-fei.zang@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <fm_eth.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_85xx.h>
|
||||
#include <asm/fsl_serdes.h>
|
||||
|
||||
u32 port_to_devdisr[] = {
|
||||
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
|
||||
[FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
|
||||
[FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
|
||||
[FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
|
||||
[FM1_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC1_5,
|
||||
[FM1_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC1_6,
|
||||
[FM1_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC1_9,
|
||||
[FM1_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC1_10,
|
||||
[FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1,
|
||||
[FM1_10GEC2] = FSL_CORENET_DEVDISR2_10GEC1_2,
|
||||
[FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
|
||||
[FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
|
||||
[FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
|
||||
[FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
|
||||
[FM2_DTSEC5] = FSL_CORENET_DEVDISR2_DTSEC2_5,
|
||||
[FM2_DTSEC6] = FSL_CORENET_DEVDISR2_DTSEC2_6,
|
||||
[FM2_DTSEC9] = FSL_CORENET_DEVDISR2_DTSEC2_9,
|
||||
[FM2_DTSEC10] = FSL_CORENET_DEVDISR2_DTSEC2_10,
|
||||
[FM2_10GEC1] = FSL_CORENET_DEVDISR2_10GEC2_1,
|
||||
[FM2_10GEC2] = FSL_CORENET_DEVDISR2_10GEC2_2,
|
||||
};
|
||||
|
||||
static int is_device_disabled(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 devdisr2 = in_be32(&gur->devdisr2);
|
||||
|
||||
return port_to_devdisr[port] & devdisr2;
|
||||
}
|
||||
|
||||
void fman_disable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
void fman_enable_port(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
|
||||
clrbits_be32(&gur->devdisr2, port_to_devdisr[port]);
|
||||
}
|
||||
|
||||
phy_interface_t fman_port_enet_if(enum fm_port port)
|
||||
{
|
||||
ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
|
||||
u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
|
||||
|
||||
if (is_device_disabled(port))
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
|
||||
if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
|
||||
((is_serdes_configured(XAUI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XAUI_FM1_MAC10)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC10))))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM1_DTSEC9 || port == FM1_DTSEC10) &&
|
||||
((is_serdes_configured(XFI_FM1_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM1_MAC10))))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
if ((port == FM2_10GEC1 || port == FM2_10GEC2) &&
|
||||
((is_serdes_configured(XAUI_FM2_MAC9)) ||
|
||||
(is_serdes_configured(XAUI_FM2_MAC10)) ||
|
||||
(is_serdes_configured(XFI_FM2_MAC9)) ||
|
||||
(is_serdes_configured(XFI_FM2_MAC10))))
|
||||
return PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
#define FSL_CORENET_RCWSR13_EC1 0x60000000 /* bits 417..418 */
|
||||
#define FSL_CORENET_RCWSR13_EC1_FM2_DTSEC5_RGMII 0x00000000
|
||||
#define FSL_CORENET_RCWSR13_EC1_FM2_GPIO 0x40000000
|
||||
#define FSL_CORENET_RCWSR13_EC2 0x18000000 /* bits 419..420 */
|
||||
#define FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_RGMII 0x00000000
|
||||
#define FSL_CORENET_RCWSR13_EC2_FM2_DTSEC6_RGMII 0x08000000
|
||||
#define FSL_CORENET_RCWSR13_EC2_FM1_GPIO 0x10000000
|
||||
/* handle RGMII first */
|
||||
if ((port == FM2_DTSEC5) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
|
||||
FSL_CORENET_RCWSR13_EC1_FM2_DTSEC5_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM1_DTSEC5) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_FM1_DTSEC5_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
|
||||
if ((port == FM2_DTSEC6) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
|
||||
FSL_CORENET_RCWSR13_EC2_FM2_DTSEC6_RGMII))
|
||||
return PHY_INTERFACE_MODE_RGMII;
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
case FM1_DTSEC5:
|
||||
case FM1_DTSEC6:
|
||||
case FM1_DTSEC9:
|
||||
case FM1_DTSEC10:
|
||||
if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
case FM2_DTSEC1:
|
||||
case FM2_DTSEC2:
|
||||
case FM2_DTSEC3:
|
||||
case FM2_DTSEC4:
|
||||
case FM2_DTSEC5:
|
||||
case FM2_DTSEC6:
|
||||
case FM2_DTSEC9:
|
||||
case FM2_DTSEC10:
|
||||
if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
|
||||
return PHY_INTERFACE_MODE_SGMII;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* handle QSGMII */
|
||||
switch (port) {
|
||||
case FM1_DTSEC1:
|
||||
case FM1_DTSEC2:
|
||||
case FM1_DTSEC3:
|
||||
case FM1_DTSEC4:
|
||||
/* check lane G on SerDes1 */
|
||||
if (is_serdes_configured(QSGMII_FM1_A))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
break;
|
||||
case FM1_DTSEC5:
|
||||
case FM1_DTSEC6:
|
||||
case FM1_DTSEC9:
|
||||
case FM1_DTSEC10:
|
||||
/* check lane C on SerDes1 */
|
||||
if (is_serdes_configured(QSGMII_FM1_B))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
break;
|
||||
case FM2_DTSEC1:
|
||||
case FM2_DTSEC2:
|
||||
case FM2_DTSEC3:
|
||||
case FM2_DTSEC4:
|
||||
/* check lane G on SerDes2 */
|
||||
if (is_serdes_configured(QSGMII_FM2_A))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
break;
|
||||
case FM2_DTSEC5:
|
||||
case FM2_DTSEC6:
|
||||
case FM2_DTSEC9:
|
||||
case FM2_DTSEC10:
|
||||
/* check lane C on SerDes2 */
|
||||
if (is_serdes_configured(QSGMII_FM2_B))
|
||||
return PHY_INTERFACE_MODE_QSGMII;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PHY_INTERFACE_MODE_NONE;
|
||||
}
|
||||
105
sources/uboot-be550/drivers/net/fm/tgec.c
Normal file
105
sources/uboot-be550/drivers/net/fm/tgec.c
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
* Dave Liu <daveliu@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* MAXFRM - maximum frame length */
|
||||
#define MAXFRM_MASK 0x0000ffff
|
||||
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_tgec.h>
|
||||
|
||||
#include "fm.h"
|
||||
|
||||
#define TGEC_CMD_CFG_INIT (TGEC_CMD_CFG_NO_LEN_CHK | \
|
||||
TGEC_CMD_CFG_RX_ER_DISC | \
|
||||
TGEC_CMD_CFG_STAT_CLR | \
|
||||
TGEC_CMD_CFG_PAUSE_IGNORE | \
|
||||
TGEC_CMD_CFG_CRC_FWD)
|
||||
#define TGEC_CMD_CFG_FINAL (TGEC_CMD_CFG_NO_LEN_CHK | \
|
||||
TGEC_CMD_CFG_RX_ER_DISC | \
|
||||
TGEC_CMD_CFG_PAUSE_IGNORE | \
|
||||
TGEC_CMD_CFG_CRC_FWD)
|
||||
|
||||
static void tgec_init_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct tgec *regs = mac->base;
|
||||
|
||||
/* mask all interrupt */
|
||||
out_be32(®s->imask, IMASK_MASK_ALL);
|
||||
|
||||
/* clear all events */
|
||||
out_be32(®s->ievent, IEVENT_CLEAR_ALL);
|
||||
|
||||
/* set the max receive length */
|
||||
out_be32(®s->maxfrm, mac->max_rx_len & MAXFRM_MASK);
|
||||
|
||||
/*
|
||||
* 1588 disable, insert second mac disable payload length check
|
||||
* disable, normal operation, any rx error frame is discarded, clear
|
||||
* counters, pause frame ignore, no promiscuous, LAN mode Rx CRC no
|
||||
* strip, Tx CRC append, Rx disable and Tx disable
|
||||
*/
|
||||
out_be32(®s->command_config, TGEC_CMD_CFG_INIT);
|
||||
udelay(1000);
|
||||
out_be32(®s->command_config, TGEC_CMD_CFG_FINAL);
|
||||
|
||||
/* multicast frame reception for the hash entry disable */
|
||||
out_be32(®s->hashtable_ctrl, 0);
|
||||
}
|
||||
|
||||
static void tgec_enable_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct tgec *regs = mac->base;
|
||||
|
||||
setbits_be32(®s->command_config, TGEC_CMD_CFG_RXTX_EN);
|
||||
}
|
||||
|
||||
static void tgec_disable_mac(struct fsl_enet_mac *mac)
|
||||
{
|
||||
struct tgec *regs = mac->base;
|
||||
|
||||
clrbits_be32(®s->command_config, TGEC_CMD_CFG_RXTX_EN);
|
||||
}
|
||||
|
||||
static void tgec_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
|
||||
{
|
||||
struct tgec *regs = mac->base;
|
||||
u32 mac_addr0, mac_addr1;
|
||||
|
||||
/*
|
||||
* if a station address of 0x12345678ABCD, perform a write to
|
||||
* MAC_ADDR0 of 0x78563412, MAC_ADDR1 of 0x0000CDAB
|
||||
*/
|
||||
mac_addr0 = (mac_addr[3] << 24) | (mac_addr[2] << 16) | \
|
||||
(mac_addr[1] << 8) | (mac_addr[0]);
|
||||
out_be32(®s->mac_addr_0, mac_addr0);
|
||||
|
||||
mac_addr1 = ((mac_addr[5] << 8) | mac_addr[4]) & 0x0000ffff;
|
||||
out_be32(®s->mac_addr_1, mac_addr1);
|
||||
}
|
||||
|
||||
static void tgec_set_interface_mode(struct fsl_enet_mac *mac,
|
||||
phy_interface_t type, int speed)
|
||||
{
|
||||
/* nothing right now */
|
||||
return;
|
||||
}
|
||||
|
||||
void init_tgec(struct fsl_enet_mac *mac, void *base,
|
||||
void *phyregs, int max_rx_len)
|
||||
{
|
||||
mac->base = base;
|
||||
mac->phyregs = phyregs;
|
||||
mac->max_rx_len = max_rx_len;
|
||||
mac->init_mac = tgec_init_mac;
|
||||
mac->enable_mac = tgec_enable_mac;
|
||||
mac->disable_mac = tgec_disable_mac;
|
||||
mac->set_mac_addr = tgec_set_mac_addr;
|
||||
mac->set_if_mode = tgec_set_interface_mode;
|
||||
}
|
||||
126
sources/uboot-be550/drivers/net/fm/tgec_phy.c
Normal file
126
sources/uboot-be550/drivers/net/fm/tgec_phy.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
||||
* Andy Fleming <afleming@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
* Some part is taken from tsec.c
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <miiphy.h>
|
||||
#include <phy.h>
|
||||
#include <asm/io.h>
|
||||
#include <fsl_tgec.h>
|
||||
#include <fm_eth.h>
|
||||
|
||||
/*
|
||||
* Write value to the PHY for this device to the register at regnum, waiting
|
||||
* until the write is done before it returns. All PHY configuration has to be
|
||||
* done through the TSEC1 MIIM regs
|
||||
*/
|
||||
static int tgec_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
u32 mdio_ctl;
|
||||
u32 stat_val;
|
||||
struct tgec_mdio_controller *regs = bus->priv;
|
||||
|
||||
if (dev_addr == MDIO_DEVAD_NONE)
|
||||
return 0;
|
||||
|
||||
/* Wait till the bus is free */
|
||||
stat_val = MDIO_STAT_CLKDIV(100);
|
||||
out_be32(®s->mdio_stat, stat_val);
|
||||
while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Set the port and dev addr */
|
||||
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
|
||||
out_be32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Set the register address */
|
||||
out_be32(®s->mdio_addr, regnum & 0xffff);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Write the value to the register */
|
||||
out_be32(®s->mdio_data, MDIO_DATA(value));
|
||||
|
||||
/* Wait till the MDIO write is complete */
|
||||
while ((in_be32(®s->mdio_data)) & MDIO_DATA_BSY)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads from register regnum in the PHY for device dev, returning the value.
|
||||
* Clears miimcom first. All PHY configuration has to be done through the
|
||||
* TSEC1 MIIM regs
|
||||
*/
|
||||
static int tgec_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
|
||||
int regnum)
|
||||
{
|
||||
u32 mdio_ctl;
|
||||
u32 stat_val;
|
||||
struct tgec_mdio_controller *regs = bus->priv;
|
||||
|
||||
if (dev_addr == MDIO_DEVAD_NONE)
|
||||
return 0xffff;
|
||||
|
||||
stat_val = MDIO_STAT_CLKDIV(100);
|
||||
out_be32(®s->mdio_stat, stat_val);
|
||||
/* Wait till the bus is free */
|
||||
while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Set the Port and Device Addrs */
|
||||
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
|
||||
out_be32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Set the register address */
|
||||
out_be32(®s->mdio_addr, regnum & 0xffff);
|
||||
|
||||
/* Wait till the bus is free */
|
||||
while ((in_be32(®s->mdio_stat)) & MDIO_STAT_BSY)
|
||||
;
|
||||
|
||||
/* Initiate the read */
|
||||
mdio_ctl |= MDIO_CTL_READ;
|
||||
out_be32(®s->mdio_ctl, mdio_ctl);
|
||||
|
||||
/* Wait till the MDIO write is complete */
|
||||
while ((in_be32(®s->mdio_data)) & MDIO_DATA_BSY)
|
||||
;
|
||||
|
||||
/* Return all Fs if nothing was there */
|
||||
if (in_be32(®s->mdio_stat) & MDIO_STAT_RD_ER)
|
||||
return 0xffff;
|
||||
|
||||
return in_be32(®s->mdio_data) & 0xffff;
|
||||
}
|
||||
|
||||
static int tgec_mdio_reset(struct mii_dev *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fm_tgec_mdio_init(bd_t *bis, struct tgec_mdio_info *info)
|
||||
{
|
||||
struct mii_dev *bus = mdio_alloc();
|
||||
|
||||
if (!bus) {
|
||||
printf("Failed to allocate FM TGEC MDIO bus\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->read = tgec_mdio_read;
|
||||
bus->write = tgec_mdio_write;
|
||||
bus->reset = tgec_mdio_reset;
|
||||
sprintf(bus->name, info->name);
|
||||
|
||||
bus->priv = info->regs;
|
||||
|
||||
return mdio_register(bus);
|
||||
}
|
||||
15
sources/uboot-be550/drivers/net/fsl-mc/Makefile
Normal file
15
sources/uboot-be550/drivers/net/fsl-mc/Makefile
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#
|
||||
# Copyright 2014 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
# Layerscape MC driver
|
||||
obj-y += mc.o \
|
||||
mc_sys.o \
|
||||
dpmng.o \
|
||||
dprc.o \
|
||||
dpbp.o \
|
||||
dpni.o \
|
||||
dpmac.o
|
||||
obj-y += dpio/
|
||||
159
sources/uboot-be550/drivers/net/fsl-mc/dpbp.c
Normal file
159
sources/uboot-be550/drivers/net/fsl-mc/dpbp.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Freescale Layerscape MC I/O wrapper
|
||||
*
|
||||
* Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
|
||||
* Author: German Rivera <German.Rivera@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <fsl-mc/fsl_mc_sys.h>
|
||||
#include <fsl-mc/fsl_mc_cmd.h>
|
||||
#include <fsl-mc/fsl_dpbp.h>
|
||||
|
||||
int dpbp_open(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
int dpbp_id,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPBP_CMD_OPEN(cmd, dpbp_id);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int dpbp_close(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpbp_create(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
const struct dpbp_cfg *cfg,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
(void)(cfg); /* unused */
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_CREATE,
|
||||
cmd_flags,
|
||||
0);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpbp_destroy(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_DESTROY,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpbp_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpbp_disable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpbp_reset(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpbp_get_attributes(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpbp_attr *attr)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_ATTR,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPBP_RSP_GET_ATTRIBUTES(cmd, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
sources/uboot-be550/drivers/net/fsl-mc/dpio/Makefile
Normal file
9
sources/uboot-be550/drivers/net/fsl-mc/dpio/Makefile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Copyright 2014 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
# Layerscape MC DPIO driver
|
||||
obj-y += dpio.o \
|
||||
qbman_portal.o
|
||||
158
sources/uboot-be550/drivers/net/fsl-mc/dpio/dpio.c
Normal file
158
sources/uboot-be550/drivers/net/fsl-mc/dpio/dpio.c
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2015 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <fsl-mc/fsl_mc_sys.h>
|
||||
#include <fsl-mc/fsl_mc_cmd.h>
|
||||
#include <fsl-mc/fsl_dpio.h>
|
||||
|
||||
int dpio_open(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
int dpio_id,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_OPEN,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPIO_CMD_OPEN(cmd, dpio_id);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpio_close(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpio_create(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
const struct dpio_cfg *cfg,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_CREATE,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPIO_CMD_CREATE(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpio_destroy(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_DESTROY,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpio_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpio_disable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpio_reset(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpio_get_attributes(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpio_attr *attr)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPIO_CMDID_GET_ATTR,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPIO_RSP_GET_ATTR(cmd, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
599
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_portal.c
Normal file
599
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_portal.c
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include "qbman_portal.h"
|
||||
|
||||
/* QBMan portal management command codes */
|
||||
#define QBMAN_MC_ACQUIRE 0x30
|
||||
#define QBMAN_WQCHAN_CONFIGURE 0x46
|
||||
|
||||
/* CINH register offsets */
|
||||
#define QBMAN_CINH_SWP_EQAR 0x8c0
|
||||
#define QBMAN_CINH_SWP_DCAP 0xac0
|
||||
#define QBMAN_CINH_SWP_SDQCR 0xb00
|
||||
#define QBMAN_CINH_SWP_RAR 0xcc0
|
||||
|
||||
/* CENA register offsets */
|
||||
#define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((uint32_t)(n) << 6))
|
||||
#define QBMAN_CENA_SWP_DQRR(n) (0x200 + ((uint32_t)(n) << 6))
|
||||
#define QBMAN_CENA_SWP_RCR(n) (0x400 + ((uint32_t)(n) << 6))
|
||||
#define QBMAN_CENA_SWP_CR 0x600
|
||||
#define QBMAN_CENA_SWP_RR(vb) (0x700 + ((uint32_t)(vb) >> 1))
|
||||
#define QBMAN_CENA_SWP_VDQCR 0x780
|
||||
|
||||
/* Reverse mapping of QBMAN_CENA_SWP_DQRR() */
|
||||
#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)p & 0xff) >> 6)
|
||||
|
||||
/*******************************/
|
||||
/* Pre-defined attribute codes */
|
||||
/*******************************/
|
||||
|
||||
struct qb_attr_code code_generic_verb = QB_CODE(0, 0, 7);
|
||||
struct qb_attr_code code_generic_rslt = QB_CODE(0, 8, 8);
|
||||
|
||||
/*************************/
|
||||
/* SDQCR attribute codes */
|
||||
/*************************/
|
||||
|
||||
/* we put these here because at least some of them are required by
|
||||
* qbman_swp_init() */
|
||||
struct qb_attr_code code_sdqcr_dct = QB_CODE(0, 24, 2);
|
||||
struct qb_attr_code code_sdqcr_fc = QB_CODE(0, 29, 1);
|
||||
struct qb_attr_code code_sdqcr_tok = QB_CODE(0, 16, 8);
|
||||
#define CODE_SDQCR_DQSRC(n) QB_CODE(0, n, 1)
|
||||
enum qbman_sdqcr_dct {
|
||||
qbman_sdqcr_dct_null = 0,
|
||||
qbman_sdqcr_dct_prio_ics,
|
||||
qbman_sdqcr_dct_active_ics,
|
||||
qbman_sdqcr_dct_active
|
||||
};
|
||||
enum qbman_sdqcr_fc {
|
||||
qbman_sdqcr_fc_one = 0,
|
||||
qbman_sdqcr_fc_up_to_3 = 1
|
||||
};
|
||||
|
||||
/*********************************/
|
||||
/* Portal constructor/destructor */
|
||||
/*********************************/
|
||||
|
||||
/* Software portals should always be in the power-on state when we initialise,
|
||||
* due to the CCSR-based portal reset functionality that MC has. */
|
||||
struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
|
||||
{
|
||||
int ret;
|
||||
struct qbman_swp *p = malloc(sizeof(struct qbman_swp));
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->desc = d;
|
||||
#ifdef QBMAN_CHECKING
|
||||
p->mc.check = swp_mc_can_start;
|
||||
#endif
|
||||
p->mc.valid_bit = QB_VALID_BIT;
|
||||
p->sdq = 0;
|
||||
qb_attr_code_encode(&code_sdqcr_dct, &p->sdq, qbman_sdqcr_dct_prio_ics);
|
||||
qb_attr_code_encode(&code_sdqcr_fc, &p->sdq, qbman_sdqcr_fc_up_to_3);
|
||||
qb_attr_code_encode(&code_sdqcr_tok, &p->sdq, 0xbb);
|
||||
atomic_set(&p->vdq.busy, 1);
|
||||
p->vdq.valid_bit = QB_VALID_BIT;
|
||||
p->dqrr.next_idx = 0;
|
||||
p->dqrr.valid_bit = QB_VALID_BIT;
|
||||
ret = qbman_swp_sys_init(&p->sys, d);
|
||||
if (ret) {
|
||||
free(p);
|
||||
printf("qbman_swp_sys_init() failed %d\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
qbman_cinh_write(&p->sys, QBMAN_CINH_SWP_SDQCR, p->sdq);
|
||||
return p;
|
||||
}
|
||||
|
||||
/***********************/
|
||||
/* Management commands */
|
||||
/***********************/
|
||||
|
||||
/*
|
||||
* Internal code common to all types of management commands.
|
||||
*/
|
||||
|
||||
void *qbman_swp_mc_start(struct qbman_swp *p)
|
||||
{
|
||||
void *ret;
|
||||
#ifdef QBMAN_CHECKING
|
||||
BUG_ON(p->mc.check != swp_mc_can_start);
|
||||
#endif
|
||||
ret = qbman_cena_write_start(&p->sys, QBMAN_CENA_SWP_CR);
|
||||
#ifdef QBMAN_CHECKING
|
||||
if (!ret)
|
||||
p->mc.check = swp_mc_can_submit;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb)
|
||||
{
|
||||
uint32_t *v = cmd;
|
||||
#ifdef QBMAN_CHECKING
|
||||
BUG_ON(p->mc.check != swp_mc_can_submit);
|
||||
#endif
|
||||
lwsync();
|
||||
/* TBD: "|=" is going to hurt performance. Need to move as many fields
|
||||
* out of word zero, and for those that remain, the "OR" needs to occur
|
||||
* at the caller side. This debug check helps to catch cases where the
|
||||
* caller wants to OR but has forgotten to do so. */
|
||||
BUG_ON((*v & cmd_verb) != *v);
|
||||
*v = cmd_verb | p->mc.valid_bit;
|
||||
qbman_cena_write_complete(&p->sys, QBMAN_CENA_SWP_CR, cmd);
|
||||
/* TODO: add prefetch support for GPP */
|
||||
#ifdef QBMAN_CHECKING
|
||||
p->mc.check = swp_mc_can_poll;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *qbman_swp_mc_result(struct qbman_swp *p)
|
||||
{
|
||||
uint32_t *ret, verb;
|
||||
#ifdef QBMAN_CHECKING
|
||||
BUG_ON(p->mc.check != swp_mc_can_poll);
|
||||
#endif
|
||||
ret = qbman_cena_read(&p->sys, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
|
||||
/* Remove the valid-bit - command completed iff the rest is non-zero */
|
||||
verb = ret[0] & ~QB_VALID_BIT;
|
||||
if (!verb)
|
||||
return NULL;
|
||||
#ifdef QBMAN_CHECKING
|
||||
p->mc.check = swp_mc_can_start;
|
||||
#endif
|
||||
p->mc.valid_bit ^= QB_VALID_BIT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********/
|
||||
/* Enqueue */
|
||||
/***********/
|
||||
|
||||
/* These should be const, eventually */
|
||||
static struct qb_attr_code code_eq_cmd = QB_CODE(0, 0, 2);
|
||||
static struct qb_attr_code code_eq_orp_en = QB_CODE(0, 2, 1);
|
||||
static struct qb_attr_code code_eq_tgt_id = QB_CODE(2, 0, 24);
|
||||
/* static struct qb_attr_code code_eq_tag = QB_CODE(3, 0, 32); */
|
||||
static struct qb_attr_code code_eq_qd_en = QB_CODE(0, 4, 1);
|
||||
static struct qb_attr_code code_eq_qd_bin = QB_CODE(4, 0, 16);
|
||||
static struct qb_attr_code code_eq_qd_pri = QB_CODE(4, 16, 4);
|
||||
static struct qb_attr_code code_eq_rsp_stash = QB_CODE(5, 16, 1);
|
||||
static struct qb_attr_code code_eq_rsp_lo = QB_CODE(6, 0, 32);
|
||||
|
||||
enum qbman_eq_cmd_e {
|
||||
/* No enqueue, primarily for plugging ORP gaps for dropped frames */
|
||||
qbman_eq_cmd_empty,
|
||||
/* DMA an enqueue response once complete */
|
||||
qbman_eq_cmd_respond,
|
||||
/* DMA an enqueue response only if the enqueue fails */
|
||||
qbman_eq_cmd_respond_reject
|
||||
};
|
||||
|
||||
void qbman_eq_desc_clear(struct qbman_eq_desc *d)
|
||||
{
|
||||
memset(d, 0, sizeof(*d));
|
||||
}
|
||||
|
||||
void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
qb_attr_code_encode(&code_eq_orp_en, cl, 0);
|
||||
qb_attr_code_encode(&code_eq_cmd, cl,
|
||||
respond_success ? qbman_eq_cmd_respond :
|
||||
qbman_eq_cmd_respond_reject);
|
||||
}
|
||||
|
||||
void qbman_eq_desc_set_response(struct qbman_eq_desc *d,
|
||||
dma_addr_t storage_phys,
|
||||
int stash)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
qb_attr_code_encode_64(&code_eq_rsp_lo, (uint64_t *)cl, storage_phys);
|
||||
qb_attr_code_encode(&code_eq_rsp_stash, cl, !!stash);
|
||||
}
|
||||
|
||||
|
||||
void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, uint32_t qdid,
|
||||
uint32_t qd_bin, uint32_t qd_prio)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
qb_attr_code_encode(&code_eq_qd_en, cl, 1);
|
||||
qb_attr_code_encode(&code_eq_tgt_id, cl, qdid);
|
||||
qb_attr_code_encode(&code_eq_qd_bin, cl, qd_bin);
|
||||
qb_attr_code_encode(&code_eq_qd_pri, cl, qd_prio);
|
||||
}
|
||||
|
||||
#define EQAR_IDX(eqar) ((eqar) & 0x7)
|
||||
#define EQAR_VB(eqar) ((eqar) & 0x80)
|
||||
#define EQAR_SUCCESS(eqar) ((eqar) & 0x100)
|
||||
|
||||
int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
|
||||
const struct qbman_fd *fd)
|
||||
{
|
||||
uint32_t *p;
|
||||
const uint32_t *cl = qb_cl(d);
|
||||
uint32_t eqar = qbman_cinh_read(&s->sys, QBMAN_CINH_SWP_EQAR);
|
||||
debug("EQAR=%08x\n", eqar);
|
||||
if (!EQAR_SUCCESS(eqar))
|
||||
return -EBUSY;
|
||||
p = qbman_cena_write_start(&s->sys,
|
||||
QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
|
||||
word_copy(&p[1], &cl[1], 7);
|
||||
word_copy(&p[8], fd, sizeof(*fd) >> 2);
|
||||
lwsync();
|
||||
/* Set the verb byte, have to substitute in the valid-bit */
|
||||
p[0] = cl[0] | EQAR_VB(eqar);
|
||||
qbman_cena_write_complete(&s->sys,
|
||||
QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)),
|
||||
p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************/
|
||||
/* Volatile (pull) dequeue */
|
||||
/***************************/
|
||||
|
||||
/* These should be const, eventually */
|
||||
static struct qb_attr_code code_pull_dct = QB_CODE(0, 0, 2);
|
||||
static struct qb_attr_code code_pull_dt = QB_CODE(0, 2, 2);
|
||||
static struct qb_attr_code code_pull_rls = QB_CODE(0, 4, 1);
|
||||
static struct qb_attr_code code_pull_stash = QB_CODE(0, 5, 1);
|
||||
static struct qb_attr_code code_pull_numframes = QB_CODE(0, 8, 4);
|
||||
static struct qb_attr_code code_pull_token = QB_CODE(0, 16, 8);
|
||||
static struct qb_attr_code code_pull_dqsource = QB_CODE(1, 0, 24);
|
||||
static struct qb_attr_code code_pull_rsp_lo = QB_CODE(2, 0, 32);
|
||||
|
||||
enum qb_pull_dt_e {
|
||||
qb_pull_dt_channel,
|
||||
qb_pull_dt_workqueue,
|
||||
qb_pull_dt_framequeue
|
||||
};
|
||||
|
||||
void qbman_pull_desc_clear(struct qbman_pull_desc *d)
|
||||
{
|
||||
memset(d, 0, sizeof(*d));
|
||||
}
|
||||
|
||||
void qbman_pull_desc_set_storage(struct qbman_pull_desc *d,
|
||||
struct ldpaa_dq *storage,
|
||||
dma_addr_t storage_phys,
|
||||
int stash)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
/* Squiggle the pointer 'storage' into the extra 2 words of the
|
||||
* descriptor (which aren't copied to the hw command) */
|
||||
*(void **)&cl[4] = storage;
|
||||
if (!storage) {
|
||||
qb_attr_code_encode(&code_pull_rls, cl, 0);
|
||||
return;
|
||||
}
|
||||
qb_attr_code_encode(&code_pull_rls, cl, 1);
|
||||
qb_attr_code_encode(&code_pull_stash, cl, !!stash);
|
||||
qb_attr_code_encode_64(&code_pull_rsp_lo, (uint64_t *)cl, storage_phys);
|
||||
}
|
||||
|
||||
void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, uint8_t numframes)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
BUG_ON(!numframes || (numframes > 16));
|
||||
qb_attr_code_encode(&code_pull_numframes, cl,
|
||||
(uint32_t)(numframes - 1));
|
||||
}
|
||||
|
||||
void qbman_pull_desc_set_token(struct qbman_pull_desc *d, uint8_t token)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
qb_attr_code_encode(&code_pull_token, cl, token);
|
||||
}
|
||||
|
||||
void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, uint32_t fqid)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
qb_attr_code_encode(&code_pull_dct, cl, 1);
|
||||
qb_attr_code_encode(&code_pull_dt, cl, qb_pull_dt_framequeue);
|
||||
qb_attr_code_encode(&code_pull_dqsource, cl, fqid);
|
||||
}
|
||||
|
||||
int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
|
||||
{
|
||||
uint32_t *p;
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
if (!atomic_dec_and_test(&s->vdq.busy)) {
|
||||
atomic_inc(&s->vdq.busy);
|
||||
return -EBUSY;
|
||||
}
|
||||
s->vdq.storage = *(void **)&cl[4];
|
||||
s->vdq.token = qb_attr_code_decode(&code_pull_token, cl);
|
||||
p = qbman_cena_write_start(&s->sys, QBMAN_CENA_SWP_VDQCR);
|
||||
word_copy(&p[1], &cl[1], 3);
|
||||
lwsync();
|
||||
/* Set the verb byte, have to substitute in the valid-bit */
|
||||
p[0] = cl[0] | s->vdq.valid_bit;
|
||||
s->vdq.valid_bit ^= QB_VALID_BIT;
|
||||
qbman_cena_write_complete(&s->sys, QBMAN_CENA_SWP_VDQCR, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************/
|
||||
/* Polling DQRR */
|
||||
/****************/
|
||||
|
||||
static struct qb_attr_code code_dqrr_verb = QB_CODE(0, 0, 8);
|
||||
static struct qb_attr_code code_dqrr_response = QB_CODE(0, 0, 7);
|
||||
static struct qb_attr_code code_dqrr_stat = QB_CODE(0, 8, 8);
|
||||
|
||||
#define QBMAN_DQRR_RESPONSE_DQ 0x60
|
||||
#define QBMAN_DQRR_RESPONSE_FQRN 0x21
|
||||
#define QBMAN_DQRR_RESPONSE_FQRNI 0x22
|
||||
#define QBMAN_DQRR_RESPONSE_FQPN 0x24
|
||||
#define QBMAN_DQRR_RESPONSE_FQDAN 0x25
|
||||
#define QBMAN_DQRR_RESPONSE_CDAN 0x26
|
||||
#define QBMAN_DQRR_RESPONSE_CSCN_MEM 0x27
|
||||
#define QBMAN_DQRR_RESPONSE_CGCU 0x28
|
||||
#define QBMAN_DQRR_RESPONSE_BPSCN 0x29
|
||||
#define QBMAN_DQRR_RESPONSE_CSCN_WQ 0x2a
|
||||
|
||||
|
||||
/* NULL return if there are no unconsumed DQRR entries. Returns a DQRR entry
|
||||
* only once, so repeated calls can return a sequence of DQRR entries, without
|
||||
* requiring they be consumed immediately or in any particular order. */
|
||||
const struct ldpaa_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
|
||||
{
|
||||
uint32_t verb;
|
||||
uint32_t response_verb;
|
||||
uint32_t flags;
|
||||
const struct ldpaa_dq *dq;
|
||||
const uint32_t *p;
|
||||
|
||||
dq = qbman_cena_read(&s->sys, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
|
||||
p = qb_cl(dq);
|
||||
verb = qb_attr_code_decode(&code_dqrr_verb, p);
|
||||
|
||||
/* If the valid-bit isn't of the expected polarity, nothing there. Note,
|
||||
* in the DQRR reset bug workaround, we shouldn't need to skip these
|
||||
* check, because we've already determined that a new entry is available
|
||||
* and we've invalidated the cacheline before reading it, so the
|
||||
* valid-bit behaviour is repaired and should tell us what we already
|
||||
* knew from reading PI.
|
||||
*/
|
||||
if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) {
|
||||
qbman_cena_invalidate_prefetch(&s->sys,
|
||||
QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
|
||||
return NULL;
|
||||
}
|
||||
/* There's something there. Move "next_idx" attention to the next ring
|
||||
* entry (and prefetch it) before returning what we found. */
|
||||
s->dqrr.next_idx++;
|
||||
s->dqrr.next_idx &= QBMAN_DQRR_SIZE - 1; /* Wrap around at 4 */
|
||||
/* TODO: it's possible to do all this without conditionals, optimise it
|
||||
* later. */
|
||||
if (!s->dqrr.next_idx)
|
||||
s->dqrr.valid_bit ^= QB_VALID_BIT;
|
||||
|
||||
/* If this is the final response to a volatile dequeue command
|
||||
indicate that the vdq is no longer busy */
|
||||
flags = ldpaa_dq_flags(dq);
|
||||
response_verb = qb_attr_code_decode(&code_dqrr_response, &verb);
|
||||
if ((response_verb == QBMAN_DQRR_RESPONSE_DQ) &&
|
||||
(flags & LDPAA_DQ_STAT_VOLATILE) &&
|
||||
(flags & LDPAA_DQ_STAT_EXPIRED))
|
||||
atomic_inc(&s->vdq.busy);
|
||||
|
||||
qbman_cena_invalidate_prefetch(&s->sys,
|
||||
QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
|
||||
return dq;
|
||||
}
|
||||
|
||||
/* Consume DQRR entries previously returned from qbman_swp_dqrr_next(). */
|
||||
void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct ldpaa_dq *dq)
|
||||
{
|
||||
qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP, QBMAN_IDX_FROM_DQRR(dq));
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Polling user-provided storage */
|
||||
/*********************************/
|
||||
|
||||
void qbman_dq_entry_set_oldtoken(struct ldpaa_dq *dq,
|
||||
unsigned int num_entries,
|
||||
uint8_t oldtoken)
|
||||
{
|
||||
memset(dq, oldtoken, num_entries * sizeof(*dq));
|
||||
}
|
||||
|
||||
int qbman_dq_entry_has_newtoken(struct qbman_swp *s,
|
||||
const struct ldpaa_dq *dq,
|
||||
uint8_t newtoken)
|
||||
{
|
||||
/* To avoid converting the little-endian DQ entry to host-endian prior
|
||||
* to us knowing whether there is a valid entry or not (and run the
|
||||
* risk of corrupting the incoming hardware LE write), we detect in
|
||||
* hardware endianness rather than host. This means we need a different
|
||||
* "code" depending on whether we are BE or LE in software, which is
|
||||
* where DQRR_TOK_OFFSET comes in... */
|
||||
static struct qb_attr_code code_dqrr_tok_detect =
|
||||
QB_CODE(0, DQRR_TOK_OFFSET, 8);
|
||||
/* The user trying to poll for a result treats "dq" as const. It is
|
||||
* however the same address that was provided to us non-const in the
|
||||
* first place, for directing hardware DMA to. So we can cast away the
|
||||
* const because it is mutable from our perspective. */
|
||||
uint32_t *p = qb_cl((struct ldpaa_dq *)dq);
|
||||
uint32_t token;
|
||||
|
||||
token = qb_attr_code_decode(&code_dqrr_tok_detect, &p[1]);
|
||||
if (token != newtoken)
|
||||
return 0;
|
||||
|
||||
/* Only now do we convert from hardware to host endianness. Also, as we
|
||||
* are returning success, the user has promised not to call us again, so
|
||||
* there's no risk of us converting the endianness twice... */
|
||||
make_le32_n(p, 16);
|
||||
|
||||
/* VDQCR "no longer busy" hook - not quite the same as DQRR, because the
|
||||
* fact "VDQCR" shows busy doesn't mean that the result we're looking at
|
||||
* is from the same command. Eg. we may be looking at our 10th dequeue
|
||||
* result from our first VDQCR command, yet the second dequeue command
|
||||
* could have been kicked off already, after seeing the 1st result. Ie.
|
||||
* the result we're looking at is not necessarily proof that we can
|
||||
* reset "busy". We instead base the decision on whether the current
|
||||
* result is sitting at the first 'storage' location of the busy
|
||||
* command. */
|
||||
if (s->vdq.storage == dq) {
|
||||
s->vdq.storage = NULL;
|
||||
atomic_inc(&s->vdq.busy);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/********************************/
|
||||
/* Categorising dequeue entries */
|
||||
/********************************/
|
||||
|
||||
static inline int __qbman_dq_entry_is_x(const struct ldpaa_dq *dq, uint32_t x)
|
||||
{
|
||||
const uint32_t *p = qb_cl(dq);
|
||||
uint32_t response_verb = qb_attr_code_decode(&code_dqrr_response, p);
|
||||
|
||||
return response_verb == x;
|
||||
}
|
||||
|
||||
int qbman_dq_entry_is_DQ(const struct ldpaa_dq *dq)
|
||||
{
|
||||
return __qbman_dq_entry_is_x(dq, QBMAN_DQRR_RESPONSE_DQ);
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* Parsing frame dequeue results */
|
||||
/*********************************/
|
||||
|
||||
/* These APIs assume qbman_dq_entry_is_DQ() is TRUE */
|
||||
|
||||
uint32_t ldpaa_dq_flags(const struct ldpaa_dq *dq)
|
||||
{
|
||||
const uint32_t *p = qb_cl(dq);
|
||||
|
||||
return qb_attr_code_decode(&code_dqrr_stat, p);
|
||||
}
|
||||
|
||||
const struct dpaa_fd *ldpaa_dq_fd(const struct ldpaa_dq *dq)
|
||||
{
|
||||
const uint32_t *p = qb_cl(dq);
|
||||
|
||||
return (const struct dpaa_fd *)&p[8];
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Buffer release */
|
||||
/******************/
|
||||
|
||||
/* These should be const, eventually */
|
||||
/* static struct qb_attr_code code_release_num = QB_CODE(0, 0, 3); */
|
||||
static struct qb_attr_code code_release_set_me = QB_CODE(0, 5, 1);
|
||||
static struct qb_attr_code code_release_bpid = QB_CODE(0, 16, 16);
|
||||
|
||||
void qbman_release_desc_clear(struct qbman_release_desc *d)
|
||||
{
|
||||
uint32_t *cl;
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
cl = qb_cl(d);
|
||||
qb_attr_code_encode(&code_release_set_me, cl, 1);
|
||||
}
|
||||
|
||||
void qbman_release_desc_set_bpid(struct qbman_release_desc *d, uint32_t bpid)
|
||||
{
|
||||
uint32_t *cl = qb_cl(d);
|
||||
|
||||
qb_attr_code_encode(&code_release_bpid, cl, bpid);
|
||||
}
|
||||
|
||||
#define RAR_IDX(rar) ((rar) & 0x7)
|
||||
#define RAR_VB(rar) ((rar) & 0x80)
|
||||
#define RAR_SUCCESS(rar) ((rar) & 0x100)
|
||||
|
||||
int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
|
||||
const uint64_t *buffers, unsigned int num_buffers)
|
||||
{
|
||||
uint32_t *p;
|
||||
const uint32_t *cl = qb_cl(d);
|
||||
uint32_t rar = qbman_cinh_read(&s->sys, QBMAN_CINH_SWP_RAR);
|
||||
debug("RAR=%08x\n", rar);
|
||||
if (!RAR_SUCCESS(rar))
|
||||
return -EBUSY;
|
||||
BUG_ON(!num_buffers || (num_buffers > 7));
|
||||
/* Start the release command */
|
||||
p = qbman_cena_write_start(&s->sys,
|
||||
QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
|
||||
/* Copy the caller's buffer pointers to the command */
|
||||
u64_to_le32_copy(&p[2], buffers, num_buffers);
|
||||
lwsync();
|
||||
/* Set the verb byte, have to substitute in the valid-bit and the number
|
||||
* of buffers. */
|
||||
p[0] = cl[0] | RAR_VB(rar) | num_buffers;
|
||||
qbman_cena_write_complete(&s->sys,
|
||||
QBMAN_CENA_SWP_RCR(RAR_IDX(rar)),
|
||||
p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/* Buffer acquires */
|
||||
/*******************/
|
||||
|
||||
/* These should be const, eventually */
|
||||
static struct qb_attr_code code_acquire_bpid = QB_CODE(0, 16, 16);
|
||||
static struct qb_attr_code code_acquire_num = QB_CODE(1, 0, 3);
|
||||
static struct qb_attr_code code_acquire_r_num = QB_CODE(1, 0, 3);
|
||||
|
||||
int qbman_swp_acquire(struct qbman_swp *s, uint32_t bpid, uint64_t *buffers,
|
||||
unsigned int num_buffers)
|
||||
{
|
||||
uint32_t *p;
|
||||
uint32_t verb, rslt, num;
|
||||
|
||||
BUG_ON(!num_buffers || (num_buffers > 7));
|
||||
|
||||
/* Start the management command */
|
||||
p = qbman_swp_mc_start(s);
|
||||
|
||||
if (!p)
|
||||
return -EBUSY;
|
||||
|
||||
/* Encode the caller-provided attributes */
|
||||
qb_attr_code_encode(&code_acquire_bpid, p, bpid);
|
||||
qb_attr_code_encode(&code_acquire_num, p, num_buffers);
|
||||
|
||||
/* Complete the management command */
|
||||
p = qbman_swp_mc_complete(s, p, p[0] | QBMAN_MC_ACQUIRE);
|
||||
|
||||
/* Decode the outcome */
|
||||
verb = qb_attr_code_decode(&code_generic_verb, p);
|
||||
rslt = qb_attr_code_decode(&code_generic_rslt, p);
|
||||
num = qb_attr_code_decode(&code_acquire_r_num, p);
|
||||
BUG_ON(verb != QBMAN_MC_ACQUIRE);
|
||||
|
||||
/* Determine success or failure */
|
||||
if (unlikely(rslt != QBMAN_MC_RSLT_OK)) {
|
||||
printf("Acquire buffers from BPID 0x%x failed, code=0x%02x\n",
|
||||
bpid, rslt);
|
||||
return -EIO;
|
||||
}
|
||||
BUG_ON(num > num_buffers);
|
||||
/* Copy the acquired buffers to the caller's array */
|
||||
u64_from_le32_copy(buffers, &p[2], num);
|
||||
return (int)num;
|
||||
}
|
||||
167
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_portal.h
Normal file
167
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_portal.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include "qbman_private.h"
|
||||
#include <fsl-mc/fsl_qbman_portal.h>
|
||||
#include <fsl-mc/fsl_dpaa_fd.h>
|
||||
|
||||
/* All QBMan command and result structures use this "valid bit" encoding */
|
||||
#define QB_VALID_BIT ((uint32_t)0x80)
|
||||
|
||||
/* Management command result codes */
|
||||
#define QBMAN_MC_RSLT_OK 0xf0
|
||||
|
||||
/* TBD: as of QBMan 4.1, DQRR will be 8 rather than 4! */
|
||||
#define QBMAN_DQRR_SIZE 4
|
||||
|
||||
|
||||
/* --------------------- */
|
||||
/* portal data structure */
|
||||
/* --------------------- */
|
||||
|
||||
struct qbman_swp {
|
||||
const struct qbman_swp_desc *desc;
|
||||
/* The qbman_sys (ie. arch/OS-specific) support code can put anything it
|
||||
* needs in here. */
|
||||
struct qbman_swp_sys sys;
|
||||
/* Management commands */
|
||||
struct {
|
||||
#ifdef QBMAN_CHECKING
|
||||
enum swp_mc_check {
|
||||
swp_mc_can_start, /* call __qbman_swp_mc_start() */
|
||||
swp_mc_can_submit, /* call __qbman_swp_mc_submit() */
|
||||
swp_mc_can_poll, /* call __qbman_swp_mc_result() */
|
||||
} check;
|
||||
#endif
|
||||
uint32_t valid_bit; /* 0x00 or 0x80 */
|
||||
} mc;
|
||||
/* Push dequeues */
|
||||
uint32_t sdq;
|
||||
/* Volatile dequeues */
|
||||
struct {
|
||||
/* VDQCR supports a "1 deep pipeline", meaning that if you know
|
||||
* the last-submitted command is already executing in the
|
||||
* hardware (as evidenced by at least 1 valid dequeue result),
|
||||
* you can write another dequeue command to the register, the
|
||||
* hardware will start executing it as soon as the
|
||||
* already-executing command terminates. (This minimises latency
|
||||
* and stalls.) With that in mind, this "busy" variable refers
|
||||
* to whether or not a command can be submitted, not whether or
|
||||
* not a previously-submitted command is still executing. In
|
||||
* other words, once proof is seen that the previously-submitted
|
||||
* command is executing, "vdq" is no longer "busy".
|
||||
*/
|
||||
atomic_t busy;
|
||||
uint32_t valid_bit; /* 0x00 or 0x80 */
|
||||
/* We need to determine when vdq is no longer busy. This depends
|
||||
* on whether the "busy" (last-submitted) dequeue command is
|
||||
* targeting DQRR or main-memory, and detected is based on the
|
||||
* presence of the dequeue command's "token" showing up in
|
||||
* dequeue entries in DQRR or main-memory (respectively). Debug
|
||||
* builds will, when submitting vdq commands, verify that the
|
||||
* dequeue result location is not already equal to the command's
|
||||
* token value. */
|
||||
struct ldpaa_dq *storage; /* NULL if DQRR */
|
||||
uint32_t token;
|
||||
} vdq;
|
||||
/* DQRR */
|
||||
struct {
|
||||
uint32_t next_idx;
|
||||
uint32_t valid_bit;
|
||||
} dqrr;
|
||||
};
|
||||
|
||||
/* -------------------------- */
|
||||
/* portal management commands */
|
||||
/* -------------------------- */
|
||||
|
||||
/* Different management commands all use this common base layer of code to issue
|
||||
* commands and poll for results. The first function returns a pointer to where
|
||||
* the caller should fill in their MC command (though they should ignore the
|
||||
* verb byte), the second function commits merges in the caller-supplied command
|
||||
* verb (which should not include the valid-bit) and submits the command to
|
||||
* hardware, and the third function checks for a completed response (returns
|
||||
* non-NULL if only if the response is complete). */
|
||||
void *qbman_swp_mc_start(struct qbman_swp *p);
|
||||
void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb);
|
||||
void *qbman_swp_mc_result(struct qbman_swp *p);
|
||||
|
||||
/* Wraps up submit + poll-for-result */
|
||||
static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd,
|
||||
uint32_t cmd_verb)
|
||||
{
|
||||
int loopvar;
|
||||
|
||||
qbman_swp_mc_submit(swp, cmd, cmd_verb);
|
||||
DBG_POLL_START(loopvar);
|
||||
do {
|
||||
DBG_POLL_CHECK(loopvar);
|
||||
cmd = qbman_swp_mc_result(swp);
|
||||
} while (!cmd);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/* ------------ */
|
||||
/* qb_attr_code */
|
||||
/* ------------ */
|
||||
|
||||
/* This struct locates a sub-field within a QBMan portal (CENA) cacheline which
|
||||
* is either serving as a configuration command or a query result. The
|
||||
* representation is inherently little-endian, as the indexing of the words is
|
||||
* itself little-endian in nature and layerscape is little endian for anything
|
||||
* that crosses a word boundary too (64-bit fields are the obvious examples).
|
||||
*/
|
||||
struct qb_attr_code {
|
||||
unsigned int word; /* which uint32_t[] array member encodes the field */
|
||||
unsigned int lsoffset; /* encoding offset from ls-bit */
|
||||
unsigned int width; /* encoding width. (bool must be 1.) */
|
||||
};
|
||||
|
||||
/* Macros to define codes */
|
||||
#define QB_CODE(a, b, c) { a, b, c}
|
||||
|
||||
/* decode a field from a cacheline */
|
||||
static inline uint32_t qb_attr_code_decode(const struct qb_attr_code *code,
|
||||
const uint32_t *cacheline)
|
||||
{
|
||||
return d32_uint32_t(code->lsoffset, code->width, cacheline[code->word]);
|
||||
}
|
||||
|
||||
|
||||
/* encode a field to a cacheline */
|
||||
static inline void qb_attr_code_encode(const struct qb_attr_code *code,
|
||||
uint32_t *cacheline, uint32_t val)
|
||||
{
|
||||
cacheline[code->word] =
|
||||
r32_uint32_t(code->lsoffset, code->width, cacheline[code->word])
|
||||
| e32_uint32_t(code->lsoffset, code->width, val);
|
||||
}
|
||||
|
||||
static inline void qb_attr_code_encode_64(const struct qb_attr_code *code,
|
||||
uint64_t *cacheline, uint64_t val)
|
||||
{
|
||||
cacheline[code->word / 2] = val;
|
||||
}
|
||||
|
||||
/* ---------------------- */
|
||||
/* Descriptors/cachelines */
|
||||
/* ---------------------- */
|
||||
|
||||
/* To avoid needless dynamic allocation, the driver API often gives the caller
|
||||
* a "descriptor" type that the caller can instantiate however they like.
|
||||
* Ultimately though, it is just a cacheline of binary storage (or something
|
||||
* smaller when it is known that the descriptor doesn't need all 64 bytes) for
|
||||
* holding pre-formatted pieces of hardware commands. The performance-critical
|
||||
* code can then copy these descriptors directly into hardware command
|
||||
* registers more efficiently than trying to construct/format commands
|
||||
* on-the-fly. The API user sees the descriptor as an array of 32-bit words in
|
||||
* order for the compiler to know its size, but the internal details are not
|
||||
* exposed. The following macro is used within the driver for converting *any*
|
||||
* descriptor pointer to a usable array pointer. The use of a macro (instead of
|
||||
* an inline) is necessary to work with different descriptor types and to work
|
||||
* correctly with const and non-const inputs (and similarly-qualified outputs).
|
||||
*/
|
||||
#define qb_cl(d) (&(d)->dont_manipulate_directly[0])
|
||||
169
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_private.h
Normal file
169
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_private.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* Perform extra checking */
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <malloc.h>
|
||||
#include <fsl-mc/fsl_qbman_base.h>
|
||||
|
||||
#define QBMAN_CHECKING
|
||||
|
||||
/* Any time there is a register interface which we poll on, this provides a
|
||||
* "break after x iterations" scheme for it. It's handy for debugging, eg.
|
||||
* where you don't want millions of lines of log output from a polling loop
|
||||
* that won't, because such things tend to drown out the earlier log output
|
||||
* that might explain what caused the problem. (NB: put ";" after each macro!)
|
||||
* TODO: we should probably remove this once we're done sanitising the
|
||||
* simulator...
|
||||
*/
|
||||
#define DBG_POLL_START(loopvar) (loopvar = 10)
|
||||
#define DBG_POLL_CHECK(loopvar) \
|
||||
do {if (!(loopvar--)) BUG_ON(NULL == "DBG_POLL_CHECK"); } while (0)
|
||||
|
||||
/* For CCSR or portal-CINH registers that contain fields at arbitrary offsets
|
||||
* and widths, these macro-generated encode/decode/isolate/remove inlines can
|
||||
* be used.
|
||||
*
|
||||
* Eg. to "d"ecode a 14-bit field out of a register (into a "uint16_t" type),
|
||||
* where the field is located 3 bits "up" from the least-significant bit of the
|
||||
* register (ie. the field location within the 32-bit register corresponds to a
|
||||
* mask of 0x0001fff8), you would do;
|
||||
* uint16_t field = d32_uint16_t(3, 14, reg_value);
|
||||
*
|
||||
* Or to "e"ncode a 1-bit boolean value (input type is "int", zero is FALSE,
|
||||
* non-zero is TRUE, so must convert all non-zero inputs to 1, hence the "!!"
|
||||
* operator) into a register at bit location 0x00080000 (19 bits "in" from the
|
||||
* LS bit), do;
|
||||
* reg_value |= e32_int(19, 1, !!field);
|
||||
*
|
||||
* If you wish to read-modify-write a register, such that you leave the 14-bit
|
||||
* field as-is but have all other fields set to zero, then "i"solate the 14-bit
|
||||
* value using;
|
||||
* reg_value = i32_uint16_t(3, 14, reg_value);
|
||||
*
|
||||
* Alternatively, you could "r"emove the 1-bit boolean field (setting it to
|
||||
* zero) but leaving all other fields as-is;
|
||||
* reg_val = r32_int(19, 1, reg_value);
|
||||
*
|
||||
*/
|
||||
#define MAKE_MASK32(width) (width == 32 ? 0xffffffff : \
|
||||
(uint32_t)((1 << width) - 1))
|
||||
#define DECLARE_CODEC32(t) \
|
||||
static inline uint32_t e32_##t(uint32_t lsoffset, uint32_t width, t val) \
|
||||
{ \
|
||||
BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return ((uint32_t)val & MAKE_MASK32(width)) << lsoffset; \
|
||||
} \
|
||||
static inline t d32_##t(uint32_t lsoffset, uint32_t width, uint32_t val) \
|
||||
{ \
|
||||
BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return (t)((val >> lsoffset) & MAKE_MASK32(width)); \
|
||||
} \
|
||||
static inline uint32_t i32_##t(uint32_t lsoffset, uint32_t width, \
|
||||
uint32_t val) \
|
||||
{ \
|
||||
BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return e32_##t(lsoffset, width, d32_##t(lsoffset, width, val)); \
|
||||
} \
|
||||
static inline uint32_t r32_##t(uint32_t lsoffset, uint32_t width, \
|
||||
uint32_t val) \
|
||||
{ \
|
||||
BUG_ON(width > (sizeof(t) * 8)); \
|
||||
return ~(MAKE_MASK32(width) << lsoffset) & val; \
|
||||
}
|
||||
DECLARE_CODEC32(uint32_t)
|
||||
DECLARE_CODEC32(uint16_t)
|
||||
DECLARE_CODEC32(uint8_t)
|
||||
DECLARE_CODEC32(int)
|
||||
|
||||
/*********************/
|
||||
/* Debugging assists */
|
||||
/*********************/
|
||||
|
||||
static inline void __hexdump(unsigned long start, unsigned long end,
|
||||
unsigned long p, size_t sz, const unsigned char *c)
|
||||
{
|
||||
while (start < end) {
|
||||
unsigned int pos = 0;
|
||||
char buf[64];
|
||||
int nl = 0;
|
||||
|
||||
pos += sprintf(buf + pos, "%08lx: ", start);
|
||||
do {
|
||||
if ((start < p) || (start >= (p + sz)))
|
||||
pos += sprintf(buf + pos, "..");
|
||||
else
|
||||
pos += sprintf(buf + pos, "%02x", *(c++));
|
||||
if (!(++start & 15)) {
|
||||
buf[pos++] = '\n';
|
||||
nl = 1;
|
||||
} else {
|
||||
nl = 0;
|
||||
if (!(start & 1))
|
||||
buf[pos++] = ' ';
|
||||
if (!(start & 3))
|
||||
buf[pos++] = ' ';
|
||||
}
|
||||
} while (start & 15);
|
||||
if (!nl)
|
||||
buf[pos++] = '\n';
|
||||
buf[pos] = '\0';
|
||||
debug("%s", buf);
|
||||
}
|
||||
}
|
||||
static inline void hexdump(const void *ptr, size_t sz)
|
||||
{
|
||||
unsigned long p = (unsigned long)ptr;
|
||||
unsigned long start = p & ~(unsigned long)15;
|
||||
unsigned long end = (p + sz + 15) & ~(unsigned long)15;
|
||||
const unsigned char *c = ptr;
|
||||
|
||||
__hexdump(start, end, p, sz, c);
|
||||
}
|
||||
|
||||
#if defined(__BIG_ENDIAN)
|
||||
#define DQRR_TOK_OFFSET 0
|
||||
#else
|
||||
#define DQRR_TOK_OFFSET 24
|
||||
#endif
|
||||
|
||||
/* Similarly-named functions */
|
||||
#define upper32(a) upper_32_bits(a)
|
||||
#define lower32(a) lower_32_bits(a)
|
||||
|
||||
/****************/
|
||||
/* arch assists */
|
||||
/****************/
|
||||
|
||||
static inline void dcbz(void *ptr)
|
||||
{
|
||||
uint32_t *p = ptr;
|
||||
BUG_ON((unsigned long)ptr & 63);
|
||||
p[0] = 0;
|
||||
p[1] = 0;
|
||||
p[2] = 0;
|
||||
p[3] = 0;
|
||||
p[4] = 0;
|
||||
p[5] = 0;
|
||||
p[6] = 0;
|
||||
p[7] = 0;
|
||||
p[8] = 0;
|
||||
p[9] = 0;
|
||||
p[10] = 0;
|
||||
p[11] = 0;
|
||||
p[12] = 0;
|
||||
p[13] = 0;
|
||||
p[14] = 0;
|
||||
p[15] = 0;
|
||||
}
|
||||
|
||||
#define lwsync()
|
||||
|
||||
#include "qbman_sys.h"
|
||||
290
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_sys.h
Normal file
290
sources/uboot-be550/drivers/net/fsl-mc/dpio/qbman_sys.h
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/* qbman_sys_decl.h and qbman_sys.h are the two platform-specific files in the
|
||||
* driver. They are only included via qbman_private.h, which is itself a
|
||||
* platform-independent file and is included by all the other driver source.
|
||||
*
|
||||
* qbman_sys_decl.h is included prior to all other declarations and logic, and
|
||||
* it exists to provide compatibility with any linux interfaces our
|
||||
* single-source driver code is dependent on (eg. kmalloc). Ie. this file
|
||||
* provides linux compatibility.
|
||||
*
|
||||
* This qbman_sys.h header, on the other hand, is included *after* any common
|
||||
* and platform-neutral declarations and logic in qbman_private.h, and exists to
|
||||
* implement any platform-specific logic of the qbman driver itself. Ie. it is
|
||||
* *not* to provide linux compatibility.
|
||||
*/
|
||||
|
||||
/* Trace the 3 different classes of read/write access to QBMan. #undef as
|
||||
* required. */
|
||||
#undef QBMAN_CCSR_TRACE
|
||||
#undef QBMAN_CINH_TRACE
|
||||
#undef QBMAN_CENA_TRACE
|
||||
|
||||
/* Temporarily define this to get around the fact that cache enabled mapping is
|
||||
* not working right now. Will remove this after uboot could map the cache
|
||||
* enabled portal memory.
|
||||
*/
|
||||
#define QBMAN_CINH_ONLY
|
||||
|
||||
static inline void word_copy(void *d, const void *s, unsigned int cnt)
|
||||
{
|
||||
uint32_t *dd = d;
|
||||
const uint32_t *ss = s;
|
||||
|
||||
while (cnt--)
|
||||
*(dd++) = *(ss++);
|
||||
}
|
||||
|
||||
/* Currently, the CENA support code expects each 32-bit word to be written in
|
||||
* host order, and these are converted to hardware (little-endian) order on
|
||||
* command submission. However, 64-bit quantities are must be written (and read)
|
||||
* as two 32-bit words with the least-significant word first, irrespective of
|
||||
* host endianness. */
|
||||
static inline void u64_to_le32_copy(void *d, const uint64_t *s,
|
||||
unsigned int cnt)
|
||||
{
|
||||
uint32_t *dd = d;
|
||||
const uint32_t *ss = (const uint32_t *)s;
|
||||
|
||||
while (cnt--) {
|
||||
/* TBD: the toolchain was choking on the use of 64-bit types up
|
||||
* until recently so this works entirely with 32-bit variables.
|
||||
* When 64-bit types become usable again, investigate better
|
||||
* ways of doing this. */
|
||||
#if defined(__BIG_ENDIAN)
|
||||
*(dd++) = ss[1];
|
||||
*(dd++) = ss[0];
|
||||
ss += 2;
|
||||
#else
|
||||
*(dd++) = *(ss++);
|
||||
*(dd++) = *(ss++);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
static inline void u64_from_le32_copy(uint64_t *d, const void *s,
|
||||
unsigned int cnt)
|
||||
{
|
||||
const uint32_t *ss = s;
|
||||
uint32_t *dd = (uint32_t *)d;
|
||||
|
||||
while (cnt--) {
|
||||
#if defined(__BIG_ENDIAN)
|
||||
dd[1] = *(ss++);
|
||||
dd[0] = *(ss++);
|
||||
dd += 2;
|
||||
#else
|
||||
*(dd++) = *(ss++);
|
||||
*(dd++) = *(ss++);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a host-native 32bit value into little endian */
|
||||
#if defined(__BIG_ENDIAN)
|
||||
static inline uint32_t make_le32(uint32_t val)
|
||||
{
|
||||
return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
|
||||
((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
|
||||
}
|
||||
#else
|
||||
#define make_le32(val) (val)
|
||||
#endif
|
||||
static inline void make_le32_n(uint32_t *val, unsigned int num)
|
||||
{
|
||||
while (num--) {
|
||||
*val = make_le32(*val);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Portal access */
|
||||
/******************/
|
||||
struct qbman_swp_sys {
|
||||
/* On GPP, the sys support for qbman_swp is here. The CENA region isi
|
||||
* not an mmap() of the real portal registers, but an allocated
|
||||
* place-holder, because the actual writes/reads to/from the portal are
|
||||
* marshalled from these allocated areas using QBMan's "MC access
|
||||
* registers". CINH accesses are atomic so there's no need for a
|
||||
* place-holder. */
|
||||
void *cena;
|
||||
void __iomem *addr_cena;
|
||||
void __iomem *addr_cinh;
|
||||
};
|
||||
|
||||
/* P_OFFSET is (ACCESS_CMD,0,12) - offset within the portal
|
||||
* C is (ACCESS_CMD,12,1) - is inhibited? (0==CENA, 1==CINH)
|
||||
* SWP_IDX is (ACCESS_CMD,16,10) - Software portal index
|
||||
* P is (ACCESS_CMD,28,1) - (0==special portal, 1==any portal)
|
||||
* T is (ACCESS_CMD,29,1) - Command type (0==READ, 1==WRITE)
|
||||
* E is (ACCESS_CMD,31,1) - Command execute (1 to issue, poll for 0==complete)
|
||||
*/
|
||||
|
||||
static inline void qbman_cinh_write(struct qbman_swp_sys *s, uint32_t offset,
|
||||
uint32_t val)
|
||||
{
|
||||
__raw_writel(val, s->addr_cinh + offset);
|
||||
#ifdef QBMAN_CINH_TRACE
|
||||
pr_info("qbman_cinh_write(%p:0x%03x) 0x%08x\n",
|
||||
s->addr_cinh, offset, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t qbman_cinh_read(struct qbman_swp_sys *s, uint32_t offset)
|
||||
{
|
||||
uint32_t reg = __raw_readl(s->addr_cinh + offset);
|
||||
|
||||
#ifdef QBMAN_CINH_TRACE
|
||||
pr_info("qbman_cinh_read(%p:0x%03x) 0x%08x\n",
|
||||
s->addr_cinh, offset, reg);
|
||||
#endif
|
||||
return reg;
|
||||
}
|
||||
|
||||
static inline void *qbman_cena_write_start(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
void *shadow = s->cena + offset;
|
||||
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_start(%p:0x%03x) %p\n",
|
||||
s->addr_cena, offset, shadow);
|
||||
#endif
|
||||
BUG_ON(offset & 63);
|
||||
dcbz(shadow);
|
||||
return shadow;
|
||||
}
|
||||
|
||||
static inline void qbman_cena_write_complete(struct qbman_swp_sys *s,
|
||||
uint32_t offset, void *cmd)
|
||||
{
|
||||
const uint32_t *shadow = cmd;
|
||||
int loop;
|
||||
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_write_complete(%p:0x%03x) %p\n",
|
||||
s->addr_cena, offset, shadow);
|
||||
hexdump(cmd, 64);
|
||||
#endif
|
||||
for (loop = 15; loop >= 0; loop--)
|
||||
#ifdef QBMAN_CINH_ONLY
|
||||
__raw_writel(shadow[loop], s->addr_cinh +
|
||||
offset + loop * 4);
|
||||
#else
|
||||
__raw_writel(shadow[loop], s->addr_cena +
|
||||
offset + loop * 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void *qbman_cena_read(struct qbman_swp_sys *s, uint32_t offset)
|
||||
{
|
||||
uint32_t *shadow = s->cena + offset;
|
||||
unsigned int loop;
|
||||
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
pr_info("qbman_cena_read(%p:0x%03x) %p\n",
|
||||
s->addr_cena, offset, shadow);
|
||||
#endif
|
||||
|
||||
for (loop = 0; loop < 16; loop++)
|
||||
#ifdef QBMAN_CINH_ONLY
|
||||
shadow[loop] = __raw_readl(s->addr_cinh + offset
|
||||
+ loop * 4);
|
||||
#else
|
||||
shadow[loop] = __raw_readl(s->addr_cena + offset
|
||||
+ loop * 4);
|
||||
#endif
|
||||
#ifdef QBMAN_CENA_TRACE
|
||||
hexdump(shadow, 64);
|
||||
#endif
|
||||
return shadow;
|
||||
}
|
||||
|
||||
static inline void qbman_cena_invalidate_prefetch(struct qbman_swp_sys *s,
|
||||
uint32_t offset)
|
||||
{
|
||||
}
|
||||
|
||||
/******************/
|
||||
/* Portal support */
|
||||
/******************/
|
||||
|
||||
/* The SWP_CFG portal register is special, in that it is used by the
|
||||
* platform-specific code rather than the platform-independent code in
|
||||
* qbman_portal.c. So use of it is declared locally here. */
|
||||
#define QBMAN_CINH_SWP_CFG 0xd00
|
||||
|
||||
/* For MC portal use, we always configure with
|
||||
* DQRR_MF is (SWP_CFG,20,3) - DQRR max fill (<- 0x4)
|
||||
* EST is (SWP_CFG,16,3) - EQCR_CI stashing threshold (<- 0x0)
|
||||
* RPM is (SWP_CFG,12,2) - RCR production notification mode (<- 0x3)
|
||||
* DCM is (SWP_CFG,10,2) - DQRR consumption notification mode (<- 0x2)
|
||||
* EPM is (SWP_CFG,8,2) - EQCR production notification mode (<- 0x3)
|
||||
* SD is (SWP_CFG,5,1) - memory stashing drop enable (<- FALSE)
|
||||
* SP is (SWP_CFG,4,1) - memory stashing priority (<- TRUE)
|
||||
* SE is (SWP_CFG,3,1) - memory stashing enable (<- 0x0)
|
||||
* DP is (SWP_CFG,2,1) - dequeue stashing priority (<- TRUE)
|
||||
* DE is (SWP_CFG,1,1) - dequeue stashing enable (<- 0x0)
|
||||
* EP is (SWP_CFG,0,1) - EQCR_CI stashing priority (<- FALSE)
|
||||
*/
|
||||
static inline uint32_t qbman_set_swp_cfg(uint8_t max_fill, uint8_t wn,
|
||||
uint8_t est, uint8_t rpm, uint8_t dcm,
|
||||
uint8_t epm, int sd, int sp, int se,
|
||||
int dp, int de, int ep)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = e32_uint8_t(20, 3, max_fill) | e32_uint8_t(16, 3, est) |
|
||||
e32_uint8_t(12, 2, rpm) | e32_uint8_t(10, 2, dcm) |
|
||||
e32_uint8_t(8, 2, epm) | e32_int(5, 1, sd) |
|
||||
e32_int(4, 1, sp) | e32_int(3, 1, se) | e32_int(2, 1, dp) |
|
||||
e32_int(1, 1, de) | e32_int(0, 1, ep) | e32_uint8_t(14, 1, wn);
|
||||
return reg;
|
||||
}
|
||||
|
||||
static inline int qbman_swp_sys_init(struct qbman_swp_sys *s,
|
||||
const struct qbman_swp_desc *d)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
s->addr_cena = d->cena_bar;
|
||||
s->addr_cinh = d->cinh_bar;
|
||||
s->cena = (void *)valloc(CONFIG_SYS_PAGE_SIZE);
|
||||
memset((void *)s->cena, 0x00, CONFIG_SYS_PAGE_SIZE);
|
||||
if (!s->cena) {
|
||||
printf("Could not allocate page for cena shadow\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef QBMAN_CHECKING
|
||||
/* We should never be asked to initialise for a portal that isn't in
|
||||
* the power-on state. (Ie. don't forget to reset portals when they are
|
||||
* decommissioned!)
|
||||
*/
|
||||
reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
|
||||
BUG_ON(reg);
|
||||
#endif
|
||||
#ifdef QBMAN_CINH_ONLY
|
||||
reg = qbman_set_swp_cfg(4, 1, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0);
|
||||
#else
|
||||
reg = qbman_set_swp_cfg(4, 0, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0);
|
||||
#endif
|
||||
qbman_cinh_write(s, QBMAN_CINH_SWP_CFG, reg);
|
||||
reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
|
||||
if (!reg) {
|
||||
printf("The portal is not enabled!\n");
|
||||
free(s->cena);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void qbman_swp_sys_finish(struct qbman_swp_sys *s)
|
||||
{
|
||||
free((void *)s->cena);
|
||||
}
|
||||
222
sources/uboot-be550/drivers/net/fsl-mc/dpmac.c
Normal file
222
sources/uboot-be550/drivers/net/fsl-mc/dpmac.c
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Freescale Layerscape MC I/O wrapper
|
||||
*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
* Author: Prabhakar Kushwaha <prabhakar@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <fsl-mc/fsl_mc_sys.h>
|
||||
#include <fsl-mc/fsl_mc_cmd.h>
|
||||
#include <fsl-mc/fsl_dpmac.h>
|
||||
|
||||
int dpmac_open(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
int dpmac_id,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPMAC_CMD_OPEN(cmd, dpmac_id);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int dpmac_close(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpmac_create(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
const struct dpmac_cfg *cfg,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPMAC_CMD_CREATE(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpmac_destroy(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpmac_get_attributes(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpmac_attr *attr)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPMAC_RSP_GET_ATTRIBUTES(cmd, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpmac_mdio_read(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpmac_mdio_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_MDIO_READ,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPMAC_CMD_MDIO_READ(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPMAC_RSP_MDIO_READ(cmd, cfg->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpmac_mdio_write(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpmac_mdio_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_MDIO_WRITE,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPMAC_CMD_MDIO_WRITE(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpmac_get_link_cfg(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpmac_link_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err = 0;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
DPMAC_RSP_GET_LINK_CFG(cmd, cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpmac_set_link_state(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpmac_link_state *link_state)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPMAC_CMD_SET_LINK_STATE(cmd, link_state);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpmac_get_counter(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
enum dpmac_counter type,
|
||||
uint64_t *counter)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err = 0;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPMAC_CMD_GET_COUNTER(cmd, type);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
DPMAC_RSP_GET_COUNTER(cmd, *counter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
sources/uboot-be550/drivers/net/fsl-mc/dpmng.c
Normal file
31
sources/uboot-be550/drivers/net/fsl-mc/dpmng.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* Copyright 2013-2015 Freescale Semiconductor Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <fsl-mc/fsl_mc_sys.h>
|
||||
#include <fsl-mc/fsl_mc_cmd.h>
|
||||
#include <fsl-mc/fsl_dpmng.h>
|
||||
#include "fsl_dpmng_cmd.h"
|
||||
|
||||
int mc_get_version(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
struct mc_version *mc_ver_info)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPMNG_CMDID_GET_VERSION,
|
||||
cmd_flags,
|
||||
0);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPMNG_RSP_GET_VERSION(cmd, mc_ver_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
604
sources/uboot-be550/drivers/net/fsl-mc/dpni.c
Normal file
604
sources/uboot-be550/drivers/net/fsl-mc/dpni.c
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2015 Freescale Semiconductor
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <fsl-mc/fsl_mc_sys.h>
|
||||
#include <fsl-mc/fsl_mc_cmd.h>
|
||||
#include <fsl-mc/fsl_dpni.h>
|
||||
|
||||
int dpni_open(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
int dpni_id,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPNI_CMD_OPEN(cmd, dpni_id);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_close(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_create(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
const struct dpni_cfg *cfg,
|
||||
uint16_t *token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_CREATE,
|
||||
cmd_flags,
|
||||
0);
|
||||
DPNI_CMD_CREATE(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
*token = MC_CMD_HDR_READ_TOKEN(cmd.header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_destroy(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_DESTROY,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_set_pools(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const struct dpni_pools_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_POOLS(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_enable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_disable(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_reset(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_attributes(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpni_attr *attr)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_ATTR(cmd, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_get_rx_buffer_layout(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpni_buffer_layout *layout)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_BUFFER_LAYOUT,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_RX_BUFFER_LAYOUT(cmd, layout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_set_rx_buffer_layout(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const struct dpni_buffer_layout *layout)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_BUFFER_LAYOUT,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_RX_BUFFER_LAYOUT(cmd, layout);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_tx_buffer_layout(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpni_buffer_layout *layout)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_BUFFER_LAYOUT,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_TX_BUFFER_LAYOUT(cmd, layout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_set_tx_buffer_layout(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const struct dpni_buffer_layout *layout)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_BUFFER_LAYOUT,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_TX_BUFFER_LAYOUT(cmd, layout);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_tx_conf_buffer_layout(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpni_buffer_layout *layout)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_CONF_BUFFER_LAYOUT,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_TX_CONF_BUFFER_LAYOUT(cmd, layout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_set_tx_conf_buffer_layout(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const struct dpni_buffer_layout *layout)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF_BUFFER_LAYOUT,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_TX_CONF_BUFFER_LAYOUT(cmd, layout);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_qdid(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint16_t *qdid)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QDID,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_QDID(cmd, *qdid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint16_t *data_offset)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_DATA_OFFSET,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_TX_DATA_OFFSET(cmd, *data_offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_get_counter(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
enum dpni_counter counter,
|
||||
uint64_t *value)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_COUNTER,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_GET_COUNTER(cmd, counter);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_COUNTER(cmd, *value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_set_counter(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
enum dpni_counter counter,
|
||||
uint64_t value)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_COUNTER,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_COUNTER(cmd, counter, value);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const struct dpni_link_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_LINK_CFG(cmd, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_link_state(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
struct dpni_link_state *state)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_LINK_STATE(cmd, state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const uint8_t mac_addr[6])
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PRIM_MAC,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_PRIMARY_MAC_ADDR(cmd, mac_addr);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t mac_addr[6])
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PRIM_MAC,
|
||||
cmd_flags,
|
||||
token);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_PRIMARY_MAC_ADDR(cmd, mac_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_add_mac_addr(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const uint8_t mac_addr[6])
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_remove_mac_addr(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
const uint8_t mac_addr[6])
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_set_tx_flow(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint16_t *flow_id,
|
||||
const struct dpni_tx_flow_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_FLOW,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_TX_FLOW(cmd, *flow_id, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_SET_TX_FLOW(cmd, *flow_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_get_tx_flow(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint16_t flow_id,
|
||||
struct dpni_tx_flow_attr *attr)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_FLOW,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_GET_TX_FLOW(cmd, flow_id);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_TX_FLOW(cmd, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpni_set_rx_flow(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t tc_id,
|
||||
uint16_t flow_id,
|
||||
const struct dpni_queue_cfg *cfg)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_FLOW,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_SET_RX_FLOW(cmd, tc_id, flow_id, cfg);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
}
|
||||
|
||||
int dpni_get_rx_flow(struct fsl_mc_io *mc_io,
|
||||
uint32_t cmd_flags,
|
||||
uint16_t token,
|
||||
uint8_t tc_id,
|
||||
uint16_t flow_id,
|
||||
struct dpni_queue_attr *attr)
|
||||
{
|
||||
struct mc_command cmd = { 0 };
|
||||
int err;
|
||||
/* prepare command */
|
||||
cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_FLOW,
|
||||
cmd_flags,
|
||||
token);
|
||||
DPNI_CMD_GET_RX_FLOW(cmd, tc_id, flow_id);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* retrieve response parameters */
|
||||
DPNI_RSP_GET_RX_FLOW(cmd, attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue