mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-23 08:37:33 -04:00
Cross-merge networking fixes after downstream PR (net-7.1-rc6). Conflicts: drivers/net/phy/air_en8811h.cd895767c33("net: phy: air_en8811h: add AN8811HB MCU assert/deassert support")dddfadd751("net: phy: Add Airoha phy library for shared code")5226bb6634("net: phy: air_phy_lib: Factorize BuckPBus register accessors")e08f0ea6da("net: phy: Rename Airoha common BuckPBus register accessors") net/sched/sch_netem.ca2f6ed7b48("net/sched: netem: add per-impairment extended statistics")9552b11e3e("net/sched: fix packet loop on netem when duplicate is on") Adjacent changes: drivers/dpll/zl3073x/core.cc1224569ce("dpll: zl3073x: make frequency monitor a per-device attribute")54e65df8cf("dpll: zl3073x: report FFO as DPLL vs input reference offset") net/iucv/af_iucv.c347fdd4df8("af_iucv: convert to getsockopt_iter")3589d20a66("net/iucv: fix locking in .getsockopt") Signed-off-by: Jakub Kicinski <kuba@kernel.org>
212 lines
5.0 KiB
C
212 lines
5.0 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Airoha Ethernet PHY common library
|
|
*
|
|
* Copyright (C) 2026 Airoha Technology Corp.
|
|
* Copyright (C) 2026 Collabora Ltd.
|
|
* Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
#include <linux/module.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/wordpart.h>
|
|
|
|
#include "air_phy_lib.h"
|
|
|
|
static int __air_buckpbus_reg_read(struct phy_device *phydev,
|
|
u32 pbus_address, u32 *pbus_data)
|
|
{
|
|
int pbus_data_low, pbus_data_high;
|
|
int ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
|
|
upper_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
|
|
lower_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
|
|
if (pbus_data_high < 0)
|
|
return pbus_data_high;
|
|
|
|
pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
|
|
if (pbus_data_low < 0)
|
|
return pbus_data_low;
|
|
|
|
*pbus_data = pbus_data_low | (pbus_data_high << 16);
|
|
return 0;
|
|
}
|
|
|
|
static int __air_buckpbus_reg_write(struct phy_device *phydev,
|
|
u32 pbus_address, u32 pbus_data)
|
|
{
|
|
int ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
|
|
upper_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
|
|
lower_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
|
|
upper_16_bits(pbus_data));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
|
|
lower_16_bits(pbus_data));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __air_buckpbus_reg_modify(struct phy_device *phydev,
|
|
u32 pbus_address, u32 mask, u32 set)
|
|
{
|
|
int pbus_data_low, pbus_data_high;
|
|
u32 pbus_data_old, pbus_data_new;
|
|
int ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
|
|
upper_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
|
|
lower_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
|
|
if (pbus_data_high < 0)
|
|
return pbus_data_high;
|
|
|
|
pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
|
|
if (pbus_data_low < 0)
|
|
return pbus_data_low;
|
|
|
|
pbus_data_old = pbus_data_low | (pbus_data_high << 16);
|
|
pbus_data_new = (pbus_data_old & ~mask) | set;
|
|
if (pbus_data_new == pbus_data_old)
|
|
return 0;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
|
|
upper_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
|
|
lower_16_bits(pbus_address));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
|
|
upper_16_bits(pbus_data_new));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
|
|
lower_16_bits(pbus_data_new));
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address,
|
|
u32 *pbus_data)
|
|
{
|
|
int saved_page;
|
|
int ret = 0;
|
|
|
|
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
|
|
|
|
if (saved_page >= 0) {
|
|
ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data);
|
|
if (ret < 0)
|
|
phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
|
|
pbus_address, ret);
|
|
}
|
|
|
|
return phy_restore_page(phydev, saved_page, ret);
|
|
}
|
|
EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_read);
|
|
|
|
int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address,
|
|
u32 pbus_data)
|
|
{
|
|
int saved_page;
|
|
int ret = 0;
|
|
|
|
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
|
|
|
|
if (saved_page >= 0) {
|
|
ret = __air_buckpbus_reg_write(phydev, pbus_address,
|
|
pbus_data);
|
|
if (ret < 0)
|
|
phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
|
|
pbus_address, ret);
|
|
}
|
|
|
|
return phy_restore_page(phydev, saved_page, ret);
|
|
}
|
|
EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_write);
|
|
|
|
int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address,
|
|
u32 mask, u32 set)
|
|
{
|
|
int saved_page;
|
|
int ret = 0;
|
|
|
|
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
|
|
|
|
if (saved_page >= 0) {
|
|
ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask,
|
|
set);
|
|
if (ret < 0)
|
|
phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
|
|
pbus_address, ret);
|
|
}
|
|
|
|
return phy_restore_page(phydev, saved_page, ret);
|
|
}
|
|
EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_modify);
|
|
|
|
int air_phy_read_page(struct phy_device *phydev)
|
|
{
|
|
return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);
|
|
}
|
|
EXPORT_SYMBOL_GPL(air_phy_read_page);
|
|
|
|
int air_phy_write_page(struct phy_device *phydev, int page)
|
|
{
|
|
return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);
|
|
}
|
|
EXPORT_SYMBOL_GPL(air_phy_write_page);
|
|
|
|
MODULE_DESCRIPTION("Airoha PHY Library");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Louis-Alexis Eyraud");
|