// SPDX-License-Identifier: GPL-2.0-only
/*
* r8169_phy_config.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/phy.h>
#include "r8169.h"
typedef void (*rtl_phy_cfg_fct)(struct rtl8169_private *tp,
struct phy_device *phydev);
static void r8168d_modify_extpage(struct phy_device *phydev, int extpage,
int reg, u16 mask, u16 val)
{
int oldpage = phy_select_page(phydev, 0x0007);
__phy_write(phydev, 0x1e, extpage);
__phy_modify(phydev, reg, mask, val);
phy_restore_page(phydev, oldpage, 0);
}
static void r8168d_phy_param(struct phy_device *phydev, u16 parm,
u16 mask, u16 val)
{
int oldpage = phy_select_page(phydev, 0x0005);
__phy_write(phydev, 0x05, parm);
__phy_modify(phydev, 0x06, mask, val);
phy_restore_page(phydev, oldpage, 0);
}
static void r8168g_phy_param(struct phy_device *phydev, u16 parm,
u16 mask, u16 val)
{
int oldpage = phy_select_page(phydev, 0x0a43);
__phy_write(phydev, 0x13, parm);
__phy_modify(phydev, 0x14, mask, val);
phy_restore_page(phydev, oldpage, 0);
}
struct phy_reg {
u16 reg;
u16 val;
};
static void __rtl_writephy_batch(struct phy_device *phydev,
const struct phy_reg *regs, int len)
{
phy_lock_mdio_bus(phydev);
while (len-- > 0) {
__phy_write(phydev, regs->reg, regs->val);
regs++;
}
phy_unlock_mdio_bus(phydev);
}
#define rtl_writephy_batch(p, a) __rtl_writephy_batch(p, a, ARRAY_SIZE(a))
static void rtl8168f_config_eee_phy(struct phy_device *phydev)
{
r8168d_modify_extpage(phydev, 0x0020, 0x15, 0, BIT(8));
r8168d_phy_param(phydev, 0x8b85, 0, BIT(13));
}
static void rtl8168g_config_eee_phy(struct phy_device *phydev)
{
phy_modify_paged(phydev, 0x0a43, 0x11, 0, BIT(4));
}
static void rtl8168h_config_eee_phy(struct phy_device *phydev)
{
rtl8168g_config_eee_phy(phydev);
phy_modify_paged(phydev, 0xa4a, 0x11, 0x0000, 0x0200);
phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080);
}
static void rtl8125a_config_eee_phy(struct phy_device *phydev)
{
rtl8168h_config_eee_phy(phydev);
phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000);
phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
}
static void rtl8125b_config_eee_phy(struct phy_device *phydev)
{
phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000);
phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000);
phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000);
phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000);
}
static void rtl8169s_hw_phy_config(struct rtl8169_private *tp,
struct phy_device *phydev)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
{ 0x06, 0x006e },
{ 0x08, 0x0708 },
{ 0x15, 0x4000 },
{ 0x18, 0x65c7 },
{ 0x1f, 0x0001 },
{ 0x03, 0x00a1 },
{ 0x02, 0x0008 },
{ 0x01, 0x0120 },
{ 0x00, 0x1000 },
{ 0x04, 0x0800 },
{ 0x04, 0x0000 },
{ 0x03, 0xff41 },
{ 0x02, 0xdf60 },
{ 0x01, 0x0140 },
{ 0x00, 0x0077 },
{ 0x04, 0x7800