Merge branch 'Add-ENETC-PTP-clock-driver'
Yangbo Lu says: ==================== Add ENETC PTP clock driver There is same QorIQ 1588 timer IP block on the new ENETC Ethernet controller with eTSEC/DPAA Ethernet controllers. However it's different endianness (little-endian) and using PCI driver. To support ENETC PTP driver, ptp_qoriq driver needed to be reworked to make functions global for reusing, to add little- endian support, to add ENETC memory map support, and to add ENETC dependency for ptp_qoriq driver. In addition, although ENETC PTP driver is a PCI driver, the dts node still could be used. Currently the ls1028a dtsi which is the only platform by now using ENETC is not complete, so there is still dependency for ENETC PTP node upstreaming. This will be done in the near future. The hardware timestamping support for ENETC is done but needs to be reworked with new method in internal git tree, and will be sent out soon. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
a263f99ca8
|
@ -19,6 +19,9 @@ Clock Properties:
|
|||
- fsl,max-adj Maximum frequency adjustment in parts per billion.
|
||||
- fsl,extts-fifo The presence of this property indicates hardware
|
||||
support for the external trigger stamp FIFO.
|
||||
- little-endian The presence of this property indicates the 1588 timer
|
||||
IP block is little-endian mode. The default endian mode
|
||||
is big-endian.
|
||||
|
||||
These properties set the operational parameters for the PTP
|
||||
clock. You must choose these carefully for the clock to work right.
|
||||
|
|
|
@ -6104,6 +6104,7 @@ FREESCALE QORIQ PTP CLOCK DRIVER
|
|||
M: Yangbo Lu <yangbo.lu@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c
|
||||
F: drivers/ptp/ptp_qoriq.c
|
||||
F: drivers/ptp/ptp_qoriq_debugfs.c
|
||||
F: include/linux/fsl/ptp_qoriq.h
|
||||
|
|
|
@ -501,7 +501,7 @@ static int dpaa_get_ts_info(struct net_device *net_dev,
|
|||
struct device_node *mac_node = dev->of_node;
|
||||
struct device_node *fman_node = NULL, *ptp_node = NULL;
|
||||
struct platform_device *ptp_dev = NULL;
|
||||
struct qoriq_ptp *ptp = NULL;
|
||||
struct ptp_qoriq *ptp = NULL;
|
||||
|
||||
info->phc_index = -1;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
#include <linux/bitops.h>
|
||||
|
||||
/* ENETC device IDs */
|
||||
#define ENETC_DEV_ID_PF 0xe100
|
||||
#define ENETC_DEV_ID_VF 0xef00
|
||||
#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
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
// 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");
|
|
@ -1492,7 +1492,7 @@ static int gfar_get_ts_info(struct net_device *dev,
|
|||
struct gfar_private *priv = netdev_priv(dev);
|
||||
struct platform_device *ptp_dev;
|
||||
struct device_node *ptp_node;
|
||||
struct qoriq_ptp *ptp = NULL;
|
||||
struct ptp_qoriq *ptp = NULL;
|
||||
|
||||
info->phc_index = -1;
|
||||
|
||||
|
|
|
@ -617,6 +617,8 @@ static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
|
|||
}
|
||||
#endif
|
||||
|
||||
#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN)
|
||||
|
||||
/* We reach this function only after checking that any of
|
||||
* the (IPv4 | IPv6) bits are set in cqe->status.
|
||||
*/
|
||||
|
@ -624,9 +626,20 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
|
|||
netdev_features_t dev_features)
|
||||
{
|
||||
__wsum hw_checksum = 0;
|
||||
void *hdr;
|
||||
|
||||
void *hdr = (u8 *)va + sizeof(struct ethhdr);
|
||||
/* CQE csum doesn't cover padding octets in short ethernet
|
||||
* frames. And the pad field is appended prior to calculating
|
||||
* and appending the FCS field.
|
||||
*
|
||||
* Detecting these padded frames requires to verify and parse
|
||||
* IP headers, so we simply force all those small frames to skip
|
||||
* checksum complete.
|
||||
*/
|
||||
if (short_frame(skb->len))
|
||||
return -EINVAL;
|
||||
|
||||
hdr = (u8 *)va + sizeof(struct ethhdr);
|
||||
hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
|
||||
|
||||
if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) &&
|
||||
|
@ -819,6 +832,11 @@ xdp_drop_no_cnt:
|
|||
skb_record_rx_queue(skb, cq_ring);
|
||||
|
||||
if (likely(dev->features & NETIF_F_RXCSUM)) {
|
||||
/* TODO: For IP non TCP/UDP packets when csum complete is
|
||||
* not an option (not supported or any other reason) we can
|
||||
* actually check cqe IPOK status bit and report
|
||||
* CHECKSUM_UNNECESSARY rather than CHECKSUM_NONE
|
||||
*/
|
||||
if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
|
||||
MLX4_CQE_STATUS_UDP)) &&
|
||||
(cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
|
||||
|
|
|
@ -43,7 +43,7 @@ config PTP_1588_CLOCK_DTE
|
|||
|
||||
config PTP_1588_CLOCK_QORIQ
|
||||
tristate "Freescale QorIQ 1588 timer as PTP clock"
|
||||
depends on GIANFAR || FSL_DPAA_ETH
|
||||
depends on GIANFAR || FSL_DPAA_ETH || FSL_ENETC || FSL_ENETC_VF
|
||||
depends on PTP_1588_CLOCK
|
||||
default y
|
||||
help
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -37,61 +36,61 @@
|
|||
* Register access functions
|
||||
*/
|
||||
|
||||
/* Caller must hold qoriq_ptp->lock. */
|
||||
static u64 tmr_cnt_read(struct qoriq_ptp *qoriq_ptp)
|
||||
/* Caller must hold ptp_qoriq->lock. */
|
||||
static u64 tmr_cnt_read(struct ptp_qoriq *ptp_qoriq)
|
||||
{
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u64 ns;
|
||||
u32 lo, hi;
|
||||
|
||||
lo = qoriq_read(®s->ctrl_regs->tmr_cnt_l);
|
||||
hi = qoriq_read(®s->ctrl_regs->tmr_cnt_h);
|
||||
lo = ptp_qoriq->read(®s->ctrl_regs->tmr_cnt_l);
|
||||
hi = ptp_qoriq->read(®s->ctrl_regs->tmr_cnt_h);
|
||||
ns = ((u64) hi) << 32;
|
||||
ns |= lo;
|
||||
return ns;
|
||||
}
|
||||
|
||||
/* Caller must hold qoriq_ptp->lock. */
|
||||
static void tmr_cnt_write(struct qoriq_ptp *qoriq_ptp, u64 ns)
|
||||
/* Caller must hold ptp_qoriq->lock. */
|
||||
static void tmr_cnt_write(struct ptp_qoriq *ptp_qoriq, u64 ns)
|
||||
{
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u32 hi = ns >> 32;
|
||||
u32 lo = ns & 0xffffffff;
|
||||
|
||||
qoriq_write(®s->ctrl_regs->tmr_cnt_l, lo);
|
||||
qoriq_write(®s->ctrl_regs->tmr_cnt_h, hi);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_cnt_l, lo);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_cnt_h, hi);
|
||||
}
|
||||
|
||||
/* Caller must hold qoriq_ptp->lock. */
|
||||
static void set_alarm(struct qoriq_ptp *qoriq_ptp)
|
||||
/* Caller must hold ptp_qoriq->lock. */
|
||||
static void set_alarm(struct ptp_qoriq *ptp_qoriq)
|
||||
{
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u64 ns;
|
||||
u32 lo, hi;
|
||||
|
||||
ns = tmr_cnt_read(qoriq_ptp) + 1500000000ULL;
|
||||
ns = tmr_cnt_read(ptp_qoriq) + 1500000000ULL;
|
||||
ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
|
||||
ns -= qoriq_ptp->tclk_period;
|
||||
ns -= ptp_qoriq->tclk_period;
|
||||
hi = ns >> 32;
|
||||
lo = ns & 0xffffffff;
|
||||
qoriq_write(®s->alarm_regs->tmr_alarm1_l, lo);
|
||||
qoriq_write(®s->alarm_regs->tmr_alarm1_h, hi);
|
||||
ptp_qoriq->write(®s->alarm_regs->tmr_alarm1_l, lo);
|
||||
ptp_qoriq->write(®s->alarm_regs->tmr_alarm1_h, hi);
|
||||
}
|
||||
|
||||
/* Caller must hold qoriq_ptp->lock. */
|
||||
static void set_fipers(struct qoriq_ptp *qoriq_ptp)
|
||||
/* Caller must hold ptp_qoriq->lock. */
|
||||
static void set_fipers(struct ptp_qoriq *ptp_qoriq)
|
||||
{
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
|
||||
set_alarm(qoriq_ptp);
|
||||
qoriq_write(®s->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
|
||||
qoriq_write(®s->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
|
||||
set_alarm(ptp_qoriq);
|
||||
ptp_qoriq->write(®s->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
|
||||
ptp_qoriq->write(®s->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
|
||||
}
|
||||
|
||||
static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index,
|
||||
static int extts_clean_up(struct ptp_qoriq *ptp_qoriq, int index,
|
||||
bool update_event)
|
||||
{
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
struct ptp_clock_event event;
|
||||
void __iomem *reg_etts_l;
|
||||
void __iomem *reg_etts_h;
|
||||
|
@ -116,17 +115,17 @@ static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index,
|
|||
event.index = index;
|
||||
|
||||
do {
|
||||
lo = qoriq_read(reg_etts_l);
|
||||
hi = qoriq_read(reg_etts_h);
|
||||
lo = ptp_qoriq->read(reg_etts_l);
|
||||
hi = ptp_qoriq->read(reg_etts_h);
|
||||
|
||||
if (update_event) {
|
||||
event.timestamp = ((u64) hi) << 32;
|
||||
event.timestamp |= lo;
|
||||
ptp_clock_event(qoriq_ptp->clock, &event);
|
||||
ptp_clock_event(ptp_qoriq->clock, &event);
|
||||
}
|
||||
|
||||
stat = qoriq_read(®s->ctrl_regs->tmr_stat);
|
||||
} while (qoriq_ptp->extts_fifo_support && (stat & valid));
|
||||
stat = ptp_qoriq->read(®s->ctrl_regs->tmr_stat);
|
||||
} while (ptp_qoriq->extts_fifo_support && (stat & valid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -135,89 +134,90 @@ static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index,
|
|||
* Interrupt service routine
|
||||
*/
|
||||
|
||||
static irqreturn_t isr(int irq, void *priv)
|
||||
irqreturn_t ptp_qoriq_isr(int irq, void *priv)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = priv;
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = priv;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
struct ptp_clock_event event;
|
||||
u64 ns;
|
||||
u32 ack = 0, lo, hi, mask, val, irqs;
|
||||
|
||||
spin_lock(&qoriq_ptp->lock);
|
||||
spin_lock(&ptp_qoriq->lock);
|
||||
|
||||
val = qoriq_read(®s->ctrl_regs->tmr_tevent);
|
||||
mask = qoriq_read(®s->ctrl_regs->tmr_temask);
|
||||
val = ptp_qoriq->read(®s->ctrl_regs->tmr_tevent);
|
||||
mask = ptp_qoriq->read(®s->ctrl_regs->tmr_temask);
|
||||
|
||||
spin_unlock(&qoriq_ptp->lock);
|
||||
spin_unlock(&ptp_qoriq->lock);
|
||||
|
||||
irqs = val & mask;
|
||||
|
||||
if (irqs & ETS1) {
|
||||
ack |= ETS1;
|
||||
extts_clean_up(qoriq_ptp, 0, true);
|
||||
extts_clean_up(ptp_qoriq, 0, true);
|
||||
}
|
||||
|
||||
if (irqs & ETS2) {
|
||||
ack |= ETS2;
|
||||
extts_clean_up(qoriq_ptp, 1, true);
|
||||
extts_clean_up(ptp_qoriq, 1, true);
|
||||
}
|
||||
|
||||
if (irqs & ALM2) {
|
||||
ack |= ALM2;
|
||||
if (qoriq_ptp->alarm_value) {
|
||||
if (ptp_qoriq->alarm_value) {
|
||||
event.type = PTP_CLOCK_ALARM;
|
||||
event.index = 0;
|
||||
event.timestamp = qoriq_ptp->alarm_value;
|
||||
ptp_clock_event(qoriq_ptp->clock, &event);
|
||||
event.timestamp = ptp_qoriq->alarm_value;
|
||||
ptp_clock_event(ptp_qoriq->clock, &event);
|
||||
}
|
||||
if (qoriq_ptp->alarm_interval) {
|
||||
ns = qoriq_ptp->alarm_value + qoriq_ptp->alarm_interval;
|
||||
if (ptp_qoriq->alarm_interval) {
|
||||
ns = ptp_qoriq->alarm_value + ptp_qoriq->alarm_interval;
|
||||
hi = ns >> 32;
|
||||
lo = ns & 0xffffffff;
|
||||
qoriq_write(®s->alarm_regs->tmr_alarm2_l, lo);
|
||||
qoriq_write(®s->alarm_regs->tmr_alarm2_h, hi);
|
||||
qoriq_ptp->alarm_value = ns;
|
||||
ptp_qoriq->write(®s->alarm_regs->tmr_alarm2_l, lo);
|
||||
ptp_qoriq->write(®s->alarm_regs->tmr_alarm2_h, hi);
|
||||
ptp_qoriq->alarm_value = ns;
|
||||
} else {
|
||||
spin_lock(&qoriq_ptp->lock);
|
||||
mask = qoriq_read(®s->ctrl_regs->tmr_temask);
|
||||
spin_lock(&ptp_qoriq->lock);
|
||||
mask = ptp_qoriq->read(®s->ctrl_regs->tmr_temask);
|
||||
mask &= ~ALM2EN;
|
||||
qoriq_write(®s->ctrl_regs->tmr_temask, mask);
|
||||
spin_unlock(&qoriq_ptp->lock);
|
||||
qoriq_ptp->alarm_value = 0;
|
||||
qoriq_ptp->alarm_interval = 0;
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_temask, mask);
|
||||
spin_unlock(&ptp_qoriq->lock);
|
||||
ptp_qoriq->alarm_value = 0;
|
||||
ptp_qoriq->alarm_interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (irqs & PP1) {
|
||||
ack |= PP1;
|
||||
event.type = PTP_CLOCK_PPS;
|
||||
ptp_clock_event(qoriq_ptp->clock, &event);
|
||||
ptp_clock_event(ptp_qoriq->clock, &event);
|
||||
}
|
||||
|
||||
if (ack) {
|
||||
qoriq_write(®s->ctrl_regs->tmr_tevent, ack);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_tevent, ack);
|
||||
return IRQ_HANDLED;
|
||||
} else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_isr);
|
||||
|
||||
/*
|
||||
* PTP clock operations
|
||||
*/
|
||||
|
||||
static int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
u64 adj, diff;
|
||||
u32 tmr_add;
|
||||
int neg_adj = 0;
|
||||
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
|
||||
if (scaled_ppm < 0) {
|
||||
neg_adj = 1;
|
||||
scaled_ppm = -scaled_ppm;
|
||||
}
|
||||
tmr_add = qoriq_ptp->tmr_add;
|
||||
tmr_add = ptp_qoriq->tmr_add;
|
||||
adj = tmr_add;
|
||||
|
||||
/* calculate diff as adj*(scaled_ppm/65536)/1000000
|
||||
|
@ -229,71 +229,74 @@ static int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|||
|
||||
tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
|
||||
|
||||
qoriq_write(®s->ctrl_regs->tmr_add, tmr_add);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_add, tmr_add);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_adjfine);
|
||||
|
||||
static int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
||||
int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
s64 now;
|
||||
unsigned long flags;
|
||||
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
|
||||
struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
|
||||
|
||||
spin_lock_irqsave(&qoriq_ptp->lock, flags);
|
||||
spin_lock_irqsave(&ptp_qoriq->lock, flags);
|
||||
|
||||
now = tmr_cnt_read(qoriq_ptp);
|
||||
now = tmr_cnt_read(ptp_qoriq);
|
||||
now += delta;
|
||||
tmr_cnt_write(qoriq_ptp, now);
|
||||
set_fipers(qoriq_ptp);
|
||||
tmr_cnt_write(ptp_qoriq, now);
|
||||
set_fipers(ptp_qoriq);
|
||||
|
||||
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
|
||||
spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_adjtime);
|
||||
|
||||
static int ptp_qoriq_gettime(struct ptp_clock_info *ptp,
|
||||
struct timespec64 *ts)
|
||||
int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
||||
{
|
||||
u64 ns;
|
||||
unsigned long flags;
|
||||
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
|
||||
struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
|
||||
|
||||
spin_lock_irqsave(&qoriq_ptp->lock, flags);
|
||||
spin_lock_irqsave(&ptp_qoriq->lock, flags);
|
||||
|
||||
ns = tmr_cnt_read(qoriq_ptp);
|
||||
ns = tmr_cnt_read(ptp_qoriq);
|
||||
|
||||
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
|
||||
spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
|
||||
|
||||
*ts = ns_to_timespec64(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_gettime);
|
||||
|
||||
static int ptp_qoriq_settime(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts)
|
||||
int ptp_qoriq_settime(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts)
|
||||
{
|
||||
u64 ns;
|
||||
unsigned long flags;
|
||||
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
|
||||
struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
|
||||
|
||||
ns = timespec64_to_ns(ts);
|
||||
|
||||
spin_lock_irqsave(&qoriq_ptp->lock, flags);
|
||||
spin_lock_irqsave(&ptp_qoriq->lock, flags);
|
||||
|
||||
tmr_cnt_write(qoriq_ptp, ns);
|
||||
set_fipers(qoriq_ptp);
|
||||
tmr_cnt_write(ptp_qoriq, ns);
|
||||
set_fipers(ptp_qoriq);
|
||||
|
||||
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
|
||||
spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_settime);
|
||||
|
||||
static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
int ptp_qoriq_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps);
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
unsigned long flags;
|
||||
u32 bit, mask = 0;
|
||||
|
||||
|
@ -311,7 +314,7 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
|
|||
}
|
||||
|
||||
if (on)
|
||||
extts_clean_up(qoriq_ptp, rq->extts.index, false);
|
||||
extts_clean_up(ptp_qoriq, rq->extts.index, false);
|
||||
|
||||
break;
|
||||
case PTP_CLK_REQ_PPS:
|
||||
|
@ -321,21 +324,22 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&qoriq_ptp->lock, flags);
|
||||
spin_lock_irqsave(&ptp_qoriq->lock, flags);
|
||||
|
||||
mask = qoriq_read(®s->ctrl_regs->tmr_temask);
|
||||
mask = ptp_qoriq->read(®s->ctrl_regs->tmr_temask);
|
||||
if (on) {
|
||||
mask |= bit;
|
||||
qoriq_write(®s->ctrl_regs->tmr_tevent, bit);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_tevent, bit);
|
||||
} else {
|
||||
mask &= ~bit;
|
||||
}
|
||||
|
||||
qoriq_write(®s->ctrl_regs->tmr_temask, mask);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_temask, mask);
|
||||
|
||||
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
|
||||
spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_enable);
|
||||
|
||||
static const struct ptp_clock_info ptp_qoriq_caps = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -354,7 +358,7 @@ static const struct ptp_clock_info ptp_qoriq_caps = {
|
|||
};
|
||||
|
||||
/**
|
||||
* qoriq_ptp_nominal_freq - calculate nominal frequency according to
|
||||
* ptp_qoriq_nominal_freq - calculate nominal frequency according to
|
||||
* reference clock frequency
|
||||
*
|
||||
* @clk_src: reference clock frequency
|
||||
|
@ -365,7 +369,7 @@ static const struct ptp_clock_info ptp_qoriq_caps = {
|
|||
*
|
||||
* Return the nominal frequency
|
||||
*/
|
||||
static u32 qoriq_ptp_nominal_freq(u32 clk_src)
|
||||
static u32 ptp_qoriq_nominal_freq(u32 clk_src)
|
||||
{
|
||||
u32 remainder = 0;
|
||||
|
||||
|
@ -385,9 +389,9 @@ static u32 qoriq_ptp_nominal_freq(u32 clk_src)
|
|||
}
|
||||
|
||||
/**
|
||||
* qoriq_ptp_auto_config - calculate a set of default configurations
|
||||
* ptp_qoriq_auto_config - calculate a set of default configurations
|
||||
*
|
||||
* @qoriq_ptp: pointer to qoriq_ptp
|
||||
* @ptp_qoriq: pointer to ptp_qoriq
|
||||
* @node: pointer to device_node
|
||||
*
|
||||
* If below dts properties are not provided, this function will be
|
||||
|
@ -401,7 +405,7 @@ static u32 qoriq_ptp_nominal_freq(u32 clk_src)
|
|||
*
|
||||
* Return 0 if success
|
||||
*/
|
||||
static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
|
||||
static int ptp_qoriq_auto_config(struct ptp_qoriq *ptp_qoriq,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
@ -411,7 +415,7 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
|
|||
u32 remainder = 0;
|
||||
u32 clk_src = 0;
|
||||
|
||||
qoriq_ptp->cksel = DEFAULT_CKSEL;
|
||||
ptp_qoriq->cksel = DEFAULT_CKSEL;
|
||||
|
||||
clk = of_clk_get(node, 0);
|
||||
if (!IS_ERR(clk)) {
|
||||
|
@ -424,12 +428,12 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
nominal_freq = qoriq_ptp_nominal_freq(clk_src);
|
||||
nominal_freq = ptp_qoriq_nominal_freq(clk_src);
|
||||
if (!nominal_freq)
|
||||
return -EINVAL;
|
||||
|
||||
qoriq_ptp->tclk_period = 1000000000UL / nominal_freq;
|
||||
qoriq_ptp->tmr_prsc = DEFAULT_TMR_PRSC;
|
||||
ptp_qoriq->tclk_period = 1000000000UL / nominal_freq;
|
||||
ptp_qoriq->tmr_prsc = DEFAULT_TMR_PRSC;
|
||||
|
||||
/* Calculate initial frequency compensation value for TMR_ADD register.
|
||||
* freq_comp = ceil(2^32 / freq_ratio)
|
||||
|
@ -440,172 +444,193 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
|
|||
if (remainder)
|
||||
freq_comp++;
|
||||
|
||||
qoriq_ptp->tmr_add = freq_comp;
|
||||
qoriq_ptp->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - qoriq_ptp->tclk_period;
|
||||
qoriq_ptp->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - qoriq_ptp->tclk_period;
|
||||
ptp_qoriq->tmr_add = freq_comp;
|
||||
ptp_qoriq->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - ptp_qoriq->tclk_period;
|
||||
ptp_qoriq->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - ptp_qoriq->tclk_period;
|
||||
|
||||
/* max_adj = 1000000000 * (freq_ratio - 1.0) - 1
|
||||
* freq_ratio = reference_clock_freq / nominal_freq
|
||||
*/
|
||||
max_adj = 1000000000ULL * (clk_src - nominal_freq);
|
||||
max_adj = div_u64(max_adj, nominal_freq) - 1;
|
||||
qoriq_ptp->caps.max_adj = max_adj;
|
||||
ptp_qoriq->caps.max_adj = max_adj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qoriq_ptp_probe(struct platform_device *dev)
|
||||
int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base,
|
||||
const struct ptp_clock_info caps)
|
||||
{
|
||||
struct device_node *node = dev->dev.of_node;
|
||||
struct qoriq_ptp *qoriq_ptp;
|
||||
struct qoriq_ptp_registers *regs;
|
||||
struct device_node *node = ptp_qoriq->dev->of_node;
|
||||
struct ptp_qoriq_registers *regs;
|
||||
struct timespec64 now;
|
||||
int err = -ENOMEM;
|
||||
u32 tmr_ctrl;
|
||||
unsigned long flags;
|
||||
void __iomem *base;
|
||||
u32 tmr_ctrl;
|
||||
|
||||
qoriq_ptp = kzalloc(sizeof(*qoriq_ptp), GFP_KERNEL);
|
||||
if (!qoriq_ptp)
|
||||
goto no_memory;
|
||||
ptp_qoriq->base = base;
|
||||
ptp_qoriq->caps = caps;
|
||||
|
||||
err = -EINVAL;
|
||||
|
||||
qoriq_ptp->dev = &dev->dev;
|
||||
qoriq_ptp->caps = ptp_qoriq_caps;
|
||||
|
||||
if (of_property_read_u32(node, "fsl,cksel", &qoriq_ptp->cksel))
|
||||
qoriq_ptp->cksel = DEFAULT_CKSEL;
|
||||
if (of_property_read_u32(node, "fsl,cksel", &ptp_qoriq->cksel))
|
||||
ptp_qoriq->cksel = DEFAULT_CKSEL;
|
||||
|
||||
if (of_property_read_bool(node, "fsl,extts-fifo"))
|
||||
qoriq_ptp->extts_fifo_support = true;
|
||||
ptp_qoriq->extts_fifo_support = true;
|
||||
else
|
||||
qoriq_ptp->extts_fifo_support = false;
|
||||
ptp_qoriq->extts_fifo_support = false;
|
||||
|
||||
if (of_property_read_u32(node,
|
||||
"fsl,tclk-period", &qoriq_ptp->tclk_period) ||
|
||||
"fsl,tclk-period", &ptp_qoriq->tclk_period) ||
|
||||
of_property_read_u32(node,
|
||||
"fsl,tmr-prsc", &qoriq_ptp->tmr_prsc) ||
|
||||
"fsl,tmr-prsc", &ptp_qoriq->tmr_prsc) ||
|
||||
of_property_read_u32(node,
|
||||
"fsl,tmr-add", &qoriq_ptp->tmr_add) ||
|
||||
"fsl,tmr-add", &ptp_qoriq->tmr_add) ||
|
||||
of_property_read_u32(node,
|
||||
"fsl,tmr-fiper1", &qoriq_ptp->tmr_fiper1) ||
|
||||
"fsl,tmr-fiper1", &ptp_qoriq->tmr_fiper1) ||
|
||||
of_property_read_u32(node,
|
||||
"fsl,tmr-fiper2", &qoriq_ptp->tmr_fiper2) ||
|
||||
"fsl,tmr-fiper2", &ptp_qoriq->tmr_fiper2) ||
|
||||
of_property_read_u32(node,
|
||||
"fsl,max-adj", &qoriq_ptp->caps.max_adj)) {
|
||||
"fsl,max-adj", &ptp_qoriq->caps.max_adj)) {
|
||||
pr_warn("device tree node missing required elements, try automatic configuration\n");
|
||||
|
||||
if (qoriq_ptp_auto_config(qoriq_ptp, node))
|
||||
goto no_config;
|
||||
if (ptp_qoriq_auto_config(ptp_qoriq, node))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "little-endian")) {
|
||||
ptp_qoriq->read = qoriq_read_le;
|
||||
ptp_qoriq->write = qoriq_write_le;
|
||||
} else {
|
||||
ptp_qoriq->read = qoriq_read_be;
|
||||
ptp_qoriq->write = qoriq_write_be;
|
||||
}
|
||||
|
||||
/* The eTSEC uses differnt memory map with DPAA/ENETC */
|
||||
if (of_device_is_compatible(node, "fsl,etsec-ptp")) {
|
||||
ptp_qoriq->regs.ctrl_regs = base + ETSEC_CTRL_REGS_OFFSET;
|
||||
ptp_qoriq->regs.alarm_regs = base + ETSEC_ALARM_REGS_OFFSET;
|
||||
ptp_qoriq->regs.fiper_regs = base + ETSEC_FIPER_REGS_OFFSET;
|
||||
ptp_qoriq->regs.etts_regs = base + ETSEC_ETTS_REGS_OFFSET;
|
||||
} else {
|
||||
ptp_qoriq->regs.ctrl_regs = base + CTRL_REGS_OFFSET;
|
||||
ptp_qoriq->regs.alarm_regs = base + ALARM_REGS_OFFSET;
|
||||
ptp_qoriq->regs.fiper_regs = base + FIPER_REGS_OFFSET;
|
||||
ptp_qoriq->regs.etts_regs = base + ETTS_REGS_OFFSET;
|
||||
}
|
||||
|
||||
ktime_get_real_ts64(&now);
|
||||
ptp_qoriq_settime(&ptp_qoriq->caps, &now);
|
||||
|
||||
tmr_ctrl =
|
||||
(ptp_qoriq->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
|
||||
(ptp_qoriq->cksel & CKSEL_MASK) << CKSEL_SHIFT;
|
||||
|
||||
spin_lock_init(&ptp_qoriq->lock);
|
||||
spin_lock_irqsave(&ptp_qoriq->lock, flags);
|
||||
|
||||
regs = &ptp_qoriq->regs;
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, tmr_ctrl);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_add, ptp_qoriq->tmr_add);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_prsc, ptp_qoriq->tmr_prsc);
|
||||
ptp_qoriq->write(®s->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
|
||||
ptp_qoriq->write(®s->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
|
||||
set_alarm(ptp_qoriq);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl,
|
||||
tmr_ctrl|FIPERST|RTPE|TE|FRD);
|
||||
|
||||
spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
|
||||
|
||||
ptp_qoriq->clock = ptp_clock_register(&ptp_qoriq->caps, ptp_qoriq->dev);
|
||||
if (IS_ERR(ptp_qoriq->clock))
|
||||
return PTR_ERR(ptp_qoriq->clock);
|
||||
|
||||
ptp_qoriq->phc_index = ptp_clock_index(ptp_qoriq->clock);
|
||||
ptp_qoriq_create_debugfs(ptp_qoriq);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_init);
|
||||
|
||||
void ptp_qoriq_free(struct ptp_qoriq *ptp_qoriq)
|
||||
{
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_temask, 0);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, 0);
|
||||
|
||||
ptp_qoriq_remove_debugfs(ptp_qoriq);
|
||||
ptp_clock_unregister(ptp_qoriq->clock);
|
||||
iounmap(ptp_qoriq->base);
|
||||
free_irq(ptp_qoriq->irq, ptp_qoriq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ptp_qoriq_free);
|
||||
|
||||
static int ptp_qoriq_probe(struct platform_device *dev)
|
||||
{
|
||||
struct ptp_qoriq *ptp_qoriq;
|
||||
int err = -ENOMEM;
|
||||
void __iomem *base;
|
||||
|
||||
ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL);
|
||||
if (!ptp_qoriq)
|
||||
goto no_memory;
|
||||
|
||||
ptp_qoriq->dev = &dev->dev;
|
||||
|
||||
err = -ENODEV;
|
||||
|
||||
qoriq_ptp->irq = platform_get_irq(dev, 0);
|
||||
|
||||
if (qoriq_ptp->irq < 0) {
|
||||
ptp_qoriq->irq = platform_get_irq(dev, 0);
|
||||
if (ptp_qoriq->irq < 0) {
|
||||
pr_err("irq not in device tree\n");
|
||||
goto no_node;
|
||||
}
|
||||
if (request_irq(qoriq_ptp->irq, isr, IRQF_SHARED, DRIVER, qoriq_ptp)) {
|
||||
if (request_irq(ptp_qoriq->irq, ptp_qoriq_isr, IRQF_SHARED,
|
||||
DRIVER, ptp_qoriq)) {
|
||||
pr_err("request_irq failed\n");
|
||||
goto no_node;
|
||||
}
|
||||
|
||||
qoriq_ptp->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!qoriq_ptp->rsrc) {
|
||||
ptp_qoriq->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!ptp_qoriq->rsrc) {
|
||||
pr_err("no resource\n");
|
||||
goto no_resource;
|
||||
}
|
||||
if (request_resource(&iomem_resource, qoriq_ptp->rsrc)) {
|
||||
if (request_resource(&iomem_resource, ptp_qoriq->rsrc)) {
|
||||
pr_err("resource busy\n");
|
||||
goto no_resource;
|
||||
}
|
||||
|
||||
spin_lock_init(&qoriq_ptp->lock);
|
||||
|
||||
base = ioremap(qoriq_ptp->rsrc->start,
|
||||
resource_size(qoriq_ptp->rsrc));
|
||||
base = ioremap(ptp_qoriq->rsrc->start,
|
||||
resource_size(ptp_qoriq->rsrc));
|
||||
if (!base) {
|
||||
pr_err("ioremap ptp registers failed\n");
|
||||
goto no_ioremap;
|
||||
}
|
||||
|
||||
qoriq_ptp->base = base;
|
||||
|
||||
if (of_device_is_compatible(node, "fsl,fman-ptp-timer")) {
|
||||
qoriq_ptp->regs.ctrl_regs = base + FMAN_CTRL_REGS_OFFSET;
|
||||
qoriq_ptp->regs.alarm_regs = base + FMAN_ALARM_REGS_OFFSET;
|
||||
qoriq_ptp->regs.fiper_regs = base + FMAN_FIPER_REGS_OFFSET;
|
||||
qoriq_ptp->regs.etts_regs = base + FMAN_ETTS_REGS_OFFSET;
|
||||
} else {
|
||||
qoriq_ptp->regs.ctrl_regs = base + CTRL_REGS_OFFSET;
|
||||
qoriq_ptp->regs.alarm_regs = base + ALARM_REGS_OFFSET;
|
||||
qoriq_ptp->regs.fiper_regs = base + FIPER_REGS_OFFSET;
|
||||
qoriq_ptp->regs.etts_regs = base + ETTS_REGS_OFFSET;
|
||||
}
|
||||
|
||||
ktime_get_real_ts64(&now);
|
||||
ptp_qoriq_settime(&qoriq_ptp->caps, &now);
|
||||
|
||||
tmr_ctrl =
|
||||
(qoriq_ptp->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
|
||||
(qoriq_ptp->cksel & CKSEL_MASK) << CKSEL_SHIFT;
|
||||
|
||||
spin_lock_irqsave(&qoriq_ptp->lock, flags);
|
||||
|
||||
regs = &qoriq_ptp->regs;
|
||||
qoriq_write(®s->ctrl_regs->tmr_ctrl, tmr_ctrl);
|
||||
qoriq_write(®s->ctrl_regs->tmr_add, qoriq_ptp->tmr_add);
|
||||
qoriq_write(®s->ctrl_regs->tmr_prsc, qoriq_ptp->tmr_prsc);
|
||||
qoriq_write(®s->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
|
||||
qoriq_write(®s->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
|
||||
set_alarm(qoriq_ptp);
|
||||
qoriq_write(®s->ctrl_regs->tmr_ctrl, tmr_ctrl|FIPERST|RTPE|TE|FRD);
|
||||
|
||||
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
|
||||
|
||||
qoriq_ptp->clock = ptp_clock_register(&qoriq_ptp->caps, &dev->dev);
|
||||
if (IS_ERR(qoriq_ptp->clock)) {
|
||||
err = PTR_ERR(qoriq_ptp->clock);
|
||||
err = ptp_qoriq_init(ptp_qoriq, base, ptp_qoriq_caps);
|
||||
if (err)
|
||||
goto no_clock;
|
||||
}
|
||||
qoriq_ptp->phc_index = ptp_clock_index(qoriq_ptp->clock);
|
||||
|
||||
ptp_qoriq_create_debugfs(qoriq_ptp);
|
||||
platform_set_drvdata(dev, qoriq_ptp);
|
||||
|
||||
platform_set_drvdata(dev, ptp_qoriq);
|
||||
return 0;
|
||||
|
||||
no_clock:
|
||||
iounmap(qoriq_ptp->base);
|
||||
iounmap(ptp_qoriq->base);
|
||||
no_ioremap:
|
||||
release_resource(qoriq_ptp->rsrc);
|
||||
release_resource(ptp_qoriq->rsrc);
|
||||
no_resource:
|
||||
free_irq(qoriq_ptp->irq, qoriq_ptp);
|
||||
no_config:
|
||||
free_irq(ptp_qoriq->irq, ptp_qoriq);
|
||||
no_node:
|
||||
kfree(qoriq_ptp);
|
||||
kfree(ptp_qoriq);
|
||||
no_memory:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int qoriq_ptp_remove(struct platform_device *dev)
|
||||
static int ptp_qoriq_remove(struct platform_device *dev)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = platform_get_drvdata(dev);
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
|
||||
qoriq_write(®s->ctrl_regs->tmr_temask, 0);
|
||||
qoriq_write(®s->ctrl_regs->tmr_ctrl, 0);
|
||||
|
||||
ptp_qoriq_remove_debugfs(qoriq_ptp);
|
||||
ptp_clock_unregister(qoriq_ptp->clock);
|
||||
iounmap(qoriq_ptp->base);
|
||||
release_resource(qoriq_ptp->rsrc);
|
||||
free_irq(qoriq_ptp->irq, qoriq_ptp);
|
||||
kfree(qoriq_ptp);
|
||||
struct ptp_qoriq *ptp_qoriq = platform_get_drvdata(dev);
|
||||
|
||||
ptp_qoriq_free(ptp_qoriq);
|
||||
release_resource(ptp_qoriq->rsrc);
|
||||
kfree(ptp_qoriq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -616,16 +641,16 @@ static const struct of_device_id match_table[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, match_table);
|
||||
|
||||
static struct platform_driver qoriq_ptp_driver = {
|
||||
static struct platform_driver ptp_qoriq_driver = {
|
||||
.driver = {
|
||||
.name = "ptp_qoriq",
|
||||
.of_match_table = match_table,
|
||||
},
|
||||
.probe = qoriq_ptp_probe,
|
||||
.remove = qoriq_ptp_remove,
|
||||
.probe = ptp_qoriq_probe,
|
||||
.remove = ptp_qoriq_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(qoriq_ptp_driver);
|
||||
module_platform_driver(ptp_qoriq_driver);
|
||||
|
||||
MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
|
||||
MODULE_DESCRIPTION("PTP clock for Freescale QorIQ 1588 timer");
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = data;
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = data;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl);
|
||||
ctrl = ptp_qoriq->read(®s->ctrl_regs->tmr_ctrl);
|
||||
*val = ctrl & PP1L ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
|
@ -19,17 +19,17 @@ static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val)
|
|||
|
||||
static int ptp_qoriq_fiper1_lpbk_set(void *data, u64 val)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = data;
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = data;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl);
|
||||
ctrl = ptp_qoriq->read(®s->ctrl_regs->tmr_ctrl);
|
||||
if (val == 0)
|
||||
ctrl &= ~PP1L;
|
||||
else
|
||||
ctrl |= PP1L;
|
||||
|
||||
qoriq_write(®s->ctrl_regs->tmr_ctrl, ctrl);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,11 +38,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper1_fops, ptp_qoriq_fiper1_lpbk_get,
|
|||
|
||||
static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = data;
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = data;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl);
|
||||
ctrl = ptp_qoriq->read(®s->ctrl_regs->tmr_ctrl);
|
||||
*val = ctrl & PP2L ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
|
@ -50,52 +50,52 @@ static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val)
|
|||
|
||||
static int ptp_qoriq_fiper2_lpbk_set(void *data, u64 val)
|
||||
{
|
||||
struct qoriq_ptp *qoriq_ptp = data;
|
||||
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
|
||||
struct ptp_qoriq *ptp_qoriq = data;
|
||||
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = qoriq_read(®s->ctrl_regs->tmr_ctrl);
|
||||
ctrl = ptp_qoriq->read(®s->ctrl_regs->tmr_ctrl);
|
||||
if (val == 0)
|
||||
ctrl &= ~PP2L;
|
||||
else
|
||||
ctrl |= PP2L;
|
||||
|
||||
qoriq_write(®s->ctrl_regs->tmr_ctrl, ctrl);
|
||||
ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper2_fops, ptp_qoriq_fiper2_lpbk_get,
|
||||
ptp_qoriq_fiper2_lpbk_set, "%llu\n");
|
||||
|
||||
void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp)
|
||||
void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq)
|
||||
{
|
||||
struct dentry *root;
|
||||
|
||||
root = debugfs_create_dir(dev_name(qoriq_ptp->dev), NULL);
|
||||
root = debugfs_create_dir(dev_name(ptp_qoriq->dev), NULL);
|
||||
if (IS_ERR(root))
|
||||
return;
|
||||
if (!root)
|
||||
goto err_root;
|
||||
|
||||
qoriq_ptp->debugfs_root = root;
|
||||
ptp_qoriq->debugfs_root = root;
|
||||
|
||||
if (!debugfs_create_file_unsafe("fiper1-loopback", 0600, root,
|
||||
qoriq_ptp, &ptp_qoriq_fiper1_fops))
|
||||
ptp_qoriq, &ptp_qoriq_fiper1_fops))
|
||||
goto err_node;
|
||||
if (!debugfs_create_file_unsafe("fiper2-loopback", 0600, root,
|
||||
qoriq_ptp, &ptp_qoriq_fiper2_fops))
|
||||
ptp_qoriq, &ptp_qoriq_fiper2_fops))
|
||||
goto err_node;
|
||||
return;
|
||||
|
||||
err_node:
|
||||
debugfs_remove_recursive(root);
|
||||
qoriq_ptp->debugfs_root = NULL;
|
||||
ptp_qoriq->debugfs_root = NULL;
|
||||
err_root:
|
||||
dev_err(qoriq_ptp->dev, "failed to initialize debugfs\n");
|
||||
dev_err(ptp_qoriq->dev, "failed to initialize debugfs\n");
|
||||
}
|
||||
|
||||
void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp)
|
||||
void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq)
|
||||
{
|
||||
debugfs_remove_recursive(qoriq_ptp->debugfs_root);
|
||||
qoriq_ptp->debugfs_root = NULL;
|
||||
debugfs_remove_recursive(ptp_qoriq->debugfs_root);
|
||||
ptp_qoriq->debugfs_root = NULL;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define __PTP_QORIQ_H__
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
/*
|
||||
|
@ -49,7 +50,7 @@ struct etts_regs {
|
|||
u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */
|
||||
};
|
||||
|
||||
struct qoriq_ptp_registers {
|
||||
struct ptp_qoriq_registers {
|
||||
struct ctrl_regs __iomem *ctrl_regs;
|
||||
struct alarm_regs __iomem *alarm_regs;
|
||||
struct fiper_regs __iomem *fiper_regs;
|
||||
|
@ -57,15 +58,15 @@ struct qoriq_ptp_registers {
|
|||
};
|
||||
|
||||
/* Offset definitions for the four register groups */
|
||||
#define CTRL_REGS_OFFSET 0x0
|
||||
#define ALARM_REGS_OFFSET 0x40
|
||||
#define FIPER_REGS_OFFSET 0x80
|
||||
#define ETTS_REGS_OFFSET 0xa0
|
||||
#define ETSEC_CTRL_REGS_OFFSET 0x0
|
||||
#define ETSEC_ALARM_REGS_OFFSET 0x40
|
||||
#define ETSEC_FIPER_REGS_OFFSET 0x80
|
||||
#define ETSEC_ETTS_REGS_OFFSET 0xa0
|
||||
|
||||
#define FMAN_CTRL_REGS_OFFSET 0x80
|
||||
#define FMAN_ALARM_REGS_OFFSET 0xb8
|
||||
#define FMAN_FIPER_REGS_OFFSET 0xd0
|
||||
#define FMAN_ETTS_REGS_OFFSET 0xe0
|
||||
#define CTRL_REGS_OFFSET 0x80
|
||||
#define ALARM_REGS_OFFSET 0xb8
|
||||
#define FIPER_REGS_OFFSET 0xd0
|
||||
#define ETTS_REGS_OFFSET 0xe0
|
||||
|
||||
|
||||
/* Bit definitions for the TMR_CTRL register */
|
||||
|
@ -136,9 +137,9 @@ struct qoriq_ptp_registers {
|
|||
#define DEFAULT_FIPER1_PERIOD 1000000000
|
||||
#define DEFAULT_FIPER2_PERIOD 100000
|
||||
|
||||
struct qoriq_ptp {
|
||||
struct ptp_qoriq {
|
||||
void __iomem *base;
|
||||
struct qoriq_ptp_registers regs;
|
||||
struct ptp_qoriq_registers regs;
|
||||
spinlock_t lock; /* protects regs */
|
||||
struct ptp_clock *clock;
|
||||
struct ptp_clock_info caps;
|
||||
|
@ -156,28 +157,48 @@ struct qoriq_ptp {
|
|||
u32 cksel;
|
||||
u32 tmr_fiper1;
|
||||
u32 tmr_fiper2;
|
||||
u32 (*read)(unsigned __iomem *addr);
|
||||
void (*write)(unsigned __iomem *addr, u32 val);
|
||||
};
|
||||
|
||||
static inline u32 qoriq_read(unsigned __iomem *addr)
|
||||
static inline u32 qoriq_read_be(unsigned __iomem *addr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = ioread32be(addr);
|
||||
return val;
|
||||
return ioread32be(addr);
|
||||
}
|
||||
|
||||
static inline void qoriq_write(unsigned __iomem *addr, u32 val)
|
||||
static inline void qoriq_write_be(unsigned __iomem *addr, u32 val)
|
||||
{
|
||||
iowrite32be(val, addr);
|
||||
}
|
||||
|
||||
static inline u32 qoriq_read_le(unsigned __iomem *addr)
|
||||
{
|
||||
return ioread32(addr);
|
||||
}
|
||||
|
||||
static inline void qoriq_write_le(unsigned __iomem *addr, u32 val)
|
||||
{
|
||||
iowrite32(val, addr);
|
||||
}
|
||||
|
||||
irqreturn_t ptp_qoriq_isr(int irq, void *priv);
|
||||
int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base,
|
||||
const struct ptp_clock_info caps);
|
||||
void ptp_qoriq_free(struct ptp_qoriq *ptp_qoriq);
|
||||
int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm);
|
||||
int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta);
|
||||
int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts);
|
||||
int ptp_qoriq_settime(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts);
|
||||
int ptp_qoriq_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on);
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp);
|
||||
void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp);
|
||||
void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq);
|
||||
void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq);
|
||||
#else
|
||||
static inline void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp)
|
||||
static inline void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq)
|
||||
{ }
|
||||
static inline void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp)
|
||||
static inline void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче