mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 23:24:38 +00:00
net: dwc_eth_qos: Add Qcom ethernet driver glue layer
The Qualcom ETHQOS hardware supports an RGMII macro which needs to be configured according to following link speeds: - SPEED_1000 - SPEED_100 - SPEED_10 So add a corresponding glue driver to configure RGMII macro. Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
This commit is contained in:
parent
a962b7cff4
commit
d382025dc5
5 changed files with 630 additions and 0 deletions
|
@ -242,6 +242,13 @@ config DWC_ETH_QOS_TEGRA186
|
|||
The Synopsys Designware Ethernet QOS IP block with specific
|
||||
configuration used in NVIDIA's Tegra186 chip.
|
||||
|
||||
config DWC_ETH_QOS_QCOM
|
||||
bool "Synopsys DWC Ethernet QOS device support for Qcom SoCs"
|
||||
depends on DWC_ETH_QOS
|
||||
help
|
||||
The Synopsys Designware Ethernet QOS IP block with specific
|
||||
configuration used in Qcom QCS404 SoC.
|
||||
|
||||
config E1000
|
||||
bool "Intel PRO/1000 Gigabit Ethernet support"
|
||||
depends on PCI
|
||||
|
|
|
@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
|
|||
obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o
|
||||
obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o
|
||||
obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
|
||||
obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o
|
||||
obj-$(CONFIG_E1000) += e1000.o
|
||||
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
|
||||
obj-$(CONFIG_EEPRO100) += eepro100.o
|
||||
|
|
|
@ -1712,6 +1712,13 @@ static const struct udevice_id eqos_ids[] = {
|
|||
},
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_QCOM)
|
||||
{
|
||||
.compatible = "qcom,qcs404-ethqos",
|
||||
.data = (ulong)&eqos_qcom_config
|
||||
},
|
||||
#endif
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -253,6 +253,7 @@ struct eqos_priv {
|
|||
struct eqos_mtl_regs *mtl_regs;
|
||||
struct eqos_dma_regs *dma_regs;
|
||||
struct eqos_tegra186_regs *tegra186_regs;
|
||||
void *eqos_qcom_rgmii_regs;
|
||||
struct reset_ctl reset_ctl;
|
||||
struct gpio_desc phy_reset_gpio;
|
||||
struct clk clk_master_bus;
|
||||
|
@ -277,6 +278,7 @@ struct eqos_priv {
|
|||
bool reg_access_ok;
|
||||
bool clk_ck_enabled;
|
||||
unsigned int tx_fifo_sz, rx_fifo_sz;
|
||||
u32 reset_delays[3];
|
||||
};
|
||||
|
||||
void eqos_inval_desc_generic(void *desc);
|
||||
|
@ -286,3 +288,4 @@ void eqos_flush_buffer_generic(void *buf, size_t size);
|
|||
int eqos_null_ops(struct udevice *dev);
|
||||
|
||||
extern struct eqos_config eqos_imx_config;
|
||||
extern struct eqos_config eqos_qcom_config;
|
||||
|
|
612
drivers/net/dwc_eth_qos_qcom.c
Normal file
612
drivers/net/dwc_eth_qos_qcom.c
Normal file
|
@ -0,0 +1,612 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2022-2023 Sumit Garg <sumit.garg@linaro.org>
|
||||
*
|
||||
* Qcom DWMAC specific glue layer
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <phy.h>
|
||||
#include <reset.h>
|
||||
#include <syscon.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "dwc_eth_qos.h"
|
||||
|
||||
/* RGMII_IO_MACRO_CONFIG fields */
|
||||
#define RGMII_CONFIG_FUNC_CLK_EN BIT(30)
|
||||
#define RGMII_CONFIG_POS_NEG_DATA_SEL BIT(23)
|
||||
#define RGMII_CONFIG_GPIO_CFG_RX_INT GENMASK(21, 20)
|
||||
#define RGMII_CONFIG_GPIO_CFG_TX_INT GENMASK(19, 17)
|
||||
#define RGMII_CONFIG_MAX_SPD_PRG_9 GENMASK(16, 8)
|
||||
#define RGMII_CONFIG_MAX_SPD_PRG_2 GENMASK(7, 6)
|
||||
#define RGMII_CONFIG_INTF_SEL GENMASK(5, 4)
|
||||
#define RGMII_CONFIG_BYPASS_TX_ID_EN BIT(3)
|
||||
#define RGMII_CONFIG_LOOPBACK_EN BIT(2)
|
||||
#define RGMII_CONFIG_PROG_SWAP BIT(1)
|
||||
#define RGMII_CONFIG_DDR_MODE BIT(0)
|
||||
|
||||
/* SDCC_HC_REG_DLL_CONFIG fields */
|
||||
#define SDCC_DLL_CONFIG_DLL_RST BIT(30)
|
||||
#define SDCC_DLL_CONFIG_PDN BIT(29)
|
||||
#define SDCC_DLL_CONFIG_MCLK_FREQ GENMASK(26, 24)
|
||||
#define SDCC_DLL_CONFIG_CDR_SELEXT GENMASK(23, 20)
|
||||
#define SDCC_DLL_CONFIG_CDR_EXT_EN BIT(19)
|
||||
#define SDCC_DLL_CONFIG_CK_OUT_EN BIT(18)
|
||||
#define SDCC_DLL_CONFIG_CDR_EN BIT(17)
|
||||
#define SDCC_DLL_CONFIG_DLL_EN BIT(16)
|
||||
#define SDCC_DLL_MCLK_GATING_EN BIT(5)
|
||||
#define SDCC_DLL_CDR_FINE_PHASE GENMASK(3, 2)
|
||||
|
||||
/* SDCC_HC_REG_DDR_CONFIG fields */
|
||||
#define SDCC_DDR_CONFIG_PRG_DLY_EN BIT(31)
|
||||
#define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY GENMASK(26, 21)
|
||||
#define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE GENMASK(29, 27)
|
||||
#define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN BIT(30)
|
||||
#define SDCC_DDR_CONFIG_PRG_RCLK_DLY GENMASK(8, 0)
|
||||
|
||||
/* SDCC_HC_REG_DLL_CONFIG2 fields */
|
||||
#define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS BIT(21)
|
||||
#define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC GENMASK(17, 10)
|
||||
#define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL GENMASK(3, 2)
|
||||
#define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW BIT(1)
|
||||
#define SDCC_DLL_CONFIG2_DDR_CAL_EN BIT(0)
|
||||
|
||||
/* SDC4_STATUS bits */
|
||||
#define SDC4_STATUS_DLL_LOCK BIT(7)
|
||||
|
||||
/* RGMII_IO_MACRO_CONFIG2 fields */
|
||||
#define RGMII_CONFIG2_RSVD_CONFIG15 GENMASK(31, 17)
|
||||
#define RGMII_CONFIG2_RGMII_CLK_SEL_CFG BIT(16)
|
||||
#define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN BIT(13)
|
||||
#define RGMII_CONFIG2_CLK_DIVIDE_SEL BIT(12)
|
||||
#define RGMII_CONFIG2_RX_PROG_SWAP BIT(7)
|
||||
#define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6)
|
||||
#define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5)
|
||||
|
||||
struct dwmac_rgmii_regs {
|
||||
u32 io_macro_config; /* 0x00 */
|
||||
u32 sdcc_hc_dll_config; /* 0x04 */
|
||||
u32 reserved_1; /* 0x08 */
|
||||
u32 sdcc_hc_ddr_config; /* 0x0c */
|
||||
u32 sdcc_hc_dll_config2; /* 0x10 */
|
||||
u32 sdc4_status; /* 0x14 */
|
||||
u32 sdcc_usr_ctl; /* 0x18 */
|
||||
u32 io_macro_config2; /* 0x1c */
|
||||
u32 io_macro_debug1; /* 0x20 */
|
||||
u32 reserved_2; /* 0x24 */
|
||||
u32 emac_sys_low_power_dbg; /* 0x28 */
|
||||
u32 reserved_3[53]; /* upto 0x100 */
|
||||
};
|
||||
|
||||
static struct dwmac_rgmii_regs emac_v2_3_0_por = {
|
||||
.io_macro_config = 0x00C01343,
|
||||
.sdcc_hc_dll_config = 0x2004642C,
|
||||
.sdcc_hc_ddr_config = 0x00000000,
|
||||
.sdcc_hc_dll_config2 = 0x00200000,
|
||||
.sdcc_usr_ctl = 0x00010800,
|
||||
.io_macro_config2 = 0x00002060
|
||||
};
|
||||
|
||||
static void ethqos_set_func_clk_en(struct dwmac_rgmii_regs *regs)
|
||||
{
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_FUNC_CLK_EN);
|
||||
}
|
||||
|
||||
static int ethqos_dll_configure(struct udevice *dev,
|
||||
struct dwmac_rgmii_regs *regs)
|
||||
{
|
||||
unsigned int val;
|
||||
int retry = 1000;
|
||||
|
||||
/* Set CDR_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CDR_EN);
|
||||
|
||||
/* Set CDR_EXT_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CDR_EXT_EN);
|
||||
|
||||
/* Clear CK_OUT_EN */
|
||||
clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CK_OUT_EN);
|
||||
|
||||
/* Set DLL_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_EN);
|
||||
|
||||
clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_MCLK_GATING_EN);
|
||||
|
||||
clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CDR_FINE_PHASE);
|
||||
|
||||
/* Wait for CK_OUT_EN clear */
|
||||
do {
|
||||
val = readl(®s->sdcc_hc_dll_config);
|
||||
val &= SDCC_DLL_CONFIG_CK_OUT_EN;
|
||||
if (!val)
|
||||
break;
|
||||
mdelay(1);
|
||||
retry--;
|
||||
} while (retry > 0);
|
||||
if (!retry)
|
||||
dev_err(dev, "Clear CK_OUT_EN timedout\n");
|
||||
|
||||
/* Set CK_OUT_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CK_OUT_EN);
|
||||
|
||||
/* Wait for CK_OUT_EN set */
|
||||
retry = 1000;
|
||||
do {
|
||||
val = readl(®s->sdcc_hc_dll_config);
|
||||
val &= SDCC_DLL_CONFIG_CK_OUT_EN;
|
||||
if (val)
|
||||
break;
|
||||
mdelay(1);
|
||||
retry--;
|
||||
} while (retry > 0);
|
||||
if (!retry)
|
||||
dev_err(dev, "Set CK_OUT_EN timedout\n");
|
||||
|
||||
/* Set DDR_CAL_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config2, SDCC_DLL_CONFIG2_DDR_CAL_EN);
|
||||
|
||||
clrbits_le32(®s->sdcc_hc_dll_config2,
|
||||
SDCC_DLL_CONFIG2_DLL_CLOCK_DIS);
|
||||
|
||||
clrsetbits_le32(®s->sdcc_hc_dll_config2,
|
||||
SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 0x1A << 10);
|
||||
|
||||
clrsetbits_le32(®s->sdcc_hc_dll_config2,
|
||||
SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, BIT(2));
|
||||
|
||||
setbits_le32(®s->sdcc_hc_dll_config2,
|
||||
SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethqos_rgmii_macro_init(struct udevice *dev,
|
||||
struct dwmac_rgmii_regs *regs,
|
||||
unsigned long speed)
|
||||
{
|
||||
/* Disable loopback mode */
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN);
|
||||
|
||||
/* Select RGMII, write 0 to interface select */
|
||||
clrbits_le32(®s->io_macro_config, RGMII_CONFIG_INTF_SEL);
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_1000:
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_DDR_MODE);
|
||||
clrbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_BYPASS_TX_ID_EN);
|
||||
setbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_POS_NEG_DATA_SEL);
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_PROG_SWAP);
|
||||
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL);
|
||||
setbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN);
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_RSVD_CONFIG15);
|
||||
setbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_RX_PROG_SWAP);
|
||||
|
||||
/* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */
|
||||
clrsetbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_PRG_RCLK_DLY, 57);
|
||||
setbits_le32(®s->sdcc_hc_ddr_config, SDCC_DDR_CONFIG_PRG_DLY_EN);
|
||||
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_LOOPBACK_EN);
|
||||
break;
|
||||
|
||||
case SPEED_100:
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_DDR_MODE);
|
||||
setbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_BYPASS_TX_ID_EN);
|
||||
clrbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_POS_NEG_DATA_SEL);
|
||||
clrbits_le32(®s->io_macro_config, RGMII_CONFIG_PROG_SWAP);
|
||||
clrsetbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_MAX_SPD_PRG_2, BIT(6));
|
||||
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL);
|
||||
setbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN);
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_RSVD_CONFIG15);
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_RX_PROG_SWAP);
|
||||
|
||||
/* Write 0x5 to PRG_RCLK_DLY_CODE */
|
||||
clrsetbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE,
|
||||
(BIT(29) | BIT(27)));
|
||||
setbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY);
|
||||
setbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN);
|
||||
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_LOOPBACK_EN);
|
||||
break;
|
||||
|
||||
case SPEED_10:
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_DDR_MODE);
|
||||
setbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_BYPASS_TX_ID_EN);
|
||||
clrbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_POS_NEG_DATA_SEL);
|
||||
clrbits_le32(®s->io_macro_config, RGMII_CONFIG_PROG_SWAP);
|
||||
clrsetbits_le32(®s->io_macro_config,
|
||||
RGMII_CONFIG_MAX_SPD_PRG_9,
|
||||
BIT(12) | GENMASK(9, 8));
|
||||
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL);
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN);
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_RSVD_CONFIG15);
|
||||
clrbits_le32(®s->io_macro_config2,
|
||||
RGMII_CONFIG2_RX_PROG_SWAP);
|
||||
|
||||
/* Write 0x5 to PRG_RCLK_DLY_CODE */
|
||||
clrsetbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE,
|
||||
(BIT(29) | BIT(27)));
|
||||
setbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY);
|
||||
setbits_le32(®s->sdcc_hc_ddr_config,
|
||||
SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN);
|
||||
|
||||
setbits_le32(®s->io_macro_config, RGMII_CONFIG_LOOPBACK_EN);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev, "Invalid speed %ld\n", speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethqos_configure(struct udevice *dev,
|
||||
struct dwmac_rgmii_regs *regs,
|
||||
unsigned long speed)
|
||||
{
|
||||
unsigned int retry = 1000;
|
||||
|
||||
/* Reset to POR values and enable clk */
|
||||
writel(emac_v2_3_0_por.io_macro_config, ®s->io_macro_config);
|
||||
writel(emac_v2_3_0_por.sdcc_hc_dll_config, ®s->sdcc_hc_dll_config);
|
||||
writel(emac_v2_3_0_por.sdcc_hc_ddr_config, ®s->sdcc_hc_ddr_config);
|
||||
writel(emac_v2_3_0_por.sdcc_hc_dll_config2, ®s->sdcc_hc_dll_config2);
|
||||
writel(emac_v2_3_0_por.sdcc_usr_ctl, ®s->sdcc_usr_ctl);
|
||||
writel(emac_v2_3_0_por.io_macro_config2, ®s->io_macro_config2);
|
||||
|
||||
ethqos_set_func_clk_en(regs);
|
||||
|
||||
/* Initialize the DLL first */
|
||||
|
||||
/* Set DLL_RST */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_RST);
|
||||
|
||||
/* Set PDN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_PDN);
|
||||
|
||||
/* Clear DLL_RST */
|
||||
clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_RST);
|
||||
|
||||
/* Clear PDN */
|
||||
clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_PDN);
|
||||
|
||||
if (speed == SPEED_1000) {
|
||||
/* Set DLL_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_EN);
|
||||
|
||||
/* Set CK_OUT_EN */
|
||||
setbits_le32(®s->sdcc_hc_dll_config,
|
||||
SDCC_DLL_CONFIG_CK_OUT_EN);
|
||||
|
||||
/* Set USR_CTL bit 26 with mask of 3 bits */
|
||||
clrsetbits_le32(®s->sdcc_usr_ctl, GENMASK(26, 24), BIT(26));
|
||||
|
||||
/* wait for DLL LOCK */
|
||||
do {
|
||||
mdelay(1);
|
||||
if (readl(®s->sdc4_status) & SDC4_STATUS_DLL_LOCK)
|
||||
break;
|
||||
retry--;
|
||||
} while (retry > 0);
|
||||
if (!retry)
|
||||
dev_err(dev, "Timeout while waiting for DLL lock\n");
|
||||
|
||||
ethqos_dll_configure(dev, regs);
|
||||
}
|
||||
|
||||
ethqos_rgmii_macro_init(dev, regs, speed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ethqos_rgmii_dump(struct udevice *dev,
|
||||
struct dwmac_rgmii_regs *regs)
|
||||
{
|
||||
dev_dbg(dev, "Rgmii register dump\n");
|
||||
dev_dbg(dev, "RGMII_IO_MACRO_CONFIG: %08x\n",
|
||||
readl(®s->io_macro_config));
|
||||
dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG: %08x\n",
|
||||
readl(®s->sdcc_hc_dll_config));
|
||||
dev_dbg(dev, "SDCC_HC_REG_DDR_CONFIG: %08x\n",
|
||||
readl(®s->sdcc_hc_ddr_config));
|
||||
dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG2: %08x\n",
|
||||
readl(®s->sdcc_hc_dll_config2));
|
||||
dev_dbg(dev, "SDC4_STATUS: %08x\n",
|
||||
readl(®s->sdc4_status));
|
||||
dev_dbg(dev, "SDCC_USR_CTL: %08x\n",
|
||||
readl(®s->sdcc_usr_ctl));
|
||||
dev_dbg(dev, "RGMII_IO_MACRO_CONFIG2: %08x\n",
|
||||
readl(®s->io_macro_config2));
|
||||
dev_dbg(dev, "RGMII_IO_MACRO_DEBUG1: %08x\n",
|
||||
readl(®s->io_macro_debug1));
|
||||
dev_dbg(dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %08x\n",
|
||||
readl(®s->emac_sys_low_power_dbg));
|
||||
}
|
||||
|
||||
static int qcom_eqos_rgmii_set_speed(struct udevice *dev,
|
||||
void *rgmii_regs,
|
||||
unsigned long speed)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ethqos_rgmii_dump(dev, rgmii_regs);
|
||||
|
||||
ret = ethqos_configure(dev, rgmii_regs, speed);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ethqos_rgmii_dump(dev, rgmii_regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_eqos_rgmii_reset(struct udevice *dev, void *rgmii_regs)
|
||||
{
|
||||
ethqos_set_func_clk_en(rgmii_regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eqos_start_clks_qcom(struct udevice *dev)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_CLK)) {
|
||||
struct clk_bulk clocks;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_bulk(dev, &clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable_bulk(&clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
debug("%s: OK\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eqos_stop_clks_qcom(struct udevice *dev)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_CLK)) {
|
||||
struct clk_bulk clocks;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_bulk(dev, &clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_disable_bulk(&clocks);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
debug("%s: OK\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eqos_start_resets_qcom(struct udevice *dev)
|
||||
{
|
||||
struct eqos_priv *eqos = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
debug("%s(dev=%p):\n", __func__, dev);
|
||||
|
||||
if (!eqos->phy) {
|
||||
ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
|
||||
if (ret < 0) {
|
||||
pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(eqos->reset_delays[0]);
|
||||
|
||||
ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
|
||||
if (ret < 0) {
|
||||
pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(eqos->reset_delays[1]);
|
||||
|
||||
ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
|
||||
if (ret < 0) {
|
||||
pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(eqos->reset_delays[2]);
|
||||
}
|
||||
|
||||
ret = reset_deassert(&eqos->reset_ctl);
|
||||
if (ret < 0) {
|
||||
pr_err("reset_deassert() failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcom_eqos_rgmii_reset(dev, eqos->eqos_qcom_rgmii_regs);
|
||||
if (ret < 0) {
|
||||
pr_err("qcom rgmii_reset failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
debug("%s: OK\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clock rates */
|
||||
#define RGMII_1000_NOM_CLK_FREQ (250 * 1000 * 1000UL)
|
||||
#define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ (50 * 1000 * 1000UL)
|
||||
#define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ (5 * 1000 * 1000UL)
|
||||
|
||||
static int eqos_set_tx_clk_speed_qcom(struct udevice *dev)
|
||||
{
|
||||
struct eqos_priv *eqos = dev_get_priv(dev);
|
||||
ulong rate;
|
||||
int ret;
|
||||
|
||||
debug("%s(dev=%p):\n", __func__, dev);
|
||||
|
||||
switch (eqos->phy->speed) {
|
||||
case SPEED_1000:
|
||||
rate = RGMII_1000_NOM_CLK_FREQ;
|
||||
break;
|
||||
case SPEED_100:
|
||||
rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ;
|
||||
break;
|
||||
case SPEED_10:
|
||||
rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ;
|
||||
break;
|
||||
default:
|
||||
pr_err("invalid speed %d", eqos->phy->speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(&eqos->clk_tx, rate);
|
||||
if (ret < 0) {
|
||||
pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcom_eqos_rgmii_set_speed(dev, eqos->eqos_qcom_rgmii_regs,
|
||||
eqos->phy->speed);
|
||||
if (ret < 0) {
|
||||
pr_err("qcom set_speed: %d, failed: %d", eqos->phy->speed, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eqos_probe_resources_qcom(struct udevice *dev)
|
||||
{
|
||||
struct eqos_priv *eqos = dev_get_priv(dev);
|
||||
phy_interface_t interface;
|
||||
int reset_flags = GPIOD_IS_OUT;
|
||||
int ret;
|
||||
|
||||
debug("%s(dev=%p):\n", __func__, dev);
|
||||
|
||||
interface = eqos->config->interface(dev);
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_NA) {
|
||||
pr_err("Invalid PHY interface\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);
|
||||
|
||||
eqos->tx_fifo_sz = dev_read_u32_default(dev, "tx-fifo-depth", 0);
|
||||
eqos->rx_fifo_sz = dev_read_u32_default(dev, "rx-fifo-depth", 0);
|
||||
|
||||
ret = reset_get_by_name(dev, "emac", &eqos->reset_ctl);
|
||||
if (ret) {
|
||||
pr_err("reset_get_by_name(rst) failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev_read_bool(dev, "snps,reset-active-low"))
|
||||
reset_flags |= GPIOD_ACTIVE_LOW;
|
||||
|
||||
ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
|
||||
&eqos->phy_reset_gpio, reset_flags);
|
||||
if (ret == 0) {
|
||||
ret = dev_read_u32_array(dev, "snps,reset-delays-us",
|
||||
eqos->reset_delays, 3);
|
||||
} else if (ret == -ENOENT) {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
eqos->eqos_qcom_rgmii_regs = (void *)dev_read_addr_name(dev, "rgmii");
|
||||
if ((fdt_addr_t)eqos->eqos_qcom_rgmii_regs == FDT_ADDR_T_NONE) {
|
||||
pr_err("Invalid RGMII address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_get_by_name(dev, "rgmii", &eqos->clk_tx);
|
||||
if (ret) {
|
||||
pr_err("clk_get_by_name(tx) failed: %d", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug("%s: OK\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eqos_remove_resources_qcom(struct udevice *dev)
|
||||
{
|
||||
struct eqos_priv *eqos = dev_get_priv(dev);
|
||||
|
||||
debug("%s(dev=%p):\n", __func__, dev);
|
||||
|
||||
clk_free(&eqos->clk_tx);
|
||||
dm_gpio_free(dev, &eqos->phy_reset_gpio);
|
||||
reset_free(&eqos->reset_ctl);
|
||||
|
||||
debug("%s: OK\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct eqos_ops eqos_qcom_ops = {
|
||||
.eqos_inval_desc = eqos_inval_desc_generic,
|
||||
.eqos_flush_desc = eqos_flush_desc_generic,
|
||||
.eqos_inval_buffer = eqos_inval_buffer_generic,
|
||||
.eqos_flush_buffer = eqos_flush_buffer_generic,
|
||||
.eqos_probe_resources = eqos_probe_resources_qcom,
|
||||
.eqos_remove_resources = eqos_remove_resources_qcom,
|
||||
.eqos_stop_resets = eqos_null_ops,
|
||||
.eqos_start_resets = eqos_start_resets_qcom,
|
||||
.eqos_stop_clks = eqos_stop_clks_qcom,
|
||||
.eqos_start_clks = eqos_start_clks_qcom,
|
||||
.eqos_calibrate_pads = eqos_null_ops,
|
||||
.eqos_disable_calibration = eqos_null_ops,
|
||||
.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_qcom,
|
||||
.eqos_get_enetaddr = eqos_null_ops,
|
||||
};
|
||||
|
||||
struct eqos_config __maybe_unused eqos_qcom_config = {
|
||||
.reg_access_always_ok = false,
|
||||
.mdio_wait = 10,
|
||||
.swr_wait = 50,
|
||||
.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
|
||||
.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
|
||||
.axi_bus_width = EQOS_AXI_WIDTH_64,
|
||||
.interface = dev_read_phy_mode,
|
||||
.ops = &eqos_qcom_ops
|
||||
};
|
Loading…
Reference in a new issue