drivers: net: Add support for QCA8084 PHY

This patch adds initial support for qca8084 PHY
which is based on qca8081 PHY.

qca8084 PHY has support for 4x2.5G.

Change-Id: Ic767c19fad050e5ee9a97ad7fa50c1b6b27893dd
Signed-off-by: Selvam Sathappan Periakaruppan <quic_speriaka@quicinc.com>
This commit is contained in:
Selvam Sathappan Periakaruppan 2022-05-17 09:14:08 +05:30 committed by Gerrit - the friendly Code Review server
parent 5837a5e6c6
commit 18d2b93ab3
15 changed files with 2698 additions and 0 deletions

View file

@ -18,4 +18,6 @@ config IPQ9574_QCA_AQUANTIA_PHY
config IPQ9574_QCA8075_PHY config IPQ9574_QCA8075_PHY
bool "Enable Malibu PHY support for ipq9574" bool "Enable Malibu PHY support for ipq9574"
config QCA8084_PHY
bool "Enable QCA8084 PHY support for ipq9574"
endif endif

View file

@ -102,6 +102,7 @@ CONFIG_CMD_NFS=y
CONFIG_IPQ9574_QCA_AQUANTIA_PHY=y CONFIG_IPQ9574_QCA_AQUANTIA_PHY=y
# CONFIG_QCA8033_PHY is not set # CONFIG_QCA8033_PHY is not set
CONFIG_QCA8081_PHY=y CONFIG_QCA8081_PHY=y
CONFIG_QCA8084_PHY=y
CONFIG_IPQ9574_QCA8075_PHY=y CONFIG_IPQ9574_QCA8075_PHY=y
# #

View file

@ -96,6 +96,9 @@ obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/athrs17_phy.o
obj-$(CONFIG_IPQ_MDIO) += ipq_common/ipq_mdio.o obj-$(CONFIG_IPQ_MDIO) += ipq_common/ipq_mdio.o
obj-$(CONFIG_GEPHY) += ipq_common/ipq_gephy.o obj-$(CONFIG_GEPHY) += ipq_common/ipq_gephy.o
obj-$(CONFIG_QCA8075_PHY) += ipq_common/ipq_qca8075.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_IPQ9574_QCA8075_PHY) += ipq9574/ipq9574_qca8075.o obj-$(CONFIG_IPQ9574_QCA8075_PHY) += ipq9574/ipq9574_qca8075.o
obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o
obj-$(CONFIG_QCA8081_PHY) += ipq_common/ipq_qca8081.o obj-$(CONFIG_QCA8081_PHY) += ipq_common/ipq_qca8081.o

View file

@ -11,6 +11,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/bitops.h>
#include <linux/compat.h>
#include <common.h> #include <common.h>
#include <command.h> #include <command.h>
#include <miiphy.h> #include <miiphy.h>
@ -19,6 +21,12 @@
#include <errno.h> #include <errno.h>
#include "ipq_mdio.h" #include "ipq_mdio.h"
#ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args);
#else
#define pr_debug(fmt, args...)
#endif
struct ipq_mdio_data { struct ipq_mdio_data {
struct mii_bus *bus; struct mii_bus *bus;
int phy_irq[PHY_MAX_ADDR]; int phy_irq[PHY_MAX_ADDR];
@ -162,6 +170,202 @@ int ipq_phy_read(struct mii_dev *bus,
return ipq_mdio_read(addr, regnum, NULL); return ipq_mdio_read(addr, regnum, NULL);
} }
#ifdef CONFIG_QCA8084_PHY
static inline void split_addr(uint32_t regaddr, uint16_t *r1, uint16_t *r2,
uint16_t *page, uint16_t *switch_phy_id)
{
*r1 = regaddr & 0x1c;
regaddr >>= 5;
*r2 = regaddr & 0x7;
regaddr >>= 3;
*page = regaddr & 0xffff;
regaddr >>= 16;
*switch_phy_id = regaddr & 0xff;
}
uint32_t ipq_mii_read(uint32_t reg)
{
uint16_t r1, r2, page, switch_phy_id;
uint16_t lo, hi;
split_addr((uint32_t) reg, &r1, &r2, &page, &switch_phy_id);
mutex_lock(&switch_mdio_lock);
ipq_mdio_write(0x18 | (switch_phy_id >> 5), switch_phy_id & 0x1f, page);
udelay(100);
lo = ipq_mdio_read(0x10 | r2, r1, NULL);
hi = ipq_mdio_read(0x10 | r2, r1 + 2, NULL);
mutex_unlock(&switch_mdio_lock);
return (hi << 16) | lo;
}
void ipq_mii_write(uint32_t reg, uint32_t val)
{
uint16_t r1, r2, page, switch_phy_id;
uint16_t lo, hi;
split_addr((uint32_t) reg, &r1, &r2, &page, &switch_phy_id);
lo = val & 0xffff;
hi = (uint16_t) (val >> 16);
mutex_lock(&switch_mdio_lock);
ipq_mdio_write(0x18 | (switch_phy_id >> 5), switch_phy_id & 0x1f, page);
udelay(100);
ipq_mdio_write(0x10 | r2, r1, lo);
ipq_mdio_write(0x10 | r2, r1 + 2, hi);
mutex_unlock(&switch_mdio_lock);
}
void ipq_mii_update(uint32_t reg, uint32_t mask, uint32_t val)
{
uint32_t new_val = 0, org_val = 0;
org_val = ipq_mii_read(reg);
new_val = org_val & ~mask;
new_val |= val & mask;
if (new_val != org_val)
ipq_mii_write(reg, new_val);
}
static inline void ipq_clk_enable(uint32_t reg)
{
u32 val;
val = ipq_mii_read(reg);
val |= BIT(0);
ipq_mii_write(reg, val);
}
static inline void ipq_clk_disable(uint32_t reg)
{
u32 val;
val = ipq_mii_read(reg);
val &= ~BIT(0);
ipq_mii_write(reg, val);
}
static inline void ipq_clk_reset(uint32_t reg)
{
u32 val;
val = ipq_mii_read(reg);
val |= BIT(2);
ipq_mii_write(reg, val);
udelay(21000);
val &= ~BIT(2);
ipq_mii_write(reg, val);
}
void ipq_clock_init(void)
{
u32 val = 0;
int i;
/* Enable serdes */
ipq_clk_enable(SRDS0_SYS_CBCR);
ipq_clk_enable(SRDS1_SYS_CBCR);
/* Reset serdes */
ipq_clk_reset(SRDS0_SYS_CBCR);
ipq_clk_reset(SRDS1_SYS_CBCR);
/* Disable EPHY GMII clock */
i = 0;
while (i < 2 * PHY_ADDR_NUM) {
ipq_clk_disable(GEPHY0_TX_CBCR + i*0x20);
i++;
}
/* Enable ephy */
ipq_clk_enable(EPHY0_SYS_CBCR);
ipq_clk_enable(EPHY1_SYS_CBCR);
ipq_clk_enable(EPHY2_SYS_CBCR);
ipq_clk_enable(EPHY3_SYS_CBCR);
/* Reset ephy */
ipq_clk_reset(EPHY0_SYS_CBCR);
ipq_clk_reset(EPHY1_SYS_CBCR);
ipq_clk_reset(EPHY2_SYS_CBCR);
ipq_clk_reset(EPHY3_SYS_CBCR);
/* Deassert EPHY DSP */
val = ipq_mii_read(GCC_GEPHY_MISC);
val &= ~GENMASK(4, 0);
ipq_mii_write(GCC_GEPHY_MISC, val);
/* Enable efuse loading into analog circuit */
val = ipq_mii_read(EPHY_CFG);
/* BIT20 for PHY0 and PHY1, BIT21 for PHY2 and PHY3 */
val &= ~GENMASK(21, 20);
ipq_mii_write(EPHY_CFG, val);
udelay(11000);
}
void ipq_phy_addr_fixup(void)
{
int phy_index, addr;
u32 val;
unsigned long phyaddr_mask = 0;
val = ipq_mii_read(EPHY_CFG);
for (phy_index = 0, addr = 1; addr <= 4; phy_index++, addr++) {
phyaddr_mask |= BIT(addr);
addr &= GENMASK(4, 0);
val &= ~(GENMASK(4, 0) << (phy_index * PHY_ADDR_LENGTH));
val |= addr << (phy_index * PHY_ADDR_LENGTH);
}
pr_debug("programme EPHY reg 0x%x with 0x%x\n", EPHY_CFG, val);
ipq_mii_write(EPHY_CFG, val);
/* Programe the UNIPHY address if uniphyaddr_fixup specified.
* the UNIPHY address will select three MDIO address from
* unoccupied MDIO address space.
*/
val = ipq_mii_read(UNIPHY_CFG);
/* For qca8386, the switch occupies the other 16 MDIO address,
* for example, if the phy address is in the range of 0 to 15,
* the switch will occupy the MDIO address from 16 to 31.
*/
phyaddr_mask |= GENMASK(31, 16);
phy_index = 0;
for_each_clear_bit_from(addr, &phyaddr_mask, PHY_MAX_ADDR) {
if (phy_index >= UNIPHY_ADDR_NUM)
break;
val &= ~(GENMASK(4, 0) << (phy_index * PHY_ADDR_LENGTH));
val |= addr << (phy_index * PHY_ADDR_LENGTH);
phy_index++;
}
if (phy_index < UNIPHY_ADDR_NUM) {
for_each_clear_bit(addr, &phyaddr_mask, PHY_MAX_ADDR) {
if (phy_index >= UNIPHY_ADDR_NUM)
break;
val &= ~(GENMASK(4, 0) << (phy_index * PHY_ADDR_LENGTH));
val |= addr << (phy_index * PHY_ADDR_LENGTH);
phy_index++;
}
}
pr_debug("programme UNIPHY reg 0x%x with 0x%x\n", UNIPHY_CFG, val);
ipq_mii_write(UNIPHY_CFG, val);
}
#endif
int ipq_sw_mdio_init(const char *name) int ipq_sw_mdio_init(const char *name)
{ {
struct mii_dev *bus = mdio_alloc(); struct mii_dev *bus = mdio_alloc();
@ -169,6 +373,7 @@ int ipq_sw_mdio_init(const char *name)
printf("Failed to allocate IPQ MDIO bus\n"); printf("Failed to allocate IPQ MDIO bus\n");
return -1; return -1;
} }
bus->read = ipq_phy_read; bus->read = ipq_phy_read;
bus->write = ipq_phy_write; bus->write = ipq_phy_write;
bus->reset = NULL; bus->reset = NULL;
@ -176,6 +381,47 @@ int ipq_sw_mdio_init(const char *name)
return mdio_register(bus); return mdio_register(bus);
} }
#ifdef CONFIG_QCA8084_PHY
static int do_ipq_mii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
char op[2];
unsigned int reg = 0;
unsigned short data = 0;
if (argc < 2)
return CMD_RET_USAGE;
op[0] = argv[1][0];
if (strlen(argv[1]) > 1)
op[1] = argv[1][1];
else
op[1] = '\0';
if (argc >= 3)
reg = simple_strtoul(argv[2], NULL, 16);
if (argc >= 4)
data = simple_strtoul(argv[3], NULL, 16);
if (op[0] == 'r') {
data = ipq_mii_read(reg);
printf("0x%x\n", data);
} else if (op[0] == 'w') {
ipq_mii_write(reg, data);
} else {
return CMD_RET_USAGE;
}
return 0;
}
U_BOOT_CMD(
ipq_mii, 4, 1, do_ipq_mii,
"IPQ mii utility commands",
"ipq_mii read <reg> - read IPQ MII register <reg>\n"
"ipq_mii write <reg> <data> - write IPQ MII register <reg> with <data>\n"
);
#endif
static int do_ipq_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) static int do_ipq_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{ {
char op[2]; char op[2];

View file

@ -34,4 +34,24 @@
#endif #endif
#define IPQ_MDIO_RETRY 1000 #define IPQ_MDIO_RETRY 1000
#define IPQ_MDIO_DELAY 5 #define IPQ_MDIO_DELAY 5
/* QCA8084 related MDIO Init macros */
#define UNIPHY_CFG 0xC90F014
#define EPHY_CFG 0xC90F018
#define GEPHY0_TX_CBCR 0xC800058
#define SRDS0_SYS_CBCR 0xC8001A8
#define SRDS1_SYS_CBCR 0xC8001AC
#define EPHY0_SYS_CBCR 0xC8001B0
#define EPHY1_SYS_CBCR 0xC8001B4
#define EPHY2_SYS_CBCR 0xC8001B8
#define EPHY3_SYS_CBCR 0xC8001BC
#define GCC_GEPHY_MISC 0xC800304
#define PHY_ADDR_LENGTH 5
#define PHY_ADDR_NUM 4
#define UNIPHY_ADDR_NUM 3
#define MII_HIGH_ADDR_PREFIX 0x18
#define MII_LOW_ADDR_PREFIX 0x10
DEFINE_MUTEX(switch_mdio_lock);
#endif /* End _IPQ_MDIO_H */ #endif /* End _IPQ_MDIO_H */

View file

@ -41,6 +41,7 @@
#define QCA8033_PHY_ADDR 0x6 #define QCA8033_PHY_ADDR 0x6
#define QCA8081_PHY 0x004DD100 #define QCA8081_PHY 0x004DD100
#define QCA8081_1_1_PHY 0x004DD101 #define QCA8081_1_1_PHY 0x004DD101
#define QCA8084_PHY 0x004DD180
#define AQUANTIA_PHY_107 0x03a1b4e2 #define AQUANTIA_PHY_107 0x03a1b4e2
#define AQUANTIA_PHY_109 0x03a1b502 #define AQUANTIA_PHY_109 0x03a1b502
#define AQUANTIA_PHY_111 0x03a1b610 #define AQUANTIA_PHY_111 0x03a1b610
@ -113,6 +114,8 @@ enum eport_wrapper_cfg {
EPORT_WRAPPER_RGMII, EPORT_WRAPPER_RGMII,
EPORT_WRAPPER_PSGMII_FIBER, EPORT_WRAPPER_PSGMII_FIBER,
EPORT_WRAPPER_SGMII_FIBER, EPORT_WRAPPER_SGMII_FIBER,
EPORT_WRAPPER_UQXGMII, /* for four channels qca8084 phy mode*/
EPORT_WRAPPER_UQXGMII_3CHANNELS, /* for three channels qca8084 phy mode */
EPORT_WRAPPER_MAX = 0xFF EPORT_WRAPPER_MAX = 0xFF
}; };
@ -134,6 +137,8 @@ enum phy_mode {
AQ_PHY_TYPE = 3, AQ_PHY_TYPE = 3,
QCA8033_PHY_TYPE = 4, QCA8033_PHY_TYPE = 4,
SFP_PHY_TYPE = 5, SFP_PHY_TYPE = 5,
QCA8084_PHY_TYPE = 6,
UNUSED_PHY_TYPE = 0xFF,
}; };
typedef struct { typedef struct {

View file

@ -0,0 +1,280 @@
/*
* Copyright (c) 2022, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that 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.
*/
#include "ipq_phy.h"
#include "ipq_qca8081.h"
#include "ipq_qca8084.h"
#include "ipq_qca8084_clk.h"
#include <linux/compat.h>
#include <malloc.h>
#ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args);
#else
#define pr_debug(fmt, args...)
#endif
extern int ipq_mdio_read(int mii_id,
int regnum, ushort *data);
extern int ipq_mdio_write(int mii_id,
int regnum, u16 data);
extern void qca8084_interface_uqxgmii_mode_set(void);
extern void qca8084_gcc_clock_init(void);
extern u8 qca8081_phy_get_link_status(u32 dev_id, u32 phy_id);
extern u32 qca8081_phy_get_duplex(u32 dev_id, u32 phy_id, fal_port_duplex_t *duplex);
extern u32 qca8081_phy_get_speed(u32 dev_id, u32 phy_id, fal_port_speed_t *speed);
extern void qca8084_uniphy_xpcs_autoneg_restart(uint32_t qca8084_port_id);
extern void qca8084_port_speed_clock_set(uint32_t qca8084_port_id,
fal_port_speed_t speed);
extern void qca8084_uniphy_xpcs_speed_set(uint32_t qca8084_port_id,
fal_port_speed_t speed);
extern void qca8084_port_clk_en_set(uint32_t qca8084_port_id, uint8_t mask,
uint8_t enable);
extern void qca8084_port_clk_reset(uint32_t qca8084_port_id, uint8_t mask);
extern void qca8084_uniphy_uqxgmii_function_reset(uint32_t qca8084_port_id);
u16 qca8084_phy_reg_read(u32 phy_addr, u32 reg_id)
{
return ipq_mdio_read(phy_addr, reg_id, NULL);
}
u16 qca8084_phy_reg_write(u32 phy_addr, u32 reg_id, u16 value)
{
return ipq_mdio_write(phy_addr, reg_id, value);
}
u16 qca8084_phy_mmd_read(u32 phy_addr, u16 mmd_num, u16 reg_id)
{
uint32_t reg_id_c45 = QCA8084_REG_C45_ADDRESS(mmd_num, reg_id);
return ipq_mdio_read(phy_addr, reg_id_c45, NULL);
}
u16 qca8084_phy_mmd_write(u32 phy_addr, u16 mmd_num, u16 reg_id, u16 value)
{
uint32_t reg_id_c45 = QCA8084_REG_C45_ADDRESS(mmd_num, reg_id);
return ipq_mdio_write(phy_addr, reg_id_c45, value);
}
void qca8084_phy_modify_mii(uint32_t phy_addr, uint32_t mii_reg, uint32_t mask,
uint32_t value)
{
uint16_t phy_data = 0, new_phy_data = 0;
phy_data = qca8084_phy_reg_read(phy_addr, mii_reg);
new_phy_data = (phy_data & ~mask) | value;
qca8084_phy_reg_write(phy_addr, mii_reg, new_phy_data);
/*check the mii register value*/
phy_data = qca8084_phy_reg_read(phy_addr, mii_reg);
pr_debug("phy_addr:0x%x, mii_reg:0x%x, phy_data:0x%x\n",
phy_addr, mii_reg, phy_data);
}
void qca8084_phy_modify_mmd(uint32_t phy_addr, uint32_t mmd_num,
uint32_t mmd_reg, uint32_t mask, uint32_t value)
{
uint16_t phy_data = 0, new_phy_data = 0;
phy_data = qca8084_phy_mmd_read(phy_addr, mmd_num, mmd_reg);
new_phy_data = (phy_data & ~mask) | value;
qca8084_phy_mmd_write(phy_addr, mmd_num, mmd_reg, new_phy_data);
/* check the mmd register value */
phy_data = qca8084_phy_mmd_read(phy_addr, mmd_num, mmd_reg);
pr_debug("phy_addr:0x%x, mmd_reg:0x%x, phy_data:0x%x\n",
phy_addr, mmd_reg, phy_data);
}
void qca8084_phy_ipg_config(uint32_t phy_id, fal_port_speed_t speed)
{
uint16_t phy_data = 0;
phy_data = qca8084_phy_mmd_read(phy_id, QCA8084_PHY_MMD7_NUM,
QCA8084_PHY_MMD7_IPG_10_11_ENABLE);
phy_data &= ~QCA8084_PHY_MMD7_IPG_11_EN;
/*If speed is 1G, enable 11 ipg tuning*/
pr_debug("if speed is 1G, enable 11 ipg tuning\n");
if (speed == FAL_SPEED_1000)
phy_data |= QCA8084_PHY_MMD7_IPG_11_EN;
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD7_NUM,
QCA8084_PHY_MMD7_IPG_10_11_ENABLE, phy_data);
}
void qca8084_phy_function_reset(uint32_t phy_id)
{
uint16_t phy_data = 0;
phy_data = qca8084_phy_reg_read(phy_id, QCA8084_PHY_FIFO_CONTROL);
qca8084_phy_reg_write(phy_id, QCA8084_PHY_FIFO_CONTROL,
phy_data & (~QCA8084_PHY_FIFO_RESET));
mdelay(50);
qca8084_phy_reg_write(phy_id, QCA8084_PHY_FIFO_CONTROL,
phy_data | QCA8084_PHY_FIFO_RESET);
}
void qca8084_phy_uqxgmii_speed_fixup(uint32_t phy_addr, uint32_t qca8084_port_id,
uint32_t status, fal_port_speed_t new_speed)
{
uint32_t port_clock_en = 0;
/*Restart the auto-neg of uniphy*/
pr_debug("Restart the auto-neg of uniphy\n");
qca8084_uniphy_xpcs_autoneg_restart(qca8084_port_id);
/*set gmii+ clock to uniphy1 and ethphy*/
pr_debug("set gmii,xgmii clock to uniphy and gmii to ethphy\n");
qca8084_port_speed_clock_set(qca8084_port_id, new_speed);
/*set xpcs speed*/
pr_debug("set xpcs speed\n");
qca8084_uniphy_xpcs_speed_set(qca8084_port_id, new_speed);
/*GMII/XGMII clock and ETHPHY GMII clock enable/disable*/
pr_debug("GMII/XGMII clock and ETHPHY GMII clock enable/disable\n");
if (status == 0)
port_clock_en = 1;
qca8084_port_clk_en_set(qca8084_port_id,
QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY,
port_clock_en);
pr_debug("UNIPHY GMII/XGMII interface and ETHPHY GMII interface reset and release\n");
qca8084_port_clk_reset(qca8084_port_id,
QCA8084_CLK_TYPE_UNIPHY | QCA8084_CLK_TYPE_EPHY);
pr_debug("ipg_tune and xgmii2gmii reset for uniphy and ETHPHY, function reset\n");
qca8084_uniphy_uqxgmii_function_reset(qca8084_port_id);
/*do ethphy function reset: PHY_FIFO_RESET*/
pr_debug("do ethphy function reset\n");
qca8084_phy_function_reset(phy_addr);
/*change IPG from 10 to 11 for 1G speed*/
qca8084_phy_ipg_config(phy_addr, new_speed);
}
void qca8084_phy_interface_mode_set(void)
{
pr_debug("Configure QCA8084 as PORT_UQXGMII..\n");
/*the work mode is PORT_UQXGMII in default*/
qca8084_interface_uqxgmii_mode_set();
/*init clock for PORT_UQXGMII*/
qca8084_gcc_clock_init();
/*init pinctrl for phy mode to be added later*/
}
void qca8084_cdt_thresh_init(u32 phy_id)
{
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL3,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL3_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL4,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL4_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL5,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL5_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL6,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL6_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL7,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL7_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL9,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL9_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL13,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL13_VAL);
qca8084_phy_mmd_write(phy_id, QCA8084_PHY_MMD3_NUM,
QCA8084_PHY_MMD3_CDT_THRESH_CTRL14,
QCA8084_PHY_MMD3_NEAR_ECHO_THRESH_VAL);
}
void qca8084_phy_modify_debug(u32 phy_addr, u32 debug_reg,
u32 mask, u32 value)
{
u16 phy_data = 0, new_phy_data = 0;
qca8084_phy_reg_write(phy_addr, QCA8084_DEBUG_PORT_ADDRESS, debug_reg);
phy_data = qca8084_phy_reg_read(phy_addr, QCA8084_DEBUG_PORT_DATA);
if (phy_data == PHY_INVALID_DATA)
pr_debug("qca8084_phy_reg_read failed\n");
new_phy_data = (phy_data & ~mask) | value;
qca8084_phy_reg_write(phy_addr, QCA8084_DEBUG_PORT_ADDRESS, debug_reg);
qca8084_phy_reg_write(phy_addr, QCA8084_DEBUG_PORT_DATA, new_phy_data);
/* check debug register value */
qca8084_phy_reg_write(phy_addr, QCA8084_DEBUG_PORT_ADDRESS, debug_reg);
phy_data = qca8084_phy_reg_read(phy_addr, QCA8084_DEBUG_PORT_DATA);
pr_debug("phy_addr:0x%x, debug_reg:0x%x, phy_data:0x%x\n",
phy_addr, debug_reg, phy_data);
}
void qca8084_phy_reset(u32 phy_addr)
{
u16 phy_data;
phy_data = qca8084_phy_reg_read(phy_addr, QCA8084_PHY_CONTROL);
qca8084_phy_reg_write(phy_addr, QCA8084_PHY_CONTROL,
phy_data | QCA8084_CTRL_SOFTWARE_RESET);
}
void qca8084_phy_adc_edge_set(u32 phy_addr, u32 adc_edge)
{
qca8084_phy_modify_debug(phy_addr,
QCA8084_PHY_DEBUG_ANA_INTERFACE_CLK_SEL, 0xf0, adc_edge);
qca8084_phy_reset(phy_addr);
}
void ipq_qca8084_phy_hw_init(struct phy_ops **ops, u32 phy_addr)
{
#ifdef DEBUG
u16 phy_data;
#endif
struct phy_ops *qca8084_ops;
qca8084_ops = (struct phy_ops *)malloc(sizeof(struct phy_ops));
if (!qca8084_ops) {
pr_debug("Error allocating memory for phy ops\n");
return;
}
/* Note that qca8084 PHY is based on qca8081 PHY and so the following
* ops functions required would be re-used from qca8081 */
qca8084_ops->phy_get_link_status = qca8081_phy_get_link_status;
qca8084_ops->phy_get_speed = qca8081_phy_get_speed;
qca8084_ops->phy_get_duplex = qca8081_phy_get_duplex;
*ops = qca8084_ops;
#ifdef DEBUG
phy_data = qca8084_phy_reg_read(phy_addr, QCA8081_PHY_ID1);
printf("PHY ID1: 0x%x\n", phy_data);
phy_data = qca8084_phy_reg_read(phy_addr, QCA8081_PHY_ID2);
printf("PHY ID2: 0x%x\n", phy_data);
#endif
/* adjust CDT threshold */
qca8084_cdt_thresh_init(phy_addr);
/* invert ADC clock edge as falling edge to fix link issue */
qca8084_phy_adc_edge_set(phy_addr, ADC_FALLING);
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2022, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that 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.
*/
#ifndef _QCA8084_PHY_H_
#define _QCA8084_PHY_H_
/*MII register*/
#define QCA8084_PHY_FIFO_CONTROL 0x19
/*MII register field*/
#define QCA8084_PHY_FIFO_RESET 0x3
/*MMD1 register*/
#define QCA8084_PHY_MMD1_NUM 0x1
/*MMD3 register*/
#define QCA8084_PHY_MMD3_NUM 0x3
#define QCA8084_PHY_MMD3_ADDR_8023AZ_EEE_2500M_CAPABILITY 0x15
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL3 0x8074
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL4 0x8075
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL5 0x8076
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL6 0x8077
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL7 0x8078
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL9 0x807a
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL13 0x807e
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL14 0x807f
/*MMD3 register field*/
#define QCA8084_PHY_EEE_CAPABILITY_2500M 0x1
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL3_VAL 0xc040
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL4_VAL 0xa060
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL5_VAL 0xc040
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL6_VAL 0xa060
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL7_VAL 0xc050
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL9_VAL 0xc060
#define QCA8084_PHY_MMD3_CDT_THRESH_CTRL13_VAL 0xb060
#define QCA8084_PHY_MMD3_NEAR_ECHO_THRESH_VAL 0x1eb0
/*MMD7 register*/
#define QCA8084_PHY_MMD7_NUM 0x7
#define QCA8084_PHY_MMD7_ADDR_8023AZ_EEE_2500M_CTRL 0x3e
#define QCA8084_PHY_MMD7_ADDR_8023AZ_EEE_2500M_PARTNER 0x3f
#define QCA8084_PHY_MMD7_IPG_10_11_ENABLE 0x901d
/*MMD7 register field*/
#define QCA8084_PHY_8023AZ_EEE_2500BT 0x1
#define QCA8084_PHY_MMD7_IPG_10_EN 0
#define QCA8084_PHY_MMD7_IPG_11_EN 0x1
/*DEBUG port analog register*/
#define QCA8084_PHY_DEBUG_ANA_INTERFACE_CLK_SEL 0x8b80
#define QCA8084_DEBUG_PORT_ADDRESS 29
#define QCA8084_DEBUG_PORT_DATA 30
#define QCA8084_PHY_CONTROL 0
#define QCA8084_CTRL_SOFTWARE_RESET 0x8000
#define PHY_INVALID_DATA 0xffff
#define QCA8084_MII_ADDR_C45 (1<<30)
#define QCA8084_REG_C45_ADDRESS(dev_type, reg_num) (QCA8084_MII_ADDR_C45 | \
((dev_type & 0x1f) << 16) | (reg_num & 0xffff))
typedef enum {
ADC_RISING = 0,
ADC_FALLING = 0xf0,
}
qca8084_adc_edge_t;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,183 @@
/*
* Copyright (c) 2022, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that 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.
*/
#ifndef _QCA8084_CLK_H_
#define _QCA8084_CLK_H_
#define QCA8084_SWITCH_CORE_CLK "qca8084_gcc_switch_core_clk"
#define QCA8084_APB_BRIDGE_CLK "qca8084_gcc_apb_bridge_clk"
#define QCA8084_MAC0_TX_CLK "qca8084_gcc_mac0_tx_clk"
#define QCA8084_MAC0_TX_UNIPHY1_CLK "qca8084_gcc_mac0_tx_srds1_clk"
#define QCA8084_MAC0_RX_CLK "qca8084_gcc_mac0_rx_clk"
#define QCA8084_MAC0_RX_UNIPHY1_CLK "qca8084_gcc_mac0_rx_srds1_clk"
#define QCA8084_MAC1_TX_CLK "qca8084_gcc_mac1_tx_clk"
#define QCA8084_MAC1_GEPHY0_TX_CLK "qca8084_gcc_mac1_gephy0_tx_clk"
#define QCA8084_MAC1_UNIPHY1_CH0_RX_CLK "qca8084_gcc_mac1_srds1_ch0_rx_clk"
#define QCA8084_MAC1_UNIPHY1_CH0_XGMII_RX_CLK "qca8084_gcc_mac1_srds1_ch0_xgmii_rx_clk"
#define QCA8084_MAC1_RX_CLK "qca8084_gcc_mac1_rx_clk"
#define QCA8084_MAC1_GEPHY0_RX_CLK "qca8084_gcc_mac1_gephy0_rx_clk"
#define QCA8084_MAC1_UNIPHY1_CH0_TX_CLK "qca8084_gcc_mac1_srds1_ch0_tx_clk"
#define QCA8084_MAC1_UNIPHY1_CH0_XGMII_TX_CLK "qca8084_gcc_mac1_srds1_ch0_xgmii_tx_clk"
#define QCA8084_MAC2_TX_CLK "qca8084_gcc_mac2_tx_clk"
#define QCA8084_MAC2_GEPHY1_TX_CLK "qca8084_gcc_mac2_gephy1_tx_clk"
#define QCA8084_MAC2_UNIPHY1_CH1_RX_CLK "qca8084_gcc_mac2_srds1_ch1_rx_clk"
#define QCA8084_MAC2_UNIPHY1_CH1_XGMII_RX_CLK "qca8084_gcc_mac2_srds1_ch1_xgmii_rx_clk"
#define QCA8084_MAC2_RX_CLK "qca8084_gcc_mac2_rx_clk"
#define QCA8084_MAC2_GEPHY1_RX_CLK "qca8084_gcc_mac2_gephy1_rx_clk"
#define QCA8084_MAC2_UNIPHY1_CH1_TX_CLK "qca8084_gcc_mac2_srds1_ch1_tx_clk"
#define QCA8084_MAC2_UNIPHY1_CH1_XGMII_TX_CLK "qca8084_gcc_mac2_srds1_ch1_xgmii_tx_clk"
#define QCA8084_MAC3_TX_CLK "qca8084_gcc_mac3_tx_clk"
#define QCA8084_MAC3_GEPHY2_TX_CLK "qca8084_gcc_mac3_gephy2_tx_clk"
#define QCA8084_MAC3_UNIPHY1_CH2_RX_CLK "qca8084_gcc_mac3_srds1_ch2_rx_clk"
#define QCA8084_MAC3_UNIPHY1_CH2_XGMII_RX_CLK "qca8084_gcc_mac3_srds1_ch2_xgmii_rx_clk"
#define QCA8084_MAC3_RX_CLK "qca8084_gcc_mac3_rx_clk"
#define QCA8084_MAC3_GEPHY2_RX_CLK "qca8084_gcc_mac3_gephy2_rx_clk"
#define QCA8084_MAC3_UNIPHY1_CH2_TX_CLK "qca8084_gcc_mac3_srds1_ch2_tx_clk"
#define QCA8084_MAC3_UNIPHY1_CH2_XGMII_TX_CLK "qca8084_gcc_mac3_srds1_ch2_xgmii_tx_clk"
#define QCA8084_MAC4_TX_CLK "qca8084_gcc_mac4_tx_clk"
#define QCA8084_MAC4_GEPHY3_TX_CLK "qca8084_gcc_mac4_gephy3_tx_clk"
#define QCA8084_MAC4_UNIPHY1_CH3_RX_CLK "qca8084_gcc_mac4_srds1_ch3_rx_clk"
#define QCA8084_MAC4_UNIPHY1_CH3_XGMII_RX_CLK "qca8084_gcc_mac4_srds1_ch3_xgmii_rx_clk"
#define QCA8084_MAC4_RX_CLK "qca8084_gcc_mac4_rx_clk"
#define QCA8084_MAC4_GEPHY3_RX_CLK "qca8084_gcc_mac4_gephy3_rx_clk"
#define QCA8084_MAC4_UNIPHY1_CH3_TX_CLK "qca8084_gcc_mac4_srds1_ch3_tx_clk"
#define QCA8084_MAC4_UNIPHY1_CH3_XGMII_TX_CLK "qca8084_gcc_mac4_srds1_ch3_xgmii_tx_clk"
#define QCA8084_MAC5_TX_CLK "qca8084_gcc_mac5_tx_clk"
#define QCA8084_MAC5_TX_UNIPHY0_CLK "qca8084_gcc_mac5_tx_srds0_clk"
#define QCA8084_MAC5_TX_SRDS0_CLK_SRC "qca8084_gcc_mac5_tx_srds0_clk_src"
#define QCA8084_MAC5_RX_CLK "qca8084_gcc_mac5_rx_clk"
#define QCA8084_MAC5_RX_UNIPHY0_CLK "qca8084_gcc_mac5_rx_srds0_clk"
#define QCA8084_MAC5_RX_SRDS0_CLK_SRC "qca8084_gcc_mac5_rx_srds0_clk_src"
#define QCA8084_SEC_CTRL_CLK "qca8084_gcc_sec_ctrl_clk"
#define QCA8084_SEC_CTRL_SENSE_CLK "qca8084_gcc_sec_ctrl_sense_clk"
#define QCA8084_SRDS0_SYS_CLK "qca8084_gcc_srds0_sys_clk"
#define QCA8084_SRDS1_SYS_CLK "qca8084_gcc_srds1_sys_clk"
#define QCA8084_GEPHY0_SYS_CLK "qca8084_gcc_gephy0_sys_clk"
#define QCA8084_GEPHY1_SYS_CLK "qca8084_gcc_gephy1_sys_clk"
#define QCA8084_GEPHY2_SYS_CLK "qca8084_gcc_gephy2_sys_clk"
#define QCA8084_GEPHY3_SYS_CLK "qca8084_gcc_gephy3_sys_clk"
#define QCA8084_AHB_CLK "qca8084_gcc_ahb_clk"
#define QCA8084_SEC_CTRL_AHB_CLK "qca8084_gcc_sec_ctrl_ahb_clk"
#define QCA8084_TLMM_CLK "qca8084_gcc_tlmm_clk"
#define QCA8084_TLMM_AHB_CLK "qca8084_gcc_tlmm_ahb_clk"
#define QCA8084_CNOC_AHB_CLK "qca8084_gcc_cnoc_ahb_clk"
#define QCA8084_MDIO_AHB_CLK "qca8084_gcc_mdio_ahb_clk"
#define QCA8084_MDIO_MASTER_AHB_CLK "qca8084_gcc_mdio_master_ahb_clk"
#define QCA8084_GLOBAL_RST "qca8084_gcc_global_rst"
#define QCA8084_UNIPHY_XPCS_RST "qca8084_uniphy_xpcs_rst"
#define QCA8084_GEPHY_DSP_HW_RST "qca8084_gephy_dsp_hw_rst"
#define QCA8084_GEPHY_P3_MDC_SW_RST "qca8084_gephy_p3_mdc_sw_rst"
#define QCA8084_GEPHY_P2_MDC_SW_RST "qca8084_gephy_p2_mdc_sw_rst"
#define QCA8084_GEPHY_P1_MDC_SW_RST "qca8084_gephy_p1_mdc_sw_rst"
#define QCA8084_GEPHY_P0_MDC_SW_RST "qca8084_gephy_p0_mdc_sw_rst"
typedef enum {
QCA8084_P_XO,
QCA8084_P_UNIPHY0_RX,
QCA8084_P_UNIPHY0_TX,
QCA8084_P_UNIPHY1_RX,
QCA8084_P_UNIPHY1_TX,
QCA8084_P_UNIPHY1_RX312P5M,
QCA8084_P_UNIPHY1_TX312P5M,
QCA8084_P_MAX,
} qca8084_clk_parent_t;
struct qca8084_clk_data {
unsigned long rate;
unsigned int rcg_val;
unsigned int cdiv_val;
unsigned int cbc_val;
};
struct qca8084_parent_data {
unsigned long prate; /* RCG input clock rate */
qca8084_clk_parent_t parent; /* RCG parent clock id */
int cfg; /* RCG clock src value */
};
struct clk_lookup {
unsigned int rcg;
unsigned int cdiv;
unsigned int cbc;
unsigned int rst_bit;
const char *clk_name;
const unsigned long *support_rate;
unsigned int num_rate;
const struct qca8084_parent_data *pdata;
unsigned int num_parent;
};
#define CLK_LOOKUP(_rcg, _cdiv, _cbc, _rst_bit, _clk_name, \
_rate, _num_rate, _pdata, _num_parent) \
{ \
.rcg = _rcg, \
.cdiv = _cdiv, \
.cbc = _cbc, \
.rst_bit = _rst_bit, \
.clk_name = _clk_name, \
.support_rate = _rate, \
.num_rate = _num_rate, \
.pdata = _pdata, \
.num_parent = _num_parent, \
}
#define QCA8084_CLK_TYPE_EPHY BIT(0)
#define QCA8084_CLK_TYPE_UNIPHY BIT(1)
#define QCA8084_CLK_TYPE_MAC BIT(2)
#define UQXGMII_SPEED_2500M_CLK 312500000
#define UQXGMII_SPEED_1000M_CLK 125000000
#define UQXGMII_SPEED_100M_CLK 25000000
#define UQXGMII_SPEED_10M_CLK 2500000
#define UQXGMII_XPCS_SPEED_2500M_CLK 78125000
#define QCA8084_AHB_CLK_RATE_104P17M 104160000
#define QCA8084_SYS_CLK_RATE_25M 25000000
#define QCA8084_XO_CLK_RATE_50M 50000000
#define QCA8084_CLK_BASE_REG 0x0c800000
#define QCA8084_CLK_MUX_SEL 0x300
#define QCA8084_UNIPHY0_MUX_SEL_MASK BITS_MASK(0, 2)
#define QCA8084_UNIPHY0_SEL_MAC5 0x3
#define QCA8084_UNIPHY0_SEL_MAC4 0
#define RCGR_CMD_ROOT_OFF BIT(31)
#define RCGR_CMD_UPDATE BIT(0)
#define RCGR_SRC_SEL BITS_MASK(8, 3)
#define RCGR_SRC_SEL_SHIFT 8
#define RCGR_HDIV BITS_MASK(0, 5)
#define RCGR_HDIV_SHIFT 0
#define RCGR_DIV_BYPASS 0
#define RCGR_DIV_MAX 0x1f
#define CDIVR_DIVIDER_10 9 /* CDIVR divided by N + 1 */
#define CDIVR_DIVIDER BITS_MASK(0, 4)
#define CDIVR_DIVIDER_SHIFT 0
#define CBCR_CLK_OFF BIT(31)
#define CBCR_CLK_RESET BIT(2)
#define CBCR_CLK_ENABLE BIT(0)
#endif /* _QCA8084_CLK_H_ */

View file

@ -0,0 +1,504 @@
/*
* Copyright (c) 2022, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that 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.
*/
#include "ipq_phy.h"
#include "ipq_qca8084.h"
#include "ipq_qca8084_clk.h"
#include "ipq_qca8084_interface_ctrl.h"
#include <malloc.h>
#ifdef DEBUG
#define pr_debug(fmt, args...) printf(fmt, ##args);
#else
#define pr_debug(fmt, args...)
#endif
extern void qca8084_phy_reset(u32 phy_id);
extern u16 qca8084_phy_reg_read(u32 phy_id, u32 reg_id);
extern u16 qca8084_phy_reg_write(u32 phy_id, u32 reg_id, u16 value);
extern u16 qca8084_phy_mmd_read(u32 phy_id, u16 mmd_num, u16 reg_id);
extern u16 qca8084_phy_mmd_write(u32 phy_id, u16 mmd_num, u16 reg_id,
u16 value);
extern void qca8084_phy_modify_mmd(uint32_t phy_addr, uint32_t mmd_num,
uint32_t mmd_reg, uint32_t mask, uint32_t value);
extern void qca8084_phy_modify_mii(uint32_t phy_addr, uint32_t mii_reg,
uint32_t mask, uint32_t value);
extern uint32_t ipq_mii_read(uint32_t reg);
extern void ipq_mii_write(uint32_t reg, uint32_t val);
extern void ipq_mii_update(uint32_t reg, uint32_t mask, uint32_t val);
extern void qca8084_port_clk_rate_set(uint32_t qca8084_port_id, uint32_t rate);
extern void qca8084_port_clk_en_set(uint32_t qca8084_port_id, uint8_t mask,
uint8_t enable);
extern void qca8084_clk_assert(const char *clock_id);
extern void qca8084_clk_deassert(const char *clock_id);
extern void qca8084_port_clk_reset(uint32_t qca8084_port_id, uint8_t mask);
void qca8084_serdes_addr_get(uint32_t serdes_id, uint32_t *address)
{
uint32_t data = 0;
data = ipq_mii_read(SERDES_CFG_OFFSET);
switch(serdes_id)
{
case QCA8084_UNIPHY_SGMII_0:
*address = (data >> SERDES_CFG_S0_ADDR_BOFFSET) & 0x1f;
break;
case QCA8084_UNIPHY_SGMII_1:
*address = (data >> SERDES_CFG_S1_ADDR_BOFFSET) & 0x1f;
break;
case QCA8084_UNIPHY_XPCS:
*address = (data >> SERDES_CFG_S1_XPCS_ADDR_BOFFSET) & 0x1f;
break;
default:
pr_debug("Serdes id not matching\n");
break;
}
}
void qca8084_ephy_addr_get(uint32_t qca8084_port_id, uint32_t *phy_addr)
{
uint32_t data = 0;
data = ipq_mii_read(EPHY_CFG_OFFSET);
switch(qca8084_port_id)
{
case PORT1:
*phy_addr = (data >> EPHY_CFG_EPHY0_ADDR_BOFFSET) & 0x1f;
break;
case PORT2:
*phy_addr = (data >> EPHY_CFG_EPHY1_ADDR_BOFFSET) & 0x1f;
break;
case PORT3:
*phy_addr = (data >> EPHY_CFG_EPHY2_ADDR_BOFFSET) & 0x1f;
break;
case PORT4:
*phy_addr = (data >> EPHY_CFG_EPHY3_ADDR_BOFFSET) & 0x1f;
break;
default:
pr_debug("qca8084_port_id not matching\n");
break;
}
}
static uint16_t qca8084_uniphy_xpcs_mmd_read(uint16_t mmd_num, uint16_t mmd_reg)
{
uint32_t uniphy_xpcs_addr = 0;
qca8084_serdes_addr_get(QCA8084_UNIPHY_XPCS, &uniphy_xpcs_addr);
return qca8084_phy_mmd_read(uniphy_xpcs_addr, mmd_num, mmd_reg);
}
static void qca8084_uniphy_xpcs_mmd_write(uint16_t mmd_num, uint16_t mmd_reg,
uint16_t reg_val)
{
uint32_t uniphy_xpcs_addr = 0;
#ifdef DEBUG
uint16_t phy_data = 0;
#endif
qca8084_serdes_addr_get(QCA8084_UNIPHY_XPCS, &uniphy_xpcs_addr);
qca8084_phy_mmd_write(uniphy_xpcs_addr, mmd_num, mmd_reg, reg_val);
/*check the mmd register value*/
#ifdef DEBUG
phy_data =
#endif
qca8084_uniphy_xpcs_mmd_read(mmd_num, mmd_reg);
pr_debug("phy_addr:0x%x, mmd_num:0x%x, mmd_reg:0x%x, phy_data:0x%x\n",
uniphy_xpcs_addr, mmd_num, mmd_reg, phy_data);
}
static void qca8084_uniphy_xpcs_modify_mmd(uint32_t mmd_num, uint32_t mmd_reg,
uint32_t mask, uint32_t value)
{
uint16_t phy_data = 0, new_phy_data = 0;
phy_data = qca8084_uniphy_xpcs_mmd_read(mmd_num, mmd_reg);
new_phy_data = (phy_data & ~mask) | value;
qca8084_uniphy_xpcs_mmd_write(mmd_num, mmd_reg, new_phy_data);
}
uint8_t qca8084_uniphy_mode_check(uint32_t uniphy_index,
qca8084_uniphy_mode_t uniphy_mode)
{
uint32_t uniphy_addr = 0;
uint16_t uniphy_mode_ctrl_data = 0;
qca8084_serdes_addr_get(uniphy_index, &uniphy_addr);
uniphy_mode_ctrl_data = qca8084_phy_mmd_read(uniphy_addr,
QCA8084_UNIPHY_MMD1, QCA8084_UNIPHY_MMD1_MODE_CTRL);
if(uniphy_mode_ctrl_data == PHY_INVALID_DATA)
return 0;
if(!(uniphy_mode & uniphy_mode_ctrl_data))
return 0;
return 1;
}
static uint32_t qca8084_uniphy_xpcs_port_to_mmd(uint32_t qca8084_port_id)
{
uint32_t mmd_id = 0;
switch(qca8084_port_id)
{
case PORT1:
mmd_id = QCA8084_UNIPHY_MMD31;
break;
case PORT2:
mmd_id = QCA8084_UNIPHY_MMD26;
break;
case PORT3:
mmd_id = QCA8084_UNIPHY_MMD27;
break;
case PORT4:
mmd_id = QCA8084_UNIPHY_MMD28;
break;
default:
pr_debug("Port not matching qca8084 ports\n");
}
return mmd_id;
}
static void qca8084_uniphy_xpcs_modify_port_mmd(uint32_t qca8084_port_id,
uint32_t mmd_reg, uint32_t mask,
uint32_t value)
{
uint32_t mmd_id = 0;
mmd_id = qca8084_uniphy_xpcs_port_to_mmd(qca8084_port_id);
qca8084_uniphy_xpcs_modify_mmd(mmd_id, mmd_reg, mask, value);
}
void qca8084_port_speed_clock_set(uint32_t qca8084_port_id,
fal_port_speed_t speed)
{
uint32_t clk_rate = 0;
switch(speed)
{
case FAL_SPEED_2500:
clk_rate = UQXGMII_SPEED_2500M_CLK;
break;
case FAL_SPEED_1000:
clk_rate = UQXGMII_SPEED_1000M_CLK;
break;
case FAL_SPEED_100:
clk_rate = UQXGMII_SPEED_100M_CLK;
break;
case FAL_SPEED_10:
clk_rate = UQXGMII_SPEED_10M_CLK;
break;
default:
pr_debug("Unknown speed\n");
return;
}
qca8084_port_clk_rate_set(qca8084_port_id, clk_rate);
}
static void qca8084_uniphy_xpcs_8023az_enable(void)
{
uint16_t uniphy_data = 0;
uniphy_data = qca8084_uniphy_xpcs_mmd_read(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_AN_LP_BASE_ABL2);
if(!(uniphy_data & QCA8084_UNIPHY_MMD3_XPCS_EEE_CAP))
return;
/*Configure the EEE related timer*/
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL,
0x0f40, QCA8084_UNIPHY_MMD3_EEE_RES_REGS |
QCA8084_UNIPHY_MMD3_EEE_SIGN_BIT_REGS);
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_TX_TIMER,
0x1fff, QCA8084_UNIPHY_MMD3_EEE_TSL_REGS|
QCA8084_UNIPHY_MMD3_EEE_TLU_REGS |
QCA8084_UNIPHY_MMD3_EEE_TWL_REGS);
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_RX_TIMER,
0x1fff, QCA8084_UNIPHY_MMD3_EEE_100US_REG_REGS|
QCA8084_UNIPHY_MMD3_EEE_RWR_REG_REGS);
/*enable TRN_LPI*/
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL1,
0x101, QCA8084_UNIPHY_MMD3_EEE_TRANS_LPI_MODE|
QCA8084_UNIPHY_MMD3_EEE_TRANS_RX_LPI_MODE);
/*enable TX/RX LPI pattern*/
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL,
0x3, QCA8084_UNIPHY_MMD3_EEE_EN);
}
static void qca8084_uniphy_calibration(uint32_t uniphy_addr)
{
uint16_t uniphy_data = 0;
uint32_t retries = 100, calibration_done = 0;
/* wait calibration done to uniphy*/
while (calibration_done != QCA8084_UNIPHY_MMD1_CALIBRATION_DONE) {
mdelay(1);
if (retries-- == 0)
pr_debug("uniphy callibration time out!\n");
uniphy_data = qca8084_phy_mmd_read(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CALIBRATION4);
calibration_done = (uniphy_data & QCA8084_UNIPHY_MMD1_CALIBRATION_DONE);
}
}
static void qca8084_uniphy_xpcs_10g_r_linkup(void)
{
uint16_t uniphy_data = 0;
uint32_t retries = 100, linkup = 0;
/* wait 10G_R link up */
while (linkup != QCA8084_UNIPHY_MMD3_10GBASE_R_UP) {
mdelay(1);
if (retries-- == 0)
pr_debug("10g_r link up timeout\n");
uniphy_data = qca8084_uniphy_xpcs_mmd_read(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_10GBASE_R_PCS_STATUS1);
linkup = (uniphy_data & QCA8084_UNIPHY_MMD3_10GBASE_R_UP);
}
}
static void qca8084_uniphy_xpcs_soft_reset(void)
{
uint16_t uniphy_data = 0;
uint32_t retries = 100, reset_done = QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET;
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_DIG_CTRL1, 0x8000,
QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET);
while (reset_done) {
mdelay(1);
if (retries-- == 0)
pr_debug("xpcs soft reset timeout\n");
uniphy_data = qca8084_uniphy_xpcs_mmd_read(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_DIG_CTRL1);
reset_done = (uniphy_data & QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET);
}
}
void qca8084_uniphy_xpcs_speed_set(uint32_t qca8084_port_id,
fal_port_speed_t speed)
{
uint32_t xpcs_speed = 0;
switch(speed)
{
case FAL_SPEED_2500:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_2500;
break;
case FAL_SPEED_1000:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_1000;
break;
case FAL_SPEED_100:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_100;
break;
case FAL_SPEED_10:
xpcs_speed = QCA8084_UNIPHY_MMD_XPC_SPEED_10;
break;
default:
pr_debug("Unknown speed\n");
return;
}
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_CTRL,
QCA8084_UNIPHY_MMD_XPC_SPEED_MASK,
xpcs_speed);
}
void qca8084_uniphy_uqxgmii_function_reset(uint32_t qca8084_port_id)
{
uint32_t uniphy_addr = 0;
qca8084_serdes_addr_get(QCA8084_UNIPHY_SGMII_1, &uniphy_addr);
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_USXGMII_RESET, BIT(qca8084_port_id-1), 0);
mdelay(1);
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_USXGMII_RESET, BIT(qca8084_port_id-1),
BIT(qca8084_port_id-1));
if(qca8084_port_id == PORT1)
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD_MII_DIG_CTRL,
0x400, QCA8084_UNIPHY_MMD3_USXG_FIFO_RESET);
else
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_DIG_CTRL,
0x20, QCA8084_UNIPHY_MMD_USXG_FIFO_RESET);
}
void qca8084_uniphy_xpcs_autoneg_restart(uint32_t qca8084_port_id)
{
uint32_t retries = 500, uniphy_data = 0, mmd_id = 0;
mmd_id = qca8084_uniphy_xpcs_port_to_mmd(qca8084_port_id);
qca8084_uniphy_xpcs_modify_mmd(mmd_id, QCA8084_UNIPHY_MMD_MII_CTRL,
QCA8084_UNIPHY_MMD_MII_AN_RESTART, QCA8084_UNIPHY_MMD_MII_AN_RESTART);
mdelay(1);
uniphy_data = qca8084_uniphy_xpcs_mmd_read(mmd_id,
QCA8084_UNIPHY_MMD_MII_ERR_SEL);
while(!(uniphy_data & QCA8084_UNIPHY_MMD_MII_AN_COMPLETE_INT))
{
mdelay(1);
if (retries-- == 0)
{
pr_debug("xpcs uniphy autoneg restart timeout\n");
}
uniphy_data = qca8084_uniphy_xpcs_mmd_read(mmd_id,
QCA8084_UNIPHY_MMD_MII_ERR_SEL);
}
}
static void _qca8084_interface_uqxgmii_mode_set(uint32_t uniphy_addr)
{
uint32_t qca8084_port_id = 0, phy_addr = 0;
/*reset xpcs*/
pr_debug("reset xpcs\n");
qca8084_clk_assert(QCA8084_UNIPHY_XPCS_RST);
/*select xpcs mode*/
pr_debug("select xpcs mode\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_MODE_CTRL, 0x1f00, QCA8084_UNIPHY_MMD1_XPCS_MODE);
/*config dapa pass as usxgmii*/
pr_debug("config dapa pass as usxgmii\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_GMII_DATAPASS_SEL, QCA8084_UNIPHY_MMD1_DATAPASS_MASK,
QCA8084_UNIPHY_MMD1_DATAPASS_USXGMII);
/*reset and release uniphy GMII/XGMII and ethphy GMII*/
pr_debug("reset and release uniphy GMII/XGMII and ethphy GMII\n");
for(qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
qca8084_port_clk_reset(qca8084_port_id,
QCA8084_CLK_TYPE_UNIPHY|QCA8084_CLK_TYPE_EPHY);
}
/*ana sw reset and release*/
pr_debug("ana sw reset and release\n");
qca8084_phy_modify_mii(uniphy_addr,
QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RESET);
mdelay(10);
qca8084_phy_modify_mii(uniphy_addr,
QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET, 0x40, QCA8084_UNIPHY_ANA_SOFT_RELEASE);
/*Wait calibration done*/
pr_debug("Wait calibration done\n");
qca8084_uniphy_calibration(uniphy_addr);
/*Enable SSCG(Spread Spectrum Clock Generator)*/
pr_debug("enable uniphy sscg\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_CDA_CONTROL1, 0x8, QCA8084_UNIPHY_MMD1_SSCG_ENABLE);
/*release XPCS*/
pr_debug("release XPCS\n");
qca8084_clk_deassert(QCA8084_UNIPHY_XPCS_RST);
/*ethphy software reset*/
pr_debug("ethphy software reset\n");
for(qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
qca8084_ephy_addr_get(qca8084_port_id, &phy_addr);
qca8084_phy_reset(phy_addr);
}
/*Set BaseR mode*/
pr_debug("Set BaseR mode\n");
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_PCS_CTRL2, 0xf, QCA8084_UNIPHY_MMD3_PCS_TYPE_10GBASE_R);
/*wait 10G base_r link up*/
pr_debug("wait 10G base_r link up\n");
qca8084_uniphy_xpcs_10g_r_linkup();
/*enable UQXGMII mode*/
pr_debug("enable UQSXGMII mode\n");
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_DIG_CTRL1, 0x200, QCA8084_UNIPHY_MMD3_USXGMII_EN);
/*set UQXGMII mode*/
pr_debug("set QXGMII mode\n");
qca8084_uniphy_xpcs_modify_mmd(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_VR_RPCS_TPC, 0x1c00, QCA8084_UNIPHY_MMD3_QXGMII_EN);
/*set AM interval*/
pr_debug("set AM interval\n");
qca8084_uniphy_xpcs_mmd_write(QCA8084_UNIPHY_MMD3,
QCA8084_UNIPHY_MMD3_MII_AM_INTERVAL, QCA8084_UNIPHY_MMD3_MII_AM_INTERVAL_VAL);
/*xpcs software reset*/
pr_debug("xpcs software reset\n");
qca8084_uniphy_xpcs_soft_reset();
}
void qca8084_interface_uqxgmii_mode_set(void)
{
uint32_t uniphy_addr = 0, qca8084_port_id = 0;
qca8084_serdes_addr_get(QCA8084_UNIPHY_SGMII_1, &uniphy_addr);
/*disable IPG_tuning bypass*/
pr_debug("disable IPG_tuning bypass\n");
qca8084_phy_modify_mmd(uniphy_addr, QCA8084_UNIPHY_MMD1,
QCA8084_UNIPHY_MMD1_BYPASS_TUNING_IPG,
QCA8084_UNIPHY_MMD1_BYPASS_TUNING_IPG_EN, 0);
/*disable uniphy GMII/XGMII clock and disable ethphy GMII clock*/
pr_debug("disable uniphy GMII/XGMII clock and ethphy GMII clock\n");
for(qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
qca8084_port_clk_en_set(qca8084_port_id,
QCA8084_CLK_TYPE_UNIPHY|QCA8084_CLK_TYPE_EPHY, 0);
}
/*configure uqxgmii mode*/
pr_debug("configure uqxgmii mode\n");
_qca8084_interface_uqxgmii_mode_set(uniphy_addr);
/*enable auto-neg complete interrupt,Mii using mii-4bits,
configure as PHY mode, enable autoneg ability*/
pr_debug("enable auto-neg complete interrupt, Mii using mii-4bits,"
" configure as PHY mode, enable autoneg ability, disable TICD\n");
for (qca8084_port_id = PORT1; qca8084_port_id <= PORT4;
qca8084_port_id++)
{
/*enable auto-neg complete interrupt,Mii using mii-4bits,configure as PHY mode*/
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_AN_INT_MSK, 0x109,
QCA8084_UNIPHY_MMD_AN_COMPLETE_INT |
QCA8084_UNIPHY_MMD_MII_4BITS_CTRL |
QCA8084_UNIPHY_MMD_TX_CONFIG_CTRL);
/*enable autoneg ability*/
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_CTRL, 0x3060, QCA8084_UNIPHY_MMD_MII_AN_ENABLE |
QCA8084_UNIPHY_MMD_XPC_SPEED_1000);
/*disable TICD*/
qca8084_uniphy_xpcs_modify_port_mmd(qca8084_port_id,
QCA8084_UNIPHY_MMD_MII_XAUI_MODE_CTRL, 0x1,
QCA8084_UNIPHY_MMD_TX_IPG_CHECK_DISABLE);
}
/*enable EEE for xpcs*/
pr_debug("enable EEE for xpcs\n");
qca8084_uniphy_xpcs_8023az_enable();
}

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2022, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that 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.
*/
#ifndef __QCA8084_IF_CTRL_H_
#define __QCA8084_IF_CTRL_H_
#define EPHY_CFG_OFFSET 0xC90F018
#define EPHY_CFG_EPHY0_ADDR_BOFFSET 0
#define EPHY_CFG_EPHY1_ADDR_BOFFSET 5
#define EPHY_CFG_EPHY2_ADDR_BOFFSET 10
#define EPHY_CFG_EPHY3_ADDR_BOFFSET 15
#define SERDES_CFG_OFFSET 0xC90F014
#define SERDES_CFG_S0_ADDR_BOFFSET 0
#define SERDES_CFG_S1_ADDR_BOFFSET 5
#define SERDES_CFG_S1_XPCS_ADDR_BOFFSET 10
#define QCA8084_UNIPHY_SGMII_0 0
#define QCA8084_UNIPHY_SGMII_1 1
#define QCA8084_UNIPHY_XPCS 2
/*UNIPHY MII registers*/
#define QCA8084_UNIPHY_PLL_POWER_ON_AND_RESET 0
/*UNIPHY MII register field*/
#define QCA8084_UNIPHY_ANA_SOFT_RESET 0
#define QCA8084_UNIPHY_ANA_SOFT_RELEASE 0x40
/*UNIPHY MMD*/
#define QCA8084_UNIPHY_MMD1 0x1
#define QCA8084_UNIPHY_MMD3 0x3
#define QCA8084_UNIPHY_MMD26 0x1a
#define QCA8084_UNIPHY_MMD27 0x1b
#define QCA8084_UNIPHY_MMD28 0x1c
#define QCA8084_UNIPHY_MMD31 0x1f
/*UNIPHY MMD1 registers*/
#define QCA8084_UNIPHY_MMD1_CDA_CONTROL1 0x20
#define QCA8084_UNIPHY_MMD1_CALIBRATION4 0x78
#define QCA8084_UNIPHY_MMD1_BYPASS_TUNING_IPG 0x189
#define QCA8084_UNIPHY_MMD1_MODE_CTRL 0x11b
#define QCA8084_UNIPHY_MMD1_CHANNEL0_CFG 0x120
#define QCA8084_UNIPHY_MMD1_GMII_DATAPASS_SEL 0x180
#define QCA8084_UNIPHY_MMD1_USXGMII_RESET 0x18c
/*UNIPHY MMD1 register field*/
#define QCA8084_UNIPHY_MMD1_BYPASS_TUNING_IPG_EN 0x0fff
#define QCA8084_UNIPHY_MMD1_XPCS_MODE 0x1000
#define QCA8084_UNIPHY_MMD1_SGMII_MODE 0x400
#define QCA8084_UNIPHY_MMD1_SGMII_PLUS_MODE 0x800
#define QCA8084_UNIPHY_MMD1_1000BASE_X 0x0
#define QCA8084_UNIPHY_MMD1_SGMII_PHY_MODE 0x10
#define QCA8084_UNIPHY_MMD1_SGMII_MAC_MODE 0x20
#define QCA8084_UNIPHY_MMD1_SGMII_MODE_CTRL_MASK 0x1f70
#define QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_MASK 0xe
#define QCA8084_UNIPHY_MMD1_CH0_AUTONEG_ENABLE 0x0
#define QCA8084_UNIPHY_MMD1_CH0_FORCE_ENABLE 0x8
#define QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_1G 0x4
#define QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_100M 0x2
#define QCA8084_UNIPHY_MMD1_CH0_FORCE_SPEED_10M 0x0
#define QCA8084_UNIPHY_MMD1_DATAPASS_MASK 0x1
#define QCA8084_UNIPHY_MMD1_DATAPASS_USXGMII 0x1
#define QCA8084_UNIPHY_MMD1_DATAPASS_SGMII 0x0
#define QCA8084_UNIPHY_MMD1_CALIBRATION_DONE 0x80
#define QCA8084_UNIPHY_MMD1_SGMII_FUNC_RESET 0x10
#define QCA8084_UNIPHY_MMD1_SGMII_ADPT_RESET 0x800
#define QCA8084_UNIPHY_MMD1_SSCG_ENABLE 0x8
/*UNIPHY MMD3 registers*/
#define QCA8084_UNIPHY_MMD3_PCS_CTRL2 0x7
#define QCA8084_UNIPHY_MMD3_AN_LP_BASE_ABL2 0x14
#define QCA8084_UNIPHY_MMD3_10GBASE_R_PCS_STATUS1 0x20
#define QCA8084_UNIPHY_MMD3_DIG_CTRL1 0x8000
#define QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL 0x8006
#define QCA8084_UNIPHY_MMD3_VR_RPCS_TPC 0x8007
#define QCA8084_UNIPHY_MMD3_EEE_TX_TIMER 0x8008
#define QCA8084_UNIPHY_MMD3_EEE_RX_TIMER 0x8009
#define QCA8084_UNIPHY_MMD3_MII_AM_INTERVAL 0x800a
#define QCA8084_UNIPHY_MMD3_EEE_MODE_CTRL1 0x800b
/*UNIPHY MMD3 register field*/
#define QCA8084_UNIPHY_MMD3_PCS_TYPE_10GBASE_R 0
#define QCA8084_UNIPHY_MMD3_10GBASE_R_UP 0x1000
#define QCA8084_UNIPHY_MMD3_USXGMII_EN 0x200
#define QCA8084_UNIPHY_MMD3_QXGMII_EN 0x1400
#define QCA8084_UNIPHY_MMD3_MII_AM_INTERVAL_VAL 0x6018
#define QCA8084_UNIPHY_MMD3_XPCS_SOFT_RESET 0x8000
#define QCA8084_UNIPHY_MMD3_XPCS_EEE_CAP 0x40
#define QCA8084_UNIPHY_MMD3_EEE_RES_REGS 0x100
#define QCA8084_UNIPHY_MMD3_EEE_SIGN_BIT_REGS 0x40
#define QCA8084_UNIPHY_MMD3_EEE_EN 0x3
#define QCA8084_UNIPHY_MMD3_EEE_TSL_REGS 0xa
#define QCA8084_UNIPHY_MMD3_EEE_TLU_REGS 0xc0
#define QCA8084_UNIPHY_MMD3_EEE_TWL_REGS 0x1600
#define QCA8084_UNIPHY_MMD3_EEE_100US_REG_REGS 0xc8
#define QCA8084_UNIPHY_MMD3_EEE_RWR_REG_REGS 0x1c00
#define QCA8084_UNIPHY_MMD3_EEE_TRANS_LPI_MODE 0x1
#define QCA8084_UNIPHY_MMD3_EEE_TRANS_RX_LPI_MODE 0x100
#define QCA8084_UNIPHY_MMD3_USXG_FIFO_RESET 0x400
/*UNIPHY MMD26 27 28 31 registers*/
#define QCA8084_UNIPHY_MMD_MII_CTRL 0
#define QCA8084_UNIPHY_MMD_MII_DIG_CTRL 0x8000
#define QCA8084_UNIPHY_MMD_MII_AN_INT_MSK 0x8001
#define QCA8084_UNIPHY_MMD_MII_ERR_SEL 0x8002
#define QCA8084_UNIPHY_MMD_MII_XAUI_MODE_CTRL 0x8004
/*UNIPHY MMD26 27 28 31 register field*/
#define QCA8084_UNIPHY_MMD_AN_COMPLETE_INT 0x1
#define QCA8084_UNIPHY_MMD_MII_4BITS_CTRL 0x0
#define QCA8084_UNIPHY_MMD_TX_CONFIG_CTRL 0x8
#define QCA8084_UNIPHY_MMD_MII_AN_ENABLE 0x1000
#define QCA8084_UNIPHY_MMD_MII_AN_RESTART 0x200
#define QCA8084_UNIPHY_MMD_MII_AN_COMPLETE_INT 0x1
#define QCA8084_UNIPHY_MMD_USXG_FIFO_RESET 0x20
#define QCA8084_UNIPHY_MMD_XPC_SPEED_MASK 0x2060
#define QCA8084_UNIPHY_MMD_XPC_SPEED_2500 0x20
#define QCA8084_UNIPHY_MMD_XPC_SPEED_1000 0x40
#define QCA8084_UNIPHY_MMD_XPC_SPEED_100 0x2000
#define QCA8084_UNIPHY_MMD_XPC_SPEED_10 0
#define QCA8084_UNIPHY_MMD_TX_IPG_CHECK_DISABLE 0x1
typedef enum {
QCA8084_UNIPHY_MAC = QCA8084_UNIPHY_MMD1_SGMII_MAC_MODE,
QCA8084_UNIPHY_PHY = QCA8084_UNIPHY_MMD1_SGMII_PHY_MODE,
QCA8084_UNIPHY_SGMII = QCA8084_UNIPHY_MMD1_SGMII_MODE,
QCA8084_UNIPHY_SGMII_PLUS = QCA8084_UNIPHY_MMD1_SGMII_PLUS_MODE,
QCA8084_UNIPHY_UQXGMII = QCA8084_UNIPHY_MMD1_XPCS_MODE,
} qca8084_uniphy_mode_t;
#endif

View file

@ -36,6 +36,8 @@
#define PORT_WRAPPER_RGMII 18 #define PORT_WRAPPER_RGMII 18
#define PORT_WRAPPER_PSGMII_FIBER 19 #define PORT_WRAPPER_PSGMII_FIBER 19
#define PORT_WRAPPER_SGMII_FIBER 20 #define PORT_WRAPPER_SGMII_FIBER 20
#define PORT_WRAPPER_UQXGMII 21
#define PORT_WRAPPER_UQXGMII_3CHANNELS 22
#define PORT_WRAPPER_MAX 0xFF #define PORT_WRAPPER_MAX 0xFF
/* ETH PHY Types */ /* ETH PHY Types */
@ -44,4 +46,6 @@
#define AQ_PHY_TYPE 0x3 #define AQ_PHY_TYPE 0x3
#define QCA8033_PHY_TYPE 0x4 #define QCA8033_PHY_TYPE 0x4
#define SFP_PHY_TYPE 0x5 #define SFP_PHY_TYPE 0x5
#define QCA8084_PHY_TYPE 0x6
#define UNUSED_PHY_TYPE 0xFF
#endif #endif

View file

@ -6,6 +6,7 @@
#define BIT(nr) (1UL << (nr)) #define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BITS_MASK(_s, _n) (((1UL << (_n)) - 1) << _s)
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
/* /*
@ -122,6 +123,17 @@ static inline unsigned int generic_hweight8(unsigned int w)
#include <asm/bitops.h> #include <asm/bitops.h>
#define for_each_clear_bit(bit, addr, size) \
for ((bit) = find_first_zero_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
/* same as for_each_clear_bit() but use bit as value to start with */
#define for_each_clear_bit_from(bit, addr, size) \
for ((bit) = find_next_zero_bit((addr), (size), (bit)); \
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
/* linux/include/asm-generic/bitops/non-atomic.h */ /* linux/include/asm-generic/bitops/non-atomic.h */
#ifndef PLATFORM__SET_BIT #ifndef PLATFORM__SET_BIT

View file

@ -19,6 +19,14 @@
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/byteorder.h> /* for nton* / ntoh* stuff */ #include <asm/byteorder.h> /* for nton* / ntoh* stuff */
#define PORT0 0
#define PORT1 1
#define PORT2 2
#define PORT3 3
#define PORT4 4
#define PORT5 5
#define PORT6 6
#define DEBUG_LL_STATE 0 /* Link local state machine changes */ #define DEBUG_LL_STATE 0 /* Link local state machine changes */
#define DEBUG_DEV_PKT 0 /* Packets or info directed to the device */ #define DEBUG_DEV_PKT 0 /* Packets or info directed to the device */
#define DEBUG_NET_PKT 0 /* Packets on info on the network at large */ #define DEBUG_NET_PKT 0 /* Packets on info on the network at large */