From 90c822915774c2ebd9981bd6126f65383596af6b Mon Sep 17 00:00:00 2001 From: Hiteshkumar Patel Date: Wed, 14 Feb 2024 01:24:49 +0000 Subject: [PATCH] nvpps: Add support for AGX Orin. Enable nvpps driver so it can be tested. - Removed passing of ethernet interface name in DT. - Require to pass Tegra ethernet controller DT phandle, where PTP server will run. Bug 4489344 Bug 3826818 Change-Id: I943ddf4071a55fb409d589473fde0075ac9f7150 Signed-off-by: Hiteshkumar Patel Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3076494 GVS: Gerrit_Virtual_Submit Reviewed-by: Jon Hunter --- drivers/nvpps/nvpps_main.c | 327 ++++++++++---------- drivers/nvpps/ptp-notifier.c | 69 +++-- include/linux/platform/tegra/ptp-notifier.h | 9 +- 3 files changed, 207 insertions(+), 198 deletions(-) diff --git a/drivers/nvpps/nvpps_main.c b/drivers/nvpps/nvpps_main.c index 7c180d0c..52e512f6 100644 --- a/drivers/nvpps/nvpps_main.c +++ b/drivers/nvpps/nvpps_main.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include @@ -22,7 +22,7 @@ #include #include #include - +#include /* the following control flags are for @@ -41,7 +41,6 @@ static dev_t s_nvpps_devt; static DEFINE_MUTEX(s_nvpps_lock); static DEFINE_IDR(s_nvpps_idr); -static char *interface_name = "eth0"; bool print_pri_ptp_failed = true; bool print_sec_ptp_failed = true; @@ -78,18 +77,18 @@ struct nvpps_device_data { wait_queue_head_t pps_event_queue; struct fasync_struct *pps_event_async_queue; - bool memmap_phc_regs; - char *iface_nm; - char *sec_iface_nm; + struct device_node *pri_emac_node; + struct device_node *sec_emac_node; + resource_size_t pri_emac_base_addr; void __iomem *mac_base_addr; u32 sts_offset; u32 stns_offset; void __iomem *tsc_reg_map_base; - bool platform_is_orin; u32 tsc_ptp_src; bool only_timer_mode; bool pri_ptp_failed; bool sec_ptp_failed; + bool support_tsc; uint8_t k_int_val; uint16_t lock_threshold_val; struct hte_ts_desc desc; @@ -103,45 +102,46 @@ struct nvpps_file_data { unsigned int pps_event_id_rd; }; - -/* MAC Base addrs */ -#define T194_EQOS_BASE_ADDR 0x2490000 -#define T234_EQOS_BASE_ADDR 0x2310000 #define EQOS_STSR_OFFSET 0xb08 #define EQOS_STNSR_OFFSET 0xb0c -#define T234_MGBE0_BASE_ADDR 0x6810000 -#define T234_MGBE1_BASE_ADDR 0x6910000 -#define T234_MGBE2_BASE_ADDR 0x6a10000 -#define T234_MGBE3_BASE_ADDR 0x6b10000 #define MGBE_STSR_OFFSET 0xd08 #define MGBE_STNSR_OFFSET 0xd0c +#define T234_MGBE0_BASE_ADDR 0x6810000 +#define T234_MGBE1_BASE_ADDR 0x6910000 +#define T234_MGBE2_BASE_ADDR 0x6a10000 +#define T234_MGBE3_BASE_ADDR 0x6b10000 +#define T234_EQOS_BASE_ADDR 0x2310000 +#define T194_EQOS_BASE_ADDR 0x2490000 + +#define TSC_PTP_SRC_EQOS 0 +#define TSC_PTP_SRC_MGBE0 1 +#define TSC_PTP_SRC_MGBE1 2 +#define TSC_PTP_SRC_MGBE2 3 +#define TSC_PTP_SRC_MGBE3 4 +#define TSC_PTP_SRC_INVALID 5 + /* Below are the tsc register offset from ioremapped * virtual base region stored in tsc_reg_map_base. */ -#define TSC_STSCRSR_OFFSET 0x0 -#define TSC_CAPTURE_CONFIGURATION_PTX_OFFSET 0x58 -#define TSC_CAPTURE_CONTROL_PTX_OFFSET 0x5c -#define TSC_LOCKING_CONFIGURATION_OFFSET 0xe4 -#define TSC_LOCKING_CONTROL_OFFSET 0xe8 -#define TSC_LOCKING_STATUS_OFFSET 0xec -#define TSC_LOCKING_REF_FREQUENCY_CONFIGURATION_OFFSET 0xf0 -#define TSC_LOCKING_DIFF_CONFIGURATION_OFFSET 0xf4 -#define TSC_LOCKING_ADJUST_CONFIGURATION_OFFSET 0x108 -#define TSC_LOCKING_FAST_ADJUST_CONFIGURATION_OFFSET 0x10c -#define TSC_LOCKING_ADJUST_NUM_CONTROL_OFFSET 0x110 -#define TSC_LOCKING_ADJUST_DELTA_CONTROL_OFFSET 0x114 +#define TSC_STSCRSR_OFFSET 0x104 +#define TSC_CAPTURE_CONFIGURATION_PTX_OFFSET (TSC_STSCRSR_OFFSET + 0x58) +#define TSC_CAPTURE_CONTROL_PTX_OFFSET (TSC_STSCRSR_OFFSET + 0x5c) +#define TSC_LOCKING_CONFIGURATION_OFFSET (TSC_STSCRSR_OFFSET + 0xe4) +#define TSC_LOCKING_CONTROL_OFFSET (TSC_STSCRSR_OFFSET + 0xe8) +#define TSC_LOCKING_STATUS_OFFSET (TSC_STSCRSR_OFFSET + 0xec) +#define TSC_LOCKING_REF_FREQUENCY_CONFIGURATION_OFFSET (TSC_STSCRSR_OFFSET + 0xf0) +#define TSC_LOCKING_DIFF_CONFIGURATION_OFFSET (TSC_STSCRSR_OFFSET + 0xf4) +#define TSC_LOCKING_ADJUST_CONFIGURATION_OFFSET (TSC_STSCRSR_OFFSET + 0x108) +#define TSC_LOCKING_FAST_ADJUST_CONFIGURATION_OFFSET (TSC_STSCRSR_OFFSET + 0x10c) +#define TSC_LOCKING_ADJUST_NUM_CONTROL_OFFSET (TSC_STSCRSR_OFFSET + 0x110) +#define TSC_LOCKING_ADJUST_DELTA_CONTROL_OFFSET (TSC_STSCRSR_OFFSET + 0x114) + #define TSC_LOCKING_FAST_ADJUST_CONFIGURATION_OFFSET_K_INT_SHIFT 8 #define SRC_SELECT_BIT_OFFSET 8 #define SRC_SELECT_BITS 0xff -#define TSC_PTP_SRC_EQOS 0 -#define TSC_PTP_SRC_MGBE0 1 -#define TSC_PTP_SRC_MGBE1 2 -#define TSC_PTP_SRC_MGBE2 3 -#define TSC_PTP_SRC_MGBE3 4 - #define TSC_LOCKED_STATUS_BIT_OFFSET 1 #define TSC_ALIGNED_STATUS_BIT_OFFSET 0 @@ -152,6 +152,8 @@ struct nvpps_file_data { #define MAC_STNSR_TSSS_LPOS 0 #define MAC_STNSR_TSSS_HPOS 30 +static struct device_node *emac_node; + #define GET_VALUE(data, lbit, hbit) ((data >> lbit) & (~(~0<<(hbit-lbit+1)))) #define MAC_STNSR_OFFSET (BASE_ADDRESS + pdev_data->stns_offset) #define MAC_STNSR_RD(data) do {\ @@ -162,6 +164,13 @@ struct nvpps_file_data { (data) = ioread32(MAC_STSR_OFFSET);\ } while (0) +/* + * tegra_chip_data Tegra chip specific data + * @support_tsc: Supported TSC sync by chip + */ +struct tegra_chip_data { + bool support_tsc; +}; #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) static inline u64 __arch_counter_get_cntvct(void) @@ -181,12 +190,12 @@ static inline u64 __arch_counter_get_cntvct(void) * * This API is available irrespective of nvpps dt availablity * When nvpps dt node is not present, interface name will - * default to "eth0". + * default to "eth0" */ int nvpps_get_ptp_ts(void *ts) { //TODO : should we support this API with memmapped method - return tegra_get_hwtime(interface_name, ts, PTP_HWTIME); + return tegra_get_hwtime(emac_node, ts, PTP_HWTIME); } EXPORT_SYMBOL(nvpps_get_ptp_ts); @@ -239,13 +248,13 @@ static void nvpps_get_ts(struct nvpps_device_data *pdev_data, u64 irq_tsc) struct ptp_tsc_data ptp_tsc_ts = {0}, sec_ptp_tsc_ts = {0}; /* get the PTP timestamp */ - if (pdev_data->memmap_phc_regs) { + if (pdev_data->mac_base_addr) { /* get both the phc(using memmap reg) and tsc */ phc = get_systime(pdev_data, &tsc); /*TODO : support fetching ptp offset using memmap method */ } else { /* get PTP_TSC concurrent timestamp(using ptp notifier) from MAC driver */ - if (tegra_get_hwtime(pdev_data->iface_nm, &ptp_tsc_ts, PTP_TSC_HWTIME)) { + if (tegra_get_hwtime(pdev_data->pri_emac_node, &ptp_tsc_ts, PTP_TSC_HWTIME)) { pdev_data->pri_ptp_failed = true; } else { pdev_data->pri_ptp_failed = false; @@ -254,15 +263,15 @@ static void nvpps_get_ts(struct nvpps_device_data *pdev_data, u64 irq_tsc) tsc = ptp_tsc_ts.tsc_ts / pdev_data->tsc_res_ns; } - - if ((pdev_data->platform_is_orin) && + if ((pdev_data->support_tsc) && /* primary & secondary ptp interface are not same */ - (strncmp(pdev_data->iface_nm, pdev_data->sec_iface_nm, strlen(pdev_data->iface_nm)))) { + (pdev_data->pri_emac_node != pdev_data->sec_emac_node)) { /* get PTP_TSC concurrent timestamp(using ptp notifier) from MAC * driver for secondary interface */ - if (tegra_get_hwtime(pdev_data->sec_iface_nm, &sec_ptp_tsc_ts, PTP_TSC_HWTIME)) { + if (tegra_get_hwtime(pdev_data->sec_emac_node, &sec_ptp_tsc_ts, + PTP_TSC_HWTIME)) { pdev_data->sec_ptp_failed = true; } else { pdev_data->sec_ptp_failed = false; @@ -590,16 +599,16 @@ static long nvpps_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* check flag to print ptp failure msg */ if ((pdev_data->pri_ptp_failed) && (print_pri_ptp_failed)) { dev_warn_ratelimited(pdev_data->dev, - "failed to get PTP_TSC concurrent timestamp from interface(%s)\nMake sure ptp is running\n", - pdev_data->iface_nm); + "failed to get PTP_TSC timestamp from emac instance\n"); + dev_warn_ratelimited(pdev_data->dev, "Make sure PTP is running\n"); print_pri_ptp_failed = false; } /* check flag to print ptp failure msg */ if ((pdev_data->sec_ptp_failed) && (print_sec_ptp_failed)) { dev_warn_ratelimited(pdev_data->dev, - "failed to get PTP_TSC concurrent timestamp from interface(%s)\nMake sure ptp is running\n", - pdev_data->iface_nm); + "failed to get PTP_TSC timestamp from emac instance\n"); + dev_warn_ratelimited(pdev_data->dev, "Make sure PTP is running\n"); print_sec_ptp_failed = false; } @@ -667,7 +676,7 @@ static long nvpps_ioctl(struct file *file, unsigned int cmd, unsigned long arg) "ioctl: Unsupported clockid\n"); } - err = tegra_get_hwtime(pdev_data->iface_nm, &ns, PTP_HWTIME); + err = tegra_get_hwtime(pdev_data->pri_emac_node, &ns, PTP_HWTIME); mutex_unlock(&pdev_data->ts_lock); if (err) { dev_dbg(pdev_data->dev, @@ -758,113 +767,62 @@ static void nvpps_dev_release(struct device *dev) } static void nvpps_fill_default_mac_phc_info(struct platform_device *pdev, - struct nvpps_device_data *pdev_data) + struct nvpps_device_data *pdev_data) { - bool use_eqos_mac = false; struct device_node *np = pdev->dev.of_node; + bool memmap_phc_regs; - pdev_data->platform_is_orin = false; - - /* Get default params from dt */ - pdev_data->iface_nm = (char *)of_get_property(np, "interface", NULL); - pdev_data->sec_iface_nm = (char *)of_get_property(np, "sec_interface", NULL); - pdev_data->memmap_phc_regs = of_property_read_bool(np, "memmap_phc_regs"); - - /* For orin */ - if (of_machine_is_compatible("nvidia,tegra234")) { - pdev_data->platform_is_orin = true; - - /* set default seconday interface for ptp timestamp */ - if (pdev_data->sec_iface_nm == NULL) { - pdev_data->sec_iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - } - - if (pdev_data->memmap_phc_regs) { - /* TODO: Add support to map secondary interfaces PHC registers */ - dev_info(&pdev->dev, "using mem mapped MAC PHC reg method\n"); - if (pdev_data->iface_nm == NULL) { - pdev_data->iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - dev_warn(&pdev->dev, "interface property not provided. Using default interface(%s)\n", pdev_data->iface_nm); - use_eqos_mac = true; - } else { - if (!strncmp(pdev_data->iface_nm, "eqos_0", sizeof("eqos_0"))) { - use_eqos_mac = true; - } else if (!strncmp(pdev_data->iface_nm, "mgbe0_0", sizeof("mgbe0_0"))) { - /* remap base address for mgbe0_0 */ - pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, T234_MGBE0_BASE_ADDR, SZ_4K); - dev_info(&pdev->dev, "map MGBE0_0 to (%p)\n", pdev_data->mac_base_addr); - pdev_data->sts_offset = MGBE_STSR_OFFSET; - pdev_data->stns_offset = MGBE_STNSR_OFFSET; - } else if (!strncmp(pdev_data->iface_nm, "mgbe1_0", sizeof("mgbe1_0"))) { - /* remap base address for mgbe1_0 */ - pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, T234_MGBE1_BASE_ADDR, SZ_4K); - dev_info(&pdev->dev, "map MGBE1_0 to (%p)\n", pdev_data->mac_base_addr); - pdev_data->sts_offset = MGBE_STSR_OFFSET; - pdev_data->stns_offset = MGBE_STNSR_OFFSET; - } else if (!strncmp(pdev_data->iface_nm, "mgbe2_0", sizeof("mgbe2_0"))) { - /* remap base address for mgbe2_0 */ - pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, T234_MGBE2_BASE_ADDR, SZ_4K); - dev_info(&pdev->dev, "map MGBE2_0 to (%p)\n", pdev_data->mac_base_addr); - pdev_data->sts_offset = MGBE_STSR_OFFSET; - pdev_data->stns_offset = MGBE_STNSR_OFFSET; - } else if (!strncmp(pdev_data->iface_nm, "mgbe3_0", sizeof("mgbe3_0"))) { - /* remap base address for mgbe3_0 */ - pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, T234_MGBE3_BASE_ADDR, SZ_4K); - dev_info(&pdev->dev, "map MGBE3_0 to (%p)\n", pdev_data->mac_base_addr); - pdev_data->sts_offset = MGBE_STSR_OFFSET; - pdev_data->stns_offset = MGBE_STNSR_OFFSET; - } else { - dev_warn(&pdev->dev, "Invalid interface(%s). Using default interface(eqos_0)\n", pdev_data->iface_nm); - pdev_data->iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - use_eqos_mac = true; - } - } - - if (use_eqos_mac) { - /* remap base address for eqos */ - pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, T234_EQOS_BASE_ADDR, SZ_4K); - dev_info(&pdev->dev, "map EQOS to (%p)\n", pdev_data->mac_base_addr); - pdev_data->sts_offset = EQOS_STSR_OFFSET; - pdev_data->stns_offset = EQOS_STNSR_OFFSET; - } - } else { - /* Using ptp-notifier method */ - if (pdev_data->iface_nm) { - if ((!strncmp(pdev_data->iface_nm, "eqos_0", sizeof("eqos_0"))) || - (!strncmp(pdev_data->iface_nm, "mgbe0_0", sizeof("mgbe0_0"))) || - (!strncmp(pdev_data->iface_nm, "mgbe1_0", sizeof("mgbe1_0"))) || - (!strncmp(pdev_data->iface_nm, "mgbe2_0", sizeof("mgbe2_0"))) || - (!strncmp(pdev_data->iface_nm, "mgbe3_0", sizeof("mgbe3_0")))) { - dev_info(&pdev->dev, "using ptp notifier method with interface(%s)\n", pdev_data->iface_nm); - } else { - dev_warn(&pdev->dev, "Invalid interface(%s). Using default interface(eqos_0)\n", pdev_data->iface_nm); - pdev_data->iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - } - } else { - pdev_data->iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - dev_info(&pdev->dev, "using ptp notifier method with interface(%s)\n", pdev_data->iface_nm); - } - } + /* identify the tsc_ptp_src and sts_offset */ + if (pdev_data->pri_emac_base_addr == T234_MGBE0_BASE_ADDR) { + pdev_data->sts_offset = MGBE_STSR_OFFSET; + pdev_data->stns_offset = MGBE_STNSR_OFFSET; + pdev_data->tsc_ptp_src = TSC_PTP_SRC_MGBE0; + } else if (pdev_data->pri_emac_base_addr == T234_MGBE1_BASE_ADDR) { + pdev_data->sts_offset = MGBE_STSR_OFFSET; + pdev_data->stns_offset = MGBE_STNSR_OFFSET; + pdev_data->tsc_ptp_src = TSC_PTP_SRC_MGBE1; + } else if (pdev_data->pri_emac_base_addr == T234_MGBE2_BASE_ADDR) { + pdev_data->sts_offset = MGBE_STSR_OFFSET; + pdev_data->stns_offset = MGBE_STNSR_OFFSET; + pdev_data->tsc_ptp_src = TSC_PTP_SRC_MGBE2; + } else if (pdev_data->pri_emac_base_addr == T234_MGBE3_BASE_ADDR) { + pdev_data->sts_offset = MGBE_STSR_OFFSET; + pdev_data->stns_offset = MGBE_STNSR_OFFSET; + pdev_data->tsc_ptp_src = TSC_PTP_SRC_MGBE3; + } else if (pdev_data->pri_emac_base_addr == T234_EQOS_BASE_ADDR) { + pdev_data->sts_offset = EQOS_STSR_OFFSET; + pdev_data->stns_offset = EQOS_STNSR_OFFSET; + pdev_data->tsc_ptp_src = TSC_PTP_SRC_EQOS; + } else if (pdev_data->pri_emac_base_addr == T194_EQOS_BASE_ADDR) { + pdev_data->sts_offset = EQOS_STSR_OFFSET; + pdev_data->stns_offset = EQOS_STNSR_OFFSET; + pdev_data->tsc_ptp_src = TSC_PTP_SRC_EQOS; } else { - if (pdev_data->memmap_phc_regs) { - if (!(pdev_data->iface_nm && (strncmp(pdev_data->iface_nm, "eqos_0", sizeof("eqos_0")) == 0))) { - dev_warn(&pdev->dev, "Invalid interface(%s). Using default interface(eqos_0)\n", pdev_data->iface_nm); - pdev_data->iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - } - - dev_info(&pdev->dev, "using mem mapped MAC PHC reg method with %s MAC\n", pdev_data->iface_nm); - /* remap base address for eqos */ - pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, T194_EQOS_BASE_ADDR, SZ_4K); - dev_info(&pdev->dev, "map EQOS to (%p)\n", pdev_data->mac_base_addr); - pdev_data->sts_offset = EQOS_STSR_OFFSET; - pdev_data->stns_offset = EQOS_STNSR_OFFSET; - } else { - pdev_data->iface_nm = devm_kstrdup(&pdev->dev, "eqos_0", GFP_KERNEL); - dev_info(&pdev->dev, "using ptp notifier method with default interface(%s)\n", pdev_data->iface_nm); - } + pdev_data->tsc_ptp_src = TSC_PTP_SRC_INVALID; + dev_err(&pdev->dev, "Invalid EMAC base address\n"); + return; + } + + /* Get default params from dt */ + memmap_phc_regs = of_property_read_bool(np, "memmap_phc_regs"); + + if (memmap_phc_regs) { + /* TODO: Add support to map secondary interfaces PHC registers */ + pdev_data->mac_base_addr = devm_ioremap(&pdev->dev, pdev_data->pri_emac_base_addr, + SZ_4K); + if (pdev_data->mac_base_addr == NULL) { + dev_err(&pdev->dev, "failed to ioremap emac base address 0x%llx\n", + pdev_data->pri_emac_base_addr); + return; + } + dev_info(&pdev->dev, "using mem mapped MAC PHC reg method with emac %s\n", + pdev_data->pri_emac_node->full_name); + } else { + if (pdev_data->pri_emac_node != NULL) + dev_info(&pdev->dev, "using ptp notifier method on emac %s\n", + pdev_data->pri_emac_node->full_name); } - interface_name = devm_kstrdup(&pdev->dev, pdev_data->iface_nm, GFP_KERNEL); } static int nvpps_gpio_hte_setup(struct nvpps_device_data *pdev_data) @@ -875,7 +833,7 @@ static int nvpps_gpio_hte_setup(struct nvpps_device_data *pdev_data) pdev_data->use_gpio_int_timestamp = false; pdev_data->gpio_in = devm_gpiod_get_optional(&pdev->dev, "nvpps", 0); if (!pdev_data->gpio_in) { - dev_warn(&pdev->dev, "PPS GPIO not provided in DT, only Timer mode available\n"); + dev_info(&pdev->dev, "PPS GPIO not provided in DT, only Timer mode available\n"); pdev_data->only_timer_mode = true; return 0; } @@ -963,26 +921,15 @@ static void nvpps_ptp_tsc_sync_config(struct platform_device *pdev) writel(0x313, pdev_data->tsc_reg_map_base + TSC_CAPTURE_CONFIGURATION_PTX_OFFSET); writel(0x1, pdev_data->tsc_reg_map_base + TSC_STSCRSR_OFFSET); - //Select PTP src for TSC to lock on based on nw interface - if (!strncmp(pdev_data->iface_nm, "mgbe0_0", sizeof("mgbe0_0"))) { - pdev_data->tsc_ptp_src = (TSC_PTP_SRC_MGBE0 << SRC_SELECT_BIT_OFFSET); - } else if (!strncmp(pdev_data->iface_nm, "mgbe1_0", sizeof("mgbe1_0"))) { - pdev_data->tsc_ptp_src = (TSC_PTP_SRC_MGBE1 << SRC_SELECT_BIT_OFFSET); - } else if (!strncmp(pdev_data->iface_nm, "mgbe2_0", sizeof("mgbe2_0"))) { - pdev_data->tsc_ptp_src = (TSC_PTP_SRC_MGBE2 << SRC_SELECT_BIT_OFFSET); - } else if (!strncmp(pdev_data->iface_nm, "mgbe3_0", sizeof("mgbe3_0"))) { - pdev_data->tsc_ptp_src = (TSC_PTP_SRC_MGBE3 << SRC_SELECT_BIT_OFFSET); - } else { - pdev_data->tsc_ptp_src = (TSC_PTP_SRC_EQOS << SRC_SELECT_BIT_OFFSET); - } - tsc_config_ptx_0 = readl(pdev_data->tsc_reg_map_base + TSC_CAPTURE_CONFIGURATION_PTX_OFFSET); /* clear and set the ptp src based on ethernet interface passed * from dt for tsc to lock onto. */ tsc_config_ptx_0 = tsc_config_ptx_0 & ~(SRC_SELECT_BITS << SRC_SELECT_BIT_OFFSET); - tsc_config_ptx_0 = tsc_config_ptx_0 | pdev_data->tsc_ptp_src; + if (pdev_data->tsc_ptp_src != TSC_PTP_SRC_INVALID) + tsc_config_ptx_0 = tsc_config_ptx_0 | + (pdev_data->tsc_ptp_src << SRC_SELECT_BIT_OFFSET); writel(tsc_config_ptx_0, pdev_data->tsc_reg_map_base + TSC_CAPTURE_CONFIGURATION_PTX_OFFSET); tsc_config_ptx_0 = readl(pdev_data->tsc_reg_map_base + TSC_CAPTURE_CONFIGURATION_PTX_OFFSET); dev_info(&pdev->dev, "TSC config ptx 0x%x\n", tsc_config_ptx_0); @@ -998,6 +945,9 @@ static int nvpps_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; dev_t devt; int err; + const struct tegra_chip_data *cdata = NULL; + struct resource res; + int index; dev_info(&pdev->dev, "%s\n", __FUNCTION__); @@ -1011,6 +961,37 @@ static int nvpps_probe(struct platform_device *pdev) return -ENOMEM; } + emac_node = NULL; + + pdev_data->pri_emac_node = of_parse_phandle(np, "primary-emac", 0); + if (pdev_data->pri_emac_node == NULL) { + dev_info(&pdev->dev, "primary-emac node not found\n"); + } else { + dev_info(&pdev->dev, "primary-emac found %s", pdev_data->pri_emac_node->full_name); + index = of_property_match_string(pdev_data->pri_emac_node, "reg-names", "mac"); + if (index >= 0) { + if (of_address_to_resource(pdev_data->pri_emac_node, index, &res)) { + dev_err(&pdev->dev, "failed to parse primary emac reg property\n"); + } else { + pdev_data->pri_emac_base_addr = res.start; + dev_info(&pdev->dev, "primary emac base address 0x%llx\n", + pdev_data->pri_emac_base_addr); + } + } else { + dev_info(&pdev->dev, "failed to find ethernet mac registers\n"); + } + } + + emac_node = pdev_data->pri_emac_node; + pdev_data->sec_emac_node = of_parse_phandle(np, "sec-emac", 0); + if (pdev_data->sec_emac_node == NULL) { + dev_info(&pdev->dev, "sec-emac node not found\n"); + pdev_data->sec_emac_node = pdev_data->pri_emac_node; + } + + cdata = of_device_get_match_data(&pdev->dev); + pdev_data->support_tsc = cdata->support_tsc; + nvpps_fill_default_mac_phc_info(pdev, pdev_data); init_waitqueue_head(&pdev_data->pps_event_queue); @@ -1100,7 +1081,7 @@ static int nvpps_probe(struct platform_device *pdev) } pdev_data->evt_mode = (pdev_data->only_timer_mode) ? NVPPS_MODE_TIMER : NVPPS_MODE_GPIO; - if (pdev_data->platform_is_orin) { + if (pdev_data->support_tsc) { struct resource *tsc_mem; tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1130,6 +1111,8 @@ static int nvpps_probe(struct platform_device *pdev) return 0; error_ret: + of_node_put(pdev_data->pri_emac_node); + of_node_put(pdev_data->sec_emac_node); cdev_del(&pdev_data->cdev); mutex_lock(&s_nvpps_lock); idr_remove(&s_nvpps_idr, pdev_data->id); @@ -1149,18 +1132,21 @@ static int nvpps_remove(struct platform_device *pdev) pdev_data->timer_inited = false; del_timer_sync(&pdev_data->timer); } - if (pdev_data->memmap_phc_regs) { + if (pdev_data->mac_base_addr) { devm_iounmap(&pdev->dev, pdev_data->mac_base_addr); dev_info(&pdev->dev, "unmap MAC reg space %p for nvpps\n", pdev_data->mac_base_addr); } - if (pdev_data->platform_is_orin) { + if (pdev_data->support_tsc) { del_timer_sync(&pdev_data->tsc_timer); iounmap(pdev_data->tsc_reg_map_base); } device_destroy(s_nvpps_class, pdev_data->dev->devt); } + of_node_put(pdev_data->pri_emac_node); + of_node_put(pdev_data->sec_emac_node); + #ifndef NVPPS_NO_DT class_unregister(s_nvpps_class); class_destroy(s_nvpps_class); @@ -1188,8 +1174,15 @@ static int nvpps_resume(struct platform_device *pdev) #ifndef NVPPS_NO_DT +static const struct tegra_chip_data tegra234_chip_data = { + .support_tsc = true, +}; +static const struct tegra_chip_data tegra194_chip_data = { + .support_tsc = false, +}; static const struct of_device_id nvpps_of_table[] = { - { .compatible = "nvidia,tegra194-nvpps", }, + { .compatible = "nvidia,tegra194-nvpps", .data = &tegra194_chip_data }, + { .compatible = "nvidia,tegra234-nvpps", .data = &tegra234_chip_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, nvpps_of_table); @@ -1269,4 +1262,4 @@ module_platform_driver(nvpps_plat_driver); MODULE_DESCRIPTION("NVidia Tegra PPS Driver"); MODULE_AUTHOR("David Tao tehyut@nvidia.com"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/nvpps/ptp-notifier.c b/drivers/nvpps/ptp-notifier.c index 24b525f2..2218dfd9 100644 --- a/drivers/nvpps/ptp-notifier.c +++ b/drivers/nvpps/ptp-notifier.c @@ -1,10 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include #include +#include #include static int (*get_systime[MAX_MAC_INSTANCES])(struct net_device *, void *, int); @@ -91,47 +90,65 @@ void tegra_unregister_hwtime_source(struct net_device *dev) } EXPORT_SYMBOL(tegra_unregister_hwtime_source); -int tegra_get_hwtime(const char *intf_name, void *ts, int ts_type) +int tegra_get_hwtime(const struct device_node *emac_node, void *ts, int ts_type) { unsigned long flags; int ret = 0, index = 0; - struct net_device *dev; + struct net_device *dev = NULL; + struct net_device *intf_dev = NULL; + const char *intf_name = "eth0"; + + if (!ts) { + pr_err("%s: time-stamp ptr is NULL\n", __func__); + return -EINVAL; + } + + if (emac_node == NULL) { + pr_debug("EMAC node is invalid, using default interface %s\n", intf_name); + intf_dev = dev_get_by_name(&init_net, intf_name); + if (!intf_dev || !(intf_dev->flags & IFF_UP)) { + pr_debug("Network interface %s is not %s", intf_name, + !intf_dev ? "found":"up"); + ret = -EINVAL; + goto out; + } + } raw_spin_lock_irqsave(&ptp_notifier_lock, flags); - if (!intf_name || !ts) { - pr_err("passed Interface_name or time-stamp ptr is NULL"); - raw_spin_unlock_irqrestore(&ptp_notifier_lock, flags); - return -1; - } - dev = dev_get_by_name(&init_net, intf_name); - - if (!dev || !(dev->flags & IFF_UP)) { - pr_debug("dev is NULL or intf is not up for %s\n", intf_name); - ret = -EINVAL; - goto out; - } for (index = 0; index < MAX_MAC_INSTANCES; index++) { - if (dev == registered_ndev[index]) + dev = registered_ndev[index]; + if (dev == NULL) { + pr_debug("No registered net device for index %d\n", index); + continue; + } + if (emac_node == dev->dev.parent->of_node) { + pr_debug("found emac name (%s)\n", emac_node->full_name); break; + } else if (intf_dev && intf_dev == dev) { + pr_debug("found ethenet interface (%s)\n", intf_name); + break; + } + } if (index == MAX_MAC_INSTANCES) { - pr_debug("Interface: %s is not registered to get HW time", intf_name); + pr_debug("%s: ethernet device %s is not registered!\n", __func__, + !emac_node ? intf_name : emac_node->full_name); ret = -EINVAL; - goto out; + goto unlock; } if (get_systime[index]) ret = (get_systime[index])(dev, ts, ts_type); else ret = -EINVAL; - -out: - if (dev) - dev_put(dev); +unlock: raw_spin_unlock_irqrestore(&ptp_notifier_lock, flags); +out: + if (intf_dev) + dev_put(intf_dev); return ret; } EXPORT_SYMBOL(tegra_get_hwtime); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform/tegra/ptp-notifier.h b/include/linux/platform/tegra/ptp-notifier.h index 9b800ff6..78777547 100644 --- a/include/linux/platform/tegra/ptp-notifier.h +++ b/include/linux/platform/tegra/ptp-notifier.h @@ -1,7 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. #ifndef __PTP_NOTIFIER_H #define __PTP_NOTIFIER_H @@ -45,6 +43,7 @@ int tegra_hwtime_notifier_call_chain(unsigned int val, void *v); * Clients may call the API every anytime PTP/TSC time is needed. * If HW time source is not registered, returns -EINVAL */ -int tegra_get_hwtime(const char *intf_name, void *ts, int ts_type); +int tegra_get_hwtime(const struct device_node *emac_node, void *ts, int ts_type); + #endif /* __PTP_NOTIFIER_H */