Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19971f5e authored by Yangbo Lu's avatar Yangbo Lu Committed by David S. Miller
Browse files

enetc: add PTP clock driver



This patch is to add PTP clock driver for ENETC.
The driver reused QorIQ PTP clock driver.

Signed-off-by: default avatarYangbo Lu <yangbo.lu@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ad6e1be6
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -17,3 +17,15 @@ config FSL_ENETC_VF
	  virtual function (VF) devices enabled by the ENETC PF driver.

	  If compiled as module (M), the module name is fsl-enetc-vf.

config FSL_ENETC_PTP_CLOCK
	tristate "ENETC PTP clock driver"
	depends on PTP_1588_CLOCK_QORIQ && (FSL_ENETC || FSL_ENETC_VF)
	default y
	help
	  This driver adds support for using the ENETC 1588 timer
	  as a PTP clock. This clock is only useful if your PTP
	  programs are getting hardware time stamps on the PTP Ethernet
	  packets using the SO_TIMESTAMPING API.

	  If compiled as module (M), the module name is fsl-enetc-ptp.
+3 −0
Original line number Diff line number Diff line
@@ -13,3 +13,6 @@ fsl-enetc-vf-$(CONFIG_FSL_ENETC_VF) += enetc.o enetc_cbdr.o \
				       enetc_ethtool.o
fsl-enetc-vf-objs := enetc_vf.o $(fsl-enetc-vf-y)
endif

obj-$(CONFIG_FSL_ENETC_PTP_CLOCK) += fsl-enetc-ptp.o
fsl-enetc-ptp-$(CONFIG_FSL_ENETC_PTP_CLOCK) += enetc_ptp.o
+3 −2
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
/* ENETC device IDs */
#define ENETC_DEV_ID_PF		0xe100
#define ENETC_DEV_ID_VF		0xef00
#define ENETC_DEV_ID_PTP	0xee02

/* ENETC register block BAR */
#define ENETC_BAR_REGS	0
+144 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */

#include <linux/module.h>
#include <linux/of.h>
#include <linux/fsl/ptp_qoriq.h>

#include "enetc.h"

static struct ptp_clock_info enetc_ptp_caps = {
	.owner		= THIS_MODULE,
	.name		= "ENETC PTP clock",
	.max_adj	= 512000,
	.n_alarm	= 0,
	.n_ext_ts	= 2,
	.n_per_out	= 0,
	.n_pins		= 0,
	.pps		= 1,
	.adjfine	= ptp_qoriq_adjfine,
	.adjtime	= ptp_qoriq_adjtime,
	.gettime64	= ptp_qoriq_gettime,
	.settime64	= ptp_qoriq_settime,
	.enable		= ptp_qoriq_enable,
};

static int enetc_ptp_probe(struct pci_dev *pdev,
			   const struct pci_device_id *ent)
{
	struct ptp_qoriq *ptp_qoriq;
	void __iomem *base;
	int err, len, n;

	if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
		dev_info(&pdev->dev, "device is disabled, skipping\n");
		return -ENODEV;
	}

	err = pci_enable_device_mem(pdev);
	if (err) {
		dev_err(&pdev->dev, "device enable failed\n");
		return err;
	}

	/* set up for high or low dma */
	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
	if (err) {
		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
		if (err) {
			dev_err(&pdev->dev,
				"DMA configuration failed: 0x%x\n", err);
			goto err_dma;
		}
	}

	err = pci_request_mem_regions(pdev, KBUILD_MODNAME);
	if (err) {
		dev_err(&pdev->dev, "pci_request_regions failed err=%d\n", err);
		goto err_pci_mem_reg;
	}

	pci_set_master(pdev);

	ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL);
	if (!ptp_qoriq) {
		err = -ENOMEM;
		goto err_alloc_ptp;
	}

	len = pci_resource_len(pdev, ENETC_BAR_REGS);

	base = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), len);
	if (!base) {
		err = -ENXIO;
		dev_err(&pdev->dev, "ioremap() failed\n");
		goto err_ioremap;
	}

	/* Allocate 1 interrupt */
	n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
	if (n != 1) {
		err = -EPERM;
		goto err_irq;
	}

	ptp_qoriq->irq = pci_irq_vector(pdev, 0);

	err = request_irq(ptp_qoriq->irq, ptp_qoriq_isr, 0, DRIVER, ptp_qoriq);
	if (err) {
		dev_err(&pdev->dev, "request_irq() failed!\n");
		goto err_irq;
	}

	ptp_qoriq->dev = &pdev->dev;

	err = ptp_qoriq_init(ptp_qoriq, base, enetc_ptp_caps);
	if (err)
		goto err_no_clock;

	pci_set_drvdata(pdev, ptp_qoriq);

	return 0;

err_no_clock:
	free_irq(ptp_qoriq->irq, ptp_qoriq);
err_irq:
	iounmap(base);
err_ioremap:
	kfree(ptp_qoriq);
err_alloc_ptp:
	pci_release_mem_regions(pdev);
err_pci_mem_reg:
err_dma:
	pci_disable_device(pdev);

	return err;
}

static void enetc_ptp_remove(struct pci_dev *pdev)
{
	struct ptp_qoriq *ptp_qoriq = pci_get_drvdata(pdev);

	ptp_qoriq_free(ptp_qoriq);
	kfree(ptp_qoriq);

	pci_release_mem_regions(pdev);
	pci_disable_device(pdev);
}

static const struct pci_device_id enetc_ptp_id_table[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PTP) },
	{ 0, } /* End of table. */
};
MODULE_DEVICE_TABLE(pci, enetc_ptp_id_table);

static struct pci_driver enetc_ptp_driver = {
	.name = KBUILD_MODNAME,
	.id_table = enetc_ptp_id_table,
	.probe = enetc_ptp_probe,
	.remove = enetc_ptp_remove,
};
module_pci_driver(enetc_ptp_driver);

MODULE_DESCRIPTION("ENETC PTP clock driver");
MODULE_LICENSE("Dual BSD/GPL");