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"; + }; +}; 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/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..bb1ec690a4e70 --- /dev/null +++ b/drivers/ethernet/eth_renesas_ra_rmac.c @@ -0,0 +1,745 @@ +/* + * 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) + +#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) + +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] __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)] __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)] __eth_renesas_desc; + +/* 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] __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 */ + +#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/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/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/arm/renesas/ra/ra8/ra8x2.dtsi b/dts/arm/renesas/ra/ra8/ra8x2.dtsi index 936bf4d669b1e..930c82cd9d7ef 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>; @@ -783,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>; 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/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/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" 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/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 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 8434c47091f99..715affece70af 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 @@ -174,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 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