diff --git a/boards/nxp/imx95_evk/Kconfig.defconfig b/boards/nxp/imx95_evk/Kconfig.defconfig new file mode 100644 index 000000000000..9635d0008939 --- /dev/null +++ b/boards/nxp/imx95_evk/Kconfig.defconfig @@ -0,0 +1,66 @@ +# Copyright 2024-2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_MIMX9596_A55 + +if ETH_NXP_IMX_NETC + +config GIC_V3_ITS + default y + +endif # ETH_NXP_IMX_NETC + +# GIC ITS depends on kernel heap which init priority is 30, so set +# GIC to be 31, mailbox and SCMI will be initialized by the order +# according to dts dependency although they use the same init priority. +config INTC_INIT_PRIORITY + default 31 + +config MBOX_INIT_PRIORITY + default 31 + +config ARM_SCMI_SHMEM_INIT_PRIORITY + default 31 + +config ARM_SCMI_TRANSPORT_INIT_PRIORITY + default 31 + +config CLOCK_CONTROL_INIT_PRIORITY + default 31 + +# Enlarge default networking stack +if NETWORKING + +config NET_L2_ETHERNET + default y + +config NET_TX_STACK_SIZE + default 8192 + +config NET_RX_STACK_SIZE + default 8192 + +if NET_TCP + +config NET_TCP_WORKQ_STACK_SIZE + default 8192 + +endif # NET_TCP + +if NET_MGMT_EVENT + +config NET_MGMT_EVENT_STACK_SIZE + default 8192 + +endif # NET_MGMT_EVENT + +if NET_SOCKETS_SERVICE + +config NET_SOCKETS_SERVICE_STACK_SIZE + default 8192 + +endif # NET_SOCKETS_SERVICE + +endif # NETWORKING + +endif # SOC_MIMX9596_A55 diff --git a/boards/nxp/imx95_evk/board.c b/boards/nxp/imx95_evk/board.c index 477bcc38f6ae..2b43501bfec0 100644 --- a/boards/nxp/imx95_evk/board.c +++ b/boards/nxp/imx95_evk/board.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * SPDX-License-Identifier: Apache-2.0 */ @@ -10,21 +10,6 @@ static int board_init(void) { -#if defined(CONFIG_ETH_NXP_IMX_NETC) && (DT_CHILD_NUM_STATUS_OKAY(DT_NODELABEL(netc)) != 0) - /* Port 0 to 2 protocol configure: RGMII, RGMII, XGMII */ - BLK_CTRL_NETCMIX->CFG_LINK_MII_PROT = 0x00000522; - BLK_CTRL_NETCMIX->CFG_LINK_PCS_PROT_2 = 0x00000040; - - /* Unlock the IERB. It will warm reset whole NETC. */ - NETC_PRIV->NETCRR &= ~NETC_PRIV_NETCRR_LOCK_MASK; - while ((NETC_PRIV->NETCRR & NETC_PRIV_NETCRR_LOCK_MASK) != 0U) { - } - - /* Lock the IERB. */ - NETC_PRIV->NETCRR |= NETC_PRIV_NETCRR_LOCK_MASK; - while ((NETC_PRIV->NETCSR & NETC_PRIV_NETCSR_STATE_MASK) != 0U) { - } -#endif return 0; } diff --git a/boards/nxp/imx95_evk/doc/index.rst b/boards/nxp/imx95_evk/doc/index.rst index 4b52b0563c8e..aba0d3f51209 100644 --- a/boards/nxp/imx95_evk/doc/index.rst +++ b/boards/nxp/imx95_evk/doc/index.rst @@ -106,9 +106,10 @@ Ethernet -------- NETC driver supports to manage the Physical Station Interface (PSI). -The first ENET1 port could be enabled for M7 by west build option -``-DEXTRA_DTC_OVERLAY_FILE=enetc_psi0.overlay``. +The first ENET1 port could be enabled on M7 DDR and A55 platforms. +For A55 Core, NETC depends on GIC ITS, so need to make sure to allocate heap memory to +be larger than 851968 byes by setting CONFIG_HEAP_MEM_POOL_SIZE. Programming and Debugging (A55) ******************************* diff --git a/boards/nxp/imx95_evk/dts/enetc_psi0.overlay b/boards/nxp/imx95_evk/dts/enetc_psi0.overlay deleted file mode 100644 index a14003810f06..000000000000 --- a/boards/nxp/imx95_evk/dts/enetc_psi0.overlay +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2025 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -&emdio { - status = "okay"; - - phy0: phy@1 { - status = "okay"; - }; -}; - -&enetc_psi0 { - status = "okay"; -}; - -&enetc_ptp_clock { - status = "okay"; -}; diff --git a/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55.dts b/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55.dts index d4aff0f100de..51b3d7f704eb 100644 --- a/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55.dts +++ b/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55.dts @@ -43,10 +43,35 @@ }; dram: memory@d0000000 { - reg = <0xd0000000 DT_SIZE_M(1)>; + reg = <0xd0000000 DT_SIZE_M(10)>; }; }; +&emdio { + pinctrl-0 = <&emdio_default>; + pinctrl-names = "default"; + status = "okay"; + + phy0: phy@1 { + compatible = "realtek,rtl8211f"; + reg = <0x1>; + status = "okay"; + }; +}; + +&enetc_psi0 { + local-mac-address = [00 00 00 01 02 00]; + pinctrl-0 = <ð0_default>; + pinctrl-names = "default"; + phy-handle = <&phy0>; + phy-connection-type = "rgmii"; + status = "okay"; +}; + +&enetc_ptp_clock { + status = "okay"; +}; + &lpi2c5 { pinctrl-0 = <&lpi2c5_default>; pinctrl-names = "default"; diff --git a/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55_defconfig b/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55_defconfig index 23e5dd52c5a4..88a5148a54ed 100644 --- a/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55_defconfig +++ b/boards/nxp/imx95_evk/imx95_evk_mimx9596_a55_defconfig @@ -31,5 +31,3 @@ CONFIG_CLOCK_CONTROL=y CONFIG_MBOX=y CONFIG_ARM_SCMI=y -CONFIG_INTC_INIT_PRIORITY=2 -CONFIG_MBOX_INIT_PRIORITY=3 diff --git a/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts b/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts index 8b661db7a8af..6c5167634d25 100644 --- a/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts +++ b/boards/nxp/imx95_evk/imx95_evk_mimx9596_m7.dts @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,12 +26,12 @@ &emdio { pinctrl-0 = <&emdio_default>; pinctrl-names = "default"; - status = "disabled"; + status = "okay"; phy0: phy@1 { compatible = "realtek,rtl8211f"; reg = <0x1>; - status = "disabled"; + status = "okay"; }; }; @@ -41,7 +41,11 @@ pinctrl-names = "default"; phy-handle = <&phy0>; phy-connection-type = "rgmii"; - status = "disabled"; + status = "okay"; +}; + +&enetc_ptp_clock { + status = "okay"; }; &flexspi { diff --git a/drivers/ethernet/nxp_imx_netc/CMakeLists.txt b/drivers/ethernet/nxp_imx_netc/CMakeLists.txt index 91fbf4d4f1ee..28631f49ba31 100644 --- a/drivers/ethernet/nxp_imx_netc/CMakeLists.txt +++ b/drivers/ethernet/nxp_imx_netc/CMakeLists.txt @@ -4,6 +4,7 @@ if(CONFIG_ETH_NXP_IMX_NETC) zephyr_library_sources(eth_nxp_imx_netc.c) zephyr_library_sources(eth_nxp_imx_netc_psi.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_NXP_IMX_NETC_BLK_CTRL_ENABLED eth_nxp_imx_netc_blk.c) endif() zephyr_library_sources_ifdef(CONFIG_DSA_NXP_IMX_NETC dsa_nxp_imx_netc.c) diff --git a/drivers/ethernet/nxp_imx_netc/Kconfig b/drivers/ethernet/nxp_imx_netc/Kconfig index 5c6af4f5c0cb..21636cb438ac 100644 --- a/drivers/ethernet/nxp_imx_netc/Kconfig +++ b/drivers/ethernet/nxp_imx_netc/Kconfig @@ -12,11 +12,25 @@ menuconfig ETH_NXP_IMX_NETC if ETH_NXP_IMX_NETC +DT_GIC_ITS_COMPAT := arm,gic-v3-its +DT_NETC_PATH := $(dt_nodelabel_path,netc) +DT_NETC_INT_PARENT_PATH := $(dt_node_ph_prop_path,$(DT_NETC_PATH),msi-parent) +DT_NETC_INT_IS_GIC := $(dt_node_has_compat,$(DT_NETC_INT_PARENT_PATH),$(DT_GIC_ITS_COMPAT)) + +config ETH_NXP_IMX_NETC_MSI_GIC + bool + default y if ($(DT_NETC_INT_IS_GIC) && DT_HAS_ARM_GIC_V3_ITS_ENABLED) + depends on GIC_V3_ITS + help + Use GIC ITS controller as MSI module for NXP NETC + +if !ETH_NXP_IMX_NETC_MSI_GIC config ETH_NXP_IMX_MSGINTR int "Message Interrupt module select" default 1 help Message Interrupt module select. +endif config ETH_NXP_IMX_RX_THREAD_PRIO int "RX thread priority" diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c index 32762582dce7..518461e8fdb5 100644 --- a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_imx_netc #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL #include @@ -21,6 +22,9 @@ LOG_MODULE_REGISTER(nxp_imx_eth); #include #include #include +#ifdef CONFIG_GIC_V3_ITS +#include +#endif #include "../eth.h" #include "eth_nxp_imx_netc_priv.h" @@ -29,6 +33,17 @@ LOG_MODULE_REGISTER(nxp_imx_eth); #define NETC_HAS_NO_SWITCH_TAG_SUPPORT 1 #endif +#define DEV_CFG(_dev) ((const struct eth_nxp_imx_netc_ecam_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct eth_nxp_imx_netc_ecam_data *)(_dev)->data) + +struct eth_nxp_imx_netc_ecam_config { + DEVICE_MMIO_NAMED_ROM(base); +}; + +struct eth_nxp_imx_netc_ecam_data { + DEVICE_MMIO_NAMED_RAM(base); +}; + const struct device *netc_dev_list[NETC_DRV_MAX_INST_SUPPORT]; #ifdef CONFIG_PTP_CLOCK_NXP_NETC @@ -173,6 +188,28 @@ static void netc_eth_rx_thread(void *arg1, void *unused1, void *unused2) } } +#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC + +static void netc_tx_isr_handler(const void *arg) +{ + const struct device *dev = (const struct device *)arg; + struct netc_eth_data *data = dev->data; + + EP_CleanTxIntrFlags(&data->handle, 1, 0); + data->tx_done = true; +} + +static void netc_rx_isr_handler(const void *arg) +{ + const struct device *dev = (const struct device *)arg; + struct netc_eth_data *data = dev->data; + + EP_CleanRxIntrFlags(&data->handle, 1); + k_sem_give(&data->rx_sem); +} + +#else /* CONFIG_ETH_NXP_IMX_NETC_MSI_GIC */ + static void msgintr_isr(void) { uint32_t irqs = NETC_MSGINTR->MSI[NETC_MSGINTR_CHANNEL].MSIR; @@ -203,6 +240,8 @@ static void msgintr_isr(void) SDK_ISR_EXIT_BARRIER; } +#endif + int netc_eth_init_common(const struct device *dev) { const struct netc_eth_config *config = dev->config; @@ -222,6 +261,51 @@ int netc_eth_init_common(const struct device *dev) #endif /* MSIX entry configuration */ +#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC + int ret; + + if (config->msi_dev == NULL) { + LOG_ERR("MSI device is not configured"); + return -ENODEV; + } + ret = its_setup_deviceid(config->msi_dev, config->msi_device_id, NETC_MSIX_ENTRY_NUM); + if (ret != 0) { + LOG_ERR("Failed to setup device ID for MSI: %d", ret); + return ret; + } + data->tx_intid = its_alloc_intid(config->msi_dev); + data->rx_intid = its_alloc_intid(config->msi_dev); + + msg_addr = its_get_msi_addr(config->msi_dev); + msix_entry[NETC_TX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit; + msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgAddr = msg_addr; + msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgData = NETC_TX_MSIX_ENTRY_IDX; + ret = its_map_intid(config->msi_dev, config->msi_device_id, NETC_TX_MSIX_ENTRY_IDX, + data->tx_intid); + if (ret != 0) { + LOG_ERR("Failed to map TX MSI interrupt: %d", ret); + return ret; + } + + msix_entry[NETC_RX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit; + msix_entry[NETC_RX_MSIX_ENTRY_IDX].msgAddr = msg_addr; + msix_entry[NETC_RX_MSIX_ENTRY_IDX].msgData = NETC_RX_MSIX_ENTRY_IDX; + ret = its_map_intid(config->msi_dev, config->msi_device_id, NETC_RX_MSIX_ENTRY_IDX, + data->rx_intid); + if (ret != 0) { + LOG_ERR("Failed to map RX MSI interrupt: %d", ret); + return ret; + } + + if (!irq_is_enabled(data->tx_intid)) { + irq_connect_dynamic(data->tx_intid, 0, netc_tx_isr_handler, dev, 0); + irq_enable(data->tx_intid); + } + if (!irq_is_enabled(data->rx_intid)) { + irq_connect_dynamic(data->rx_intid, 0, netc_rx_isr_handler, dev, 0); + irq_enable(data->rx_intid); + } +#else msg_addr = MSGINTR_GetIntrSelectAddr(NETC_MSGINTR, NETC_MSGINTR_CHANNEL); msix_entry[NETC_TX_MSIX_ENTRY_IDX].control = kNETC_MsixIntrMaskBit; msix_entry[NETC_TX_MSIX_ENTRY_IDX].msgAddr = msg_addr; @@ -235,6 +319,7 @@ int netc_eth_init_common(const struct device *dev) IRQ_CONNECT(NETC_MSGINTR_IRQ, 0, msgintr_isr, 0, 0); irq_enable(NETC_MSGINTR_IRQ); } +#endif /* Endpoint configuration. */ EP_GetDefaultConfig(&ep_config); @@ -456,3 +541,22 @@ int netc_eth_set_config(const struct device *dev, enum ethernet_config_type type return ret; } + +static int eth_nxp_imx_netc_ecam_init(const struct device *dev) +{ + DEVICE_MMIO_NAMED_MAP(dev, base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + + return 0; +} + +#define ETH_NXP_IMX_NETC_ECAM_INIT(inst) \ + static struct eth_nxp_imx_netc_ecam_data eth_nxp_imx_netc_ecam_data_##inst; \ + static const struct eth_nxp_imx_netc_ecam_config eth_nxp_imx_netc_ecam_config_##inst = { \ + DEVICE_MMIO_NAMED_ROM_INIT(base, DT_DRV_INST(inst)), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, eth_nxp_imx_netc_ecam_init, NULL, \ + ð_nxp_imx_netc_ecam_data_##inst, \ + ð_nxp_imx_netc_ecam_config_##inst, POST_KERNEL, \ + CONFIG_ETH_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(ETH_NXP_IMX_NETC_ECAM_INIT) diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_blk.c b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_blk.c new file mode 100644 index 000000000000..5e6aaa9e8797 --- /dev/null +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_blk.c @@ -0,0 +1,210 @@ +/* NXP NETC Block Controller Driver + * + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT nxp_imx_netc_blk_ctrl + +#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL +#include +LOG_MODULE_REGISTER(nxp_imx_netc_blk); + +#include +#include + +/* NETC integrated endpoint register block register */ +#define IERB_EMDIOFAUXR 0x344 +#define IERB_T0FAUXR 0x444 +#define IERB_ETBCR(a) (0x300c + 0x100 * (a)) +#define IERB_EFAUXR(a) (0x3044 + 0x100 * (a)) +#define IERB_VFAUXR(a) (0x4004 + 0x40 * (a)) + +/* 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) + +/* NETCMIX CFG Link register */ +#define CFG_LINK_MII_PROT 0x10 +enum { + MII, + RMII, + RGMII, + reserved, + SGMII, + XGMII, +}; +#define CFG_LINK_MII_PROT_0_SHIFT 0 +#define CFG_LINK_MII_PROT_1_SHIFT 4 +#define CFG_LINK_MII_PROT_2_SHIFT 8 +#define MII_PROT_N(prot, n) ((prot) << CFG_LINK_MII_PROT_##n##_SHIFT) + +/* NETCMIX PCS protocol register */ +#define CFG_LINK_PCS_PROT_0 0x14 +#define CFG_LINK_PCS_PROT_1 0x18 +#define CFG_LINK_PCS_PROT_2 0x1c +/* PCS Protocols */ +#define CFG_LINK_PCS_PROT_1G_SGMII BIT(0) +#define CFG_LINK_PCS_PROT_2500M_SGMII BIT(1) +#define CFG_LINK_PCS_PROT_XFI BIT(3) +#define CFG_LINK_PCS_PROT_10G_SXGMII BIT(6) + +struct eth_nxp_imx_netc_blk_config { + DEVICE_MMIO_NAMED_ROM(ierb); + DEVICE_MMIO_NAMED_ROM(prb); + DEVICE_MMIO_NAMED_ROM(netcmix); +}; + +struct eth_nxp_imx_netc_blk_data { + DEVICE_MMIO_NAMED_RAM(ierb); + DEVICE_MMIO_NAMED_RAM(prb); + DEVICE_MMIO_NAMED_RAM(netcmix); +}; + +#define DEV_CFG(_dev) ((const struct eth_nxp_imx_netc_blk_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct eth_nxp_imx_netc_blk_data *)(_dev)->data) + +#define read_and_poll_timeout(reg, val, cond) \ + ({ \ + unsigned int count = 1000000; /* 1s! */ \ + while (1) { \ + (val) = sys_read32(reg); \ + if (cond) { \ + break; \ + } \ + count--; \ + if (!count) { \ + break; \ + } \ + k_usleep(1); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ + }) + +static bool ierb_is_locked(const struct device *dev) +{ + uintptr_t base = DEVICE_MMIO_NAMED_GET(dev, prb); + + return sys_read32(base + PRB_NETCRR) & NETCRR_LOCK; +} + +static int ierb_lock(const struct device *dev) +{ + uintptr_t base = DEVICE_MMIO_NAMED_GET(dev, prb); + uint32_t val; + + sys_write32(NETCRR_LOCK, base + PRB_NETCRR); + + return read_and_poll_timeout(base + PRB_NETCSR, val, !(val & NETCSR_STATE)); +} + +static int ierb_unlock(const struct device *dev) +{ + uintptr_t base = DEVICE_MMIO_NAMED_GET(dev, prb); + uint32_t val; + + sys_write32(1, base + PRB_NETCRR); + + return read_and_poll_timeout(base + PRB_NETCRR, val, !(val & NETCRR_LOCK)); +} + +#ifdef CONFIG_SOC_MIMX9596 +/* Set LDID */ +static int ierb_init(const struct device *dev) +{ + uintptr_t base = DEVICE_MMIO_NAMED_GET(dev, ierb); + + /* EMDIO : No MSI-X interrupt */ + sys_write32(0, base + IERB_EMDIOFAUXR); + /* ENETC0 PF */ + sys_write32(0, base + IERB_EFAUXR(0)); + /* ENETC0 VF0 */ + sys_write32(1, base + IERB_VFAUXR(0)); + /* ENETC0 VF1 */ + sys_write32(2, base + IERB_VFAUXR(1)); + /* ENETC1 PF */ + sys_write32(3, base + IERB_EFAUXR(1)); + /* ENETC1 VF0 : Disabled on 19x19 board dts */ + sys_write32(5, base + IERB_VFAUXR(2)); + /* ENETC1 VF1 : Disabled on 19x19 board dts */ + sys_write32(6, base + IERB_VFAUXR(3)); + /* ENETC2 PF */ + sys_write32(4, base + IERB_EFAUXR(2)); + /* ENETC2 VF0 : Disabled on 15x15 board dts */ + sys_write32(5, base + IERB_VFAUXR(4)); + /* ENETC2 VF1 : Disabled on 15x15 board dts */ + sys_write32(6, base + IERB_VFAUXR(5)); + /* NETC TIMER */ + sys_write32(7, base + IERB_T0FAUXR); + + return 0; +} + +static int netcmix_init(const struct device *dev) +{ + uintptr_t base = DEVICE_MMIO_NAMED_GET(dev, netcmix); + uint32_t reg_val; + + /* ToDo: configure PSC protocol and MII protocol according to PHY mode */ + reg_val = MII_PROT_N(RGMII, 0) | MII_PROT_N(RGMII, 1) | MII_PROT_N(XGMII, 2); + sys_write32(reg_val, base + CFG_LINK_MII_PROT); + sys_write32(CFG_LINK_PCS_PROT_10G_SXGMII, base + CFG_LINK_PCS_PROT_2); + + return 0; +} +#endif + +static int eth_nxp_imx_netc_blk_init(const struct device *dev) +{ + int ret; + + DEVICE_MMIO_NAMED_MAP(dev, ierb, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + DEVICE_MMIO_NAMED_MAP(dev, prb, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + DEVICE_MMIO_NAMED_MAP(dev, netcmix, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + + if (ierb_is_locked(dev)) { + ret = ierb_unlock(dev); + if (ret) { + LOG_ERR("Unlock IERB failed."); + return ret; + } + } + + if (ierb_init(dev) != 0) { + LOG_ERR("Failed to initialize IERB"); + return -EIO; + } + + ret = ierb_lock(dev); + if (ret) { + LOG_ERR("Lock IERB failed."); + return ret; + } + + ret = netcmix_init(dev); + if (ret) { + LOG_ERR("NETCMIX init failed."); + return ret; + } + + return 0; +} + +#define ETH_NXP_IMX_NETC_BLK_INIT(inst) \ + static struct eth_nxp_imx_netc_blk_data eth_nxp_imx_netc_blk_data_##inst; \ + static const struct eth_nxp_imx_netc_blk_config eth_nxp_imx_netc_blk_config_##inst = { \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(ierb, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(prb, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(netcmix, DT_DRV_INST(inst)), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, eth_nxp_imx_netc_blk_init, NULL, \ + ð_nxp_imx_netc_blk_data_##inst, \ + ð_nxp_imx_netc_blk_config_##inst, POST_KERNEL, \ + CONFIG_MDIO_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(ETH_NXP_IMX_NETC_BLK_INIT) diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h index 157f7e61bae4..008a95ac3e4c 100644 --- a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_priv.h @@ -9,7 +9,9 @@ #include "nxp_imx_netc.h" #include "fsl_netc_endpoint.h" +#ifndef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC #include "fsl_msgintr.h" +#endif /* Buffer and descriptor alignment */ #define NETC_BUFF_ALIGN 64 @@ -33,6 +35,7 @@ #define NETC_MSGINTR_IRQ DT_IRQN_BY_IDX(DT_NODELABEL(netc), 0) #endif +#ifndef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC #if (CONFIG_ETH_NXP_IMX_MSGINTR == 1) #define NETC_MSGINTR MSGINTR1 #ifndef NETC_MSGINTR_IRQ @@ -46,6 +49,7 @@ #else #error "Current CONFIG_ETH_NXP_IMX_MSGINTR not support" #endif +#endif /* CONFIG_ETH_NXP_IMX_NETC_MSI_GIC */ /* Timeout for various operations */ #define NETC_TIMEOUT K_MSEC(20) @@ -82,6 +86,7 @@ } struct netc_eth_config { + DEVICE_MMIO_NAMED_ROM(base); uint16_t si_idx; const struct device *phy_dev; netc_hw_mii_mode_t phy_mode; @@ -90,8 +95,13 @@ struct netc_eth_config { void (*bdr_init)(netc_bdr_config_t *bdr_config, netc_rx_bdr_config_t *rx_bdr_config, netc_tx_bdr_config_t *tx_bdr_config); const struct pinctrl_dev_config *pincfg; +#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC + const struct device *msi_dev; + uint8_t msi_device_id; /* MSI device ID */ +#else uint8_t tx_intr_msg_data; uint8_t rx_intr_msg_data; +#endif #ifdef CONFIG_PTP_CLOCK_NXP_NETC const struct device *ptp_clock; #endif @@ -100,6 +110,7 @@ struct netc_eth_config { typedef uint8_t rx_buffer_t[NETC_RX_RING_BUF_SIZE_ALIGN]; struct netc_eth_data { + DEVICE_MMIO_NAMED_RAM(base); ep_handle_t handle; struct net_if *iface; uint8_t mac_addr[6]; @@ -113,6 +124,10 @@ struct netc_eth_data { K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_NXP_IMX_RX_THREAD_STACK_SIZE); uint8_t *rx_frame; +#ifdef CONFIG_ETH_NXP_IMX_NETC_MSI_GIC + unsigned int tx_intid; + unsigned int rx_intid; +#endif }; int netc_eth_init_common(const struct device *dev); diff --git a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c index 3dc10ae87246..8c79c59a56db 100644 --- a/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c +++ b/drivers/ethernet/nxp_imx_netc/eth_nxp_imx_netc_psi.c @@ -22,6 +22,9 @@ LOG_MODULE_REGISTER(nxp_imx_eth_psi); #include "../eth.h" #include "eth_nxp_imx_netc_priv.h" +#define DEV_CFG(_dev) ((const struct netc_eth_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct netc_eth_data *)(_dev)->data) + static void netc_eth_phylink_callback(const struct device *pdev, struct phy_link_state *state, void *user_data) { @@ -104,6 +107,8 @@ static int netc_eth_init(const struct device *dev) const struct netc_eth_config *cfg = dev->config; int err; + DEVICE_MMIO_NAMED_MAP(dev, base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + if (cfg->pseudo_mac) { goto init_common; } @@ -192,6 +197,7 @@ static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_ifac .rx_frame = eth##n##_rx_frame, \ }; \ static const struct netc_eth_config netc_eth##n##_config = { \ + DEVICE_MMIO_NAMED_ROM_INIT(base, DT_DRV_INST(n)), \ .generate_mac = netc_eth##n##_generate_mac, \ .bdr_init = netc_eth##n##_bdr_init, \ .phy_dev = (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, phy_handle), \ @@ -200,8 +206,14 @@ static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_ifac .pseudo_mac = DT_ENUM_HAS_VALUE(DT_DRV_INST(n), phy_connection_type, internal), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .si_idx = (DT_INST_PROP(n, mac_index) << 8) | DT_INST_PROP(n, si_index), \ - .tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n, \ - .rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n, \ + IF_ENABLED(CONFIG_ETH_NXP_IMX_NETC_MSI_GIC, \ + (.msi_device_id = DT_INST_PROP_OR(n, msi_device_id, 0), \ + .msi_dev = (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_PARENT(n), msi_parent), \ + (DEVICE_DT_GET(DT_PHANDLE(DT_INST_PARENT(n), msi_parent))), NULL)), \ + )) \ + IF_DISABLED(CONFIG_ETH_NXP_IMX_NETC_MSI_GIC, \ + (.tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n, \ + .rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n,)) \ IF_ENABLED(CONFIG_PTP_CLOCK_NXP_NETC, \ (.ptp_clock = DEVICE_DT_GET(DT_INST_PHANDLE(n, ptp_clock)),)) \ }; \ diff --git a/drivers/interrupt_controller/Kconfig.gic b/drivers/interrupt_controller/Kconfig.gic index b482bf3336b1..c3175c74ff2f 100644 --- a/drivers/interrupt_controller/Kconfig.gic +++ b/drivers/interrupt_controller/Kconfig.gic @@ -73,4 +73,13 @@ config GIC_SAFE_CONFIG crash the OS has already been started. With this enabled, it will bypass GIC distributor configuration if it has been configured by other OS. +config GIC_V3_RDIST_DMA_NONCOHERENT + bool "GIC redistributor is DMA noncoherent" + depends on GIC_V3 + default n + help + GIC redistributor on Some platform are connected to a non-coherent + downstream interconnect, it need to use Non-cahable and Non-shareable + access atttributes to access external memory. + endif # CPU_CORTEX diff --git a/drivers/interrupt_controller/intc_gicv3.c b/drivers/interrupt_controller/intc_gicv3.c index cc22eaedb17f..afc5c6d4377b 100644 --- a/drivers/interrupt_controller/intc_gicv3.c +++ b/drivers/interrupt_controller/intc_gicv3.c @@ -1,11 +1,12 @@ /* * Copyright 2020 Broadcom - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * Copyright 2025 Arm Limited and/or its affiliates * * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -111,7 +112,11 @@ static void arm_gic_lpi_setup(unsigned int intid, bool enable) *cfg &= ~BIT(0); } +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(cfg, sizeof(*cfg)); +#else barrier_dsync_fence_full(); +#endif its_rdist_invall(); } @@ -123,7 +128,11 @@ static void arm_gic_lpi_set_priority(unsigned int intid, unsigned int prio) *cfg &= 0xfc; *cfg |= prio & 0xfc; +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(cfg, sizeof(*cfg)); +#else barrier_dsync_fence_full(); +#endif its_rdist_invall(); } @@ -406,7 +415,7 @@ static void gicv3_rdist_setup_lpis(mem_addr_t rdist) unsigned int lpi_id_bits = MIN(GICD_TYPER_IDBITS(sys_read32(GICD_TYPER)), ITS_MAX_LPI_NRBITS); uintptr_t lpi_pend_table; - uint64_t reg; + uint64_t reg, tmp; uint32_t ctlr; /* If not, alloc a common prop table for all redistributors */ @@ -418,6 +427,11 @@ static void gicv3_rdist_setup_lpis(mem_addr_t rdist) lpi_pend_table = (uintptr_t)k_aligned_alloc(64 * 1024, LPI_PENDBASE_SZ(lpi_id_bits)); memset((void *)lpi_pend_table, 0, LPI_PENDBASE_SZ(lpi_id_bits)); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range((void *)lpi_prop_table, LPI_PROPBASE_SZ(lpi_id_bits)); + arch_dcache_flush_and_invd_range((void *)lpi_pend_table, LPI_PENDBASE_SZ(lpi_id_bits)); +#endif + ctlr = sys_read32(rdist + GICR_CTLR); ctlr &= ~GICR_CTLR_ENABLE_LPIS; sys_write32(ctlr, rdist + GICR_CTLR); @@ -429,7 +443,16 @@ static void gicv3_rdist_setup_lpis(mem_addr_t rdist) (GIC_BASER_CACHE_INNERLIKE << GITR_PROPBASER_OUTER_CACHE_SHIFT) | ((lpi_id_bits - 1) & GITR_PROPBASER_ID_BITS_MASK); sys_write64(reg, rdist + GICR_PROPBASER); - /* TOFIX: check SHAREABILITY validity */ + /* Check SHAREABILITY validity */ + tmp = sys_read64(rdist + GICR_PROPBASER); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + tmp &= ~MASK(GITR_PROPBASER_SHAREABILITY); +#endif + if (!(tmp & MASK(GITR_PROPBASER_SHAREABILITY))) { + reg &= ~(MASK(GITR_PROPBASER_SHAREABILITY) | MASK(GITR_PROPBASER_INNER_CACHE)); + reg |= GIC_BASER_CACHE_NCACHEABLE << GITR_PROPBASER_INNER_CACHE_SHIFT; + sys_write64(reg, rdist + GICR_PROPBASER); + } /* PENDBASE */ reg = (GIC_BASER_SHARE_INNER << GITR_PENDBASER_SHAREABILITY_SHIFT) | @@ -437,7 +460,16 @@ static void gicv3_rdist_setup_lpis(mem_addr_t rdist) (lpi_pend_table & (GITR_PENDBASER_ADDR_MASK << GITR_PENDBASER_ADDR_SHIFT)) | (GIC_BASER_CACHE_INNERLIKE << GITR_PENDBASER_OUTER_CACHE_SHIFT) | GITR_PENDBASER_PTZ; sys_write64(reg, rdist + GICR_PENDBASER); - /* TOFIX: check SHAREABILITY validity */ + /* Check SHAREABILITY validity */ + tmp = sys_read64(rdist + GICR_PENDBASER); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + tmp &= ~MASK(GITR_PENDBASER_SHAREABILITY); +#endif + if (!(tmp & MASK(GITR_PENDBASER_SHAREABILITY))) { + reg &= ~(MASK(GITR_PENDBASER_SHAREABILITY) | MASK(GITR_PENDBASER_INNER_CACHE)); + reg |= GIC_BASER_CACHE_NCACHEABLE << GITR_PENDBASER_INNER_CACHE_SHIFT; + sys_write64(reg, rdist + GICR_PENDBASER); + } ctlr = sys_read32(rdist + GICR_CTLR); ctlr |= GICR_CTLR_ENABLE_LPIS; diff --git a/drivers/interrupt_controller/intc_gicv3_its.c b/drivers/interrupt_controller/intc_gicv3_its.c index 6316e686c755..544158685e1d 100644 --- a/drivers/interrupt_controller/intc_gicv3_its.c +++ b/drivers/interrupt_controller/intc_gicv3_its.c @@ -1,5 +1,6 @@ /* * Copyright 2021 BayLibre, SAS + * Copyright 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +8,7 @@ #include LOG_MODULE_REGISTER(intc_gicv3_its, LOG_LEVEL_ERR); +#include #include #include #include @@ -39,6 +41,9 @@ struct its_cmd_block { #define ITS_CMD_QUEUE_SIZE SIZE_64K #define ITS_CMD_QUEUE_NR_ENTRIES (ITS_CMD_QUEUE_SIZE / sizeof(struct its_cmd_block)) +/* The level 1 entry size is a 64bit pointer */ +#define GITS_LVL1_ENTRY_SIZE (8UL) + struct gicv3_its_data { mm_reg_t base; struct its_cmd_block *cmd_base; @@ -190,8 +195,7 @@ static int its_alloc_tables(struct gicv3_its_data *data) lvl2_width = fls_z(page_size / entry_size) - 1; device_ids -= lvl2_width + 1; - /* The level 1 entry size is a 64bit pointer */ - entry_size = sizeof(uint64_t); + entry_size = GITS_LVL1_ENTRY_SIZE; indirect = true; } @@ -229,13 +233,22 @@ static int its_alloc_tables(struct gicv3_its_data *data) } reg |= MASK_SET(page_cnt - 1, GITS_BASER_SIZE); - reg |= MASK_SET(GIC_BASER_SHARE_INNER, GITS_BASER_SHAREABILITY); reg |= MASK_SET((uintptr_t)alloc_addr >> GITS_BASER_ADDR_SHIFT, GITS_BASER_ADDR); reg |= MASK_SET(GIC_BASER_CACHE_INNERLIKE, GITS_BASER_OUTER_CACHE); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + reg |= MASK_SET(GIC_BASER_SHARE_NO, GITS_BASER_SHAREABILITY); + reg |= MASK_SET(GIC_BASER_CACHE_NCACHEABLE, GITS_BASER_INNER_CACHE); +#else + reg |= MASK_SET(GIC_BASER_SHARE_INNER, GITS_BASER_SHAREABILITY); reg |= MASK_SET(GIC_BASER_CACHE_RAWAWB, GITS_BASER_INNER_CACHE); +#endif reg |= MASK_SET(indirect ? 1 : 0, GITS_BASER_INDIRECT); reg |= MASK_SET(1, GITS_BASER_VALID); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(alloc_addr, page_size * page_cnt); +#endif + sys_write64(reg, data->base + GITS_BASER(i)); /* TOFIX: check page size & SHAREABILITY validity after write */ @@ -300,6 +313,10 @@ static int its_post_command(struct gicv3_its_data *data, struct its_cmd_block *c uint64_t wr_idx, rd_idx, idx; unsigned int count = 1000000; /* 1s! */ +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(cmd, sizeof(*cmd)); +#endif + wr_idx = (data->cmd_write - data->cmd_base) * sizeof(*cmd); rd_idx = sys_read32(data->base + GITS_CREADR); @@ -320,7 +337,11 @@ static int its_post_command(struct gicv3_its_data *data, struct its_cmd_block *c rd_idx, idx, wr_idx); return -ETIMEDOUT; } - k_usleep(1); + if (k_is_pre_kernel()) { + k_busy_wait(1); + } else { + k_usleep(1); + } } return 0; @@ -335,7 +356,7 @@ static int its_send_sync_cmd(struct gicv3_its_data *data, uintptr_t rd_addr) } cmd->raw_cmd[0] = MASK_SET(GITS_CMD_ID_SYNC, GITS_CMD_ID); - cmd->raw_cmd[2] = MASK_SET(rd_addr >> GITS_CMD_RDBASE_ALIGN, GITS_CMD_RDBASE); + cmd->raw_cmd[2] = MASK_SET(rd_addr, GITS_CMD_RDBASE); return its_post_command(data, cmd); } @@ -350,8 +371,7 @@ static int its_send_mapc_cmd(struct gicv3_its_data *data, uint32_t icid, } cmd->raw_cmd[0] = MASK_SET(GITS_CMD_ID_MAPC, GITS_CMD_ID); - cmd->raw_cmd[2] = MASK_SET(icid, GITS_CMD_ICID) | - MASK_SET(rd_addr >> GITS_CMD_RDBASE_ALIGN, GITS_CMD_RDBASE) | + cmd->raw_cmd[2] = MASK_SET(icid, GITS_CMD_ICID) | MASK_SET(rd_addr, GITS_CMD_RDBASE) | MASK_SET(valid ? 1 : 0, GITS_CMD_VALID); return its_post_command(data, cmd); @@ -426,7 +446,6 @@ static int its_send_invall_cmd(struct gicv3_its_data *data, uint32_t icid) static int gicv3_its_send_int(const struct device *dev, uint32_t device_id, uint32_t event_id) { struct gicv3_its_data *data = dev->data; - /* TOFIX check device_id & event_id bounds */ return its_send_int_cmd(data, device_id, event_id); @@ -436,7 +455,7 @@ static void its_setup_cmd_queue(const struct device *dev) { const struct gicv3_its_config *cfg = dev->config; struct gicv3_its_data *data = dev->data; - uint64_t reg = 0; + uint64_t reg = 0, tmp; /* Zero out cmd table */ memset(cfg->cmd_queue, 0, cfg->cmd_queue_size); @@ -450,6 +469,17 @@ static void its_setup_cmd_queue(const struct device *dev) sys_write64(reg, data->base + GITS_CBASER); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + reg &= ~(MASK(GITS_BASER_SHAREABILITY)); +#endif + /* Check whether hardware supports sharable */ + tmp = sys_read64(data->base + GITS_CBASER); + if (!(tmp & MASK(GITS_BASER_SHAREABILITY))) { + reg &= ~(MASK(GITS_BASER_SHAREABILITY) | MASK(GITS_BASER_INNER_CACHE)); + reg |= MASK_SET(GIC_BASER_CACHE_NCACHEABLE, GITS_CBASER_INNER_CACHE); + sys_write64(reg, data->base + GITS_CBASER); + } + data->cmd_base = (struct its_cmd_block *)cfg->cmd_queue; data->cmd_write = data->cmd_base; @@ -462,12 +492,18 @@ static uintptr_t gicv3_rdist_get_rdbase(const struct device *dev, unsigned int c { struct gicv3_its_data *data = dev->data; uint64_t typer = sys_read64(data->base + GITS_TYPER); + uintptr_t rdbase; if (GITS_TYPER_PTA_GET(typer)) { - return gic_rdists[cpuid]; + rdbase = gic_rdists[cpuid]; + /* RDbase must be 64KB aligned, only return bits[51:16] of the address */ + rdbase = rdbase >> GITS_CMD_RDBASE_ALIGN; } else { - return GICR_TYPER_PROCESSOR_NUMBER_GET(sys_read64(gic_rdists[cpuid] + GICR_TYPER)); + rdbase = + GICR_TYPER_PROCESSOR_NUMBER_GET(sys_read64(gic_rdists[cpuid] + GICR_TYPER)); } + + return rdbase; } static int gicv3_its_map_intid(const struct device *dev, uint32_t device_id, uint32_t event_id, @@ -529,9 +565,18 @@ static int gicv3_its_init_device_id(const struct device *dev, uint32_t device_id memset(alloc_addr, 0, data->indirect_dev_page_size); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(alloc_addr, data->indirect_dev_page_size); +#endif + data->indirect_dev_lvl1_table[offset] = (uintptr_t)alloc_addr | MASK_SET(1, GITS_BASER_VALID); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(data->indirect_dev_lvl1_table + offset, + GITS_LVL1_ENTRY_SIZE); +#endif + barrier_dsync_fence_full(); } } @@ -547,6 +592,10 @@ static int gicv3_its_init_device_id(const struct device *dev, uint32_t device_id if (!itt) { return -ENOMEM; } + memset(itt, 0, alloc_size); +#ifdef CONFIG_GIC_V3_RDIST_DMA_NONCOHERENT + arch_dcache_flush_and_invd_range(itt, alloc_size); +#endif /* size is log2(ites) - 1, equivalent to (fls(ites) - 1) - 1 */ ret = its_send_mapd_cmd(data, device_id, fls_z(nr_ites) - 2, (uintptr_t)itt, true); diff --git a/drivers/mdio/mdio_nxp_imx_netc.c b/drivers/mdio/mdio_nxp_imx_netc.c index 4882f16b08d9..c9afc4a4c405 100644 --- a/drivers/mdio/mdio_nxp_imx_netc.c +++ b/drivers/mdio/mdio_nxp_imx_netc.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 NXP + * Copyright 2024-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,13 +15,20 @@ #include "fsl_netc_mdio.h" LOG_MODULE_REGISTER(nxp_imx_netc_emdio, CONFIG_MDIO_LOG_LEVEL); +#define DEV_CFG(_dev) ((const struct nxp_imx_netc_mdio_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct nxp_imx_netc_mdio_data *)(_dev)->data) + struct nxp_imx_netc_mdio_config { + DEVICE_MMIO_NAMED_ROM(basic); + DEVICE_MMIO_NAMED_ROM(pfconfig); const struct pinctrl_dev_config *pincfg; const struct device *clock_dev; clock_control_subsys_t clock_subsys; }; struct nxp_imx_netc_mdio_data { + DEVICE_MMIO_NAMED_RAM(basic); + DEVICE_MMIO_NAMED_RAM(pfconfig); struct k_mutex rw_mutex; netc_mdio_handle_t handle; }; @@ -60,6 +67,9 @@ static int nxp_imx_netc_mdio_initialize(const struct device *dev) status_t result; int err; + DEVICE_MMIO_NAMED_MAP(dev, basic, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + DEVICE_MMIO_NAMED_MAP(dev, pfconfig, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); if (err) { return err; @@ -89,6 +99,8 @@ static DEVICE_API(mdio, nxp_imx_netc_mdio_api) = { PINCTRL_DT_INST_DEFINE(n); \ static struct nxp_imx_netc_mdio_data nxp_imx_netc_mdio##n##_data; \ static const struct nxp_imx_netc_mdio_config nxp_imx_netc_mdio##n##_cfg = { \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(basic, DT_DRV_INST(n)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(pfconfig, DT_DRV_INST(n)), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ diff --git a/dts/arm/nxp/nxp_imx943_m33.dtsi b/dts/arm/nxp/nxp_imx943_m33.dtsi index 787fbcfd2974..86366ae4805b 100644 --- a/dts/arm/nxp/nxp_imx943_m33.dtsi +++ b/dts/arm/nxp/nxp_imx943_m33.dtsi @@ -264,21 +264,13 @@ }; netc: ethernet@4ca00000 { + compatible = "nxp,imx-netc"; reg = <0x4ca00000 0x500000>; interrupts = <294 0>; #address-cells = <1>; #size-cells = <1>; ranges; - emdio: mdio@4cde0000 { - compatible = "nxp,imx-netc-emdio"; - reg = <0x4cde0000 0x10000>; - clocks = <&scmi_clk IMX943_CLK_ENET>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - enetc_psi0: ethernet@4cc80000 { compatible = "nxp,imx-netc-psi"; reg = <0x4cc80000 0x10000>; @@ -324,6 +316,17 @@ status = "disabled"; }; }; + + emdio: mdio@4cde0000 { + compatible = "nxp,imx-netc-emdio"; + reg = <0x4cde0000 0x10000>, + <0x4cbc0000 0x40000>; + reg-names = "basic", "pfconfig"; + clocks = <&scmi_clk IMX943_CLK_ENET>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/nxp/nxp_imx95_m7.dtsi b/dts/arm/nxp/nxp_imx95_m7.dtsi index 1751f15014eb..1c3dc9c7ab8d 100644 --- a/dts/arm/nxp/nxp_imx95_m7.dtsi +++ b/dts/arm/nxp/nxp_imx95_m7.dtsi @@ -526,44 +526,59 @@ }; }; - netc: ethernet@4ca00000 { - reg = <0x4ca00000 0x1000000>; - interrupt-parent = <&irqsteer_master0>; - interrupts = <13 0 0>; + netc_blk_ctrl: netc-blk-ctrl@4cde0000 { + compatible = "nxp,imx-netc-blk-ctrl"; + reg = <0x4cde0000 0x10000>, + <0x4cdf0000 0x10000>, + <0x4c810000 0x18>; + reg-names = "ierb", "prb", "netcmix"; #address-cells = <1>; #size-cells = <1>; ranges; - emdio: mdio@4cce0000 { - compatible = "nxp,imx-netc-emdio"; - reg = <0x4cce0000 0x1c44>; - clocks = <&scmi_clk IMX95_CLK_ENET>; + netc: ethernet@4ca00000 { + compatible = "nxp,imx-netc"; + reg = <0x4ca00000 0x100000>; + interrupt-parent = <&irqsteer_master0>; + interrupts = <13 0 0>; #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; + #size-cells = <1>; + ranges; + + enetc_psi0: ethernet@4cc00000 { + compatible = "nxp,imx-netc-psi"; + reg = <0x4cc00000 0x10000>; + mac-index = <0>; + si-index = <0>; + status = "disabled"; + }; - enetc_psi0: ethernet@4cc00000 { - compatible = "nxp,imx-netc-psi"; - reg = <0x4cc00000 0x10000>; - mac-index = <0>; - si-index = <0>; - status = "disabled"; - }; + enetc_psi1: ethernet@4cc40000 { + compatible = "nxp,imx-netc-psi"; + reg = <0x4cc40000 0x10000>; + mac-index = <1>; + si-index = <1>; + status = "disabled"; + }; + + enetc_psi2: ethernet@4cc80000 { + compatible = "nxp,imx-netc-psi"; + reg = <0x4cc80000 0x10000>; + mac-index = <2>; + si-index = <2>; + status = "disabled"; + }; - enetc_psi1: ethernet@4cc40000 { - compatible = "nxp,imx-netc-psi"; - reg = <0x4cc40000 0x10000>; - mac-index = <1>; - si-index = <1>; - status = "disabled"; }; - enetc_psi2: ethernet@4cc80000 { - compatible = "nxp,imx-netc-psi"; - reg = <0x4cc80000 0x10000>; - mac-index = <2>; - si-index = <2>; + emdio: mdio@4cb00000 { + compatible = "nxp,imx-netc-emdio"; + reg = <0x4cce0000 0x2000>, + <0x4cb00000 0x100000>; + reg-names = "basic", "pfconfig"; + clocks = <&scmi_clk IMX95_CLK_ENET>; + #address-cells = <1>; + #size-cells = <0>; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt118x.dtsi b/dts/arm/nxp/nxp_rt118x.dtsi index dc25cfb24ecb..33f4429edce6 100644 --- a/dts/arm/nxp/nxp_rt118x.dtsi +++ b/dts/arm/nxp/nxp_rt118x.dtsi @@ -619,6 +619,7 @@ }; netc: ethernet@60000000 { + compatible = "nxp,imx-netc"; reg = <0x60000000 0x1000000>; #address-cells = <1>; #size-cells = <1>; @@ -641,15 +642,6 @@ status = "disabled"; }; - emdio: mdio@60ba0000 { - compatible = "nxp,imx-netc-emdio"; - reg = <0x60ba0000 0x1c44>; - clocks = <&ccm IMX_CCM_NETC_CLK 0x0 0>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - switch: dsa { compatible = "nxp,netc-switch"; status = "disabled"; @@ -686,6 +678,17 @@ }; }; + emdio: mdio@60ba0000 { + compatible = "nxp,imx-netc-emdio"; + reg = <0x60ba0000 0x1c44>, + <0x60001000 0x1000>; + reg-names = "basic", "pfconfig"; + clocks = <&ccm IMX_CCM_NETC_CLK 0x0 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + flexcan1: can@43a0000 { compatible = "nxp,flexcan-fd", "nxp,flexcan"; reg = <0x43a0000 0x1000>; diff --git a/dts/arm64/nxp/nxp_mimx95_a55.dtsi b/dts/arm64/nxp/nxp_mimx95_a55.dtsi index 37df069d3dd0..359b2aa4e239 100644 --- a/dts/arm64/nxp/nxp_mimx95_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx95_a55.dtsi @@ -76,7 +76,15 @@ <0x48060000 0xc0000>; /* GICR (RD_base + SGI_base) */ interrupt-controller; #interrupt-cells = <4>; + #address-cells = <1>; + #size-cells = <1>; status = "okay"; + + its: msi-controller@48040000 { + compatible = "arm,gic-v3-its"; + reg = <0x48040000 0x20000>; + status = "okay"; + }; }; reserved-memory { @@ -99,6 +107,12 @@ #address-cells = <1>; #size-cells = <0>; + scmi_devpd: protocol@11 { + compatible = "arm,scmi-power"; + reg = <0x11>; + #power-domain-cells = <1>; + }; + scmi_clk: protocol@14 { compatible = "arm,scmi-clock"; reg = <0x14>; @@ -468,6 +482,71 @@ ngpios = <16>; status = "disabled"; }; + + netc_blk_ctrl: netc-blk-ctrl@4cde0000 { + compatible = "nxp,imx-netc-blk-ctrl"; + reg = <0x4cde0000 0x10000>, + <0x4cdf0000 0x10000>, + <0x4c810000 0x18>; + reg-names = "ierb", "prb", "netcmix"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + netc: ethernet@4ca00000 { + compatible = "nxp,imx-netc"; + reg = <0x4ca00000 0x100000>; + msi-parent = <&its>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + enetc_psi0: ethernet@4cc00000 { + compatible = "nxp,imx-netc-psi"; + reg = <0x4cc00000 0x40000>; + msi-device-id = <0x60>; + mac-index = <0>; + si-index = <0>; + status = "disabled"; + }; + + enetc_psi1: ethernet@4cc40000 { + compatible = "nxp,imx-netc-psi"; + reg = <0x4cc40000 0x40000>; + msi-device-id = <0x63>; + mac-index = <1>; + si-index = <1>; + status = "disabled"; + }; + + enetc_psi2: ethernet@4cc80000 { + compatible = "nxp,imx-netc-psi"; + reg = <0x4cc80000 0x40000>; + msi-device-id = <0x64>; + mac-index = <2>; + si-index = <2>; + status = "disabled"; + }; + }; + + emdio: mdio@4cb00000 { + compatible = "nxp,imx-netc-emdio"; + reg = <0x4cce0000 0x2000>, + <0x4cb00000 0x100000>; + reg-names = "basic", "pfconfig"; + clocks = <&scmi_clk IMX95_CLK_ENET>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + enetc_ptp_clock: ptp_clock@4ccc0000 { + compatible = "nxp,netc-ptp-clock"; + reg = <0x4ccc0000 0x10000>; + clocks = <&scmi_clk IMX95_CLK_ENET>; + status = "disabled"; + }; + }; }; /* diff --git a/dts/bindings/ethernet/nxp,imx-netc-blk-ctrl.yaml b/dts/bindings/ethernet/nxp,imx-netc-blk-ctrl.yaml new file mode 100644 index 000000000000..7ad70ebaf5e3 --- /dev/null +++ b/dts/bindings/ethernet/nxp,imx-netc-blk-ctrl.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP i.MX NETC Block Controller + +compatible: "nxp,imx-netc-blk-ctrl" + +include: [base.yaml] + +properties: + reg: + required: true diff --git a/dts/bindings/ethernet/nxp,imx-netc-psi.yaml b/dts/bindings/ethernet/nxp,imx-netc-psi.yaml index 7aba10df1e35..128a385af07a 100644 --- a/dts/bindings/ethernet/nxp,imx-netc-psi.yaml +++ b/dts/bindings/ethernet/nxp,imx-netc-psi.yaml @@ -20,3 +20,7 @@ properties: required: true type: int description: The SI index of this PSI. + + msi-device-id: + type: int + description: The device ID passed to MSI controller. diff --git a/dts/bindings/ethernet/nxp,imx-netc.yaml b/dts/bindings/ethernet/nxp,imx-netc.yaml new file mode 100644 index 000000000000..bf1d53254a24 --- /dev/null +++ b/dts/bindings/ethernet/nxp,imx-netc.yaml @@ -0,0 +1,16 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP i.MX NETC Controller + +compatible: "nxp,imx-netc" + +include: [base.yaml] + +properties: + reg: + required: true + + msi-parent: + type: phandle + description: MSI controller diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index b794013ca972..d7fa09bed855 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -142,7 +142,9 @@ set_variable_ifdef(CONFIG_MIPI_DBI_NXP_DCNANO_LCDIF CONFIG_MCUX_COMPONENT_driver set_variable_ifdef(CONFIG_MIPI_DBI_NXP_FLEXIO_LCDIF CONFIG_MCUX_COMPONENT_driver.flexio_mculcd) set_variable_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX CONFIG_MCUX_COMPONENT_driver.mipi_csi2rx) set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver.netc) -set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver.netc_switch) +if(NOT CONFIG_SOC_MIMX9596) + set_variable_ifdef(CONFIG_ETH_NXP_IMX_NETC CONFIG_MCUX_COMPONENT_driver.netc_switch) +endif() set_variable_ifdef(CONFIG_SOC_SERIES_IMXRT10XX CONFIG_MCUX_COMPONENT_driver.ocotp) set_variable_ifdef(CONFIG_SOC_SERIES_IMXRT11XX CONFIG_MCUX_COMPONENT_driver.ocotp) diff --git a/samples/net/zperf/boards/imx95_evk_mimx9596_a55.conf b/samples/net/zperf/boards/imx95_evk_mimx9596_a55.conf new file mode 100644 index 000000000000..70a699068df6 --- /dev/null +++ b/samples/net/zperf/boards/imx95_evk_mimx9596_a55.conf @@ -0,0 +1,15 @@ +# The GICv3 & ITS drivers allocation needs are: +# - LPI prop table: global 1x64K aligned on 64K +# - LPI pend table: for each redistributor/cpu 1x64K aligned on 64K +# - Devices table: 128x4K aligned on 4K +# - Interrupt Collections table: 1x4K aligned on 4K +# +# This makes 11x64K to permit all allocations to success. +# +# Note, will need 64K HEAP_MEM per CPUs added. +# +# This doesn't necessarily include the Interrupt Translation Table, which are +# 256bytes aligned tables, for reference a 32 ITEs table needs 256bytes. +# +# To permit allocating 256 ITT tables of 32 ITEs, 13x64K HEAP_MEM is needed +CONFIG_HEAP_MEM_POOL_SIZE=851968 diff --git a/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.a55 b/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.a55 index 0fc9f23d6888..0d7fef5ac1fd 100644 --- a/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.a55 +++ b/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.a55 @@ -16,14 +16,19 @@ config FLASH_BASE_ADDRESS config GIC_SAFE_CONFIG default y +config GIC_V3_RDIST_DMA_NONCOHERENT + default y + # Disable data cache until MMU is enabled when booting from EL2 config ARM64_DCACHE_ALL_OPS default y config ARM64_BOOT_DISABLE_DCACHE default y +# Reserve 8192 LPI interrupt ID starts from 8192 when ITS is enabled config NUM_IRQS - default 320 + default 16384 if GIC_V3_ITS + default 407 if !GIC_V3_ITS config SYS_CLOCK_HW_CYCLES_PER_SEC default 24000000 diff --git a/soc/nxp/imx/imx9/imx95/a55/soc.c b/soc/nxp/imx/imx9/imx95/a55/soc.c index 29d2c963578d..91aeb788e671 100644 --- a/soc/nxp/imx/imx9/imx95/a55/soc.c +++ b/soc/nxp/imx/imx9/imx95/a55/soc.c @@ -9,12 +9,18 @@ #include #include #include +#include #include +#include #include #define FREQ_24M_HZ 24000000 /* 24 MHz */ -static int soc_clk_init(void) +/* SCMI power domain states */ +#define POWER_DOMAIN_STATE_ON 0x00000000 +#define POWER_DOMAIN_STATE_OFF 0x40000000 + +static int lpuart_clk_init(void) { #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart1), okay) || \ DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart3), okay) @@ -57,9 +63,65 @@ static int soc_clk_init(void) return 0; } +static int netc_init(void) +{ +#if defined(CONFIG_ETH_NXP_IMX_NETC) && (DT_CHILD_NUM_STATUS_OKAY(DT_NODELABEL(netc)) != 0) + const struct device *clk_dev = DEVICE_DT_GET(DT_NODELABEL(scmi_clk)); + struct scmi_protocol *proto = clk_dev->data; + struct scmi_clock_rate_config clk_cfg = {0}; + struct scmi_power_state_config pwr_cfg = {0}; + uint32_t power_state = POWER_DOMAIN_STATE_OFF; + uint64_t enetref_clk = 250000000; /* 250 MHz*/ + int ret; + + /* Power up NETCMIX */ + pwr_cfg.domain_id = IMX95_PD_NETC; + pwr_cfg.power_state = POWER_DOMAIN_STATE_ON; + + ret = scmi_power_state_set(&pwr_cfg); + if (ret) { + return ret; + } + + while (power_state != POWER_DOMAIN_STATE_ON) { + ret = scmi_power_state_get(IMX95_PD_NETC, &power_state); + if (ret) { + return ret; + } + } + + /* ENETREF clock init */ + ret = scmi_clock_parent_set(proto, IMX95_CLK_ENETREF, IMX95_CLK_SYSPLL1_PFD0); + if (ret) { + return ret; + } + + clk_cfg.flags = SCMI_CLK_RATE_SET_FLAGS_ROUNDS_AUTO; + clk_cfg.clk_id = IMX95_CLK_ENETREF; + clk_cfg.rate[0] = enetref_clk & 0xffffffff; + clk_cfg.rate[1] = (enetref_clk >> 32) & 0xffffffff; + + ret = scmi_clock_rate_set(proto, &clk_cfg); + if (ret) { + return ret; + } +#endif + + return 0; +} + static int soc_init(void) { - return soc_clk_init(); + int ret; + + ret = lpuart_clk_init(); + if (ret) { + return ret; + } + + ret = netc_init(); + + return ret; } /* * Because platform is using ARM SCMI, drivers like scmi, mbox etc are diff --git a/tests/arch/arm64/arm64_gicv3_its/boards/imx95_evk_mimx9596_a55.conf b/tests/arch/arm64/arm64_gicv3_its/boards/imx95_evk_mimx9596_a55.conf new file mode 100644 index 000000000000..70a699068df6 --- /dev/null +++ b/tests/arch/arm64/arm64_gicv3_its/boards/imx95_evk_mimx9596_a55.conf @@ -0,0 +1,15 @@ +# The GICv3 & ITS drivers allocation needs are: +# - LPI prop table: global 1x64K aligned on 64K +# - LPI pend table: for each redistributor/cpu 1x64K aligned on 64K +# - Devices table: 128x4K aligned on 4K +# - Interrupt Collections table: 1x4K aligned on 4K +# +# This makes 11x64K to permit all allocations to success. +# +# Note, will need 64K HEAP_MEM per CPUs added. +# +# This doesn't necessarily include the Interrupt Translation Table, which are +# 256bytes aligned tables, for reference a 32 ITEs table needs 256bytes. +# +# To permit allocating 256 ITT tables of 32 ITEs, 13x64K HEAP_MEM is needed +CONFIG_HEAP_MEM_POOL_SIZE=851968 diff --git a/tests/arch/arm64/arm64_gicv3_its/src/main.c b/tests/arch/arm64/arm64_gicv3_its/src/main.c index 42f18067b33f..940e4f504f0d 100644 --- a/tests/arch/arm64/arm64_gicv3_its/src/main.c +++ b/tests/arch/arm64/arm64_gicv3_its/src/main.c @@ -19,12 +19,19 @@ static void lpi_irq_handle(const void *parameter) last_lpi_irq_num = i; } +#ifdef CONFIG_SOC_MIMX9596_A55 +/* DeviceID is 8bits */ +#define ITS_TEST_DEV(id) (id & 0xff) +/* Cover up to 832 LPIs over 26 DevicesIDs and 32 EventIDs per DeviceID */ +#define ITS_TEST_NUM_DEVS 26 +#define ITS_TEST_NUM_ITES 32 +#else /* Generate a DeviceID over the whole 16bits */ #define ITS_TEST_DEV(id) ((((id + 256) % 16) << 12) | (((id + 256) % 24) << 8) | (id & 0xff)) - /* Cover up to 8192 LPIs over 256 DevicesIDs and 32 EventIDs per DeviceID */ #define ITS_TEST_NUM_DEVS 256 #define ITS_TEST_NUM_ITES 32 +#endif /* Do not test all 8192 irqs, iterate with a prime offset to cover most of the possible event_ids */ #define ITS_TEST_NEXT 13 diff --git a/west.yml b/west.yml index fe8253bfa2f2..cbc16958256a 100644 --- a/west.yml +++ b/west.yml @@ -210,7 +210,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 7a52cbb7cb56db3a276cbd617db3ea7cc3435d12 + revision: refs/pull/571/head path: modules/hal/nxp groups: - hal