diff --git a/boards/nxp/imx95_evk/dts/enetc_psi0.overlay b/boards/nxp/imx95_evk/dts/enetc_psi0.overlay index 2e24f5ff94b72..a14003810f063 100644 --- a/boards/nxp/imx95_evk/dts/enetc_psi0.overlay +++ b/boards/nxp/imx95_evk/dts/enetc_psi0.overlay @@ -15,3 +15,7 @@ &enetc_psi0 { status = "okay"; }; + +&enetc_ptp_clock { + status = "okay"; +}; diff --git a/drivers/ptp_clock/CMakeLists.txt b/drivers/ptp_clock/CMakeLists.txt index c80575787898c..8a5eaceb361a9 100644 --- a/drivers/ptp_clock/CMakeLists.txt +++ b/drivers/ptp_clock/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK ptp_clock.c) zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK_SHELL ptp_clock_shell.c) zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK_NXP_ENET ptp_clock_nxp_enet.c) +zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK_NXP_NETC ptp_clock_nxp_netc.c) diff --git a/drivers/ptp_clock/Kconfig b/drivers/ptp_clock/Kconfig index 9b87301495f17..54d023b1b7d23 100644 --- a/drivers/ptp_clock/Kconfig +++ b/drivers/ptp_clock/Kconfig @@ -9,6 +9,7 @@ menuconfig PTP_CLOCK if PTP_CLOCK source "drivers/ptp_clock/Kconfig.nxp_enet" +source "drivers/ptp_clock/Kconfig.nxp_netc" config PTP_CLOCK_INIT_PRIORITY int "Init priority" diff --git a/drivers/ptp_clock/Kconfig.nxp_netc b/drivers/ptp_clock/Kconfig.nxp_netc new file mode 100644 index 0000000000000..76c4b41d7bbfc --- /dev/null +++ b/drivers/ptp_clock/Kconfig.nxp_netc @@ -0,0 +1,10 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config PTP_CLOCK_NXP_NETC + bool "NXP NETC PTP Clock driver" + default y + depends on DT_HAS_NXP_NETC_PTP_CLOCK_ENABLED + depends on ETH_NXP_IMX_NETC + help + Enable NXP NETC PTP clock support. diff --git a/drivers/ptp_clock/ptp_clock_nxp_netc.c b/drivers/ptp_clock/ptp_clock_nxp_netc.c new file mode 100644 index 0000000000000..01a8385c42ec7 --- /dev/null +++ b/drivers/ptp_clock/ptp_clock_nxp_netc.c @@ -0,0 +1,149 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_netc_ptp_clock + +#include +#include +#include +#include +#include + +#include + +struct ptp_clock_nxp_netc_config { + const struct device *dev; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; +}; + +struct ptp_clock_nxp_netc_data { + NETC_ENETC_Type *base; + netc_timer_handle_t handle; + struct k_mutex ptp_mutex; + netc_timer_config_t ptp_config; +}; + +static int ptp_clock_nxp_netc_set(const struct device *dev, + struct net_ptp_time *tm) +{ + struct ptp_clock_nxp_netc_data *data = dev->data; + uint64_t nanosecond; + int key; + + nanosecond = tm->second * NSEC_PER_SEC + tm->nanosecond; + + key = irq_lock(); + data->handle.hw.base->TMR_CNT_L = (uint32_t)nanosecond; + data->handle.hw.base->TMR_CNT_H = (uint32_t)(nanosecond >> 32U); + data->handle.hw.base->TMROFF_L = 0U; + data->handle.hw.base->TMROFF_H = 0U; + irq_unlock(key); + + return 0; +} + +static int ptp_clock_nxp_netc_get(const struct device *dev, + struct net_ptp_time *tm) +{ + struct ptp_clock_nxp_netc_data *data = dev->data; + uint64_t nanosecond; + + NETC_TimerGetCurrentTime(&data->handle, &nanosecond); + + tm->second = nanosecond / NSEC_PER_SEC; + tm->nanosecond = nanosecond % NSEC_PER_SEC; + + return 0; +} + +static int ptp_clock_nxp_netc_adjust(const struct device *dev, + int increment) +{ + struct ptp_clock_nxp_netc_data *data = dev->data; + int key; + + key = irq_lock(); + NETC_TimerAddOffset(&data->handle, (int64_t)increment * NSEC_PER_SEC); + irq_unlock(key); + + return 0; + +} + +static int ptp_clock_nxp_netc_rate_adjust(const struct device *dev, + double ratio) +{ + struct ptp_clock_nxp_netc_data *data = dev->data; + netc_timer_config_t *ptp_config = &data->ptp_config; + + ptp_config->defaultPpb = (ratio - 1.0) * 1000000000LL; + + k_mutex_lock(&data->ptp_mutex, K_FOREVER); + + NETC_TimerAdjustFreq(&data->handle, ptp_config->defaultPpb); + + k_mutex_unlock(&data->ptp_mutex); + + return 0; +} + +static int ptp_clock_nxp_netc_init(const struct device *dev) +{ + const struct ptp_clock_nxp_netc_config *config = dev->config; + struct ptp_clock_nxp_netc_data *data = dev->data; + netc_timer_config_t *ptp_config = &data->ptp_config; + uint32_t netc_ref_pll_rate; + int ret = 0; + + ret = clock_control_get_rate(config->clock_dev, config->clock_subsys, &netc_ref_pll_rate); + if (ret) { + return ret; + } + ptp_config->refClkHz = netc_ref_pll_rate/2; + ptp_config->entryNum = 0U; + ptp_config->defaultPpb = 0U; + ptp_config->clockSelect = kNETC_TimerSystemClk; + + k_mutex_init(&data->ptp_mutex); + + ret = NETC_TimerInit(&data->handle, ptp_config); + if (ret != kStatus_Success) { + return ret; + } + + NETC_TimerEnable(&data->handle, true); + + return ret; +} + + +static DEVICE_API(ptp_clock, ptp_clock_nxp_netc_api) = { + .set = ptp_clock_nxp_netc_set, + .get = ptp_clock_nxp_netc_get, + .adjust = ptp_clock_nxp_netc_adjust, + .rate_adjust = ptp_clock_nxp_netc_rate_adjust, +}; + +#define PTP_CLOCK_NXP_NETC_INIT(n) \ + static const struct ptp_clock_nxp_netc_config \ + ptp_clock_nxp_netc_##n##_config = { \ + .dev = DEVICE_DT_INST_GET(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(n, name), \ + }; \ + \ + static struct ptp_clock_nxp_netc_data ptp_clock_nxp_netc_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &ptp_clock_nxp_netc_init, NULL, \ + &ptp_clock_nxp_netc_##n##_data, \ + &ptp_clock_nxp_netc_##n##_config, \ + POST_KERNEL, CONFIG_PTP_CLOCK_INIT_PRIORITY, \ + &ptp_clock_nxp_netc_api); + +/* Only one instance supported right now */ +DT_INST_FOREACH_STATUS_OKAY(PTP_CLOCK_NXP_NETC_INIT) diff --git a/dts/arm/nxp/nxp_imx95_m7.dtsi b/dts/arm/nxp/nxp_imx95_m7.dtsi index 7327668b868f8..a5b6cdb1837d4 100644 --- a/dts/arm/nxp/nxp_imx95_m7.dtsi +++ b/dts/arm/nxp/nxp_imx95_m7.dtsi @@ -547,6 +547,13 @@ si-index = <2>; status = "disabled"; }; + + enetc_ptp_clock: ptp_clock@4ccc0000 { + compatible = "nxp,netc-ptp-clock"; + reg = <0x4ccc0000 0x10000>; + clocks = <&scmi_clk IMX95_CLK_ENET>; + status = "disabled"; + }; }; }; }; diff --git a/dts/bindings/ethernet/nxp,netc-ptp-clock.yaml b/dts/bindings/ethernet/nxp,netc-ptp-clock.yaml new file mode 100644 index 0000000000000..614d5496eefd9 --- /dev/null +++ b/dts/bindings/ethernet/nxp,netc-ptp-clock.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP NETC PTP (Precision Time Protocol) Clock + +compatible: "nxp,netc-ptp-clock" + +include: ["base.yaml"] + +properties: + reg: + required: true diff --git a/west.yml b/west.yml index 702bc9b784e32..1b02b5f3bb17b 100644 --- a/west.yml +++ b/west.yml @@ -210,7 +210,7 @@ manifest: groups: - hal - name: hal_nxp - revision: e0b43431640a565b4500c58fc5e1aaebec2f463d + revision: 5d05592d6be03c7e4b14be831b62501e93f0af13 path: modules/hal/nxp groups: - hal