From ac249e40f825752b1c8732b68962fe3cdc55b42f Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Fri, 24 Oct 2025 15:02:47 +0700 Subject: [PATCH 1/8] manifest: update hal_renesas revision Change hal_renesas revision to support ethernet for ra8x2 Signed-off-by: Nhat Ta --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 48e1d5834fc42..8e680dfc91b9d 100644 --- a/west.yml +++ b/west.yml @@ -226,7 +226,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: d01039075990309dcbbec9b86510ed9f70a01dff + revision: pull/178/head groups: - hal - name: hal_rpi_pico From b196fba698f908f895c59fea9037e0eddd5060c5 Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Mon, 6 Oct 2025 15:42:13 +0700 Subject: [PATCH 2/8] drivers: entropy: add trng for ra8x2 This commit add entropy support for ra8x2. Signed-off-by: Nhat Ta --- drivers/entropy/Kconfig.renesas_ra | 4 ++-- drivers/entropy/entropy_renesas_ra.c | 3 ++- dts/arm/renesas/ra/ra8/ra8x2.dtsi | 5 +++++ dts/bindings/rng/renesas,ra-rsip-e50d-trng.yaml | 8 ++++++++ modules/Kconfig.renesas | 7 +++++++ 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 dts/bindings/rng/renesas,ra-rsip-e50d-trng.yaml diff --git a/drivers/entropy/Kconfig.renesas_ra b/drivers/entropy/Kconfig.renesas_ra index fc5b14dc31564..37058cb823aa9 100644 --- a/drivers/entropy/Kconfig.renesas_ra +++ b/drivers/entropy/Kconfig.renesas_ra @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Renesas Electronics Corporation +# Copyright (c) 2024-2025 Renesas Electronics Corporation # SPDX-License-Identifier: Apache-2.0 # Renesas RA entropy generator driver configuration @@ -8,7 +8,7 @@ config ENTROPY_RENESAS_RA default y depends on DT_HAS_RENESAS_RA_RSIP_E51A_TRNG_ENABLED || DT_HAS_RENESAS_RA_SCE9_RNG_ENABLED \ || DT_HAS_RENESAS_RA_SCE7_RNG_ENABLED || DT_HAS_RENESAS_RA_SCE5_RNG_ENABLED \ - || DT_HAS_RENESAS_RA_TRNG_ENABLED + || DT_HAS_RENESAS_RA_TRNG_ENABLED || DT_HAS_RENESAS_RA_RSIP_E50D_TRNG_ENABLED select ENTROPY_HAS_DRIVER select USE_RA_FSP_SCE help diff --git a/drivers/entropy/entropy_renesas_ra.c b/drivers/entropy/entropy_renesas_ra.c index 4ac70c17142fa..8439f70186cfb 100644 --- a/drivers/entropy/entropy_renesas_ra.c +++ b/drivers/entropy/entropy_renesas_ra.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Renesas Electronics Corporation + * Copyright (c) 2024-2025 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,6 +48,7 @@ static int entropy_renesas_ra_init(const struct device *dev) CONFIG_ENTROPY_INIT_PRIORITY, &entropy_renesas_ra_api) DT_FOREACH_STATUS_OKAY(renesas_ra_rsip_e51a_trng, RENESAS_RA_ENTROPY_INIT) +DT_FOREACH_STATUS_OKAY(renesas_ra_rsip_e50d_trng, RENESAS_RA_ENTROPY_INIT) DT_FOREACH_STATUS_OKAY(renesas_ra_sce5_rng, RENESAS_RA_ENTROPY_INIT) DT_FOREACH_STATUS_OKAY(renesas_ra_sce7_rng, RENESAS_RA_ENTROPY_INIT) DT_FOREACH_STATUS_OKAY(renesas_ra_sce9_rng, RENESAS_RA_ENTROPY_INIT) diff --git a/dts/arm/renesas/ra/ra8/ra8x2.dtsi b/dts/arm/renesas/ra/ra8/ra8x2.dtsi index 936bf4d669b1e..084d73e22c422 100644 --- a/dts/arm/renesas/ra/ra8/ra8x2.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x2.dtsi @@ -103,6 +103,11 @@ status = "okay"; }; + trng: trng { + compatible = "renesas,ra-rsip-e50d-trng"; + status = "disabled"; + }; + ioport0: gpio@40400000 { compatible = "renesas,ra-gpio-ioport"; reg = <0x40400000 0x20>; diff --git a/dts/bindings/rng/renesas,ra-rsip-e50d-trng.yaml b/dts/bindings/rng/renesas,ra-rsip-e50d-trng.yaml new file mode 100644 index 0000000000000..5cf74fe1dc830 --- /dev/null +++ b/dts/bindings/rng/renesas,ra-rsip-e50d-trng.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA RSIP-E51A TRNG + +compatible: "renesas,ra-rsip-e50d-trng" + +include: base.yaml diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 8434c47091f99..5b6fd648534d8 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -99,6 +99,13 @@ config HAS_RENESAS_RA_RSIP_E51A help Includes RSIP-E51A implementation for SCE driver +config HAS_RENESAS_RA_RSIP_E50D + bool + default y + depends on DT_HAS_RENESAS_RA_RSIP_E50D_TRNG_ENABLED + help + Includes RSIP-E50D implementation for SCE driver + config HAS_RENESAS_RA_SCE9 bool default y From c33d241d3f2ee70777f3c03165150e8a4207d495 Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Tue, 21 Oct 2025 16:37:35 +0700 Subject: [PATCH 3/8] drivers: ethernet: initial support for ethernet rmac driver This commit add ethernet driver support for ra8x2. Signed-off-by: Nhat Ta --- drivers/ethernet/CMakeLists.txt | 1 + drivers/ethernet/Kconfig | 1 + drivers/ethernet/Kconfig.renesas_ra_rmac | 48 ++ drivers/ethernet/eth_renesas_ra_rmac.c | 733 ++++++++++++++++++ dts/bindings/ethernet/renesas,ra-eswm.yaml | 32 + .../ethernet/renesas,ra-ethernet-rmac.yaml | 67 ++ .../drivers/clock_control/renesas_ra_cgc.h | 3 + .../drivers/ethernet/eth_renesas_ra_rmac.h | 29 + .../dt-bindings/pinctrl/renesas/pinctrl-ra.h | 2 + modules/Kconfig.renesas | 15 + 10 files changed, 931 insertions(+) create mode 100644 drivers/ethernet/Kconfig.renesas_ra_rmac create mode 100644 drivers/ethernet/eth_renesas_ra_rmac.c create mode 100644 dts/bindings/ethernet/renesas,ra-eswm.yaml create mode 100644 dts/bindings/ethernet/renesas,ra-ethernet-rmac.yaml create mode 100644 include/zephyr/drivers/ethernet/eth_renesas_ra_rmac.h diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 17b7538572b8c..cd4fa3f6e671d 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -50,6 +50,7 @@ zephyr_library_sources_ifdef(CONFIG_ETH_NUMAKER eth_numaker.c) zephyr_library_sources_ifdef(CONFIG_ETH_NXP_ENET eth_nxp_enet.c) zephyr_library_sources_ifdef(CONFIG_ETH_NXP_S32_GMAC eth_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_ETH_RENESAS_RA eth_renesas_ra.c) +zephyr_library_sources_ifdef(CONFIG_ETH_RENESAS_RA_RMAC eth_renesas_ra_rmac.c) zephyr_library_sources_ifdef(CONFIG_ETH_SAM_GMAC eth_sam_gmac.c) zephyr_library_sources_ifdef(CONFIG_ETH_SMSC911X eth_smsc911x.c) zephyr_library_sources_ifdef(CONFIG_ETH_SMSC91X eth_smsc91x.c) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index 3c7b4b795b7ee..d5892e6a032be 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -68,6 +68,7 @@ source "drivers/ethernet/Kconfig.nxp_enet" source "drivers/ethernet/Kconfig.nxp_s32_gmac" source "drivers/ethernet/Kconfig.nxp_s32_netc" source "drivers/ethernet/Kconfig.renesas_ra" +source "drivers/ethernet/Kconfig.renesas_ra_rmac" source "drivers/ethernet/Kconfig.sam_gmac" source "drivers/ethernet/Kconfig.smsc911x" source "drivers/ethernet/Kconfig.smsc91x" diff --git a/drivers/ethernet/Kconfig.renesas_ra_rmac b/drivers/ethernet/Kconfig.renesas_ra_rmac new file mode 100644 index 0000000000000..064a671430b90 --- /dev/null +++ b/drivers/ethernet/Kconfig.renesas_ra_rmac @@ -0,0 +1,48 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config ETH_RENESAS_RA_RMAC + bool "Renesas RA ethernet RMAC driver" + default y + depends on DT_HAS_RENESAS_RA_ETHERNET_RMAC_ENABLED + select USE_RA_FSP_RMAC + select USE_RA_FSP_LAYER3_SWITCH + select MDIO + help + Add support for Renesas RA ethernet device driver. + +if ETH_RENESAS_RA_RMAC + +config ETH_RENESAS_RA_RX_THREAD_STACK_SIZE + int "Stack size for internal incoming packet handler" + default 1500 + help + Size of the stack used for internal thread which is ran for + incoming packet processing. + +config ETH_RENESAS_RA_RX_THREAD_PRIORITY + int "Renesas RA Ethernet receive thread priority" + default 2 + +config ETH_RENESAS_RA_USE_ZERO_COPY + bool "Use zero-copy for ethernet buffers" + default y + help + Enable this option to use zero-copy mode, allowing the driver to directly + access DMA buffers without using a staging buffer. + +config ETH_RENESAS_RA_USE_HW_WRITEBACK + bool "Wait hardware writeback of ethernet buffers" + default y + help + Enable this option to wait for Ethernet descriptor writeback, ensuring + that the TX frame is written successfully. Note that enabling this option + may cause ethernet write operations to take slightly longer. + +config ESWM_RENESAS_RA_INIT_PRIORITY + int "Ethernet driver init priority" + default 55 + help + Ethernet switch module ESWM device driver initialization priority. + +endif diff --git a/drivers/ethernet/eth_renesas_ra_rmac.c b/drivers/ethernet/eth_renesas_ra_rmac.c new file mode 100644 index 0000000000000..60ce80bbc7fac --- /dev/null +++ b/drivers/ethernet/eth_renesas_ra_rmac.c @@ -0,0 +1,733 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "r_rmac.h" +#include "r_layer3_switch.h" +#include "eth.h" + +LOG_MODULE_REGISTER(eth_renesas_ra, CONFIG_ETHERNET_LOG_LEVEL); + +/* At this time , HAL only support single descriptor, set fixed buffer length */ +#define ETH_BUF_SIZE (1536) + +#define ETHPHYCLK_25MHZ MHZ(25) +#define ETHPHYCLK_50MHZ MHZ(50) + +enum phy_clock_type { + ETH_PHY_REF_CLK_XTAL, + ETH_PHY_REF_CLK_INTERNAL +}; + +struct eswm_renesas_ra_data { + layer3_switch_instance_ctrl_t *fsp_ctrl; + ether_switch_cfg_t *fsp_cfg; +}; + +struct eswm_renesas_ra_config { + const struct device *gwcaclk_dev; + const struct device *pclk_dev; + const struct device *eswclk_dev; + const struct device *eswphyclk_dev; + const struct device *ethphyclk_dev; + struct clock_control_ra_subsys_cfg pclk_subsys; + struct clock_control_ra_subsys_cfg ethphyclk_subsys; + const uint8_t ethphyclk_enable; + const struct pinctrl_dev_config *pin_cfg; + void (*en_irq)(void); +}; + +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) +struct eth_renesas_ra_buf_header { + uint8_t *buf; +}; +#endif + +struct eth_renesas_ra_data { + struct net_if *iface; + uint8_t mac_addr[NET_ETH_ADDR_LEN]; + +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) + /* DMA buffer header */ + struct eth_renesas_ra_buf_header *tx_buf_header; + uint8_t tx_buf_idx; + uint8_t tx_buf_num; +#else + /* staging buffer */ + uint8_t *rx_frame; + uint8_t *tx_frame; +#endif + struct k_thread rx_thread; + + K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_RENESAS_RA_RX_THREAD_STACK_SIZE); + struct k_sem rx_sem; +#if defined(CONFIG_ETH_RENESAS_RA_USE_HW_WRITEBACK) + struct k_sem tx_sem; +#endif + uint8_t phy_link_up; +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + struct net_stats_eth stats; +#endif + rmac_instance_ctrl_t *fsp_ctrl; + ether_cfg_t *fsp_cfg; + ether_callback_args_t fsp_cb; +}; + +struct eth_renesas_ra_config { + uint8_t random_mac; /* 0 if not using random mac */ + uint8_t valid_mac; /* 1 if mac is valid */ + ether_phy_mii_type_t mii_type; + const struct pinctrl_dev_config *pin_cfg; + const struct device *phy_dev; + const struct device *phy_clock; + enum phy_clock_type phy_clock_type; +}; + +extern void layer3_switch_gwdi_isr(void); +extern void rmac_init_buffers(rmac_instance_ctrl_t *const p_instance_ctrl); +extern void rmac_init_descriptors(rmac_instance_ctrl_t *const p_instance_ctrl); +extern void rmac_configure_reception_filter(rmac_instance_ctrl_t const *const p_instance_ctrl); +extern void r_rmac_disable_reception(rmac_instance_ctrl_t *p_instance_ctrl); +extern fsp_err_t rmac_do_link(rmac_instance_ctrl_t *const p_instance_ctrl, + const layer3_switch_magic_packet_detection_t mode); + +static void phy_link_cb(const struct device *phy_dev, struct phy_link_state *state, void *eth_dev) +{ + const struct device *dev = (struct device *)eth_dev; + struct eth_renesas_ra_data *data = dev->data; + fsp_err_t fsp_err = FSP_SUCCESS; + + if (state->is_up) { + data->fsp_ctrl->link_establish_status = ETHER_LINK_ESTABLISH_STATUS_UP; + data->phy_link_up = 1; + + /* Chage ETHA to config mode */ + r_rmac_phy_set_operation_mode(data->fsp_cfg->channel, RENESAS_RA_ETHA_DISABLE_MODE); + r_rmac_phy_set_operation_mode(data->fsp_cfg->channel, RENESAS_RA_ETHA_CONFIG_MODE); + + switch (state->speed) { + case LINK_HALF_10BASE: + __fallthrough; + case LINK_FULL_10BASE: + data->fsp_ctrl->p_reg_rmac->MPIC_b.LSC = RENESAS_RA_MPIC_LSC_10; + break; + case LINK_HALF_100BASE: + __fallthrough; + case LINK_FULL_100BASE: + data->fsp_ctrl->p_reg_rmac->MPIC_b.LSC = RENESAS_RA_MPIC_LSC_100; + break; + case LINK_HALF_1000BASE: + __fallthrough; + case LINK_FULL_1000BASE: + data->fsp_ctrl->p_reg_rmac->MPIC_b.LSC = RENESAS_RA_MPIC_LSC_1000; + break; + default: + LOG_DBG("phy link speed is not supported"); + break; + } + + /* Chage ETHA to operate mode */ + r_rmac_phy_set_operation_mode(data->fsp_cfg->channel, RENESAS_RA_ETHA_DISABLE_MODE); + r_rmac_phy_set_operation_mode(data->fsp_cfg->channel, + RENESAS_RA_ETHA_OPERATION_MODE); + + rmac_init_buffers(data->fsp_ctrl); + rmac_init_descriptors(data->fsp_ctrl); + rmac_configure_reception_filter(data->fsp_ctrl); + + fsp_err = + rmac_do_link(data->fsp_ctrl, LAYER3_SWITCH_MAGIC_PACKET_DETECTION_DISABLE); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("link MAC failed, err=%d", fsp_err); + return; + } + + LOG_DBG("link up"); + + net_eth_carrier_on(data->iface); + } else { + if (data->phy_link_up == 1) { + /* phy state change from up to down */ + r_rmac_disable_reception(data->fsp_ctrl); + + data->fsp_ctrl->link_establish_status = ETHER_LINK_ESTABLISH_STATUS_DOWN; + data->phy_link_up = 0; + + LOG_DBG("link down"); + net_eth_carrier_off(data->iface); + } + } +} + +static void eth_rmac_cb(ether_callback_args_t *args) +{ + struct device *eth_dev = (struct device *)args->p_context; + struct eth_renesas_ra_data *data = eth_dev->data; + + switch (args->event) { +#if defined(CONFIG_ETH_RENESAS_RA_USE_HW_WRITEBACK) + case ETHER_EVENT_TX_COMPLETE: + /* tx frame writen */ + k_sem_give(&data->tx_sem); + break; +#endif + case ETHER_EVENT_RX_MESSAGE_LOST: + /* rx queue is full to append new frame */ + __fallthrough; + case ETHER_EVENT_RX_COMPLETE: + /* new rx frame is ready to read */ + k_sem_give(&data->rx_sem); + break; + default: + break; + } +} + +static void eth_switch_cb(ether_switch_callback_args_t *args) +{ + /* Do nothing */ + ARG_UNUSED(args); +} + +static enum ethernet_hw_caps eth_renesas_ra_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + + return ETHERNET_LINK_10BASE | ETHERNET_LINK_100BASE | ETHERNET_LINK_1000BASE; +} + +static void eth_renesas_ra_init_iface(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct eth_renesas_ra_data *data = dev->data; + const struct eth_renesas_ra_config *config = dev->config; + + net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), NET_LINK_ETHERNET); + + if (data->iface == NULL) { + data->iface = iface; + } + + if (!device_is_ready(config->phy_dev)) { + LOG_DBG("phy is not ready"); + return; + } + + ethernet_init(iface); + + net_if_carrier_off(data->iface); + + data->phy_link_up = 0; + phy_link_callback_set(config->phy_dev, &phy_link_cb, (void *)dev); +} + +#if defined(CONFIG_NET_STATISTICS_ETHERNET) +static struct net_stats_eth *eth_renesas_ra_get_stats(const struct device *dev) +{ + struct eth_renesas_ra_data *data = dev->data; + + return &data->stats; +} + +#endif /* CONFIG_NET_STATISTICS_ETHERNET */ + +const struct device *eth_renesas_ra_get_phy(const struct device *dev) +{ + const struct eth_renesas_ra_config *config = dev->config; + + return config->phy_dev; +} + +static int eth_renesas_ra_tx(const struct device *dev, struct net_pkt *pkt) +{ + struct eth_renesas_ra_data *data = dev->data; + size_t len = net_pkt_get_len(pkt); + fsp_err_t fsp_err = FSP_ERR_NOT_INITIALIZED; + int ret = 0; + uint8_t *tx_buf; + +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) + tx_buf = data->tx_buf_header[data->tx_buf_idx].buf; + data->tx_buf_idx = (data->tx_buf_idx + 1) % (data->tx_buf_num); +#else + tx_buf = data->tx_frame; +#endif + +#if defined(CONFIG_ETH_RENESAS_RA_USE_HW_WRITEBACK) + k_sem_reset(&data->tx_sem); +#endif + + ret = net_pkt_read(pkt, tx_buf, len); + if (ret < 0) { + LOG_DBG("failed to read TX packet"); + goto tx_end; + } + + if (len > NET_ETH_MAX_FRAME_SIZE) { + ret = -EINVAL; + LOG_DBG("TX packet too large"); + goto tx_end; + } + + fsp_err = R_RMAC_Write(data->fsp_ctrl, tx_buf, (uint32_t)len); + if (fsp_err != FSP_SUCCESS) { + ret = (fsp_err == FSP_ERR_ETHER_ERROR_TRANSMIT_BUFFER_FULL) ? -ENOBUFS : -EIO; + LOG_DBG("write to FIFO failed, err=%d", fsp_err); + } + +tx_end: + +#if defined(CONFIG_ETH_RENESAS_RA_USE_HW_WRITEBACK) + if (fsp_err == FSP_SUCCESS) { + /* wait descriptor write back complete */ + ret = k_sem_take(&data->tx_sem, K_MSEC(1)); + +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) + fsp_err = R_RMAC_TxStatusGet(data->fsp_ctrl, tx_buf); + if (fsp_err != FSP_SUCCESS) { + ret = -EIO; + } +#endif + } +#endif + + if (ret) { + eth_stats_update_errors_tx(data->iface); + } + + return ret; +} + +static void renesas_ra_eth_rx(const struct device *dev) +{ + struct eth_renesas_ra_data *data = dev->data; + struct net_pkt *pkt = NULL; + size_t len = 0; + fsp_err_t fsp_err = FSP_SUCCESS; + int ret = 0; + uint8_t *rx_buf; + +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) + fsp_err = R_RMAC_Read(data->fsp_ctrl, &rx_buf, (uint32_t *)&len); +#else + rx_buf = data->rx_frame; + fsp_err = R_RMAC_Read(data->fsp_ctrl, rx_buf, (uint32_t *)&len); +#endif + + if (fsp_err == FSP_ERR_ETHER_ERROR_NO_DATA) { + /* Nothing to receive, all desc in queue was read */ + k_sem_reset(&data->rx_sem); + return; + } else if (fsp_err != FSP_SUCCESS) { + LOG_DBG("failed to read from FIFO"); + ret = -EIO; + goto rx_end; + } + + /* read again for remaining data */ + k_sem_give(&data->rx_sem); + + pkt = net_pkt_rx_alloc_with_buffer(data->iface, (size_t)len, AF_UNSPEC, 0, K_MSEC(100)); + if (pkt == NULL) { + LOG_DBG("failed to obtain RX buffer"); + goto rx_end; + } + + ret = net_pkt_write(pkt, rx_buf, len); + if (ret < 0) { + LOG_DBG("failed to append RX buffer to packet"); + net_pkt_unref(pkt); + goto rx_end; + } + +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) + fsp_err = R_RMAC_RxBufferUpdate(data->fsp_ctrl, (void *)rx_buf); + if (fsp_err != FSP_SUCCESS) { + LOG_DBG("failed to release RX buffer"); + } +#endif + + ret = net_recv_data(net_pkt_iface(pkt), pkt); + if (ret < 0) { + LOG_DBG("failed to push pkt to network stack"); + net_pkt_unref(pkt); + } + +rx_end: + if (ret) { + eth_stats_update_errors_rx(data->iface); + } +} + +static void eth_rx_thread(void *arg1, void *unused1, void *unused2) +{ + const struct device *dev = (const struct device *)arg1; + struct eth_renesas_ra_data *data = dev->data; + + ARG_UNUSED(unused1); + ARG_UNUSED(unused2); + + while (1) { + if (k_sem_take(&data->rx_sem, K_MSEC(100))) { + continue; + } + + renesas_ra_eth_rx(dev); + } +} + +static int renesas_ra_eswm_init(const struct device *dev) +{ + struct eswm_renesas_ra_data *data = dev->data; + const struct eswm_renesas_ra_config *config = dev->config; + uint32_t gwcaclk, pclk, eswclk, eswphyclk, ethphyclk; + fsp_err_t fsp_err = FSP_SUCCESS; + int ret = 0; + + clock_control_get_rate(config->gwcaclk_dev, NULL, &gwcaclk); + clock_control_get_rate(config->pclk_dev, NULL, &pclk); + clock_control_get_rate(config->eswclk_dev, NULL, &eswclk); + clock_control_get_rate(config->eswphyclk_dev, NULL, &eswphyclk); + clock_control_get_rate(config->ethphyclk_dev, NULL, ðphyclk); + + /* Clock restrictions for eswm on HM */ + if ((gwcaclk * 1.5 < eswclk) || (eswclk <= pclk) || (gwcaclk <= pclk)) { + LOG_ERR("ESWM clock invalid"); + return -EIO; + } + + fsp_err = R_LAYER3_SWITCH_Open(data->fsp_ctrl, data->fsp_cfg); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("ESWM open failed, err=%d", fsp_err); + return -EIO; + } + + if (config->ethphyclk_enable) { + ret = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + ret = clock_control_on(config->ethphyclk_dev, + (clock_control_subsys_t)&config->ethphyclk_subsys); + if (ret) { + LOG_DBG("failed to start eth phy clock, err=%d", ret); + } + } else { + (void)clock_control_off(config->ethphyclk_dev, + (clock_control_subsys_t)&config->ethphyclk_subsys); + } + + config->en_irq(); + + return 0; +} + +static int renesas_ra_eth_init(const struct device *dev) +{ + struct eth_renesas_ra_data *data = dev->data; + const struct eth_renesas_ra_config *config = dev->config; + fsp_err_t fsp_err = FSP_SUCCESS; + int ret = 0; + uint32_t phy_ref_rate; + + clock_control_get_rate(config->phy_clock, NULL, &phy_ref_rate); + + if (config->phy_clock_type == ETH_PHY_REF_CLK_INTERNAL) { + /* internal phy clock should be 25/50 MHz */ + if (phy_ref_rate != ETHPHYCLK_25MHZ && phy_ref_rate != ETHPHYCLK_50MHZ) { + LOG_DBG("internal PHY clock %d differ from 25/50 MHz", phy_ref_rate); + } + } else if (config->phy_clock_type != ETH_PHY_REF_CLK_XTAL) { + LOG_DBG("invalid phy clock type"); + } + + ret = pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + if (config->random_mac || !config->valid_mac) { + gen_random_mac(&data->mac_addr[0], RENESAS_OUI_B0, RENESAS_OUI_B1, RENESAS_OUI_B2); + } + + data->fsp_cfg->p_mac_address = &data->mac_addr[0]; + + if (data->fsp_ctrl->open != 0) { + R_RMAC_Close(data->fsp_ctrl); + } + + fsp_err = R_RMAC_Open(data->fsp_ctrl, data->fsp_cfg); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("RMAC open failed, err=%d", fsp_err); + return -EIO; + } + + fsp_err = R_RMAC_CallbackSet(data->fsp_ctrl, (void *)ð_rmac_cb, (void *)dev, + &data->fsp_cb); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("RMAC set cb failed, err=%d", fsp_err); + return -EIO; + } + + k_sem_init(&data->rx_sem, 0, K_SEM_MAX_LIMIT); +#if defined(CONFIG_ETH_RENESAS_RA_USE_HW_WRITEBACK) + k_sem_init(&data->tx_sem, 0, 1); +#endif + + k_thread_create(&data->rx_thread, data->rx_thread_stack, + K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), eth_rx_thread, (void *)dev, + NULL, NULL, K_PRIO_COOP(CONFIG_ETH_RENESAS_RA_RX_THREAD_PRIORITY), 0, + K_NO_WAIT); + k_thread_name_set(&data->rx_thread, "eth_renesas_ra_rx"); + + return 0; +} + +static const struct ethernet_api eth_renesas_ra_api = { + .iface_api.init = eth_renesas_ra_init_iface, +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + .get_stats = eth_renesas_ra_get_stats, +#endif /* CONFIG_NET_STATISTICS_ETHERNET */ + .get_capabilities = eth_renesas_ra_get_capabilities, + .get_phy = eth_renesas_ra_get_phy, + .send = eth_renesas_ra_tx, +}; + +#define DT_DRV_COMPAT renesas_ra_eswm + +#define ETH_USE_INTERNAL_PHY_CLK(id) \ + COND_CODE_1(UTIL_AND(DT_NODE_HAS_COMPAT(id, renesas_ra_ethernet_rmac), \ + DT_ENUM_HAS_VALUE(id, phy_clock_type, internal)), (1), (0)) + +PINCTRL_DT_INST_DEFINE(0); + +static void renesas_ra_eswm_init_irq(void) +{ + R_ICU->IELSR_b[DT_INST_IRQ_BY_NAME(0, gwdi, irq)].IELS = + BSP_PRV_IELS_ENUM(EVENT_ETHER_GWDI0); + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, gwdi, irq), DT_INST_IRQ_BY_NAME(0, gwdi, priority), + layer3_switch_gwdi_isr, DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQ_BY_NAME(0, gwdi, irq)); +} + +static layer3_switch_extended_cfg_t eswm_ext_cfg = { + .p_ether_phy_instances = {NULL, NULL}, + .fowarding_target_port_masks = {LAYER3_SWITCH_PORT_BITMASK_PORT2, + LAYER3_SWITCH_PORT_BITMASK_PORT2}, +}; +static layer3_switch_instance_ctrl_t eswm_ctrl = {0}; +static ether_switch_cfg_t eswm_cfg = { + .channel = 0, + .p_extend = &eswm_ext_cfg, + .p_callback = ð_switch_cb, + .p_context = (void *)DEVICE_DT_INST_GET(0), + .irq = DT_INST_IRQ_BY_NAME(0, gwdi, irq), + .ipl = DT_INST_IRQ_BY_NAME(0, gwdi, priority), +}; +static ether_switch_instance_t eswm_inst = { + .p_ctrl = (ether_switch_ctrl_t *)&eswm_ctrl, + .p_cfg = (ether_switch_cfg_t *)&eswm_cfg, + .p_api = (ether_switch_api_t *)&g_ether_switch_on_layer3_switch, +}; +static struct eswm_renesas_ra_data eswm_data = { + .fsp_ctrl = &eswm_ctrl, + .fsp_cfg = &eswm_cfg, +}; +static struct eswm_renesas_ra_config eswm_config = { + .gwcaclk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(0, gwcaclk)), + .pclk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(0, pclk)), + .eswclk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(0, eswclk)), + .eswphyclk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(0, eswphyclk)), + .ethphyclk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(0, ethphyclk)), + .pclk_subsys.mstp = (uint32_t)DT_INST_CLOCKS_CELL_BY_NAME(0, pclk, mstp), + .pclk_subsys.stop_bit = DT_INST_CLOCKS_CELL_BY_NAME(0, pclk, stop_bit), + .ethphyclk_subsys.mstp = (uint32_t)DT_INST_CLOCKS_CELL_BY_NAME(0, ethphyclk, mstp), + .ethphyclk_subsys.stop_bit = DT_INST_CLOCKS_CELL_BY_NAME(0, ethphyclk, stop_bit), + .ethphyclk_enable = DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(0, ETH_USE_INTERNAL_PHY_CLK, (+)), + .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .en_irq = &renesas_ra_eswm_init_irq, +}; +DEVICE_DT_INST_DEFINE(0, renesas_ra_eswm_init, NULL, &eswm_data, &eswm_config, POST_KERNEL, + CONFIG_ESWM_RENESAS_RA_INIT_PRIORITY, NULL); + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT renesas_ra_ethernet_rmac + +#define ETH_TX_QUEUE_NUM(n) DT_INST_PROP(n, txq_num) +#define ETH_RX_QUEUE_NUM(n) DT_INST_PROP(n, rxq_num) +#define ETH_TX_QUEUE_LEN(n) DT_INST_PROP(n, txq_len) +#define ETH_RX_QUEUE_LEN(n) DT_INST_PROP(n, rxq_len) +#define ETH_TX_BUF_NUM(n) DT_INST_PROP(n, txb_num) +#define ETH_RX_BUF_NUM(n) DT_INST_PROP(n, rxb_num) +#define ETH_BUF_NUM(n) (ETH_TX_BUF_NUM(n) + ETH_RX_BUF_NUM(n)) +#define ETH_DESC_NUM(n) \ + (ETH_TX_QUEUE_NUM(n) * (ETH_TX_QUEUE_LEN(n) - 1) + \ + (ETH_RX_QUEUE_NUM(n) * (ETH_RX_QUEUE_LEN(n) - 1))) + +#define ETH_PHY_CONN_TYPE(n) \ + ((DT_INST_ENUM_HAS_VALUE(n, phy_connection_type, rgmii) \ + ? ETHER_PHY_MII_TYPE_RGMII \ + : (DT_INST_ENUM_HAS_VALUE(n, phy_connection_type, gmii) \ + ? ETHER_PHY_MII_TYPE_GMII \ + : (DT_INST_ENUM_HAS_VALUE(n, phy_connection_type, rmii) \ + ? ETHER_PHY_MII_TYPE_RMII \ + : ETHER_PHY_MII_TYPE_MII)))) +#define ETH_PHY_CLOCK_TYPE(n) \ + DT_INST_ENUM_HAS_VALUE(n, phy_clock_type, xtal) ? ETH_PHY_REF_CLK_XTAL \ + : ETH_PHY_REF_CLK_INTERNAL + +/* Buffers declare */ +#define ETH_TX_BUF_DECLARE(idx, n) static uint8_t eth##n##_tx_buf##idx[ETH_BUF_SIZE]; +#define ETH_RX_BUF_DECLARE(idx, n) static uint8_t eth##n##_rx_buf##idx[ETH_BUF_SIZE]; +#define ETH_TX_BUF_PTR_DECLARE(idx, n) (uint8_t *)ð##n##_tx_buf##idx[0] +#define ETH_RX_BUF_PTR_DECLARE(idx, n) (uint8_t *)ð##n##_rx_buf##idx[0] + +/* Descriptors declare */ +#define ETH_TX_DESC_DECLARE(idx, n) \ + static layer3_switch_descriptor_t eth##n##_tx_desc_array##idx[ETH_TX_BUF_NUM(n)]; +#define ETH_RX_DESC_DECLARE(idx, n) \ + static layer3_switch_descriptor_t eth##n##_rx_desc_array##idx[ETH_RX_BUF_NUM(n)]; + +/* Queues declare */ +#define ETH_TX_QUEUE_DECLARE(idx, n) \ + { \ + .queue_cfg = \ + { \ + .array_length = ETH_TX_QUEUE_LEN(n), \ + .p_descriptor_array = eth##n##_tx_desc_array##idx, \ + .p_ts_descriptor_array = NULL, \ + .ports = 1 << DT_INST_PROP(n, channel), \ + .type = LAYER3_SWITCH_QUEUE_TYPE_TX, \ + .write_back_mode = LAYER3_SWITCH_WRITE_BACK_MODE_FULL, \ + .descriptor_format = LAYER3_SWITCH_DISCRIPTOR_FORMTAT_EXTENDED, \ + .rx_timestamp_storage = \ + LAYER3_SWITCH_RX_TIMESTAMP_STORAGE_DISABLE, \ + }, \ + } +#define ETH_RX_QUEUE_DECLARE(idx, n) \ + { \ + .queue_cfg = \ + { \ + .array_length = ETH_RX_QUEUE_LEN(n), \ + .p_descriptor_array = eth##n##_rx_desc_array##idx, \ + .p_ts_descriptor_array = NULL, \ + .ports = 1 << DT_INST_PROP(n, channel), \ + .type = LAYER3_SWITCH_QUEUE_TYPE_RX, \ + .write_back_mode = LAYER3_SWITCH_WRITE_BACK_MODE_FULL, \ + .descriptor_format = LAYER3_SWITCH_DISCRIPTOR_FORMTAT_EXTENDED, \ + .rx_timestamp_storage = \ + LAYER3_SWITCH_RX_TIMESTAMP_STORAGE_DISABLE, \ + }, \ + } + +/* Buffer configuration for device data */ +#if defined(CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY) +#define ETH_RENESAS_RA_DATA_BUF_MODE ETHER_ZEROCOPY_ENABLE +#define ETH_TX_BUF_HEADER_DECLARE(idx, n) \ + { \ + .buf = ETH_TX_BUF_PTR_DECLARE(idx, n), \ + } +#define ETH_RENESAS_RA_DATA_BUF_DECLARE(n) \ + struct eth_renesas_ra_buf_header eth##n##_tx_buf_header[] = { \ + LISTIFY(ETH_TX_BUF_NUM(n), ETH_TX_BUF_HEADER_DECLARE, (,), n), \ + } +#define ETH_RENESAS_RA_DATA_BUF_PROP_DECLARE(n) \ + .tx_buf_header = eth##n##_tx_buf_header, .tx_buf_idx = 0, .tx_buf_num = ETH_TX_BUF_NUM(n) +#else /* CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY */ +#define ETH_RENESAS_RA_DATA_BUF_MODE ETHER_ZEROCOPY_DISABLE +#define ETH_RENESAS_RA_DATA_BUF_DECLARE(n) \ + static uint8_t eth##n##_rx_frame[ETH_BUF_SIZE]; \ + static uint8_t eth##n##_tx_frame[ETH_BUF_SIZE]; +#define ETH_RENESAS_RA_DATA_BUF_PROP_DECLARE(n) \ + .rx_frame = eth##n##_rx_frame, .tx_frame = eth##n##_tx_frame +#endif /* CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY */ + +#define ETH_RENESAS_RA_INIT(n) \ + BUILD_ASSERT(DT_INST_PROP(n, channel) <= BSP_FEATURE_ETHER_NUM_CHANNELS); \ + BUILD_ASSERT( \ + (ETH_TX_QUEUE_NUM(n) + ETH_RX_QUEUE_NUM(n) <= \ + LAYER3_SWITCH_CFG_AVAILABLE_QUEUE_NUM) && \ + (LAYER3_SWITCH_CFG_AVAILABLE_QUEUE_NUM < BSP_FEATURE_ESWM_MAX_QUEUE_NUM), \ + "invalid queue settings"); \ + BUILD_ASSERT(ETH_DESC_NUM(n) <= ETH_BUF_NUM(n), "invalid buffer settings"); \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + LISTIFY(ETH_RX_BUF_NUM(n), ETH_RX_BUF_DECLARE, (), n); \ + LISTIFY(ETH_TX_BUF_NUM(n), ETH_TX_BUF_DECLARE, (), n); \ + static uint8_t *eth##n##_pp_buffers[] = { \ + LISTIFY(ETH_RX_BUF_NUM(n), ETH_RX_BUF_PTR_DECLARE, (,), n), \ + LISTIFY(ETH_TX_BUF_NUM(n), ETH_TX_BUF_PTR_DECLARE, (,), n), \ + }; \ + \ + LISTIFY(ETH_RX_QUEUE_NUM(n), ETH_RX_DESC_DECLARE, (), n); \ + LISTIFY(ETH_TX_QUEUE_NUM(n), ETH_TX_DESC_DECLARE, (), n); \ + static rmac_queue_info_t eth##n##_rx_queue_list[ETH_RX_QUEUE_NUM(n)] = { \ + LISTIFY(ETH_RX_QUEUE_NUM(n), ETH_RX_QUEUE_DECLARE, (,), n), \ + }; \ + static rmac_queue_info_t eth##n##_tx_queue_list[ETH_TX_QUEUE_NUM(n)] = { \ + LISTIFY(ETH_TX_QUEUE_NUM(n), ETH_TX_QUEUE_DECLARE, (,), n), \ + }; \ + static rmac_buffer_node_t eth##n##_buffer_node_list[ETH_BUF_NUM(n)]; \ + ETH_RENESAS_RA_DATA_BUF_DECLARE(n); \ + \ + static rmac_instance_ctrl_t eth##n##_ctrl; \ + static rmac_extended_cfg_t eth##n##_ext_cfg = { \ + .p_ether_switch = &eswm_inst, \ + .tx_queue_num = ETH_TX_QUEUE_NUM(n), \ + .rx_queue_num = ETH_RX_QUEUE_NUM(n), \ + .p_tx_queue_list = eth##n##_tx_queue_list, \ + .p_rx_queue_list = eth##n##_rx_queue_list, \ + .p_buffer_node_list = eth##n##_buffer_node_list, \ + .buffer_node_num = ETH_BUF_NUM(n), \ + .rmpi_irq = FSP_INVALID_VECTOR, \ + .rmpi_ipl = BSP_IRQ_DISABLED, \ + }; \ + static ether_cfg_t eth##n##_cfg = { \ + .channel = DT_INST_PROP(n, channel), \ + .num_tx_descriptors = ETH_TX_BUF_NUM(n), \ + .num_rx_descriptors = ETH_RX_BUF_NUM(n), \ + .pp_ether_buffers = eth##n##_pp_buffers, \ + .ether_buffer_size = ETH_BUF_SIZE, \ + .padding = ETHER_PADDING_DISABLE, \ + .zerocopy = ETH_RENESAS_RA_DATA_BUF_MODE, \ + .multicast = ETHER_MULTICAST_ENABLE, \ + .promiscuous = ETHER_PROMISCUOUS_DISABLE, \ + .flow_control = ETHER_FLOW_CONTROL_DISABLE, \ + .p_callback = ð_rmac_cb, \ + .p_context = (void *)DEVICE_DT_INST_GET(n), \ + .p_extend = ð##n##_ext_cfg, \ + }; \ + static struct eth_renesas_ra_data eth##n##_renesas_ra_data = { \ + .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ + .fsp_ctrl = ð##n##_ctrl, \ + .fsp_cfg = ð##n##_cfg, \ + ETH_RENESAS_RA_DATA_BUF_PROP_DECLARE(n)}; \ + static struct eth_renesas_ra_config eth##n##_renesas_ra_config = { \ + .random_mac = DT_INST_PROP(n, zephyr_random_mac_address), \ + .valid_mac = NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)), \ + .mii_type = ETH_PHY_CONN_TYPE(n), \ + .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \ + .phy_clock = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_clock)), \ + .phy_clock_type = ETH_PHY_CLOCK_TYPE(n), \ + }; \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, renesas_ra_eth_init, NULL, ð##n##_renesas_ra_data, \ + ð##n##_renesas_ra_config, CONFIG_ETH_INIT_PRIORITY, \ + ð_renesas_ra_api, NET_ETH_MTU /*MTU*/); + +DT_INST_FOREACH_STATUS_OKAY(ETH_RENESAS_RA_INIT); diff --git a/dts/bindings/ethernet/renesas,ra-eswm.yaml b/dts/bindings/ethernet/renesas,ra-eswm.yaml new file mode 100644 index 0000000000000..12647e30e5820 --- /dev/null +++ b/dts/bindings/ethernet/renesas,ra-eswm.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA Ethernet MAC Controller + +compatible: "renesas,ra-eswm" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + interrupts: + required: true + + clocks: + required: true + + clock-names: + required: true + enum: + - "gwcaclk" + - "pclk" + - "eswclk" + - "eswphyclk" + - "ethphyclk" + description: | + Clocks must be given corresponding names so that the shim driver can recognize them. + "gwcaclk": operating clock for gateway CPU agent + "pclk": peripheral clock for COMA and PTP timer + "eswclk": operating clock for ethernet switch module + "eswphyclk": operating clock for xMII interface + "ethphyclk": operating clock for ETHPHYLCK pin output. Enable this clock if any PHY + device use ETHPHYCLK pin output as clock source. diff --git a/dts/bindings/ethernet/renesas,ra-ethernet-rmac.yaml b/dts/bindings/ethernet/renesas,ra-ethernet-rmac.yaml new file mode 100644 index 0000000000000..55fdab77d317b --- /dev/null +++ b/dts/bindings/ethernet/renesas,ra-ethernet-rmac.yaml @@ -0,0 +1,67 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA Ethernet MAC Controller + +compatible: "renesas,ra-ethernet-rmac" + +include: [ethernet-controller.yaml, pinctrl-device.yaml] + +properties: + channel: + type: int + required: true + + phy-handle: + required: true + + phy-clock: + type: phandle + required: true + description: | + Specifies the reference clock node for PHY device. + + phy-clock-type: + type: string + required: true + enum: + - "xtal" + - "internal" + description: | + Specifies the clock type of reference clock: + "xtal": use xtal as clock source + "internal": use ETHPHYCLK pin output as clock source + + txq-num: + type: int + default: 2 + description: Number of TX queues + + rxq-num: + type: int + default: 2 + description: Number of RX queues + + txq-len: + type: int + default: 4 + description: | + Number of descriptors in each TX queue + + rxq-len: + type: int + default: 4 + description: | + Number of descriptors in each RX queue + + txb-num: + type: int + default: 12 + description: | + Number of TX buffers + + rxb-num: + type: int + default: 12 + description: | + Number of RX buffers diff --git a/include/zephyr/drivers/clock_control/renesas_ra_cgc.h b/include/zephyr/drivers/clock_control/renesas_ra_cgc.h index 4482bd000a6ee..a3c5c84a73620 100644 --- a/include/zephyr/drivers/clock_control/renesas_ra_cgc.h +++ b/include/zephyr/drivers/clock_control/renesas_ra_cgc.h @@ -31,6 +31,9 @@ #define RA_CGC_DIV_CPUCLK(n) UTIL_CAT(BSP_CLOCKS_SYS_CLOCK_DIV_, n) #define RA_CGC_DIV_FCLK(n) UTIL_CAT(BSP_CLOCKS_SYS_CLOCK_DIV_, n) #define RA_CGC_DIV_I3CCLK(n) UTIL_CAT(BSP_CLOCKS_I3C_CLOCK_DIV_, n) +#define RA_CGC_DIV_ESWCLK(n) UTIL_CAT(BSP_CLOCKS_ESW_CLOCK_DIV_, n) +#define RA_CGC_DIV_ESWPHYCLK(n) UTIL_CAT(BSP_CLOCKS_ESWPHY_CLOCK_DIV_, n) +#define RA_CGC_DIV_ETHPHYCLK(n) UTIL_CAT(BSP_CLOCKS_ETHPHY_CLOCK_DIV_, n) #define RA_CGC_DIV_ICLK(n) UTIL_CAT(BSP_CLOCKS_SYS_CLOCK_DIV_, n) #define RA_CGC_DIV_LCDCLK(n) UTIL_CAT(BSP_CLOCKS_LCD_CLOCK_DIV_, n) #define RA_CGC_DIV_OCTASPICLK(n) UTIL_CAT(BSP_CLOCKS_OCTA_CLOCK_DIV_, n) diff --git a/include/zephyr/drivers/ethernet/eth_renesas_ra_rmac.h b/include/zephyr/drivers/ethernet/eth_renesas_ra_rmac.h new file mode 100644 index 0000000000000..47b6e96dff11d --- /dev/null +++ b/include/zephyr/drivers/ethernet/eth_renesas_ra_rmac.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ETH_RENESAS_RA_RMAC_H__ +#define ZEPHYR_INCLUDE_DRIVERS_ETH_RENESAS_RA_RMAC_H__ + +#include +#include "r_rmac_phy.h" + +/* Organizationally Unique Identifier for MAC */ +#define RENESAS_OUI_B0 0x74 +#define RENESAS_OUI_B1 0x90 +#define RENESAS_OUI_B2 0x50 + +#define RENESAS_RA_MPIC_LSC_10 0 +#define RENESAS_RA_MPIC_LSC_100 1 +#define RENESAS_RA_MPIC_LSC_1000 2 + +#define RENESAS_RA_ETHA_DISABLE_MODE 1 +#define RENESAS_RA_ETHA_CONFIG_MODE 2 +#define RENESAS_RA_ETHA_OPERATION_MODE 3 + +extern uint8_t r_rmac_phy_get_operation_mode(rmac_phy_instance_ctrl_t *p_instance_ctrl); +extern void r_rmac_phy_set_operation_mode(uint8_t channel, uint8_t mode); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ETH_RENESAS_RA_RMAC_H__ */ diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h index 70fe975e8be18..5c36118bb04c2 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h @@ -34,6 +34,7 @@ #define RA_PSEL_I2C 0x7 #define RA_PSEL_I3C 0x7 #define RA_PSEL_CLKOUT_RTC 0x9 +#define RA_PSEL_ETHPHYCLK 0x9 #define RA_PSEL_ACMPHS_VCOUT 0x9 #define RA_PSEL_CAC_ADC 0xa #define RA_PSEL_CAC_DAC 0xa @@ -46,6 +47,7 @@ #define RA_PSEL_SDHI 0x15 #define RA_PSEL_ETH_MII 0x16 #define RA_PSEL_ETH_RMII 0x17 +#define RA_PSEL_ETH_RGMII 0x18 #define RA_PSEL_GLCDC 0x19 #define RA_PSEL_OSPI 0x1c #define RA_PSEL_CTSU 0x0c diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 5b6fd648534d8..715affece70af 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -181,6 +181,21 @@ config USE_RA_FSP_ETHER help Enable RA FSP Ethernet driver +config USE_RA_FSP_RMAC_PHY + bool + help + Enable RA FSP Ethernet RMAC phy driver + +config USE_RA_FSP_RMAC + bool + help + Enable RA FSP Ethernet RMAC driver + +config USE_RA_FSP_LAYER3_SWITCH + bool + help + Enable RA FSP Ethernet Layer3 Switch driver + config USE_RA_FSP_USB_DEVICE bool help From 4a3078e182c9bb6b3e84956a8a77da4a7b2c3a3a Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Fri, 24 Oct 2025 14:34:49 +0700 Subject: [PATCH 4/8] drivers: ethernet: Put DMA buffer to nocache This commit put ethernet buffers and descriptors to nocache . Signed-off-by: Nhat Ta --- drivers/ethernet/eth_renesas_ra_rmac.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/ethernet/eth_renesas_ra_rmac.c b/drivers/ethernet/eth_renesas_ra_rmac.c index 60ce80bbc7fac..bb1ec690a4e70 100644 --- a/drivers/ethernet/eth_renesas_ra_rmac.c +++ b/drivers/ethernet/eth_renesas_ra_rmac.c @@ -25,6 +25,14 @@ LOG_MODULE_REGISTER(eth_renesas_ra, CONFIG_ETHERNET_LOG_LEVEL); /* At this time , HAL only support single descriptor, set fixed buffer length */ #define ETH_BUF_SIZE (1536) +#if defined(CONFIG_NOCACHE_MEMORY) +#define __eth_renesas_desc __nocache __aligned(32) +#define __eth_renesas_buf __nocache __aligned(32) +#else /* CONFIG_NOCACHE_MEMORY */ +#define __eth_renesas_desc +#define __eth_renesas_buf +#endif /* CONFIG_NOCACHE_MEMORY */ + #define ETHPHYCLK_25MHZ MHZ(25) #define ETHPHYCLK_50MHZ MHZ(50) @@ -592,16 +600,20 @@ DEVICE_DT_INST_DEFINE(0, renesas_ra_eswm_init, NULL, &eswm_data, &eswm_config, P : ETH_PHY_REF_CLK_INTERNAL /* Buffers declare */ -#define ETH_TX_BUF_DECLARE(idx, n) static uint8_t eth##n##_tx_buf##idx[ETH_BUF_SIZE]; -#define ETH_RX_BUF_DECLARE(idx, n) static uint8_t eth##n##_rx_buf##idx[ETH_BUF_SIZE]; +#define ETH_TX_BUF_DECLARE(idx, n) \ + static uint8_t eth##n##_tx_buf##idx[ETH_BUF_SIZE] __eth_renesas_buf; +#define ETH_RX_BUF_DECLARE(idx, n) \ + static uint8_t eth##n##_rx_buf##idx[ETH_BUF_SIZE] __eth_renesas_buf; #define ETH_TX_BUF_PTR_DECLARE(idx, n) (uint8_t *)ð##n##_tx_buf##idx[0] #define ETH_RX_BUF_PTR_DECLARE(idx, n) (uint8_t *)ð##n##_rx_buf##idx[0] /* Descriptors declare */ #define ETH_TX_DESC_DECLARE(idx, n) \ - static layer3_switch_descriptor_t eth##n##_tx_desc_array##idx[ETH_TX_BUF_NUM(n)]; + static layer3_switch_descriptor_t \ + eth##n##_tx_desc_array##idx[ETH_TX_BUF_NUM(n)] __eth_renesas_desc; #define ETH_RX_DESC_DECLARE(idx, n) \ - static layer3_switch_descriptor_t eth##n##_rx_desc_array##idx[ETH_RX_BUF_NUM(n)]; + static layer3_switch_descriptor_t \ + eth##n##_rx_desc_array##idx[ETH_RX_BUF_NUM(n)] __eth_renesas_desc; /* Queues declare */ #define ETH_TX_QUEUE_DECLARE(idx, n) \ @@ -651,8 +663,8 @@ DEVICE_DT_INST_DEFINE(0, renesas_ra_eswm_init, NULL, &eswm_data, &eswm_config, P #else /* CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY */ #define ETH_RENESAS_RA_DATA_BUF_MODE ETHER_ZEROCOPY_DISABLE #define ETH_RENESAS_RA_DATA_BUF_DECLARE(n) \ - static uint8_t eth##n##_rx_frame[ETH_BUF_SIZE]; \ - static uint8_t eth##n##_tx_frame[ETH_BUF_SIZE]; + static uint8_t eth##n##_rx_frame[ETH_BUF_SIZE] __eth_renesas_buf; \ + static uint8_t eth##n##_tx_frame[ETH_BUF_SIZE] __eth_renesas_buf; #define ETH_RENESAS_RA_DATA_BUF_PROP_DECLARE(n) \ .rx_frame = eth##n##_rx_frame, .tx_frame = eth##n##_tx_frame #endif /* CONFIG_ETH_RENESAS_RA_USE_ZERO_COPY */ From e4c4c95ebc7f43b10fef940ef55d20060b50d3bd Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Mon, 6 Oct 2025 15:43:50 +0700 Subject: [PATCH 5/8] drivers: mdio: initial support for mdio rmac driver This commit add mdio driver support for ra8x2. Signed-off-by: Nhat Ta --- drivers/mdio/CMakeLists.txt | 1 + drivers/mdio/Kconfig.renesas_ra | 29 ++- drivers/mdio/mdio_renesas_ra_rmac.c | 195 ++++++++++++++++++++ dts/bindings/mdio/renesas,ra-mdio-rmac.yaml | 29 +++ 4 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 drivers/mdio/mdio_renesas_ra_rmac.c create mode 100644 dts/bindings/mdio/renesas,ra-mdio-rmac.yaml diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 8e92204037f6a..168ccb07d78d6 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -20,6 +20,7 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_IMX_NETC mdio_nxp_imx_netc.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_GMAC mdio_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_NETC mdio_nxp_s32_netc.c) zephyr_library_sources_ifdef(CONFIG_MDIO_RENESAS_RA mdio_renesas_ra.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_RENESAS_RA_RMAC mdio_renesas_ra_rmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_SENSRY_SY1XX mdio_sy1xx.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ST_STM32_HAL mdio_stm32_hal.c) zephyr_library_sources_ifdef(CONFIG_MDIO_XILINX_AXI_ENET mdio_xilinx_axienet.c) diff --git a/drivers/mdio/Kconfig.renesas_ra b/drivers/mdio/Kconfig.renesas_ra index 9702bf9b2b465..78a51412d4616 100644 --- a/drivers/mdio/Kconfig.renesas_ra +++ b/drivers/mdio/Kconfig.renesas_ra @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Renesas Electronics Corporation +# Copyright (c) 2024-2025 Renesas Electronics Corporation # SPDX-License-Identifier: Apache-2.0 config MDIO_RENESAS_RA @@ -9,3 +9,30 @@ config MDIO_RENESAS_RA select USE_RA_FSP_ETHER_PHY help Enable RENESAS MDIO support. + +config MDIO_RENESAS_RA_RMAC + bool "RENESAS MDIO RMAC controller driver" + default y + depends on DT_HAS_RENESAS_RA_MDIO_RMAC_ENABLED + select PINCTRL + select USE_RA_FSP_RMAC_PHY + help + Enable RENESAS MDIO RMAC support. + +if MDIO_RENESAS_RA_RMAC + +config MDIO_RENESAS_RA_RMAC_MDIO_HOLD_NS + int "MDIO hold time" + default 0 + help + Time for changing MDO after rising edge of MDC in nanoseconds. + This value depends on PHY chip AC Characteristics. Use 0 to disable. + +config MDIO_RENESAS_RA_RMAC_MDIO_CAPTURE_NS + int "MDIO capture time" + default 0 + help + Time for capturing MDI after rising edge of MDC in nanoseconds. + This value depends on PHY chip AC Characteristics. Use 0 to disable. + +endif diff --git a/drivers/mdio/mdio_renesas_ra_rmac.c b/drivers/mdio/mdio_renesas_ra_rmac.c new file mode 100644 index 0000000000000..3c5ff389f64b0 --- /dev/null +++ b/drivers/mdio/mdio_renesas_ra_rmac.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "r_rmac_phy.h" + +#include + +LOG_MODULE_REGISTER(renesas_ra_mdio, CONFIG_MDIO_LOG_LEVEL); + +#define DT_DRV_COMPAT renesas_ra_mdio_rmac + +struct mdio_renesas_ra_config { + const struct device *eswclk_dev; + const struct pinctrl_dev_config *pincfg; +}; + +struct mdio_renesas_ra_data { + struct k_mutex rw_lock; + rmac_phy_instance_ctrl_t fsp_ctrl; + ether_phy_cfg_t fsp_cfg; +}; + +static int mdio_renesas_ra_get_port(const struct device *dev, uint8_t prtad, uint8_t *port) +{ + struct mdio_renesas_ra_data *data = dev->data; + rmac_phy_extended_cfg_t *p_extend = + (rmac_phy_extended_cfg_t *)data->fsp_ctrl.p_ether_phy_cfg->p_extend; + + for (int i = 0; i < BSP_FEATURE_ETHER_NUM_CHANNELS; i++) { + if (p_extend->p_phy_lsi_cfg_list[i]->address == prtad) { + *port = i; + return 0; + } + } + + return -ENXIO; +} + +static int mdio_renesas_ra_read(const struct device *dev, uint8_t prtad, uint8_t regad, + uint16_t *regval) +{ + struct mdio_renesas_ra_data *data = dev->data; + fsp_err_t fsp_err = FSP_SUCCESS; + uint32_t val = 0; + uint8_t port; + int ret; + + ret = r_rmac_phy_get_operation_mode(&data->fsp_ctrl); + if (ret != RENESAS_RA_ETHA_OPERATION_MODE) { + return -EACCES; + } + + ret = mdio_renesas_ra_get_port(dev, prtad, &port); + if (ret < 0) { + return ret; + } + + k_mutex_lock(&data->rw_lock, K_FOREVER); + + R_RMAC_PHY_ChipSelect(&data->fsp_ctrl, port); + fsp_err = R_RMAC_PHY_Read(&data->fsp_ctrl, regad, &val); + ret = (fsp_err == FSP_SUCCESS) ? 0 : -EIO; + + *regval = val & UINT16_MAX; + + k_mutex_unlock(&data->rw_lock); + + return ret; +} + +static int mdio_renesas_ra_write(const struct device *dev, uint8_t prtad, uint8_t regad, + uint16_t regval) +{ + struct mdio_renesas_ra_data *data = dev->data; + fsp_err_t fsp_err = FSP_SUCCESS; + uint8_t port; + int ret; + + ret = r_rmac_phy_get_operation_mode(&data->fsp_ctrl); + if (ret != RENESAS_RA_ETHA_OPERATION_MODE) { + return -EACCES; + } + + ret = mdio_renesas_ra_get_port(dev, prtad, &port); + if (ret < 0) { + return ret; + } + + k_mutex_lock(&data->rw_lock, K_FOREVER); + + R_RMAC_PHY_ChipSelect(&data->fsp_ctrl, port); + fsp_err = R_RMAC_PHY_Write(&data->fsp_ctrl, regad, (uint32_t)regval); + ret = (fsp_err == FSP_SUCCESS) ? 0 : -EIO; + + k_mutex_unlock(&data->rw_lock); + + return ret; +} + +static int mdio_renesas_ra_initialize(const struct device *dev) +{ + struct mdio_renesas_ra_data *data = dev->data; + const struct mdio_renesas_ra_config *config = dev->config; + rmac_phy_extended_cfg_t *p_extend = (rmac_phy_extended_cfg_t *)data->fsp_cfg.p_extend; + uint32_t eswclk; + fsp_err_t fsp_err = FSP_SUCCESS; + int ret = 0; + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + ret = clock_control_get_rate(config->eswclk_dev, NULL, &eswclk); + if (ret < 0) { + return ret; + } + + p_extend->mdio_hold_time = + DIV_ROUND_UP(eswclk * CONFIG_MDIO_RENESAS_RA_RMAC_MDIO_HOLD_NS, 1e9); + p_extend->mdio_capture_time = + DIV_ROUND_UP(eswclk * CONFIG_MDIO_RENESAS_RA_RMAC_MDIO_CAPTURE_NS, 1e9); + + fsp_err = R_RMAC_PHY_Open(&data->fsp_ctrl, &data->fsp_cfg); + if (fsp_err != FSP_SUCCESS) { + LOG_ERR("Failed to init mdio driver - R_RMAC_PHY_Open fail, err=%d", fsp_err); + return -EIO; + } + + k_mutex_init(&data->rw_lock); + + return 0; +} + +static DEVICE_API(mdio, mdio_renesas_ra_api) = { + .read = mdio_renesas_ra_read, + .write = mdio_renesas_ra_write, +}; + +#define PHY_CONFIG_DEFINE(id) \ + static ether_phy_lsi_cfg_t phy_cfg_list##id = {.address = DT_REG_ADDR(id), \ + .type = ETHER_PHY_LSI_TYPE_CUSTOM}; +#define PHY_CONFIG_PTR_DECLARE(id) &phy_cfg_list##id, + +#define PHY_CONNECTION_TYPE(n) \ + ((DT_INST_ENUM_HAS_VALUE(n, phy_connection_type, rgmii) \ + ? ETHER_PHY_MII_TYPE_RGMII \ + : (DT_INST_ENUM_HAS_VALUE(n, phy_connection_type, gmii) \ + ? ETHER_PHY_MII_TYPE_GMII \ + : (DT_INST_ENUM_HAS_VALUE(n, phy_connection_type, rmii) \ + ? ETHER_PHY_MII_TYPE_RMII \ + : ETHER_PHY_MII_TYPE_MII)))) + +#define RENSAS_RA_MDIO_RMAC_DEFINE(n) \ + BUILD_ASSERT(DT_INST_CHILD_NUM(n) <= BSP_FEATURE_ETHER_NUM_CHANNELS); \ + PINCTRL_DT_INST_DEFINE(n); \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PHY_CONFIG_DEFINE); \ + \ + static rmac_phy_extended_cfg_t renesas_ra_mdio##n##_p_extend = { \ + .frame_format = RMAC_PHY_FRAME_FORMAT_MDIO, \ + .mdc_clock_rate = DT_INST_PROP(n, clock_frequency), \ + .p_phy_lsi_cfg_list = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(n, PHY_CONFIG_PTR_DECLARE)}}; \ + \ + static struct mdio_renesas_ra_data renesas_ra_mdio##n##_data = { \ + .fsp_cfg = \ + { \ + .channel = DT_INST_PROP(n, channel), \ + .flow_control = ETHER_PHY_FLOW_CONTROL_DISABLE, \ + .mii_type = PHY_CONNECTION_TYPE(n), \ + .p_extend = &renesas_ra_mdio##n##_p_extend, \ + }, \ + }; \ + static const struct mdio_renesas_ra_config renesas_ra_mdio##n##_cfg = { \ + .eswclk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR_BY_NAME(DT_INST_PARENT(n), eswclk)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &mdio_renesas_ra_initialize, NULL, &renesas_ra_mdio##n##_data, \ + &renesas_ra_mdio##n##_cfg, POST_KERNEL, CONFIG_MDIO_INIT_PRIORITY, \ + &mdio_renesas_ra_api); + +DT_INST_FOREACH_STATUS_OKAY(RENSAS_RA_MDIO_RMAC_DEFINE) diff --git a/dts/bindings/mdio/renesas,ra-mdio-rmac.yaml b/dts/bindings/mdio/renesas,ra-mdio-rmac.yaml new file mode 100644 index 0000000000000..b3fcef41fd5fd --- /dev/null +++ b/dts/bindings/mdio/renesas,ra-mdio-rmac.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA External MDIO controller + +compatible: "renesas,ra-mdio-rmac" + +include: [mdio-controller.yaml, pinctrl-device.yaml] + +properties: + channel: + type: int + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + phy-connection-type: + type: string + description: | + Specifies the interface connection type between ethernet MAC and PHY. + enum: + - "mii" + - "rmii" + - "gmii" + - "rgmii" From fe576c94aac84b0c4b65ae6c85f2c730740c7e12 Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Fri, 24 Oct 2025 14:35:27 +0700 Subject: [PATCH 6/8] dts: arm: renesas: ra: ra8: add Ethernet for ra8x2 This commit define eswm module for ra8x2 that includes ethernet and mdio nodes. Signed-off-by: Nhat Ta --- dts/arm/renesas/ra/ra8/ra8x2.dtsi | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dts/arm/renesas/ra/ra8/ra8x2.dtsi b/dts/arm/renesas/ra/ra8/ra8x2.dtsi index 084d73e22c422..930c82cd9d7ef 100644 --- a/dts/arm/renesas/ra/ra8/ra8x2.dtsi +++ b/dts/arm/renesas/ra/ra8/ra8x2.dtsi @@ -788,6 +788,52 @@ }; }; + eswm: eswm@403c8000 { + compatible = "renesas,ra-eswm"; + reg = <0x403c8000 0x19424>; + clocks = <&iclk 0 0>, + <&pclka MSTPC 30>, + <&eswclk 0 0>, + <&eswphyclk 0 0>, + <ðphyclk MSTPC 28>; + clock-names = "gwcaclk", "pclk", "eswclk", "eswphyclk", "ethphyclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + eth0: ethernet_mac@403cb000 { + compatible = "renesas,ra-ethernet-rmac"; + reg = <0x403cb000 0x530>; + channel = <0>; + status = "disabled"; + }; + + eth1: ethernet_mac@403cd000 { + compatible = "renesas,ra-ethernet-rmac"; + reg = <0x403cd000 0x530>; + channel = <1>; + status = "disabled"; + }; + + mdio0: mdio@403cb000 { + compatible = "renesas,ra-mdio-rmac"; + reg = <0x403cb000 0x530>; + #address-cells = <1>; + #size-cells = <0>; + channel = <0>; + status = "disabled"; + }; + + mdio1: mdio@403cd000 { + compatible = "renesas,ra-mdio-rmac"; + reg = <0x403cd000 0x530>; + #address-cells = <1>; + #size-cells = <0>; + channel = <1>; + status = "disabled"; + }; + }; + ulpt0: ulpt@40220000 { compatible = "renesas,ra-ulpt"; reg = <0x40220000 0x100>; From 7d1b70e12f946e8e33ab84a0810f91ecc4daf9e5 Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Mon, 6 Oct 2025 15:42:39 +0700 Subject: [PATCH 7/8] drivers: ethernet: phy: add Maxlinear GPY111 phy driver This commit add phy driver support for Maxlinear GPY111. This driver implements vendor specific behaviour rgmii delay time setup, which is not present in the generic MII driver. Signed-off-by: Nhat Ta --- drivers/ethernet/phy/CMakeLists.txt | 1 + drivers/ethernet/phy/Kconfig | 10 + drivers/ethernet/phy/phy_maxlinear_gpy111.c | 631 ++++++++++++++++++ .../ethernet/phy/maxlinear,gpy111.yaml | 74 ++ dts/bindings/vendor-prefixes.txt | 1 + 5 files changed, 717 insertions(+) create mode 100644 drivers/ethernet/phy/phy_maxlinear_gpy111.c create mode 100644 dts/bindings/ethernet/phy/maxlinear,gpy111.yaml diff --git a/drivers/ethernet/phy/CMakeLists.txt b/drivers/ethernet/phy/CMakeLists.txt index dc926c54adab4..270b40b092ee9 100644 --- a/drivers/ethernet/phy/CMakeLists.txt +++ b/drivers/ethernet/phy/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources_ifdef(CONFIG_PHY_GENERIC_FIXED_LINK phy_fixed_link.c) # zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_PHY_ADIN2111 phy_adin2111.c) zephyr_library_sources_ifdef(CONFIG_PHY_DM8806 phy_dm8806.c) +zephyr_library_sources_ifdef(CONFIG_PHY_MAXLINEAR_GPY111 phy_maxlinear_gpy111.c) zephyr_library_sources_ifdef(CONFIG_PHY_MICROCHIP_KSZ8081 phy_microchip_ksz8081.c) zephyr_library_sources_ifdef(CONFIG_PHY_MICROCHIP_KSZ9131 phy_microchip_ksz9131.c) zephyr_library_sources_ifdef(CONFIG_PHY_MICROCHIP_LAN8742 phy_microchip_lan8742.c) diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index 4cc0f5cdc898c..6b6c5a9a4d791 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -134,6 +134,16 @@ config PHY_QUALCOMM_AR8031 help Enable Qualcomm Atheros AR8031 Ethernet PHY Driver +config PHY_MAXLINEAR_GPY111 + bool "Maxlinear GPY111 PHY Driver" + default y + depends on DT_HAS_MAXLINEAR_GPY111_ENABLED + select MDIO + select GPIO if ($(dt_compat_any_has_prop,$(DT_COMPAT_MAXLINEAR_GPY111),reset-gpios) || \ + $(dt_compat_any_has_prop,$(DT_COMPAT_MAXLINEAR_GPY111),int-gpios)) + help + Enable Maxlinear GPY111 Ethernet PHY Driver + config PHY_AUTONEG_TIMEOUT_MS int "Auto-negotiation timeout value in milliseconds" default 4000 diff --git a/drivers/ethernet/phy/phy_maxlinear_gpy111.c b/drivers/ethernet/phy/phy_maxlinear_gpy111.c new file mode 100644 index 0000000000000..ff1c4ba28fdcd --- /dev/null +++ b/drivers/ethernet/phy/phy_maxlinear_gpy111.c @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * Inspiration from phy_mii.c, which is: + * Copyright (c) 2021 IP-Logix Inc. + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxlinear_gpy111 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(phy_mxl_gpy111, CONFIG_PHY_LOG_LEVEL); + +#include "phy_mii.h" + +#define GPY111_MIICTRL 0x17 +#define GPY111_MIICTRL_RX_SKEW_MASK GENMASK(14, 12) +#define GPY111_MIICTRL_RX_SKEW_POS 12 +#define GPY111_MIICTRL_RX_SKEW_DEFAULT 0x8 +#define GPY111_MIICTRL_TX_SKEW_MASK GENMASK(10, 8) +#define GPY111_MIICTRL_TX_SKEW_POS 8 +#define GPY111_MIICTRL_TX_SKEW_DEFAULT 0x8 + +#define ANY_INT_GPIO DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios) +#define ANY_RESET_GPIO DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) + +enum gpy111_interface { + GPY111_RGMII, + GPY111_GMII, +}; + +struct maxlinear_gpy111_dev_config { + uint8_t phy_addr; + bool no_reset; + enum gpy111_interface mii_type; + enum phy_link_speed default_speeds; + const struct device *const mdio; + uint8_t rx_skew; + uint8_t tx_skew; +#if ANY_RESET_GPIO + const struct gpio_dt_spec reset_gpio; + uint32_t reset_assert_duration_us; + uint32_t reset_deassertion_timeout_ms; +#endif /* ANY_RESET_GPIO */ +#if ANY_INT_GPIO + const struct gpio_dt_spec int_gpio; +#endif /* ANY_INT_GPIO */ +}; + +struct maxlinear_gpy111_dev_data { + const struct device *dev; + phy_callback_t cb; + void *cb_data; + struct phy_link_state state; + struct k_sem sem; + struct k_work_delayable monitor_work; + bool gigabit_supported; + bool autoneg_in_progress; + k_timepoint_t autoneg_timeout; +}; + +/* Offset to align capabilities bits of 1000BASE-T Control and Status regs */ +#define MII_1KSTSR_OFFSET 2 + +#define MII_INVALID_PHY_ID UINT32_MAX + +/* How often to poll auto-negotiation status while waiting for it to complete */ +#define MII_AUTONEG_POLL_INTERVAL_MS 100 + +static void invoke_link_cb(const struct device *dev); +static int phy_gpy111_config_link(const struct device *dev, enum phy_link_speed adv_speeds, + enum phy_cfg_link_flag flags); + +static int check_autonegotiation_completion(const struct device *dev); + +static inline int maxlinear_gpy111_reg_read(const struct device *dev, uint16_t reg_addr, + uint16_t *value) +{ + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + + return mdio_read(cfg->mdio, cfg->phy_addr, reg_addr, value); +} + +static inline int maxlinear_gpy111_reg_write(const struct device *dev, uint16_t reg_addr, + uint16_t value) +{ + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + + return mdio_write(cfg->mdio, cfg->phy_addr, reg_addr, value); +} + +static int read_gigabit_supported_flag(const struct device *dev, bool *supported) +{ + uint16_t bmsr_reg; + uint16_t estat_reg; + + if (maxlinear_gpy111_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { + return -EIO; + } + + if ((bmsr_reg & MII_BMSR_EXTEND_STATUS) != 0U) { + if (maxlinear_gpy111_reg_read(dev, MII_ESTAT, &estat_reg) < 0) { + return -EIO; + } + + if ((estat_reg & (MII_ESTAT_1000BASE_T_HALF | MII_ESTAT_1000BASE_T_FULL)) != 0U) { + *supported = true; + return 0; + } + } + + *supported = false; + return 0; +} + +static void phy_gpy111_config_mii(const struct device *dev) +{ + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + uint16_t miictrl; + int ret; + + if (cfg->mii_type != GPY111_RGMII) { + return; + } + + ret = maxlinear_gpy111_reg_read(dev, GPY111_MIICTRL, &miictrl); + if (ret < 0) { + return; + } + + if (cfg->rx_skew != GPY111_MIICTRL_RX_SKEW_DEFAULT) { + miictrl = (miictrl & ~(GPY111_MIICTRL_RX_SKEW_MASK)) | + (cfg->rx_skew << GPY111_MIICTRL_RX_SKEW_POS); + } + if (cfg->tx_skew != GPY111_MIICTRL_TX_SKEW_DEFAULT) { + miictrl = (miictrl & ~(GPY111_MIICTRL_TX_SKEW_MASK)) | + (cfg->tx_skew << GPY111_MIICTRL_TX_SKEW_POS); + } + + maxlinear_gpy111_reg_write(dev, GPY111_MIICTRL, miictrl); +} + +static int reset(const struct device *dev) +{ + uint32_t timeout = 12U; + uint16_t value; + +#if ANY_RESET_GPIO + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + int ret; + + if (gpio_is_ready_dt(&cfg->reset_gpio)) { + /* Issue a hard reset */ + ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to configure RST pin (%d)", ret); + return ret; + } + + /* assertion time */ + k_busy_wait(cfg->reset_assert_duration_us); + + ret = gpio_pin_set_dt(&cfg->reset_gpio, 0); + if (ret < 0) { + LOG_ERR("Failed to de-assert RST pin (%d)", ret); + return ret; + } + + k_msleep(cfg->reset_deassertion_timeout_ms); + + return 0; + } +#endif /* ANY_RESET_GPIO */ + + /* Issue a soft reset */ + if (maxlinear_gpy111_reg_write(dev, MII_BMCR, MII_BMCR_RESET) < 0) { + return -EIO; + } + + /* Wait up to 0.6s for the reset sequence to finish. According to + * IEEE 802.3, Section 2, Subsection 22.2.4.1.1 a PHY reset may take + * up to 0.5 s. + */ + do { + if (timeout-- == 0U) { + return -ETIMEDOUT; + } + + k_sleep(K_MSEC(50)); + + if (maxlinear_gpy111_reg_read(dev, MII_BMCR, &value) < 0) { + return -EIO; + } + } while ((value & MII_BMCR_RESET) != 0U); + + return 0; +} + +static int get_id(const struct device *dev, uint32_t *phy_id) +{ + uint16_t value; + + if (maxlinear_gpy111_reg_read(dev, MII_PHYID1R, &value) < 0) { + return -EIO; + } + + *phy_id = value << 16; + + if (maxlinear_gpy111_reg_read(dev, MII_PHYID2R, &value) < 0) { + return -EIO; + } + + *phy_id |= value; + + return 0; +} + +static int update_link_state(const struct device *dev) +{ + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + struct maxlinear_gpy111_dev_data *const data = dev->data; + bool link_up; + + uint16_t bmcr_reg = 0; + uint16_t bmsr_reg = 0; + + if (maxlinear_gpy111_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { + return -EIO; + } + + link_up = IS_BIT_SET(bmsr_reg, MII_BMSR_LINK_STATUS_BIT); + /* If link is down, we can stop here. */ + if (!link_up) { + data->state.speed = 0; + if (link_up != data->state.is_up) { + data->state.is_up = false; + LOG_INF("PHY (%d) is down", cfg->phy_addr); + return 0; + } + return -EAGAIN; + } + + if (maxlinear_gpy111_reg_read(dev, MII_BMCR, &bmcr_reg) < 0) { + return -EIO; + } + + /* If auto-negotiation is not enabled, we only need to check the link speed */ + if (!IS_BIT_SET(bmcr_reg, MII_BMCR_AUTONEG_ENABLE_BIT)) { + enum phy_link_speed new_speed = phy_mii_get_link_speed_bmcr_reg(dev, bmcr_reg); + + if ((data->state.speed != new_speed) || !data->state.is_up) { + data->state.is_up = true; + data->state.speed = new_speed; + + LOG_INF("PHY (%d) Link speed %s Mb, %s duplex", cfg->phy_addr, + PHY_LINK_IS_SPEED_1000M(data->state.speed) + ? "1000" + : (PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" + : "10"), + PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half"); + + return 0; + } + return -EAGAIN; + } + + /* If auto-negotiation is enabled and the link was already up last time we checked, + * we can return immediately, as the link state has not changed. + * If the link was down, we will start the auto-negotiation sequence. + */ + if (data->state.is_up) { + return -EAGAIN; + } + + data->state.is_up = true; + + LOG_DBG("PHY (%d) Starting MII PHY auto-negotiate sequence", cfg->phy_addr); + + data->autoneg_timeout = sys_timepoint_calc(K_MSEC(CONFIG_PHY_AUTONEG_TIMEOUT_MS)); + + return check_autonegotiation_completion(dev); +} + +static int check_autonegotiation_completion(const struct device *dev) +{ + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + struct maxlinear_gpy111_dev_data *const data = dev->data; + + uint16_t anar_reg = 0; + uint16_t bmsr_reg = 0; + uint16_t anlpar_reg = 0; + uint16_t c1kt_reg = 0; + uint16_t s1kt_reg = 0; + + if (maxlinear_gpy111_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { + return -EIO; + } + + if (!IS_BIT_SET(bmsr_reg, MII_BMSR_AUTONEG_COMPLETE_BIT)) { + if (sys_timepoint_expired(data->autoneg_timeout)) { + LOG_DBG("PHY (%d) auto-negotiate timeout", cfg->phy_addr); + return -ETIMEDOUT; + } + return -EINPROGRESS; + } + + /* Link status bit is latched low, so read it again to get current status */ + if (unlikely(!IS_BIT_SET(bmsr_reg, MII_BMSR_LINK_STATUS_BIT))) { + /* Second read, clears the latched bits and gives the correct status */ + if (maxlinear_gpy111_reg_read(dev, MII_BMSR, &bmsr_reg) < 0) { + return -EIO; + } + + if (!IS_BIT_SET(bmsr_reg, MII_BMSR_LINK_STATUS_BIT)) { + return -EAGAIN; + } + } + + LOG_DBG("PHY (%d) auto-negotiate sequence completed", cfg->phy_addr); + + /* Read PHY default advertising parameters */ + if (maxlinear_gpy111_reg_read(dev, MII_ANAR, &anar_reg) < 0) { + return -EIO; + } + + /** Read peer device capability */ + if (maxlinear_gpy111_reg_read(dev, MII_ANLPAR, &anlpar_reg) < 0) { + return -EIO; + } + + if (data->gigabit_supported) { + if (maxlinear_gpy111_reg_read(dev, MII_1KTCR, &c1kt_reg) < 0) { + return -EIO; + } + if (maxlinear_gpy111_reg_read(dev, MII_1KSTSR, &s1kt_reg) < 0) { + return -EIO; + } + s1kt_reg = (uint16_t)(s1kt_reg >> MII_1KSTSR_OFFSET); + } + + if (data->gigabit_supported && ((c1kt_reg & s1kt_reg & MII_ADVERTISE_1000_FULL) != 0U)) { + data->state.speed = LINK_FULL_1000BASE; + } else if (data->gigabit_supported && + ((c1kt_reg & s1kt_reg & MII_ADVERTISE_1000_HALF) != 0U)) { + data->state.speed = LINK_HALF_1000BASE; + } else if ((anar_reg & anlpar_reg & MII_ADVERTISE_100_FULL) != 0U) { + data->state.speed = LINK_FULL_100BASE; + } else if ((anar_reg & anlpar_reg & MII_ADVERTISE_100_HALF) != 0U) { + data->state.speed = LINK_HALF_100BASE; + } else if ((anar_reg & anlpar_reg & MII_ADVERTISE_10_FULL) != 0U) { + data->state.speed = LINK_FULL_10BASE; + } else { + data->state.speed = LINK_HALF_10BASE; + } + + data->state.is_up = true; + + LOG_INF("PHY (%d) Link speed %s Mb, %s duplex", cfg->phy_addr, + PHY_LINK_IS_SPEED_1000M(data->state.speed) + ? "1000" + : (PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half"); + + return 0; +} + +static void monitor_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct maxlinear_gpy111_dev_data *const data = + CONTAINER_OF(dwork, struct maxlinear_gpy111_dev_data, monitor_work); + const struct device *dev = data->dev; + int rc; + + if (k_sem_take(&data->sem, K_NO_WAIT) == 0) { + if (data->autoneg_in_progress) { + rc = check_autonegotiation_completion(dev); + } else { + /* If autonegotiation is not in progress, just update the link state */ + rc = update_link_state(dev); + } + + data->autoneg_in_progress = (rc == -EINPROGRESS); + + k_sem_give(&data->sem); + + /* If link state has changed and a callback is set, invoke callback */ + if (rc == 0) { + invoke_link_cb(dev); + } + } + + k_work_reschedule(&data->monitor_work, data->autoneg_in_progress + ? K_MSEC(MII_AUTONEG_POLL_INTERVAL_MS) + : K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); +} + +static int maxlinear_gpy111_read(const struct device *dev, uint16_t reg_addr, uint32_t *data) +{ + return maxlinear_gpy111_reg_read(dev, reg_addr, (uint16_t *)data); +} + +static int maxlinear_gpy111_write(const struct device *dev, uint16_t reg_addr, uint32_t data) +{ + return maxlinear_gpy111_reg_write(dev, reg_addr, (uint16_t)data); +} + +static int phy_gpy111_config_link(const struct device *dev, enum phy_link_speed adv_speeds, + enum phy_cfg_link_flag flags) +{ + struct maxlinear_gpy111_dev_data *const data = dev->data; + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + int ret = 0; + + k_sem_take(&data->sem, K_FOREVER); + + if ((flags & PHY_FLAG_AUTO_NEGOTIATION_DISABLED) != 0U) { + /* If auto-negotiation is disabled, only one speed can be selected. + * If gigabit is not supported, this speed must not be 1000M. + */ + if (!data->gigabit_supported && PHY_LINK_IS_SPEED_1000M(adv_speeds)) { + LOG_ERR("PHY (%d) Gigabit not supported, can't configure link", + cfg->phy_addr); + ret = -ENOTSUP; + goto cfg_link_end; + } + + ret = phy_mii_set_bmcr_reg_autoneg_disabled(dev, adv_speeds); + if (ret >= 0) { + data->autoneg_in_progress = false; + k_work_reschedule(&data->monitor_work, K_NO_WAIT); + } + } else { + ret = phy_mii_cfg_link_autoneg(dev, adv_speeds, data->gigabit_supported); + if (ret >= 0) { + LOG_DBG("PHY (%d) Starting MII PHY auto-negotiate sequence", cfg->phy_addr); + data->autoneg_in_progress = true; + data->autoneg_timeout = + sys_timepoint_calc(K_MSEC(CONFIG_PHY_AUTONEG_TIMEOUT_MS)); + k_work_reschedule(&data->monitor_work, + K_MSEC(MII_AUTONEG_POLL_INTERVAL_MS)); + } + } + + if (ret == -EALREADY) { + LOG_DBG("PHY (%d) Link already configured", cfg->phy_addr); + } + +cfg_link_end: + k_sem_give(&data->sem); + + return ret; +} + +static int maxlinear_gpy111_get_link_state(const struct device *dev, struct phy_link_state *state) +{ + struct maxlinear_gpy111_dev_data *const data = dev->data; + + k_sem_take(&data->sem, K_FOREVER); + + memcpy(state, &data->state, sizeof(struct phy_link_state)); + + if (state->speed == 0) { + /* If speed is 0, then link is also down, happens when autonegotiation is in + * progress + */ + state->is_up = false; + } + + k_sem_give(&data->sem); + + return 0; +} + +static void invoke_link_cb(const struct device *dev) +{ + struct maxlinear_gpy111_dev_data *const data = dev->data; + struct phy_link_state state; + + if (data->cb == NULL) { + return; + } + + maxlinear_gpy111_get_link_state(dev, &state); + + data->cb(dev, &state, data->cb_data); +} + +static int maxlinear_gpy111_link_cb_set(const struct device *dev, phy_callback_t cb, + void *user_data) +{ + struct maxlinear_gpy111_dev_data *const data = dev->data; + + data->cb = cb; + data->cb_data = user_data; + + /** + * Immediately invoke the callback to notify the caller of the + * current link status. + */ + invoke_link_cb(dev); + + return 0; +} + +static int maxlinear_gpy111_init(const struct device *dev) +{ + const struct maxlinear_gpy111_dev_config *const cfg = dev->config; + struct maxlinear_gpy111_dev_data *const data = dev->data; + uint32_t phy_id; + int ret = 0; + + data->state.is_up = false; + +#if ANY_INT_GPIO + if (gpio_is_ready_dt(&cfg->reset_gpio)) { + ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure INT pin (%d)", ret); + return ret; + } + } +#endif /* ANY_INT_GPIO */ + + if (cfg->no_reset == false) { + ret = reset(dev); + if (ret < 0) { + LOG_ERR("Failed to reset PHY (%d): %d", cfg->phy_addr, ret); + return ret; + } + } + + if (get_id(dev, &phy_id) == 0) { + if (phy_id == MII_INVALID_PHY_ID) { + LOG_ERR("No PHY found at address %d", cfg->phy_addr); + + return -EINVAL; + } + + LOG_INF("PHY (%d) ID %X", cfg->phy_addr, phy_id); + } + + ret = read_gigabit_supported_flag(dev, &data->gigabit_supported); + if (ret < 0) { + LOG_ERR("Failed to read PHY capabilities: %d", ret); + return ret; + } + + phy_gpy111_config_mii(dev); + + k_work_init_delayable(&data->monitor_work, monitor_work_handler); + + /* Advertise default speeds */ + ret = phy_gpy111_config_link(dev, cfg->default_speeds, 0); + if (ret == -EALREADY) { + data->autoneg_in_progress = true; + data->autoneg_timeout = sys_timepoint_calc(K_MSEC(CONFIG_PHY_AUTONEG_TIMEOUT_MS)); + } + + /* This will schedule the monitor work, if not already scheduled by phy_mii_cfg_link(). */ + k_work_schedule(&data->monitor_work, K_NO_WAIT); + + return 0; +} + +static DEVICE_API(ethphy, maxlinear_gpy111_driver_api) = { + .get_link = maxlinear_gpy111_get_link_state, + .link_cb_set = maxlinear_gpy111_link_cb_set, + .cfg_link = phy_gpy111_config_link, + .read = maxlinear_gpy111_read, + .write = maxlinear_gpy111_write, +}; + +#if ANY_RESET_GPIO +#define RESET_GPIO(n) \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ + .reset_assert_duration_us = DT_INST_PROP_OR(n, reset_assert_duration_us, 0), \ + .reset_deassertion_timeout_ms = DT_INST_PROP_OR(n, reset_deassertion_timeout_ms, 0), +#else +#define RESET_GPIO(n) +#endif /* ANY_RESET_GPIO */ + +#if ANY_INT_GPIO +#define INT_GPIO(n) .int_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}), +#else +#define INT_GPIO(n) +#endif /* ANY_INT_GPIO */ + +#define PHY_GPY111_CONFIG(n) \ + BUILD_ASSERT(PHY_INST_GENERATE_DEFAULT_SPEEDS(n) != 0, \ + "At least one valid speed must be configured for this driver"); \ + \ + static const struct maxlinear_gpy111_dev_config maxlinear_gpy111_dev_config_##n = { \ + .phy_addr = 0, \ + .no_reset = DT_INST_PROP(n, no_reset), \ + .mii_type = DT_INST_ENUM_IDX(n, maxlinear_interface_type), \ + .rx_skew = DT_INST_ENUM_IDX_OR(n, maxlinear_rx_internal_delay, \ + GPY111_MIICTRL_RX_SKEW_DEFAULT), \ + .tx_skew = DT_INST_ENUM_IDX_OR(n, maxlinear_tx_internal_delay, \ + GPY111_MIICTRL_TX_SKEW_DEFAULT), \ + .default_speeds = PHY_INST_GENERATE_DEFAULT_SPEEDS(n), \ + .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \ + RESET_GPIO(n) INT_GPIO(n)}; + +#define PHY_GPY111_DATA(n) \ + static struct maxlinear_gpy111_dev_data maxlinear_gpy111_dev_data_##n = { \ + .dev = DEVICE_DT_INST_GET(n), \ + .cb = NULL, \ + .sem = Z_SEM_INITIALIZER(maxlinear_gpy111_dev_data_##n.sem, 1, 1), \ + .state = {0}, \ + }; + +#define PHY_GPY111_DEVICE(n) \ + PHY_GPY111_CONFIG(n); \ + PHY_GPY111_DATA(n); \ + DEVICE_DT_INST_DEFINE(n, &maxlinear_gpy111_init, NULL, &maxlinear_gpy111_dev_data_##n, \ + &maxlinear_gpy111_dev_config_##n, POST_KERNEL, \ + CONFIG_PHY_INIT_PRIORITY, &maxlinear_gpy111_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PHY_GPY111_DEVICE) diff --git a/dts/bindings/ethernet/phy/maxlinear,gpy111.yaml b/dts/bindings/ethernet/phy/maxlinear,gpy111.yaml new file mode 100644 index 0000000000000..5f701780b0a0f --- /dev/null +++ b/dts/bindings/ethernet/phy/maxlinear,gpy111.yaml @@ -0,0 +1,74 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Maxlinear GPY111 Ethernet PHY device + +compatible: "maxlinear,gpy111" + +include: + - name: ethernet-phy-common.yaml + - name: ethernet-phy-reset-gpios.yaml + +on-bus: mdio + +properties: + no-reset: + type: boolean + description: Do not reset the PHY during initialization + + fixed-link: + type: string + description: This link is fixed and does not require PHY configuration + enum: + - "10BASE-T Half-Duplex" + - "10BASE-T Full-Duplex" + - "100BASE-T Half-Duplex" + - "100BASE-T Full-Duplex" + - "1000BASE-T Half-Duplex" + - "1000BASE-T Full-Duplex" + + default-speeds: + default: ["10BASE Half-Duplex", "10BASE Full-Duplex", "100BASE Half-Duplex", + "100BASE Full-Duplex", "1000BASE Half-Duplex", "1000BASE Full-Duplex"] + + maxlinear,interface-type: + type: string + required: true + description: Which type of phy connection the phy is set up for + enum: + - "rgmii" + - "gmii" + + maxlinear,rx-internal-delay: + type: string + enum: + - "rx_skew_0n0" + - "rx_skew_0n5" + - "rx_skew_1n0" + - "rx_skew_1n5" + - "rx_skew_2n0" + - "rx_skew_2n5" + - "rx_skew_3n0" + - "rx_skew_3n5" + description: | + RGMII Receive PHY Clock Delay defined in nano seconds. + When undefined, use default reset values which depend on soft pin-strappings. + + maxlinear,tx-internal-delay: + type: string + enum: + - "tx_skew_0n0" + - "tx_skew_0n5" + - "tx_skew_1n0" + - "tx_skew_1n5" + - "tx_skew_2n0" + - "tx_skew_2n5" + - "tx_skew_3n0" + - "tx_skew_3n5" + description: | + RGMII Transmit PHY Clock Delay defined in nano seconds. + When undefined, use default reset values which depend on soft pin-strappings. + + int-gpios: + type: phandle-array + description: GPIO for interrupt signal indicating PHY state change. diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 7e7d27b533117..79f2aa89afbf2 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -416,6 +416,7 @@ mapleboard Mapleboard.org marvell Marvell Technology Group Ltd. maxbotix MaxBotix Inc. maxim Maxim Integrated Products +maxlinear Maxlinear, Inc. mbvl Mobiveil Inc. mcube mCube meas Measurement Specialties From a241ee33abcc7a6f9ff25faa44f3f5995b7372d2 Mon Sep 17 00:00:00 2001 From: Nhat Ta Date: Wed, 29 Oct 2025 17:26:00 +0700 Subject: [PATCH 8/8] board: renesas: add ethernet for ra8x2 boards This commit add ethernet support for ek_ra8p1, ek_ra8m2, ek_ra8d2, mck_ra8t2. Signed-off-by: Nhat Ta --- boards/renesas/ek_ra8d2/Kconfig.defconfig | 17 ++++++ boards/renesas/ek_ra8d2/ek_ra8d2-pinctrl.dtsi | 26 +++++++++ boards/renesas/ek_ra8d2/ek_ra8d2.dtsi | 34 +++++++++++ .../ek_ra8d2/ek_ra8d2_r7ka8d2kflcac_cm85.dts | 37 ++++++++++++ boards/renesas/ek_ra8m2/Kconfig.defconfig | 27 +++++++++ boards/renesas/ek_ra8m2/ek_ra8m2-pinctrl.dtsi | 26 +++++++++ boards/renesas/ek_ra8m2/ek_ra8m2.dtsi | 38 +++++++++++++ .../ek_ra8m2/ek_ra8m2_r7ka8m2jflcac_cm85.dts | 37 ++++++++++++ boards/renesas/ek_ra8p1/Kconfig.defconfig | 11 ++++ boards/renesas/ek_ra8p1/ek_ra8p1-pinctrl.dtsi | 26 +++++++++ boards/renesas/ek_ra8p1/ek_ra8p1.dtsi | 34 +++++++++++ .../ek_ra8p1/ek_ra8p1_r7ka8p1kflcac_cm85.dts | 37 ++++++++++++ boards/renesas/mck_ra8t2/CMakeLists.txt | 5 ++ boards/renesas/mck_ra8t2/Kconfig.defconfig | 23 ++++++++ boards/renesas/mck_ra8t2/board.c | 46 +++++++++++++++ .../renesas/mck_ra8t2/mck_ra8t2-pinctrl.dtsi | 55 ++++++++++++++++++ boards/renesas/mck_ra8t2/mck_ra8t2.dtsi | 26 +++++++++ .../mck_ra8t2_r7ka8t2lfecac_cm85.dts | 56 +++++++++++++++++++ 18 files changed, 561 insertions(+) create mode 100644 boards/renesas/ek_ra8d2/Kconfig.defconfig create mode 100644 boards/renesas/ek_ra8m2/Kconfig.defconfig create mode 100644 boards/renesas/mck_ra8t2/CMakeLists.txt create mode 100644 boards/renesas/mck_ra8t2/Kconfig.defconfig create mode 100644 boards/renesas/mck_ra8t2/board.c diff --git a/boards/renesas/ek_ra8d2/Kconfig.defconfig b/boards/renesas/ek_ra8d2/Kconfig.defconfig new file mode 100644 index 0000000000000..53355cf1f58cd --- /dev/null +++ b/boards/renesas/ek_ra8d2/Kconfig.defconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_EK_RA8D2 + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +# Enable fixed clock for ethernet phy +config CLOCK_CONTROL_FIXED_RATE_CLOCK + default y if ETH_PHY_DRIVER + +endif # BOARD_EK_RA8D2 diff --git a/boards/renesas/ek_ra8d2/ek_ra8d2-pinctrl.dtsi b/boards/renesas/ek_ra8d2/ek_ra8d2-pinctrl.dtsi index 107eae94f06a9..0d48a5684ce06 100644 --- a/boards/renesas/ek_ra8d2/ek_ra8d2-pinctrl.dtsi +++ b/boards/renesas/ek_ra8d2/ek_ra8d2-pinctrl.dtsi @@ -162,4 +162,30 @@ drive-strength = "highspeed-high"; }; }; + + mdio1_default: mdio1_default { + group1 { + psels = , /* MDC */ + ; /* MDIO */ + drive-strength = "medium"; + }; + }; + + eth1_default: eth1_default { + group1 { + psels = , /* RGMII_TXD0 */ + , /* RGMII_TXD1 */ + , /* RGMII_TXD2 */ + , /* RGMII_TXD3 */ + , /* RGMII_TX_CTL */ + , /* RGMII_TX_CLK */ + , /* RGMII_RXD0 */ + , /* RGMII_RXD1 */ + , /* RGMII_RXD2 */ + , /* RGMII_RXD3 */ + , /* RGMII_RX_CTL */ + ; /* RGMII_RX_CLK */ + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra8d2/ek_ra8d2.dtsi b/boards/renesas/ek_ra8d2/ek_ra8d2.dtsi index 85d6734513c48..169c72d7e0e3f 100644 --- a/boards/renesas/ek_ra8d2/ek_ra8d2.dtsi +++ b/boards/renesas/ek_ra8d2/ek_ra8d2.dtsi @@ -88,6 +88,18 @@ }; }; +/* In ek_ra8d2, phy chip use xtal as clock source + * so internal phy clock is not required. + */ +&clocks { + phyxtal: phy-xtal { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0x0>; + status = "okay"; + }; +}; + &xtal { clock-frequency = ; mosel = <0>; @@ -147,6 +159,28 @@ status = "okay"; }; +&eswclk { + clocks = <&pllp>; + div = <4>; + status = "okay"; +}; + +&eswphyclk { + clocks = <&pllp>; + div = <2>; + status = "okay"; +}; + +ðphyclk { + clocks = <&pllr>; + div = <16>; + status = "okay"; +}; + +&trng { + status = "okay"; +}; + &ioport0 { status = "okay"; }; diff --git a/boards/renesas/ek_ra8d2/ek_ra8d2_r7ka8d2kflcac_cm85.dts b/boards/renesas/ek_ra8d2/ek_ra8d2_r7ka8d2kflcac_cm85.dts index 2aad05ce741eb..88b2da3f2ecd1 100644 --- a/boards/renesas/ek_ra8d2/ek_ra8d2_r7ka8d2kflcac_cm85.dts +++ b/boards/renesas/ek_ra8d2/ek_ra8d2_r7ka8d2kflcac_cm85.dts @@ -21,6 +21,7 @@ zephyr,console = &uart8; zephyr,shell-uart = &uart8; zephyr,crc = &crc; + zephyr,entropy = &trng; }; aliases { @@ -211,3 +212,39 @@ arducam_ffc_40pin_i2c: &iic1 {}; arducam_ffc_40pin_dvp_interface: &ceu {}; arducam_ffc_40pin_dvp_xclk: &cam_clock {}; + +&eswm { + interrupts = <27 1>; + interrupt-names = "gwdi"; + status = "okay"; +}; + +ð1 { + phy-connection-type = "rgmii"; + local-mac-address = [74 90 50 01 02 04]; + phy-clock = <&phyxtal>; + phy-clock-type = "xtal"; + phy-handle = <&phy0>; + pinctrl-0 = <ð1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&mdio1 { + pinctrl-0 = <&mdio1_default>; + pinctrl-names = "default"; + phy-connection-type = "rgmii"; + status = "okay"; + + phy0: phy@0 { + compatible = "maxlinear,gpy111"; + maxlinear,interface-type = "rgmii"; + maxlinear,rx-internal-delay = "rx_skew_1n5"; + reg = <0>; + int-gpios = <&ioport1 7 GPIO_ACTIVE_LOW>; + reset-gpios = <&ioport7 8 GPIO_ACTIVE_LOW>; + reset-assert-duration-us = <2000>; + reset-deassertion-timeout-ms = <300>; + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra8m2/Kconfig.defconfig b/boards/renesas/ek_ra8m2/Kconfig.defconfig new file mode 100644 index 0000000000000..7cf0827000e9c --- /dev/null +++ b/boards/renesas/ek_ra8m2/Kconfig.defconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_EK_RA8M2 + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +# Enable fixed clock for ethernet phy +config CLOCK_CONTROL_FIXED_RATE_CLOCK + default y if ETH_PHY_DRIVER + +if MDIO + +config MDIO_RENESAS_RA_RMAC_MDIO_HOLD_NS + default 4 + +config MDIO_RENESAS_RA_RMAC_MDIO_CAPTURE_NS + default 4 + +endif #MDIO + +endif # BOARD_EK_RA8M2 diff --git a/boards/renesas/ek_ra8m2/ek_ra8m2-pinctrl.dtsi b/boards/renesas/ek_ra8m2/ek_ra8m2-pinctrl.dtsi index 155183cb49fb1..86db6af0cb0be 100644 --- a/boards/renesas/ek_ra8m2/ek_ra8m2-pinctrl.dtsi +++ b/boards/renesas/ek_ra8m2/ek_ra8m2-pinctrl.dtsi @@ -83,4 +83,30 @@ drive-strength = "high"; }; }; + + mdio0_default: mdio0_default { + group1 { + psels = , /* MDC */ + ; /* MDIO */ + drive-strength = "medium"; + }; + }; + + eth0_default: eth0_default { + group1 { + psels = , /* RGMII_TXD0 */ + , /* RGMII_TXD1 */ + , /* RGMII_TXD2 */ + , /* RGMII_TXD3 */ + , /* RGMII_TX_CTL */ + , /* RGMII_TX_CLK */ + , /* RGMII_RXD0 */ + , /* RGMII_RXD1 */ + , /* RGMII_RXD2 */ + , /* RGMII_RXD3 */ + , /* RGMII_RX_CTL */ + ; /* RGMII_RX_CLK */ + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra8m2/ek_ra8m2.dtsi b/boards/renesas/ek_ra8m2/ek_ra8m2.dtsi index d4c76ab26b3c3..a665998e727a1 100644 --- a/boards/renesas/ek_ra8m2/ek_ra8m2.dtsi +++ b/boards/renesas/ek_ra8m2/ek_ra8m2.dtsi @@ -76,6 +76,18 @@ }; }; +/* In ek_ra8m2, phy chip use xtal as clock source + * so internal phy clock is not required. + */ +&clocks { + phyxtal: phy-xtal { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0x0>; + status = "okay"; + }; +}; + &xtal { clock-frequency = ; mosel = <0>; @@ -135,6 +147,28 @@ status = "okay"; }; +&eswclk { + clocks = <&pllp>; + div = <4>; + status = "okay"; +}; + +&eswphyclk { + clocks = <&pllp>; + div = <2>; + status = "okay"; +}; + +ðphyclk { + clocks = <&pllr>; + div = <16>; + status = "okay"; +}; + +&trng { + status = "okay"; +}; + &ioport0 { status = "okay"; }; @@ -151,6 +185,10 @@ status = "okay"; }; +&ioport5 { + status = "okay"; +}; + &ioport6 { status = "okay"; }; diff --git a/boards/renesas/ek_ra8m2/ek_ra8m2_r7ka8m2jflcac_cm85.dts b/boards/renesas/ek_ra8m2/ek_ra8m2_r7ka8m2jflcac_cm85.dts index 7b00090b1372d..5bd34ae59317d 100644 --- a/boards/renesas/ek_ra8m2/ek_ra8m2_r7ka8m2jflcac_cm85.dts +++ b/boards/renesas/ek_ra8m2/ek_ra8m2_r7ka8m2jflcac_cm85.dts @@ -21,6 +21,7 @@ zephyr,shell-uart = &uart8; zephyr,canbus = &canfd1; zephyr,crc = &crc; + zephyr,entropy = &trng; }; aliases { @@ -183,3 +184,39 @@ mikrobus_serial: &uart7 {}; mikrobus_spi: &spi1 {}; + +&eswm { + interrupts = <29 1>; + interrupt-names = "gwdi"; + status = "okay"; +}; + +ð0 { + phy-connection-type = "rgmii"; + local-mac-address = [74 90 50 01 02 05]; + phy-clock = <&phyxtal>; + phy-clock-type = "xtal"; + phy-handle = <&phy0>; + pinctrl-0 = <ð0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&mdio0 { + pinctrl-0 = <&mdio0_default>; + pinctrl-names = "default"; + phy-connection-type = "rgmii"; + status = "okay"; + + phy0: phy@0 { + compatible = "maxlinear,gpy111"; + maxlinear,interface-type = "rgmii"; + maxlinear,rx-internal-delay = "rx_skew_1n5"; + reg = <0>; + int-gpios = <&ioportc 13 GPIO_ACTIVE_LOW>; + reset-gpios = <&ioport5 14 GPIO_ACTIVE_LOW>; + reset-assert-duration-us = <2000>; + reset-deassertion-timeout-ms = <300>; + status = "okay"; + }; +}; diff --git a/boards/renesas/ek_ra8p1/Kconfig.defconfig b/boards/renesas/ek_ra8p1/Kconfig.defconfig index 6b28a1674754e..2abb6d6b1629a 100644 --- a/boards/renesas/ek_ra8p1/Kconfig.defconfig +++ b/boards/renesas/ek_ra8p1/Kconfig.defconfig @@ -10,4 +10,15 @@ config SD_CMD_TIMEOUT endif # DISK_DRIVER_SDMMC +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +# Enable fixed clock for ethernet phy +config CLOCK_CONTROL_FIXED_RATE_CLOCK + default y if ETH_PHY_DRIVER + endif # BOARD_EK_RA8P1 diff --git a/boards/renesas/ek_ra8p1/ek_ra8p1-pinctrl.dtsi b/boards/renesas/ek_ra8p1/ek_ra8p1-pinctrl.dtsi index 778ada777d72c..8d61d5bff0fbc 100644 --- a/boards/renesas/ek_ra8p1/ek_ra8p1-pinctrl.dtsi +++ b/boards/renesas/ek_ra8p1/ek_ra8p1-pinctrl.dtsi @@ -177,4 +177,30 @@ drive-strength = "highspeed-high"; }; }; + + mdio1_default: mdio1_default { + group1 { + psels = , /* MDC */ + ; /* MDIO */ + drive-strength = "medium"; + }; + }; + + eth1_default: eth1_default { + group1 { + psels = , /* RGMII_TXD0 */ + , /* RGMII_TXD1 */ + , /* RGMII_TXD2 */ + , /* RGMII_TXD3 */ + , /* RGMII_TX_CTL */ + , /* RGMII_TX_CLK */ + , /* RGMII_RXD0 */ + , /* RGMII_RXD1 */ + , /* RGMII_RXD2 */ + , /* RGMII_RXD3 */ + , /* RGMII_RX_CTL */ + ; /* RGMII_RX_CLK */ + drive-strength = "high"; + }; + }; }; diff --git a/boards/renesas/ek_ra8p1/ek_ra8p1.dtsi b/boards/renesas/ek_ra8p1/ek_ra8p1.dtsi index 7a1a2a05bdccb..7186ec9e3c73f 100644 --- a/boards/renesas/ek_ra8p1/ek_ra8p1.dtsi +++ b/boards/renesas/ek_ra8p1/ek_ra8p1.dtsi @@ -65,6 +65,18 @@ }; }; +/* In ek_ra8p1, phy chip use xtal as clock source + * so internal phy clock is not required. + */ +&clocks { + phyxtal: phy-xtal { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0x0>; + status = "okay"; + }; +}; + &xtal { clock-frequency = ; mosel = <0>; @@ -137,6 +149,28 @@ status = "okay"; }; +&eswclk { + clocks = <&pllp>; + div = <4>; + status = "okay"; +}; + +&eswphyclk { + clocks = <&pllp>; + div = <2>; + status = "okay"; +}; + +ðphyclk { + clocks = <&pllr>; + div = <16>; + status = "okay"; +}; + +&trng { + status = "okay"; +}; + &ioport0 { status = "okay"; }; diff --git a/boards/renesas/ek_ra8p1/ek_ra8p1_r7ka8p1kflcac_cm85.dts b/boards/renesas/ek_ra8p1/ek_ra8p1_r7ka8p1kflcac_cm85.dts index 4923dcc87cced..235d270c90196 100644 --- a/boards/renesas/ek_ra8p1/ek_ra8p1_r7ka8p1kflcac_cm85.dts +++ b/boards/renesas/ek_ra8p1/ek_ra8p1_r7ka8p1kflcac_cm85.dts @@ -20,6 +20,7 @@ zephyr,code-partition = &slot0_partition; zephyr,console = &uart8; zephyr,shell-uart = &uart8; + zephyr,entropy = &trng; }; aliases { @@ -180,3 +181,39 @@ arducam_ffc_40pin_i2c: &iic1 {}; arducam_ffc_40pin_dvp_interface: &ceu {}; arducam_ffc_40pin_dvp_xclk: &cam_clock {}; + +&eswm { + interrupts = <24 1>; + interrupt-names = "gwdi"; + status = "okay"; +}; + +ð1 { + phy-connection-type = "rgmii"; + local-mac-address = [74 90 50 01 02 03]; + phy-clock = <&phyxtal>; + phy-clock-type = "xtal"; + phy-handle = <&phy0>; + pinctrl-0 = <ð1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&mdio1 { + pinctrl-0 = <&mdio1_default>; + pinctrl-names = "default"; + phy-connection-type = "rgmii"; + status = "okay"; + + phy0: phy@0 { + compatible = "maxlinear,gpy111"; + maxlinear,interface-type = "rgmii"; + maxlinear,rx-internal-delay = "rx_skew_1n5"; + reg = <0>; + int-gpios = <&ioport1 7 GPIO_ACTIVE_LOW>; + reset-gpios = <&ioport7 8 GPIO_ACTIVE_LOW>; + reset-assert-duration-us = <2000>; + reset-deassertion-timeout-ms = <300>; + status = "okay"; + }; +}; diff --git a/boards/renesas/mck_ra8t2/CMakeLists.txt b/boards/renesas/mck_ra8t2/CMakeLists.txt new file mode 100644 index 0000000000000..aec8a5c773469 --- /dev/null +++ b/boards/renesas/mck_ra8t2/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(board.c) diff --git a/boards/renesas/mck_ra8t2/Kconfig.defconfig b/boards/renesas/mck_ra8t2/Kconfig.defconfig new file mode 100644 index 0000000000000..c2445d7c757ab --- /dev/null +++ b/boards/renesas/mck_ra8t2/Kconfig.defconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_MCK_RA8T2 + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +if MDIO + +config MDIO_RENESAS_RA_RMAC_MDIO_HOLD_NS + default 10 + +config MDIO_RENESAS_RA_RMAC_MDIO_CAPTURE_NS + default 10 + +endif #MDIO + +endif # BOARD_MCK_RA8T2 diff --git a/boards/renesas/mck_ra8t2/board.c b/boards/renesas/mck_ra8t2/board.c new file mode 100644 index 0000000000000..1d1a5271b32ed --- /dev/null +++ b/boards/renesas/mck_ra8t2/board.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(board_control, CONFIG_LOG_DEFAULT_LEVEL); + +#if defined(CONFIG_ETH_PHY_DRIVER) +static int phy_init(void) +{ + const struct gpio_dt_spec phy_reset_gpios = + GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), phy_reset_gpios); + const uint16_t phy_reset_assert = DT_PROP_OR(DT_PATH(zephyr_user), phy_reset_assert_ms, 0); + const uint16_t phy_reset_deassert = + DT_PROP_OR(DT_PATH(zephyr_user), phy_reset_deassert_ms, 0); + + if (!gpio_is_ready_dt(&phy_reset_gpios)) { + LOG_DBG("PHY reset pin is not set"); + return -ENODEV; + } + + if (gpio_pin_configure_dt(&phy_reset_gpios, GPIO_OUTPUT)) { + LOG_DBG("Failed to hardware reset PHY"); + return -EIO; + } + + /* Issue a hardware reset */ + if (phy_reset_assert > 0 && phy_reset_deassert > 0) { + gpio_pin_set_dt(&phy_reset_gpios, 1); + k_msleep(phy_reset_assert); + + gpio_pin_set_dt(&phy_reset_gpios, 0); + k_msleep(phy_reset_deassert); + } + + return 0; +} + +SYS_INIT(phy_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif diff --git a/boards/renesas/mck_ra8t2/mck_ra8t2-pinctrl.dtsi b/boards/renesas/mck_ra8t2/mck_ra8t2-pinctrl.dtsi index 835c5809557e2..8bea7f68f01c9 100644 --- a/boards/renesas/mck_ra8t2/mck_ra8t2-pinctrl.dtsi +++ b/boards/renesas/mck_ra8t2/mck_ra8t2-pinctrl.dtsi @@ -67,6 +67,61 @@ }; }; + mdio0_default: mdio0_default { + group1 { + psels = , /* MDC */ + ; /* MDIO */ + drive-strength = "medium"; + }; + }; + + ethphyclk_default: ethphyclk_default { + group1 { + psels = ; /* PHY_REF */ + drive-strength = "high"; + }; + }; + + eth0_default: eth0_default { + group1 { + psels = , /* MII_LINKSTA */ + , /* MII_TX_EN */ + , /* MII_TX_CLK */ + , /* MII_TXD0 */ + , /* MII_TXD1 */ + , /* MII_TXD2 */ + , /* MII_TXD3 */ + , /* MII_RX_ER */ + , /* MII_RX_DV */ + , /* MII_RX_CLK */ + , /* MII_RXD0 */ + , /* MII_RXD1 */ + , /* MII_RXD2 */ + ; /* MII_RXD3 */ + drive-strength = "high"; + }; + }; + + eth1_default: eth1_default { + group1 { + psels = , /* MII_LINKSTA */ + , /* MII_TX_EN */ + , /* MII_TX_CLK */ + , /* MII_TXD0 */ + , /* MII_TXD1 */ + , /* MII_TXD2 */ + , /* MII_TXD3 */ + , /* MII_RX_ER */ + , /* MII_RX_DV */ + , /* MII_RX_CLK */ + , /* MII_RXD0 */ + , /* MII_RXD1 */ + , /* MII_RXD2 */ + ; /* MII_RXD3 */ + drive-strength = "high"; + }; + }; + /omit-if-no-ref/ acmphs_ivref0: acmphs_ivref0 { group1 { /* IVREF0 */ diff --git a/boards/renesas/mck_ra8t2/mck_ra8t2.dtsi b/boards/renesas/mck_ra8t2/mck_ra8t2.dtsi index 31a12eac78406..2f76ab5a6bf51 100644 --- a/boards/renesas/mck_ra8t2/mck_ra8t2.dtsi +++ b/boards/renesas/mck_ra8t2/mck_ra8t2.dtsi @@ -95,6 +95,28 @@ status = "okay"; }; +&eswclk { + clocks = <&pllp>; + div = <4>; + status = "okay"; +}; + +&eswphyclk { + clocks = <&pllp>; + div = <2>; + status = "okay"; +}; + +ðphyclk { + clocks = <&pllr>; + div = <16>; + status = "okay"; +}; + +&trng { + status = "okay"; +}; + &ioport5 { status = "okay"; }; @@ -103,6 +125,10 @@ status = "okay"; }; +&ioport7 { + status = "okay"; +}; + &ioport9 { status = "okay"; }; diff --git a/boards/renesas/mck_ra8t2/mck_ra8t2_r7ka8t2lfecac_cm85.dts b/boards/renesas/mck_ra8t2/mck_ra8t2_r7ka8t2lfecac_cm85.dts index 2603cf3fb9592..caf9d8a7fbb1c 100644 --- a/boards/renesas/mck_ra8t2/mck_ra8t2_r7ka8t2lfecac_cm85.dts +++ b/boards/renesas/mck_ra8t2/mck_ra8t2_r7ka8t2lfecac_cm85.dts @@ -19,12 +19,19 @@ zephyr,code-partition = &slot0_partition; zephyr,console = &uart9; zephyr,shell-uart = &uart9; + zephyr,entropy = &trng; }; aliases { led0 = &led1; sdhc0 = &sdhc0; }; + + zephyr,user { + phy-reset-gpios = <&ioport7 11 GPIO_ACTIVE_LOW>; + phy-reset-assert-ms = <200>; + phy-reset-deassert-ms = <35>; + }; }; &sci9 { @@ -132,3 +139,52 @@ }; }; }; + +&eswm { + status = "okay"; + interrupts = <18 1>; + interrupt-names = "gwdi"; + pinctrl-0 = <ðphyclk_default>; + pinctrl-names = "default"; +}; + +ð0 { + phy-connection-type = "mii"; + local-mac-address = [74 90 50 01 02 05]; + phy-clock = <ðphyclk>; + phy-clock-type = "internal"; + phy-handle = <&phy1>; + pinctrl-0 = <ð0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +ð1 { + phy-connection-type = "mii"; + local-mac-address = [74 90 50 01 02 06]; + phy-clock = <ðphyclk>; + phy-clock-type = "internal"; + phy-handle = <&phy2>; + pinctrl-0 = <ð1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&mdio0 { + pinctrl-0 = <&mdio0_default>; + pinctrl-names = "default"; + phy-connection-type = "mii"; + status = "okay"; + + phy1: phy@1 { + compatible = "ethernet-phy"; + reg = <1>; + status = "okay"; + }; + + phy2: phy@2 { + compatible = "ethernet-phy"; + reg = <2>; + status = "okay"; + }; +};