mediatek: add support for Realtek RTL8261n 10G PHYs

There is no upstream driver yet. Merge the RTL SDK driver for now.

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin 2024-10-29 13:37:40 +01:00
parent 7c8bfc0be5
commit 0f6aafcc24
23 changed files with 6300 additions and 0 deletions

View File

@ -0,0 +1,5 @@
config RTL8261N_PHY
tristate "Driver for Realtek RTL8261N PHYs"
help
Currently supports the RTL8261N,RTL8264B PHYs.

View File

@ -0,0 +1,11 @@
obj-$(CONFIG_RTL8261N_PHY) += rtl8621n.o
rtl8621n-objs += phy_patch.o
rtl8621n-objs += phy_rtl826xb_patch.o
rtl8621n-objs += rtk_osal.o
rtl8621n-objs += rtk_phy.o
rtl8621n-objs += rtk_phylib.o
rtl8621n-objs += rtk_phylib_rtl826xb.o
ccflags-y += -Werror -DRTK_PHYDRV_IN_LINUX

View 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__ */

View 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;
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View 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;
}

View 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 */

View File

@ -0,0 +1,282 @@
/*
* 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 "phy_rtl826xb_patch.h"
#include "rtk_phylib_rtl826xb.h"
#include "rtk_phylib.h"
#define REALTEK_PHY_ID_RTL8261N 0x001CCAF3
#define REALTEK_PHY_ID_RTL8264B 0x001CC813
static int rtl826xb_get_features(struct phy_device *phydev)
{
int ret;
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);
/* 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);
return 0;
}
static int rtl826xb_probe(struct phy_device *phydev)
{
struct rtk_phy_priv *priv = NULL;
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;
priv->phytype = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (RTK_PHYLIB_RTL8261N) : (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_modify_mmd_changed(phydev, 30, 0x145, BIT(0) , 1);
phy_modify_mmd_changed(phydev, 30, 0x145, BIT(0) , 0);
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;
}
#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)
{
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;
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
if (phydev->autoneg == AUTONEG_DISABLE)
return genphy_c45_pma_setup_forced(phydev);
ret = genphy_c45_an_config_aneg(phydev);
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 struct phy_driver rtk_phy_drivers[] = {
{
PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N),
.name = "Realtek RTL8261N",
.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,
},
{
PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B),
.name = "Realtek RTL8264B",
.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,
},
};
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");

View File

@ -0,0 +1,108 @@
/*
* SPDX-License-Identifier: GPL-2.0-only
*
* Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved.
*/
#include "rtk_phylib.h"
#include <linux/phy.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
}
/* 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);
#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;
}

View File

@ -0,0 +1,101 @@
/*
* 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 "type.h"
#include "rtk_phylib_def.h"
#else
//#include SDK headers
#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)
#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)
#endif
typedef enum rtk_phylib_phy_e
{
RTK_PHYLIB_NONE,
RTK_PHYLIB_RTL8261N,
RTK_PHYLIB_RTL8264B,
RTK_PHYLIB_END
} rtk_phylib_phy_t;
struct rtk_phy_priv {
rtk_phylib_phy_t phytype;
uint8 isBasePort;
rt_phy_patch_db_t *patch;
};
#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[_start+_i] = (_val >> (8* (_valbytes - _i - 1)));\
}while(0)
#define RTK_PHYLIB_BYTE_ARRAY_TO_VAL(_val, _array, _start, _bytes)\
do{\
uint32 _i = 0;\
for (_i = 0; _i < _bytes; _i++)\
_val = (_val << 8) | _array[_start + _i];\
}while(0)
/* OSAL */
void rtk_phylib_mdelay(uint32 msec);
void rtk_phylib_udelay(uint32 usec);
/* 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);
#endif /* __RTK_PHYLIB_H */

View File

@ -0,0 +1,166 @@
/*
* 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 0
#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)
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
#endif /* __RTK_PHYLIB_DEF_H */

View File

@ -0,0 +1,57 @@
/*
* 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;
}

View File

@ -0,0 +1,19 @@
/*
* 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
#if defined(RTK_PHYDRV_IN_LINUX)
#include "rtk_phylib.h"
#else
//#include SDK headers
#endif
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);
#endif /* __RTK_PHYLIB_RTL826XB_H */

View 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__ */

View File

@ -428,6 +428,7 @@ CONFIG_RPS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MT7622=y
CONFIG_RTC_I2C_AND_SPI=y
CONFIG_RTL8261N_PHY=y
# CONFIG_RTL8367S_GSW is not set
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_SCHED_MC=y

View File

@ -424,6 +424,7 @@ CONFIG_RPS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MT7622=y
CONFIG_RTC_I2C_AND_SPI=y
# CONFIG_RTL8261N_PHY is not set
CONFIG_RTL8367S_GSW=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_SCHED_MC=y

View File

@ -541,6 +541,7 @@ CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_MT7622 is not set
CONFIG_RTC_I2C_AND_SPI=y
CONFIG_RTC_MC146818_LIB=y
# CONFIG_RTL8261N_PHY is not set
# CONFIG_RTL8367S_GSW is not set
CONFIG_RWSEM_SPIN_ON_OWNER=y
# CONFIG_SERIAL_8250_DMA is not set

View File

@ -301,6 +301,7 @@ CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
# CONFIG_RTL8261N_PHY is not set
# CONFIG_RTL8367S_GSW is not set
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_SCSI=y

View File

@ -0,0 +1,21 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -334,6 +334,8 @@ config REALTEK_PHY
help
Supports the Realtek 821x PHY.
+source "drivers/net/phy/rtl8261n/Kconfig"
+
config RENESAS_PHY
tristate "Renesas PHYs"
help
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_ADIN_PHY) += adin.o
obj-y += qcom/
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
+obj-y += rtl8261n/
obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o
obj-$(CONFIG_SMSC_PHY) += smsc.o