CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/24263

- Add i.MX95 EMDIO support
- Guard binman nodes with CONFIG_OPTEE on imx8m
- Enable CAAM in phycore-imx8mp SPL.
- Fix Fix NULL dereference in imx_pinctrl_probe().
This commit is contained in:
Tom Rini
2025-01-20 12:08:16 -06:00
13 changed files with 876 additions and 112 deletions

View File

@@ -164,6 +164,7 @@
};
#endif
#ifdef CONFIG_OPTEE
tee: tee {
description = "OP-TEE";
type = "tee";
@@ -178,6 +179,7 @@
optional;
};
};
#endif
binman_fip: fip {
arch = "arm64";
@@ -207,7 +209,11 @@
fdt = "fdt-SEQ";
firmware = "uboot";
#ifndef CONFIG_ARMV8_PSCI
#ifdef CONFIG_OPTEE
loadables = "atf", "tee";
#else
loadables = "atf";
#endif
#endif
};
};

View File

@@ -240,6 +240,7 @@
};
#endif
#ifdef CONFIG_OPTEE
tee: tee {
description = "OP-TEE";
type = "tee";
@@ -254,6 +255,7 @@
optional;
};
};
#endif
binman_fip: fip {
arch = "arm64";
@@ -283,7 +285,11 @@
fdt = "fdt-SEQ";
firmware = "uboot";
#ifndef CONFIG_ARMV8_PSCI
#ifdef CONFIG_OPTEE
loadables = "atf", "tee";
#else
loadables = "atf";
#endif
#endif
};
};

View File

@@ -185,6 +185,7 @@
};
#endif
#ifdef CONFIG_OPTEE
tee: tee {
description = "OP-TEE";
type = "tee";
@@ -199,6 +200,7 @@
optional;
};
};
#endif
@fdt-SEQ {
description = "NAME";
@@ -219,7 +221,11 @@
fdt = "fdt-SEQ";
firmware = "uboot";
#ifndef CONFIG_ARMV8_PSCI
#ifdef CONFIG_OPTEE
loadables = "atf", "tee";
#else
loadables = "atf";
#endif
#endif
};
};

View File

@@ -144,6 +144,7 @@
};
#endif
#ifdef CONFIG_OPTEE
tee: tee {
description = "OP-TEE";
type = "tee";
@@ -158,6 +159,7 @@
optional;
};
};
#endif
fdt {
compression = "none";
@@ -179,7 +181,11 @@
fdt = "fdt";
firmware = "uboot";
#ifndef CONFIG_ARMV8_PSCI
#ifdef CONFIG_OPTEE
loadables = "atf", "tee";
#else
loadables = "atf";
#endif
#endif
};
};

View File

@@ -165,6 +165,8 @@ int power_init_board(void)
void spl_board_init(void)
{
arch_misc_init();
/* Set GIC clock to 500Mhz for OD VDD_SOC. */
clock_enable(CCGR_GIC, 0);
clock_set_target_val(GIC_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(5));

View File

@@ -52,7 +52,6 @@ CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x42200000
CONFIG_SPL_SYS_MALLOC_SIZE=0x80000
CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x300
# CONFIG_SPL_CRYPTO is not set
CONFIG_SPL_I2C=y
CONFIG_SPL_NOR_SUPPORT=y
CONFIG_SPL_POWER=y
@@ -180,4 +179,3 @@ CONFIG_USB_GADGET_MANUFACTURER="PHYTEC"
CONFIG_USB_GADGET_VENDOR_NUM=0x0525
CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
CONFIG_IMX_WATCHDOG=y
# CONFIG_SPL_SHA_HW_ACCEL is not set

View File

@@ -1019,6 +1019,20 @@ config FSL_ENETC
This driver supports the NXP ENETC Ethernet controller found on some
of the NXP SoCs.
config FSL_ENETC_NETC_BLK_CTRL
bool "NXP ENETC NETC blocks control driver"
depends on FSL_ENETC && IMX95
default y if IMX95
help
This driver configures Integrated Endpoint Register Block (IERB) and
Privileged Register Block (PRB) of NETC. For i.MX platforms, it also
includes the configuration of NETCMIX block.
The IERB contains registers that are used for pre-boot initialization,
debug, and non-customer configuration. The PRB controls global reset
and global error handling for NETC. The NETCMIX block is mainly used
to set MII protocol and PCS protocol of the links, it also contains
settings for some other functions.
config MDIO_GPIO_BITBANG
bool "GPIO bitbanging MDIO driver"
depends on DM_MDIO && DM_GPIO

View File

@@ -44,6 +44,7 @@ obj-$(CONFIG_FEC_MXC) += fec_mxc.o
obj-$(CONFIG_FMAN_ENET) += fm/
obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o
obj-$(CONFIG_FSL_ENETC_NETC_BLK_CTRL) += fsl_enetc_netc_blk_ctrl.o
obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o
obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/

View File

@@ -2,6 +2,7 @@
/*
* ENETC ethernet controller driver
* Copyright 2017-2021 NXP
* Copyright 2023-2025 NXP
*/
#include <dm.h>
@@ -16,52 +17,267 @@
#include <miiphy.h>
#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/build_bug.h>
#ifdef CONFIG_ARCH_IMX9
#include <asm/mach-imx/sys_proto.h>
#include <cpu_func.h>
#endif
#include "fsl_enetc.h"
#define ENETC_DRIVER_NAME "enetc_eth"
/*
* Calculate number of buffer descriptors per cacheline, and compile-time
* validate that:
* - the RX and TX descriptors are the same size
* - the descriptors fit exactly into cachelines without overlap
* - all descriptors fit exactly into cachelines
*/
#define ENETC_NUM_BD_IN_CL \
((ARCH_DMA_MINALIGN / sizeof(struct enetc_tx_bd)) + \
BUILD_BUG_ON_ZERO(sizeof(struct enetc_tx_bd) != \
sizeof(union enetc_rx_bd)) + \
BUILD_BUG_ON_ZERO(ARCH_DMA_MINALIGN % sizeof(struct enetc_tx_bd)) + \
BUILD_BUG_ON_ZERO(ARCH_DMA_MINALIGN % sizeof(union enetc_rx_bd)) + \
BUILD_BUG_ON_ZERO(ENETC_BD_CNT % \
(ARCH_DMA_MINALIGN / sizeof(struct enetc_tx_bd))))
static int enetc_remove(struct udevice *dev);
static int enetc_is_imx95(struct udevice *dev)
{
struct pci_child_plat *pplat = dev_get_parent_plat(dev);
/* Test whether this is i.MX95 ENETCv4. This may be optimized out. */
return IS_ENABLED(CONFIG_ARCH_IMX9) &&
pplat->vendor == PCI_VENDOR_ID_PHILIPS;
}
static int enetc_is_ls1028a(struct udevice *dev)
{
struct pci_child_plat *pplat = dev_get_parent_plat(dev);
/* Test whether this is LS1028A ENETC. This may be optimized out. */
return IS_ENABLED(CONFIG_ARCH_LS1028A) &&
pplat->vendor == PCI_VENDOR_ID_FREESCALE;
}
static int enetc_dev_id(struct udevice *dev)
{
if (enetc_is_imx95(dev))
return PCI_DEV(pci_get_devfn(dev)) >> 3;
if (enetc_is_ls1028a(dev))
return PCI_FUNC(pci_get_devfn(dev));
return 0;
}
static void enetc_inval_rxbd(struct udevice *dev)
{
struct enetc_priv *priv = dev_get_priv(dev);
union enetc_rx_bd *desc = &priv->enetc_rxbd[priv->rx_bdr.next_prod_idx];
unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN);
unsigned long end = roundup((unsigned long)desc + sizeof(*desc),
ARCH_DMA_MINALIGN);
if (enetc_is_imx95(dev))
invalidate_dcache_range(start, end);
}
static void enetc_flush_bd(struct udevice *dev, int pi, bool tx)
{
struct enetc_priv *priv = dev_get_priv(dev);
union enetc_rx_bd *rxdesc = &priv->enetc_rxbd[pi];
struct enetc_tx_bd *txdesc = &priv->enetc_txbd[pi];
unsigned long desc = tx ? (unsigned long)txdesc : (unsigned long)rxdesc;
unsigned long size = tx ? sizeof(*txdesc) : sizeof(*rxdesc);
unsigned long start = rounddown(desc, ARCH_DMA_MINALIGN);
unsigned long end = roundup(desc + size, ARCH_DMA_MINALIGN);
if (enetc_is_imx95(dev))
flush_dcache_range(start, end);
}
static void enetc_inval_buffer(struct udevice *dev, void *buf, size_t size)
{
unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
unsigned long end = roundup((unsigned long)buf + size,
ARCH_DMA_MINALIGN);
if (enetc_is_imx95(dev))
invalidate_dcache_range(start, end);
}
static void enetc_flush_buffer(struct udevice *dev, void *buf, size_t size)
{
unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
unsigned long end = roundup((unsigned long)buf + size,
ARCH_DMA_MINALIGN);
if (enetc_is_imx95(dev))
flush_dcache_range(start, end);
}
/* register accessors */
static u32 enetc_read_reg(void __iomem *addr)
{
return readl(addr);
}
static void enetc_write_reg(void __iomem *addr, u32 val)
{
writel(val, addr);
}
static void enetc_write(struct enetc_priv *priv, u32 off, u32 val)
{
enetc_write_reg(priv->regs_base + off, val);
}
/* base port register accessors */
static void enetc_write_pmr(struct udevice *dev, u32 val)
{
struct enetc_data *data = (struct enetc_data *)dev_get_driver_data(dev);
struct enetc_priv *priv = dev_get_priv(dev);
const u32 off = ENETC_PMR + data->reg_offset_pmr;
enetc_write_reg(priv->port_regs + off, val);
}
static void enetc_write_psipmar(struct udevice *dev, int n, u32 val)
{
struct enetc_data *data = (struct enetc_data *)dev_get_driver_data(dev);
struct enetc_priv *priv = dev_get_priv(dev);
const u32 off = (n ? ENETC_PSIPMAR1 : ENETC_PSIPMAR0) +
data->reg_offset_psipmar;
enetc_write_reg(priv->port_regs + off, val);
}
/* port station register accessors */
static void enetc_write_psicfgr(struct udevice *dev, int port, u32 val)
{
struct enetc_data *data = (struct enetc_data *)dev_get_driver_data(dev);
struct enetc_priv *priv = dev_get_priv(dev);
const u32 off = ENETC_PSICFGR(port, ENETC_PSICFGR_SHIFT_LS) +
data->reg_offset_psicfgr;
enetc_write_reg(priv->port_regs + off, val);
}
/* port register accessors */
static u32 enetc_read_pcapr_mdio(struct udevice *dev)
{
struct enetc_data *data = (struct enetc_data *)dev_get_driver_data(dev);
struct enetc_priv *priv = dev_get_priv(dev);
const u32 off = ENETC_PCAPR0 + data->reg_offset_pcapr;
const u32 reg = enetc_read_reg(priv->port_regs + off);
if (enetc_is_imx95(dev))
return reg & ENETC_PCS_PROT;
else if (enetc_is_ls1028a(dev))
return reg & ENETC_PCAPRO_MDIO;
return 0;
}
static void enetc_write_port(struct enetc_priv *priv, u32 off, u32 val)
{
enetc_write_reg(priv->port_regs + off, val);
}
/* MAC port register accessors */
static u32 enetc_read_mac_port(struct udevice *dev, u32 off)
{
struct enetc_data *data = (struct enetc_data *)dev_get_driver_data(dev);
struct enetc_priv *priv = dev_get_priv(dev);
return enetc_read_reg(priv->port_regs + data->reg_offset_mac + off);
}
static void enetc_write_mac_port(struct udevice *dev, u32 off, u32 val)
{
struct enetc_data *data = (struct enetc_data *)dev_get_driver_data(dev);
struct enetc_priv *priv = dev_get_priv(dev);
enetc_write_reg(priv->port_regs + data->reg_offset_mac + off, val);
}
/* BDR register accessor, see also ENETC_BDR() */
static void enetc_bdr_write(struct enetc_priv *priv, int type, int n,
u32 off, u32 val)
{
enetc_write(priv, ENETC_BDR(type, n, off), val);
}
/*
* sets the MAC address in IERB registers, this setting is persistent and
* carried over to Linux.
*/
static void enetc_set_ierb_primary_mac(struct udevice *dev, int devfn,
const u8 *enetaddr)
{
#ifdef CONFIG_ARCH_LS1028A
/*
* LS1028A is the only part with IERB at this time and there are plans to change
* its structure, keep this LS1028A specific for now
*/
#define IERB_BASE 0x1f0800000ULL
#define IERB_PFMAC(pf, vf, n) (IERB_BASE + 0x8000 + (pf) * 0x100 + (vf) * 8 \
+ (n) * 4)
static int ierb_fn_to_pf[] = {0, 1, 2, -1, -1, -1, 3};
static void enetc_set_ierb_primary_mac(struct udevice *dev, void *blob)
{
static int ierb_fn_to_pf[] = { 0, 1, 2, -1, -1, -1, 3 };
struct pci_child_plat *ppdata = dev_get_parent_plat(dev);
struct eth_pdata *pdata = dev_get_plat(dev);
struct enetc_priv *priv = dev_get_priv(dev);
const u8 *enetaddr = pdata->enetaddr;
u16 lower = *(const u16 *)(enetaddr + 4);
u32 upper = *(const u32 *)enetaddr;
int devfn, offset;
char path[256];
if (ierb_fn_to_pf[devfn] < 0)
if (enetc_is_imx95(dev)) {
/*
* Configure the ENETC primary MAC addresses - Set register
* PMAR0/1 for SI 0 and PSIaPMAR0/1 for SI 1, 2 .. a
* (optionally pre-configured in IERB).
*/
devfn = enetc_dev_id(dev);
if (devfn > 2)
return;
enetc_write(priv, IMX95_ENETC_SIPMAR0, upper);
enetc_write(priv, IMX95_ENETC_SIPMAR1, lower);
snprintf(path, 256, "/soc/pcie@%x/ethernet@%x,%x",
PCI_BUS(dm_pci_get_bdf(dev)), PCI_DEV(ppdata->devfn),
PCI_FUNC(ppdata->devfn));
} else if (enetc_is_ls1028a(dev)) {
/*
* LS1028A is the only part with IERB at this time and
* there are plans to change its structure, keep this
* LS1028A specific for now.
*/
devfn = PCI_FUNC(ppdata->devfn);
if (ierb_fn_to_pf[devfn] < 0)
return;
out_le32(IERB_PFMAC(ierb_fn_to_pf[devfn], 0, 0), upper);
out_le32(IERB_PFMAC(ierb_fn_to_pf[devfn], 0, 1), (u32)lower);
snprintf(path, 256, "/soc/pcie@1f0000000/ethernet@%x,%x",
PCI_DEV(ppdata->devfn), PCI_FUNC(ppdata->devfn));
} else {
return;
}
out_le32(IERB_PFMAC(ierb_fn_to_pf[devfn], 0, 0), upper);
out_le32(IERB_PFMAC(ierb_fn_to_pf[devfn], 0, 1), (u32)lower);
#endif
offset = fdt_path_offset(blob, path);
if (offset >= 0)
fdt_setprop(blob, offset, "mac-address", pdata->enetaddr, 6);
}
/* sets up primary MAC addresses in DT/IERB */
void fdt_fixup_enetc_mac(void *blob)
{
struct pci_child_plat *ppdata;
struct eth_pdata *pdata;
struct udevice *dev;
struct uclass *uc;
char path[256];
int offset;
int devfn;
uclass_get(UCLASS_ETH, &uc);
uclass_foreach_dev(dev, uc) {
@@ -69,18 +285,7 @@ void fdt_fixup_enetc_mac(void *blob)
strcmp(dev->driver->name, ENETC_DRIVER_NAME))
continue;
pdata = dev_get_plat(dev);
ppdata = dev_get_parent_plat(dev);
devfn = PCI_FUNC(ppdata->devfn);
enetc_set_ierb_primary_mac(dev, devfn, pdata->enetaddr);
snprintf(path, 256, "/soc/pcie@1f0000000/ethernet@%x,%x",
PCI_DEV(ppdata->devfn), PCI_FUNC(ppdata->devfn));
offset = fdt_path_offset(blob, path);
if (offset < 0)
continue;
fdt_setprop(blob, offset, "mac-address", pdata->enetaddr, 6);
enetc_set_ierb_primary_mac(dev, blob);
}
}
@@ -101,7 +306,7 @@ static int enetc_bind(struct udevice *dev)
* PCI function # and enetc#N based on interface count
*/
if (ofnode_valid(dev_ofnode(dev)))
sprintf(name, "enetc-%u", PCI_FUNC(pci_get_devfn(dev)));
sprintf(name, "enetc-%u", enetc_dev_id(dev));
else
sprintf(name, "enetc#%u", eth_num_devices++);
device_set_name(dev, name);
@@ -181,10 +386,9 @@ static int enetc_init_sgmii(struct udevice *dev)
/* set up MAC for RGMII */
static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev)
{
struct enetc_priv *priv = dev_get_priv(dev);
u32 old_val, val;
u32 old_val, val, dpx = 0;
old_val = val = enetc_read_port(priv, ENETC_PM_IF_MODE);
old_val = val = enetc_read_mac_port(dev, ENETC_PM_IF_MODE);
/* disable unreliable RGMII in-band signaling and force the MAC into
* the speed negotiated by the PHY.
@@ -202,15 +406,20 @@ static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev)
val |= ENETC_PM_IFM_SSP_10;
}
if (enetc_is_imx95(dev))
dpx = ENETC_PM_IFM_FULL_DPX_IMX;
else if (enetc_is_ls1028a(dev))
dpx = ENETC_PM_IFM_FULL_DPX_LS;
if (phydev->duplex == DUPLEX_FULL)
val |= ENETC_PM_IFM_FULL_DPX;
val |= dpx;
else
val &= ~ENETC_PM_IFM_FULL_DPX;
val &= ~dpx;
if (val == old_val)
return;
enetc_write_port(priv, ENETC_PM_IF_MODE, val);
enetc_write_mac_port(dev, ENETC_PM_IF_MODE, val);
}
/* set up MAC configuration for the given interface type */
@@ -230,9 +439,12 @@ static void enetc_setup_mac_iface(struct udevice *dev,
case PHY_INTERFACE_MODE_USXGMII:
case PHY_INTERFACE_MODE_10GBASER:
/* set ifmode to (US)XGMII */
if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
if_mode &= ~ENETC_PM_IF_IFMODE_MASK;
enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
if_mode = enetc_read_mac_port(dev, ENETC_PM_IF_MODE);
if (enetc_is_imx95(dev))
if_mode &= ~ENETC_PM_IF_IFMODE_MASK_IMX;
else if (enetc_is_ls1028a(dev))
if_mode &= ~ENETC_PM_IF_IFMODE_MASK_LS;
enetc_write_mac_port(dev, ENETC_PM_IF_MODE, if_mode);
break;
};
}
@@ -263,7 +475,7 @@ static void enetc_start_pcs(struct udevice *dev)
struct enetc_priv *priv = dev_get_priv(dev);
/* register internal MDIO for debug purposes */
if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) {
if (enetc_read_pcapr_mdio(dev)) {
priv->imdio.read = enetc_mdio_read;
priv->imdio.write = enetc_mdio_write;
priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE;
@@ -375,6 +587,21 @@ static int enetc_remove(struct udevice *dev)
return 0;
}
static int enetc_imx95_write_hwaddr(struct udevice *dev)
{
struct eth_pdata *plat = dev_get_plat(dev);
struct enetc_priv *priv = dev_get_priv(dev);
u8 *addr = plat->enetaddr;
u16 lower = *(const u16 *)(addr + 4);
u32 upper = *(const u32 *)addr;
enetc_write_port(priv, IMX95_ENETC_PMAR0, upper);
enetc_write_port(priv, IMX95_ENETC_PMAR1, lower);
return 0;
}
/*
* LS1028A is the only part with IERB at this time and there are plans to
* change its structure, keep this LS1028A specific for now.
@@ -413,39 +640,46 @@ static int enetc_ls1028a_write_hwaddr(struct udevice *dev)
static int enetc_write_hwaddr(struct udevice *dev)
{
struct eth_pdata *plat = dev_get_plat(dev);
struct enetc_priv *priv = dev_get_priv(dev);
u8 *addr = plat->enetaddr;
if (IS_ENABLED(CONFIG_ARCH_LS1028A))
if (enetc_is_imx95(dev))
return enetc_imx95_write_hwaddr(dev);
if (enetc_is_ls1028a(dev))
return enetc_ls1028a_write_hwaddr(dev);
u16 lower = *(const u16 *)(addr + 4);
u32 upper = *(const u32 *)addr;
enetc_write_port(priv, ENETC_PSIPMAR0, upper);
enetc_write_port(priv, ENETC_PSIPMAR1, lower);
enetc_write_psipmar(dev, 0, upper);
enetc_write_psipmar(dev, 1, lower);
return 0;
}
/* Configure port parameters (# of rings, frame size, enable port) */
static void enetc_enable_si_port(struct enetc_priv *priv)
static void enetc_enable_si_port(struct udevice *dev)
{
u32 val;
struct enetc_priv *priv = dev_get_priv(dev);
u32 val = ENETC_PM_CC_TXP_IMX | ENETC_PM_CC_TX | ENETC_PM_CC_RX;
/* set Rx/Tx BDR count */
val = ENETC_PSICFGR_SET_TXBDR(ENETC_TX_BDR_CNT);
val |= ENETC_PSICFGR_SET_RXBDR(ENETC_RX_BDR_CNT);
enetc_write_port(priv, ENETC_PSICFGR(0), val);
enetc_write_psicfgr(dev, 0, ENETC_PSICFGR_SET_BDR(ENETC_RX_BDR_CNT,
ENETC_TX_BDR_CNT));
/* set Rx max frame size */
enetc_write_port(priv, ENETC_PM_MAXFRM, ENETC_RX_MAXFRM_SIZE);
enetc_write_mac_port(dev, ENETC_PM_MAXFRM, ENETC_RX_MAXFRM_SIZE);
/* enable MAC port */
enetc_write_port(priv, ENETC_PM_CC, ENETC_PM_CC_RX_TX_EN);
if (enetc_is_ls1028a(dev))
val |= ENETC_PM_CC_TXP_LS | ENETC_PM_CC_PROMIS;
enetc_write_mac_port(dev, ENETC_PM_CC, val);
/* enable port */
enetc_write_port(priv, ENETC_PMR, ENETC_PMR_SI0_EN);
if (enetc_is_imx95(dev))
enetc_write_port(priv, ENETC_POR, 0x0);
enetc_write_pmr(dev, ENETC_PMR_SI0_EN);
/* set SI cache policy */
enetc_write(priv, ENETC_SICAR0,
ENETC_SICAR_RD_CFG | ENETC_SICAR_WR_CFG);
enetc_write(priv, ENETC_SICAR0, ENETC_SICAR_WR_CFG |
(enetc_is_imx95(dev) ?
ENETC_SICAR_RD_CFG_IMX :
ENETC_SICAR_RD_CFG_LS));
/* enable SI */
enetc_write(priv, ENETC_SIMR, ENETC_SIMR_EN);
}
@@ -536,6 +770,8 @@ static void enetc_setup_rx_bdr(struct udevice *dev)
priv->enetc_rxbd[i].w.addr = enetc_rxb_address(dev, i);
/* each RX buffer must be aligned to 64B */
WARN_ON(priv->enetc_rxbd[i].w.addr & (ARCH_DMA_MINALIGN - 1));
enetc_flush_bd(dev, i, false);
}
/* reset producer (ENETC owned) and consumer (SW owned) index */
@@ -556,6 +792,7 @@ static void enetc_setup_rx_bdr(struct udevice *dev)
*/
static int enetc_start(struct udevice *dev)
{
int ret;
struct enetc_priv *priv = dev_get_priv(dev);
/* reset and enable the PCI device */
@@ -563,15 +800,19 @@ static int enetc_start(struct udevice *dev)
dm_pci_clrset_config16(dev, PCI_COMMAND, 0,
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
enetc_enable_si_port(priv);
enetc_enable_si_port(dev);
/* setup Tx/Rx buffer descriptors */
enetc_setup_tx_bdr(dev);
enetc_setup_rx_bdr(dev);
ret = phy_startup(priv->phy);
if (ret)
return ret;
enetc_setup_mac_iface(dev, priv->phy);
return phy_startup(priv->phy);
return 0;
}
/*
@@ -614,6 +855,8 @@ static int enetc_send(struct udevice *dev, void *packet, int length)
enetc_dbg(dev, "TxBD[%d]send: pkt_len=%d, buff @0x%x%08x\n", pi, length,
upper_32_bits((u64)nv_packet), lower_32_bits((u64)nv_packet));
enetc_flush_buffer(dev, packet, length);
/* prepare Tx BD */
memset(&priv->enetc_txbd[pi], 0x0, sizeof(struct enetc_tx_bd));
priv->enetc_txbd[pi].addr =
@@ -621,7 +864,10 @@ static int enetc_send(struct udevice *dev, void *packet, int length)
priv->enetc_txbd[pi].buf_len = cpu_to_le16(length);
priv->enetc_txbd[pi].frm_len = cpu_to_le16(length);
priv->enetc_txbd[pi].flags = cpu_to_le16(ENETC_TXBD_FLAGS_F);
dmb();
enetc_flush_bd(dev, pi, true);
/* send frame: increment producer index */
pi = (pi + 1) % txr->bd_count;
txr->next_prod_idx = pi;
@@ -643,15 +889,15 @@ static int enetc_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct enetc_priv *priv = dev_get_priv(dev);
struct bd_ring *rxr = &priv->rx_bdr;
int tries = ENETC_POLL_TRIES;
int pi = rxr->next_prod_idx;
int ci = rxr->next_cons_idx;
int tries = ENETC_POLL_TRIES;
u32 status;
int len;
u8 rdy;
do {
dmb();
enetc_inval_rxbd(dev);
status = le32_to_cpu(priv->enetc_rxbd[pi].r.lstatus);
/* check if current BD is ready to be consumed */
rdy = ENETC_RXBD_STATUS_R(status);
@@ -663,45 +909,142 @@ static int enetc_recv(struct udevice *dev, int flags, uchar **packetp)
dmb();
len = le16_to_cpu(priv->enetc_rxbd[pi].r.buf_len);
*packetp = (uchar *)enetc_rxb_address(dev, pi);
enetc_inval_buffer(dev, *packetp, len);
enetc_dbg(dev, "RxBD[%d]: len=%d err=%d pkt=0x%x%08x\n", pi, len,
ENETC_RXBD_STATUS_ERRORS(status),
upper_32_bits((u64)*packetp), lower_32_bits((u64)*packetp));
/* BD clean up and advance to next in ring */
memset(&priv->enetc_rxbd[pi], 0, sizeof(union enetc_rx_bd));
priv->enetc_rxbd[pi].w.addr = enetc_rxb_address(dev, pi);
return len;
}
static int enetc_free_pkt(struct udevice *dev, uchar *packet, int length)
{
const int bd_num_in_cl = enetc_is_imx95(dev) ? ENETC_NUM_BD_IN_CL : 1;
struct enetc_priv *priv = dev_get_priv(dev);
struct bd_ring *rxr = &priv->rx_bdr;
int pi = rxr->next_prod_idx;
int ci = rxr->next_cons_idx;
uchar *packet_expected;
int i;
packet_expected = (uchar *)enetc_rxb_address(dev, pi);
if (packet != packet_expected) {
printf("%s: Unexpected packet (expected %p)\n", __func__,
packet_expected);
return -EINVAL;
}
rxr->next_prod_idx = (pi + 1) % rxr->bd_count;
ci = (ci + 1) % rxr->bd_count;
rxr->next_cons_idx = ci;
dmb();
/* free up the slot in the ring for HW */
enetc_write_reg(rxr->cons_idx, ci);
return len;
if ((pi + 1) % bd_num_in_cl == 0) {
/* BD clean up and advance to next in ring */
for (i = 0; i < bd_num_in_cl; i++) {
memset(&priv->enetc_rxbd[pi - i], 0, sizeof(union enetc_rx_bd));
priv->enetc_rxbd[pi - i].w.addr = enetc_rxb_address(dev, pi - i);
}
/* Will flush all bds in one cacheline */
enetc_flush_bd(dev, pi - bd_num_in_cl + 1, false);
/* free up the slot in the ring for HW */
enetc_write_reg(rxr->cons_idx, ci);
}
return 0;
}
static const struct eth_ops enetc_ops = {
#if IS_ENABLED(CONFIG_ARCH_IMX9)
static int enetc_read_rom_hwaddr(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_plat(dev);
unsigned int dev_id = enetc_dev_id(dev);
unsigned char *mac = pdata->enetaddr;
if (dev_id > 2)
return -EINVAL;
imx_get_mac_from_fuse(dev_id, mac);
return !is_valid_ethaddr(mac);
}
static const struct eth_ops enetc_ops_imx = {
.start = enetc_start,
.send = enetc_send,
.recv = enetc_recv,
.stop = enetc_stop,
.free_pkt = enetc_free_pkt,
.write_hwaddr = enetc_write_hwaddr,
.read_rom_hwaddr = enetc_read_rom_hwaddr,
};
U_BOOT_DRIVER(eth_enetc_imx) = {
.name = ENETC_DRIVER_NAME,
.id = UCLASS_ETH,
.bind = enetc_bind,
.probe = enetc_probe,
.remove = enetc_remove,
.ops = &enetc_ops_imx,
.priv_auto = sizeof(struct enetc_priv),
.plat_auto = sizeof(struct eth_pdata),
};
static const struct enetc_data enetc_data_imx = {
.reg_offset_pmr = ENETC_PMR_OFFSET_IMX,
.reg_offset_psipmar = ENETC_PSIPMARn_OFFSET_IMX,
.reg_offset_pcapr = ENETC_PCAPR_OFFSET_IMX,
.reg_offset_psicfgr = ENETC_PSICFGR_OFFSET_IMX,
.reg_offset_mac = ENETC_PM_OFFSET_IMX,
};
static struct pci_device_id enetc_ids_imx[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_ENETC4_ETH),
.driver_data = (ulong)&enetc_data_imx,
},
{}
};
U_BOOT_PCI_DEVICE(eth_enetc_imx, enetc_ids_imx);
#endif
static const struct eth_ops enetc_ops_ls = {
.start = enetc_start,
.send = enetc_send,
.recv = enetc_recv,
.stop = enetc_stop,
.free_pkt = enetc_free_pkt,
.write_hwaddr = enetc_write_hwaddr,
};
U_BOOT_DRIVER(eth_enetc) = {
U_BOOT_DRIVER(eth_enetc_ls) = {
.name = ENETC_DRIVER_NAME,
.id = UCLASS_ETH,
.bind = enetc_bind,
.probe = enetc_probe,
.remove = enetc_remove,
.ops = &enetc_ops,
.ops = &enetc_ops_ls,
.priv_auto = sizeof(struct enetc_priv),
.plat_auto = sizeof(struct eth_pdata),
};
static struct pci_device_id enetc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_ETH) },
static const struct enetc_data enetc_data_ls = {
.reg_offset_pmr = ENETC_PMR_OFFSET_LS,
.reg_offset_psipmar = ENETC_PSIPMARn_OFFSET_LS,
.reg_offset_pcapr = ENETC_PCAPR_OFFSET_LS,
.reg_offset_psicfgr = ENETC_PSICFGR_OFFSET_LS,
.reg_offset_mac = ENETC_PM_OFFSET_LS,
};
static struct pci_device_id enetc_ids_ls[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_ETH),
.driver_data = (ulong)&enetc_data_ls,
},
{}
};
U_BOOT_PCI_DEVICE(eth_enetc, enetc_ids);
U_BOOT_PCI_DEVICE(eth_enetc_ls, enetc_ids_ls);

View File

@@ -12,7 +12,9 @@
/* PCI function IDs */
#define PCI_DEVICE_ID_ENETC_ETH 0xE100
#define PCI_DEVICE_ID_ENETC4_ETH 0xE101
#define PCI_DEVICE_ID_ENETC_MDIO 0xEE01
#define PCI_DEVICE_ID_ENETC4_EMDIO 0xEE00
/* ENETC Ethernet controller registers */
/* Station interface register offsets */
@@ -22,7 +24,8 @@
/* write cache cfg: snoop, no allocate, data & BD coherent */
#define ENETC_SICAR_WR_CFG 0x6767
/* read cache cfg: coherent copy, look up, don't alloc in cache */
#define ENETC_SICAR_RD_CFG 0x27270000
#define ENETC_SICAR_RD_CFG_LS 0x27270000
#define ENETC_SICAR_RD_CFG_IMX 0x2b2b0000
#define ENETC_SIROCT 0x300
#define ENETC_SIRFRM 0x308
#define ENETC_SITOCT 0x320
@@ -57,32 +60,60 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PORT_REGS_OFF 0x10000
/* Port registers */
#define ENETC_PMR_OFFSET_IMX 0x0010
#define ENETC_PMR_OFFSET_LS 0x0000
#define ENETC_PMR 0x0000
#define ENETC_PMR_SI0_EN BIT(16)
#define ENETC_PSIPMMR 0x0018
#define ENETC_PSIPMAR0 0x0100
#define ENETC_PSIPMAR1 0x0104
#define ENETC_PCAPR0 0x0900
#define ENETC_PCAPRO_MDIO BIT(11)
#define ENETC_PSICFGR(n) (0x0940 + (n) * 0x10)
#define ENETC_PSICFGR_SET_TXBDR(val) ((val) & 0xff)
#define ENETC_PSICFGR_SET_RXBDR(val) (((val) & 0xff) << 16)
#define ENETC_PSIPMARn_OFFSET_IMX 0x0000
#define ENETC_PSIPMARn_OFFSET_LS 0x0080
#define ENETC_PSIPMAR0 0x0080
#define ENETC_PSIPMAR1 0x0084
#define ENETC_PCAPR_OFFSET_IMX 0x4008
#define ENETC_PCAPR_OFFSET_LS 0x0900
#define ENETC_PCAPR0 0x0000
#define ENETC_PCAPRO_MDIO BIT(11) /* LS only */
#define ENETC_PCS_PROT GENMASK(15, 0) /* IMX only */
/* ENETC base registers */
#define ENETC_PSICFGR_OFFSET_LS 0x0940
#define ENETC_PSICFGR_SHIFT_LS 0x10
#define ENETC_PSICFGR_OFFSET_IMX 0x2010
#define ENETC_PSICFGR_SHIFT_IMX 0x80
#define ENETC_PSICFGR(n, s) ((n) * (s))
#define ENETC_PSICFGR_SET_BDR(rx, tx) (((rx) << 16) | (tx))
/* MAC configuration */
#define ENETC_PM_CC 0x8008
#define ENETC_PM_OFFSET_IMX 0x5000
#define ENETC_PM_OFFSET_LS 0x8000
#define ENETC_PM_CC 0x0008
#define ENETC_PM_CC_DEFAULT 0x0810
#define ENETC_PM_CC_RX_TX_EN 0x8813
#define ENETC_PM_MAXFRM 0x8014
#define ENETC_PM_CC_TXP_IMX BIT(15)
#define ENETC_PM_CC_TXP_LS BIT(11)
#define ENETC_PM_CC_PROMIS BIT(4)
#define ENETC_PM_CC_TX BIT(1)
#define ENETC_PM_CC_RX BIT(0)
#define ENETC_PM_MAXFRM 0x0014
#define ENETC_RX_MAXFRM_SIZE PKTSIZE_ALIGN
#define ENETC_PM_IMDIO_BASE 0x8030
#define ENETC_PM_IF_MODE 0x8300
#define ENETC_PM_IMDIO_BASE 0x0030
#define ENETC_PM_IF_MODE 0x0300
#define ENETC_PM_IF_MODE_RG BIT(2)
#define ENETC_PM_IF_MODE_AN_ENA BIT(15)
#define ENETC_PM_IFM_SSP_MASK GENMASK(14, 13)
#define ENETC_PM_IFM_SSP_1000 (2 << 13)
#define ENETC_PM_IFM_SSP_100 (0 << 13)
#define ENETC_PM_IFM_SSP_10 (1 << 13)
#define ENETC_PM_IFM_FULL_DPX BIT(12)
#define ENETC_PM_IF_IFMODE_MASK GENMASK(1, 0)
#define ENETC_PM_IFM_FULL_DPX_IMX BIT(6)
#define ENETC_PM_IFM_FULL_DPX_LS BIT(12)
#define ENETC_PM_IF_IFMODE_MASK_IMX GENMASK(2, 0)
#define ENETC_PM_IF_IFMODE_MASK_LS GENMASK(1, 0)
/* i.MX95 specific registers */
#define IMX95_ENETC_SIPMAR0 0x80
#define IMX95_ENETC_SIPMAR1 0x84
/* Port registers */
#define IMX95_ENETC_PMAR0 0x4020
#define IMX95_ENETC_PMAR1 0x4024
#define ENETC_POR 0x4100
/* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */
#define ENETC_BD_CNT CONFIG_SYS_RX_ETH_BUFFER
@@ -163,25 +194,14 @@ struct enetc_priv {
struct phy_device *phy;
};
/* register accessors */
#define enetc_read_reg(x) readl((x))
#define enetc_write_reg(x, val) writel((val), (x))
#define enetc_read(priv, off) enetc_read_reg((priv)->regs_base + (off))
#define enetc_write(priv, off, v) \
enetc_write_reg((priv)->regs_base + (off), v)
/* port register accessors */
#define enetc_port_regs(priv, off) ((priv)->port_regs + (off))
#define enetc_read_port(priv, off) \
enetc_read_reg(enetc_port_regs((priv), (off)))
#define enetc_write_port(priv, off, v) \
enetc_write_reg(enetc_port_regs((priv), (off)), v)
/* BDR register accessors, see ENETC_BDR() */
#define enetc_bdr_read(priv, t, n, off) \
enetc_read(priv, ENETC_BDR(t, n, off))
#define enetc_bdr_write(priv, t, n, off, val) \
enetc_write(priv, ENETC_BDR(t, n, off), val)
struct enetc_data {
/* Register layout offsets */
u16 reg_offset_pmr;
u16 reg_offset_psipmar;
u16 reg_offset_pcapr;
u16 reg_offset_psicfgr;
u16 reg_offset_mac;
};
/* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */
#define ENETC_PCS_PHY_ADDR 0

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* ENETC ethernet controller driver
* Copyright 2019 NXP
* Copyright 2019-2025 NXP
*/
#include <dm.h>
@@ -14,6 +14,16 @@
#include "fsl_enetc.h"
static u32 enetc_read(struct enetc_mdio_priv *priv, u32 off)
{
return readl(priv->regs_base + off);
}
static void enetc_write(struct enetc_mdio_priv *priv, u32 off, u32 val)
{
writel(val, priv->regs_base + off);
}
static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
{
int to = 10000;
@@ -122,7 +132,9 @@ static int enetc_mdio_bind(struct udevice *dev)
static int enetc_mdio_probe(struct udevice *dev)
{
struct pci_child_plat *pplat = dev_get_parent_plat(dev);
struct enetc_mdio_priv *priv = dev_get_priv(dev);
u16 cmd = PCI_COMMAND_MEMORY;
priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->regs_base) {
@@ -132,7 +144,10 @@ static int enetc_mdio_probe(struct udevice *dev)
priv->regs_base += ENETC_MDIO_BASE;
dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
if (pplat->vendor == PCI_VENDOR_ID_PHILIPS) /* i.MX95 */
cmd |= PCI_COMMAND_MASTER;
dm_pci_clrset_config16(dev, PCI_COMMAND, 0, cmd);
return 0;
}
@@ -148,6 +163,7 @@ U_BOOT_DRIVER(enetc_mdio) = {
static struct pci_device_id enetc_mdio_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
{ PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_ENETC4_EMDIO) },
{ }
};

View File

@@ -0,0 +1,346 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
* NXP NETC Blocks Control Driver
*
* Copyright 2024 NXP
*
* This driver is used for pre-initialization of NETC, such as PCS and MII
* protocols, LDID, warm reset, etc. Therefore, all NETC device drivers can
* only be probed after the netc-blk-crtl driver has completed initialization.
* In addition, when the system enters suspend mode, IERB, PRB, and NETCMIX
* will be powered off, except for WOL. Therefore, when the system resumes,
* these blocks need to be reinitialized.
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/iopoll.h>
#include <phy_interface.h>
/* NETCMIX registers */
#define IMX95_CFG_LINK_IO_VAR 0x0
#define IO_VAR_16FF_16G_SERDES 0x1
#define IO_VAR(port, var) (((var) & 0xf) << ((port) << 2))
#define IMX95_CFG_LINK_MII_PROT 0x4
#define CFG_LINK_MII_PORT_0 GENMASK(3, 0)
#define CFG_LINK_MII_PORT_1 GENMASK(7, 4)
#define MII_PROT_MII 0x0
#define MII_PROT_RMII 0x1
#define MII_PROT_RGMII 0x2
#define MII_PROT_SERIAL 0x3
#define MII_PROT(port, prot) (((prot) & 0xf) << ((port) << 2))
#define IMX95_CFG_LINK_PCS_PROT(a) (0x8 + (a) * 4)
#define PCS_PROT_1G_SGMII BIT(0)
#define PCS_PROT_2500M_SGMII BIT(1)
#define PCS_PROT_XFI BIT(3)
#define PCS_PROT_SFI BIT(4)
#define PCS_PROT_10G_SXGMII BIT(6)
/* NETC privileged register block register */
#define PRB_NETCRR 0x100
#define NETCRR_SR BIT(0)
#define NETCRR_LOCK BIT(1)
#define PRB_NETCSR 0x104
#define NETCSR_ERROR BIT(0)
#define NETCSR_STATE BIT(1)
/* NETC integrated endpoint register block register */
#define IERB_EMDIOFAUXR 0x344
#define IERB_T0FAUXR 0x444
#define IERB_EFAUXR(a) (0x3044 + 0x100 * (a))
#define IERB_VFAUXR(a) (0x4004 + 0x40 * (a))
#define FAUXR_LDID GENMASK(3, 0)
/* Platform information */
#define IMX95_ENETC0_BUS_DEVFN 0x0
#define IMX95_ENETC1_BUS_DEVFN 0x40
#define IMX95_ENETC2_BUS_DEVFN 0x80
/* Flags for different platforms */
#define NETC_HAS_NETCMIX BIT(0)
struct netc_blk_ctrl {
void __iomem *prb;
void __iomem *ierb;
void __iomem *netcmix;
};
static void netc_reg_write(void __iomem *base, u32 offset, u32 val)
{
writel(val, base + offset);
}
static u32 netc_reg_read(void __iomem *base, u32 offset)
{
return readl(base + offset);
}
static int netc_of_pci_get_bus_devfn(ofnode node)
{
u32 reg[5];
int error;
error = ofnode_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg));
if (error)
return error;
return (reg[0] >> 8) & 0xffff;
}
static int netc_get_link_mii_protocol(phy_interface_t interface)
{
switch (interface) {
case PHY_INTERFACE_MODE_MII:
return MII_PROT_MII;
case PHY_INTERFACE_MODE_RMII:
return MII_PROT_RMII;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
return MII_PROT_RGMII;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_2500BASEX:
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_USXGMII:
return MII_PROT_SERIAL;
default:
return -EINVAL;
}
}
static int imx95_netcmix_init(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
ofnode child, gchild;
phy_interface_t interface;
int bus_devfn, mii_proto;
u32 val;
/* Default setting of MII protocol */
val = MII_PROT(0, MII_PROT_RGMII) | MII_PROT(1, MII_PROT_RGMII) |
MII_PROT(2, MII_PROT_SERIAL);
/* Update the link MII protocol through parsing phy-mode */
dev_for_each_subnode(child, dev) {
if (!ofnode_is_enabled(child))
continue;
ofnode_for_each_subnode(gchild, child) {
if (!ofnode_is_enabled(gchild))
continue;
if (!ofnode_device_is_compatible(gchild, "pci1131,e101"))
continue;
bus_devfn = netc_of_pci_get_bus_devfn(gchild);
if (bus_devfn < 0)
return -EINVAL;
if (bus_devfn == IMX95_ENETC2_BUS_DEVFN)
continue;
interface = ofnode_read_phy_mode(gchild);
if (interface == -1)
continue;
mii_proto = netc_get_link_mii_protocol(interface);
if (mii_proto < 0)
return -EINVAL;
switch (bus_devfn) {
case IMX95_ENETC0_BUS_DEVFN:
val &= ~CFG_LINK_MII_PORT_0;
val |= FIELD_PREP(CFG_LINK_MII_PORT_0, mii_proto);
break;
case IMX95_ENETC1_BUS_DEVFN:
val &= ~CFG_LINK_MII_PORT_1;
val |= FIELD_PREP(CFG_LINK_MII_PORT_1, mii_proto);
break;
default:
return -EINVAL;
}
}
}
/* Configure Link I/O variant */
netc_reg_write(priv->netcmix, IMX95_CFG_LINK_IO_VAR,
IO_VAR(2, IO_VAR_16FF_16G_SERDES));
/* Configure Link 2 PCS protocol */
netc_reg_write(priv->netcmix, IMX95_CFG_LINK_PCS_PROT(2),
PCS_PROT_10G_SXGMII);
netc_reg_write(priv->netcmix, IMX95_CFG_LINK_MII_PROT, val);
return 0;
}
static bool netc_ierb_is_locked(struct netc_blk_ctrl *priv)
{
return !!(netc_reg_read(priv->prb, PRB_NETCRR) & NETCRR_LOCK);
}
static int netc_lock_ierb(struct netc_blk_ctrl *priv)
{
u32 val;
netc_reg_write(priv->prb, PRB_NETCRR, NETCRR_LOCK);
return readl_poll_timeout(priv->prb + PRB_NETCSR, val,
!(val & NETCSR_STATE), 2000);
}
static int netc_unlock_ierb_with_warm_reset(struct netc_blk_ctrl *priv)
{
u32 val;
netc_reg_write(priv->prb, PRB_NETCRR, 0);
return readl_poll_timeout(priv->prb + PRB_NETCRR, val,
!(val & NETCRR_LOCK), 100000);
}
static int imx95_ierb_init(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
/* EMDIO : No MSI-X intterupt */
netc_reg_write(priv->ierb, IERB_EMDIOFAUXR, 0);
/* ENETC0 PF */
netc_reg_write(priv->ierb, IERB_EFAUXR(0), 0);
/* ENETC0 VF0 */
netc_reg_write(priv->ierb, IERB_VFAUXR(0), 1);
/* ENETC0 VF1 */
netc_reg_write(priv->ierb, IERB_VFAUXR(1), 2);
/* ENETC1 PF */
netc_reg_write(priv->ierb, IERB_EFAUXR(1), 3);
/* ENETC1 VF0 */
netc_reg_write(priv->ierb, IERB_VFAUXR(2), 5);
/* ENETC1 VF1 */
netc_reg_write(priv->ierb, IERB_VFAUXR(3), 6);
/* ENETC2 PF */
netc_reg_write(priv->ierb, IERB_EFAUXR(2), 4);
/* ENETC2 VF0 */
netc_reg_write(priv->ierb, IERB_VFAUXR(4), 5);
/* ENETC2 VF1 */
netc_reg_write(priv->ierb, IERB_VFAUXR(5), 6);
/* NETC TIMER */
netc_reg_write(priv->ierb, IERB_T0FAUXR, 7);
return 0;
}
static int netc_ierb_init(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
int err;
if (netc_ierb_is_locked(priv)) {
err = netc_unlock_ierb_with_warm_reset(priv);
if (err) {
dev_err(dev, "Unlock IERB failed.\n");
return err;
}
}
err = imx95_ierb_init(dev);
if (err)
return err;
err = netc_lock_ierb(priv);
if (err) {
dev_err(dev, "Lock IERB failed.\n");
return err;
}
return 0;
}
static int netc_prb_check_error(struct netc_blk_ctrl *priv)
{
if (netc_reg_read(priv->prb, PRB_NETCSR) & NETCSR_ERROR)
return -1;
return 0;
}
static const struct udevice_id netc_blk_ctrl_match[] = {
{ .compatible = "nxp,imx95-netc-blk-ctrl" },
{},
};
static int netc_blk_ctrl_probe(struct udevice *dev)
{
struct netc_blk_ctrl *priv = dev_get_priv(dev);
struct clk *ipg_clk;
fdt_addr_t regs;
int err;
ipg_clk = devm_clk_get_optional(dev, "ipg");
if (IS_ERR(ipg_clk)) {
dev_err(dev, "Set ipg clock failed\n");
return PTR_ERR(ipg_clk);
}
err = clk_prepare_enable(ipg_clk);
if (err) {
dev_err(dev, "Enable ipg clock failed\n");
return PTR_ERR(ipg_clk);
}
regs = dev_read_addr_name(dev, "ierb");
if (regs == FDT_ADDR_T_NONE) {
dev_err(dev, "Missing IERB resource\n");
return -EINVAL;
}
priv->ierb = (void __iomem *)regs;
regs = dev_read_addr_name(dev, "prb");
if (regs == FDT_ADDR_T_NONE) {
dev_err(dev, "Missing PRB resource\n");
return -EINVAL;
}
priv->prb = (void __iomem *)regs;
regs = dev_read_addr_name(dev, "netcmix");
if (regs == FDT_ADDR_T_NONE) {
dev_err(dev, "Missing NETCMIX resource\n");
return -EINVAL;
}
priv->netcmix = (void __iomem *)regs;
err = imx95_netcmix_init(dev);
if (err) {
dev_err(dev, "Initializing NETCMIX failed\n");
return err;
}
err = netc_ierb_init(dev);
if (err) {
dev_err(dev, "Initializing IERB failed\n");
return err;
}
if (netc_prb_check_error(priv) < 0)
dev_warn(dev, "The current IERB configuration is invalid\n");
return 0;
}
U_BOOT_DRIVER(netc_blk_ctrl_drv) = {
.name = "netc_blk_ctrl",
.id = UCLASS_SIMPLE_BUS,
.of_match = netc_blk_ctrl_match,
.probe = netc_blk_ctrl_probe,
.priv_auto = sizeof(struct netc_blk_ctrl),
.flags = DM_FLAG_PRE_RELOC,
};

View File

@@ -219,7 +219,7 @@ int imx_pinctrl_probe(struct udevice *dev,
if (info->flags & IMX8_USE_SCU)
return 0;
addr = ofnode_get_addr_size_index(dev_ofnode(dev), 0, &size);
addr = ofnode_get_addr_size_index(node, 0, &size);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
@@ -228,7 +228,7 @@ int imx_pinctrl_probe(struct udevice *dev,
return -ENOMEM;
priv->info = info;
info->mux_mask = ofnode_read_u32(node, "fsl,mux_mask", 0);
info->mux_mask = ofnode_read_u32_default(node, "fsl,mux_mask", 0);
/*
* Refer to linux documentation for details:
* Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt