Commit a263f99c authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 4ea7b0cf 74abc07d
...@@ -19,6 +19,9 @@ Clock Properties: ...@@ -19,6 +19,9 @@ Clock Properties:
- fsl,max-adj Maximum frequency adjustment in parts per billion. - fsl,max-adj Maximum frequency adjustment in parts per billion.
- fsl,extts-fifo The presence of this property indicates hardware - fsl,extts-fifo The presence of this property indicates hardware
support for the external trigger stamp FIFO. 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 These properties set the operational parameters for the PTP
clock. You must choose these carefully for the clock to work right. clock. You must choose these carefully for the clock to work right.
......
...@@ -6104,6 +6104,7 @@ FREESCALE QORIQ PTP CLOCK DRIVER ...@@ -6104,6 +6104,7 @@ FREESCALE QORIQ PTP CLOCK DRIVER
M: Yangbo Lu <yangbo.lu@nxp.com> M: Yangbo Lu <yangbo.lu@nxp.com>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c
F: drivers/ptp/ptp_qoriq.c F: drivers/ptp/ptp_qoriq.c
F: drivers/ptp/ptp_qoriq_debugfs.c F: drivers/ptp/ptp_qoriq_debugfs.c
F: include/linux/fsl/ptp_qoriq.h F: include/linux/fsl/ptp_qoriq.h
......
...@@ -501,7 +501,7 @@ static int dpaa_get_ts_info(struct net_device *net_dev, ...@@ -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 *mac_node = dev->of_node;
struct device_node *fman_node = NULL, *ptp_node = NULL; struct device_node *fman_node = NULL, *ptp_node = NULL;
struct platform_device *ptp_dev = NULL; struct platform_device *ptp_dev = NULL;
struct qoriq_ptp *ptp = NULL; struct ptp_qoriq *ptp = NULL;
info->phc_index = -1; info->phc_index = -1;
......
...@@ -17,3 +17,15 @@ config FSL_ENETC_VF ...@@ -17,3 +17,15 @@ config FSL_ENETC_VF
virtual function (VF) devices enabled by the ENETC PF driver. virtual function (VF) devices enabled by the ENETC PF driver.
If compiled as module (M), the module name is fsl-enetc-vf. 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 \ ...@@ -13,3 +13,6 @@ fsl-enetc-vf-$(CONFIG_FSL_ENETC_VF) += enetc.o enetc_cbdr.o \
enetc_ethtool.o enetc_ethtool.o
fsl-enetc-vf-objs := enetc_vf.o $(fsl-enetc-vf-y) fsl-enetc-vf-objs := enetc_vf.o $(fsl-enetc-vf-y)
endif 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 @@ ...@@ -4,8 +4,9 @@
#include <linux/bitops.h> #include <linux/bitops.h>
/* ENETC device IDs */ /* ENETC device IDs */
#define ENETC_DEV_ID_PF 0xe100 #define ENETC_DEV_ID_PF 0xe100
#define ENETC_DEV_ID_VF 0xef00 #define ENETC_DEV_ID_VF 0xef00
#define ENETC_DEV_ID_PTP 0xee02
/* ENETC register block BAR */ /* ENETC register block BAR */
#define ENETC_BAR_REGS 0 #define ENETC_BAR_REGS 0
......
// 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, ...@@ -1492,7 +1492,7 @@ static int gfar_get_ts_info(struct net_device *dev,
struct gfar_private *priv = netdev_priv(dev); struct gfar_private *priv = netdev_priv(dev);
struct platform_device *ptp_dev; struct platform_device *ptp_dev;
struct device_node *ptp_node; struct device_node *ptp_node;
struct qoriq_ptp *ptp = NULL; struct ptp_qoriq *ptp = NULL;
info->phc_index = -1; info->phc_index = -1;
......
...@@ -617,6 +617,8 @@ static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb, ...@@ -617,6 +617,8 @@ static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
} }
#endif #endif
#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN)
/* We reach this function only after checking that any of /* We reach this function only after checking that any of
* the (IPv4 | IPv6) bits are set in cqe->status. * 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, ...@@ -624,9 +626,20 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
netdev_features_t dev_features) netdev_features_t dev_features)
{ {
__wsum hw_checksum = 0; __wsum hw_checksum = 0;
void *hdr;
/* 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;
void *hdr = (u8 *)va + sizeof(struct ethhdr); hdr = (u8 *)va + sizeof(struct ethhdr);
hw_checksum = csum_unfold((__force __sum16)cqe->checksum); hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) && if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) &&
...@@ -819,6 +832,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ...@@ -819,6 +832,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
skb_record_rx_queue(skb, cq_ring); skb_record_rx_queue(skb, cq_ring);
if (likely(dev->features & NETIF_F_RXCSUM)) { 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 | if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
MLX4_CQE_STATUS_UDP)) && MLX4_CQE_STATUS_UDP)) &&
(cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
......
...@@ -43,7 +43,7 @@ config PTP_1588_CLOCK_DTE ...@@ -43,7 +43,7 @@ config PTP_1588_CLOCK_DTE
config PTP_1588_CLOCK_QORIQ config PTP_1588_CLOCK_QORIQ
tristate "Freescale QorIQ 1588 timer as PTP clock" 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 depends on PTP_1588_CLOCK
default y default y
help help
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -37,61 +36,61 @@ ...@@ -37,61 +36,61 @@
* Register access functions * Register access functions
*/ */
/* Caller must hold qoriq_ptp->lock. */ /* Caller must hold ptp_qoriq->lock. */
static u64 tmr_cnt_read(struct qoriq_ptp *qoriq_ptp) 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; u64 ns;
u32 lo, hi; u32 lo, hi;
lo = qoriq_read(&regs->ctrl_regs->tmr_cnt_l); lo = ptp_qoriq->read(&regs->ctrl_regs->tmr_cnt_l);
hi = qoriq_read(&regs->ctrl_regs->tmr_cnt_h); hi = ptp_qoriq->read(&regs->ctrl_regs->tmr_cnt_h);
ns = ((u64) hi) << 32; ns = ((u64) hi) << 32;
ns |= lo; ns |= lo;
return ns; return ns;
} }
/* Caller must hold qoriq_ptp->lock. */ /* Caller must hold ptp_qoriq->lock. */
static void tmr_cnt_write(struct qoriq_ptp *qoriq_ptp, u64 ns) 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 hi = ns >> 32;
u32 lo = ns & 0xffffffff; u32 lo = ns & 0xffffffff;
qoriq_write(&regs->ctrl_regs->tmr_cnt_l, lo); ptp_qoriq->write(&regs->ctrl_regs->tmr_cnt_l, lo);
qoriq_write(&regs->ctrl_regs->tmr_cnt_h, hi); ptp_qoriq->write(&regs->ctrl_regs->tmr_cnt_h, hi);
} }
/* Caller must hold qoriq_ptp->lock. */ /* Caller must hold ptp_qoriq->lock. */
static void set_alarm(struct qoriq_ptp *qoriq_ptp) 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; u64 ns;
u32 lo, hi; u32 lo, hi;
ns = tmr_cnt_read(qoriq_ptp) + 1500000000ULL; ns = tmr_cnt_read(ptp_qoriq) + 1500000000ULL;
ns = div_u64(ns, 1000000000UL) * 1000000000ULL; ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
ns -= qoriq_ptp->tclk_period; ns -= ptp_qoriq->tclk_period;
hi = ns >> 32; hi = ns >> 32;
lo = ns & 0xffffffff; lo = ns & 0xffffffff;
qoriq_write(&regs->alarm_regs->tmr_alarm1_l, lo); ptp_qoriq->write(&regs->alarm_regs->tmr_alarm1_l, lo);
qoriq_write(&regs->alarm_regs->tmr_alarm1_h, hi); ptp_qoriq->write(&regs->alarm_regs->tmr_alarm1_h, hi);
} }
/* Caller must hold qoriq_ptp->lock. */ /* Caller must hold ptp_qoriq->lock. */
static void set_fipers(struct qoriq_ptp *qoriq_ptp) 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); set_alarm(ptp_qoriq);
qoriq_write(&regs->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1); ptp_qoriq->write(&regs->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
qoriq_write(&regs->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2); ptp_qoriq->write(&regs->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) bool update_event)
{ {
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
struct ptp_clock_event event; struct ptp_clock_event event;
void __iomem *reg_etts_l; void __iomem *reg_etts_l;
void __iomem *reg_etts_h; void __iomem *reg_etts_h;
...@@ -116,17 +115,17 @@ static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index, ...@@ -116,17 +115,17 @@ static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index,
event.index = index; event.index = index;
do { do {
lo = qoriq_read(reg_etts_l); lo = ptp_qoriq->read(reg_etts_l);
hi = qoriq_read(reg_etts_h); hi = ptp_qoriq->read(reg_etts_h);
if (update_event) { if (update_event) {
event.timestamp = ((u64) hi) << 32; event.timestamp = ((u64) hi) << 32;
event.timestamp |= lo; event.timestamp |= lo;
ptp_clock_event(qoriq_ptp->clock, &event); ptp_clock_event(ptp_qoriq->clock, &event);
} }
stat = qoriq_read(&regs->ctrl_regs->tmr_stat); stat = ptp_qoriq->read(&regs->ctrl_regs->tmr_stat);
} while (qoriq_ptp->extts_fifo_support && (stat & valid)); } while (ptp_qoriq->extts_fifo_support && (stat & valid));
return 0; return 0;
} }
...@@ -135,89 +134,90 @@ static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index, ...@@ -135,89 +134,90 @@ static int extts_clean_up(struct qoriq_ptp *qoriq_ptp, int index,
* Interrupt service routine * 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 ptp_qoriq *ptp_qoriq = priv;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
struct ptp_clock_event event; struct ptp_clock_event event;
u64 ns; u64 ns;
u32 ack = 0, lo, hi, mask, val, irqs; u32 ack = 0, lo, hi, mask, val, irqs;
spin_lock(&qoriq_ptp->lock); spin_lock(&ptp_qoriq->lock);
val = qoriq_read(&regs->ctrl_regs->tmr_tevent); val = ptp_qoriq->read(&regs->ctrl_regs->tmr_tevent);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask); mask = ptp_qoriq->read(&regs->ctrl_regs->tmr_temask);
spin_unlock(&qoriq_ptp->lock); spin_unlock(&ptp_qoriq->lock);
irqs = val & mask; irqs = val & mask;
if (irqs & ETS1) { if (irqs & ETS1) {
ack |= ETS1; ack |= ETS1;
extts_clean_up(qoriq_ptp, 0, true); extts_clean_up(ptp_qoriq, 0, true);
} }
if (irqs & ETS2) { if (irqs & ETS2) {
ack |= ETS2; ack |= ETS2;
extts_clean_up(qoriq_ptp, 1, true); extts_clean_up(ptp_qoriq, 1, true);
} }
if (irqs & ALM2) { if (irqs & ALM2) {
ack |= ALM2; ack |= ALM2;
if (qoriq_ptp->alarm_value) { if (ptp_qoriq->alarm_value) {
event.type = PTP_CLOCK_ALARM; event.type = PTP_CLOCK_ALARM;
event.index = 0; event.index = 0;
event.timestamp = qoriq_ptp->alarm_value; event.timestamp = ptp_qoriq->alarm_value;
ptp_clock_event(qoriq_ptp->clock, &event); ptp_clock_event(ptp_qoriq->clock, &event);
} }
if (qoriq_ptp->alarm_interval) { if (ptp_qoriq->alarm_interval) {
ns = qoriq_ptp->alarm_value + qoriq_ptp->alarm_interval; ns = ptp_qoriq->alarm_value + ptp_qoriq->alarm_interval;
hi = ns >> 32; hi = ns >> 32;
lo = ns & 0xffffffff; lo = ns & 0xffffffff;
qoriq_write(&regs->alarm_regs->tmr_alarm2_l, lo); ptp_qoriq->write(&regs->alarm_regs->tmr_alarm2_l, lo);
qoriq_write(&regs->alarm_regs->tmr_alarm2_h, hi); ptp_qoriq->write(&regs->alarm_regs->tmr_alarm2_h, hi);
qoriq_ptp->alarm_value = ns; ptp_qoriq->alarm_value = ns;
} else { } else {
spin_lock(&qoriq_ptp->lock); spin_lock(&ptp_qoriq->lock);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask); mask = ptp_qoriq->read(&regs->ctrl_regs->tmr_temask);
mask &= ~ALM2EN; mask &= ~ALM2EN;
qoriq_write(&regs->ctrl_regs->tmr_temask, mask); ptp_qoriq->write(&regs->ctrl_regs->tmr_temask, mask);
spin_unlock(&qoriq_ptp->lock); spin_unlock(&ptp_qoriq->lock);
qoriq_ptp->alarm_value = 0; ptp_qoriq->alarm_value = 0;
qoriq_ptp->alarm_interval = 0; ptp_qoriq->alarm_interval = 0;
} }
} }
if (irqs & PP1) { if (irqs & PP1) {
ack |= PP1; ack |= PP1;
event.type = PTP_CLOCK_PPS; event.type = PTP_CLOCK_PPS;
ptp_clock_event(qoriq_ptp->clock, &event); ptp_clock_event(ptp_qoriq->clock, &event);
} }
if (ack) { if (ack) {
qoriq_write(&regs->ctrl_regs->tmr_tevent, ack); ptp_qoriq->write(&regs->ctrl_regs->tmr_tevent, ack);
return IRQ_HANDLED; return IRQ_HANDLED;
} else } else
return IRQ_NONE; return IRQ_NONE;
} }
EXPORT_SYMBOL_GPL(ptp_qoriq_isr);
/* /*
* PTP clock operations * 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; u64 adj, diff;
u32 tmr_add; u32 tmr_add;
int neg_adj = 0; int neg_adj = 0;
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps); struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
if (scaled_ppm < 0) { if (scaled_ppm < 0) {
neg_adj = 1; neg_adj = 1;
scaled_ppm = -scaled_ppm; scaled_ppm = -scaled_ppm;
} }
tmr_add = qoriq_ptp->tmr_add; tmr_add = ptp_qoriq->tmr_add;
adj = tmr_add; adj = tmr_add;
/* calculate diff as adj*(scaled_ppm/65536)/1000000 /* 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) ...@@ -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; tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
qoriq_write(&regs->ctrl_regs->tmr_add, tmr_add); ptp_qoriq->write(&regs->ctrl_regs->tmr_add, tmr_add);
return 0; 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; s64 now;
unsigned long flags; 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; now += delta;
tmr_cnt_write(qoriq_ptp, now); tmr_cnt_write(ptp_qoriq, now);
set_fipers(qoriq_ptp); set_fipers(ptp_qoriq);
spin_unlock_irqrestore(&qoriq_ptp->lock, flags); spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ptp_qoriq_adjtime);
static int ptp_qoriq_gettime(struct ptp_clock_info *ptp, int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
struct timespec64 *ts)
{ {
u64 ns; u64 ns;
unsigned long flags; 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); *ts = ns_to_timespec64(ns);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ptp_qoriq_gettime);
static int ptp_qoriq_settime(struct ptp_clock_info *ptp, int ptp_qoriq_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts) const struct timespec64 *ts)
{ {
u64 ns; u64 ns;
unsigned long flags; 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); 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); tmr_cnt_write(ptp_qoriq, ns);
set_fipers(qoriq_ptp); set_fipers(ptp_qoriq);
spin_unlock_irqrestore(&qoriq_ptp->lock, flags); spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ptp_qoriq_settime);
static int ptp_qoriq_enable(struct ptp_clock_info *ptp, int ptp_qoriq_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on) struct ptp_clock_request *rq, int on)
{ {
struct qoriq_ptp *qoriq_ptp = container_of(ptp, struct qoriq_ptp, caps); struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
unsigned long flags; unsigned long flags;
u32 bit, mask = 0; u32 bit, mask = 0;
...@@ -311,7 +314,7 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp, ...@@ -311,7 +314,7 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
} }
if (on) if (on)
extts_clean_up(qoriq_ptp, rq->extts.index, false); extts_clean_up(ptp_qoriq, rq->extts.index, false);
break; break;
case PTP_CLK_REQ_PPS: case PTP_CLK_REQ_PPS:
...@@ -321,21 +324,22 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp, ...@@ -321,21 +324,22 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
spin_lock_irqsave(&qoriq_ptp->lock, flags); spin_lock_irqsave(&ptp_qoriq->lock, flags);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask); mask = ptp_qoriq->read(&regs->ctrl_regs->tmr_temask);
if (on) { if (on) {
mask |= bit; mask |= bit;
qoriq_write(&regs->ctrl_regs->tmr_tevent, bit); ptp_qoriq->write(&regs->ctrl_regs->tmr_tevent, bit);
} else { } else {
mask &= ~bit; mask &= ~bit;
} }
qoriq_write(&regs->ctrl_regs->tmr_temask, mask); ptp_qoriq->write(&regs->ctrl_regs->tmr_temask, mask);
spin_unlock_irqrestore(&qoriq_ptp->lock, flags); spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ptp_qoriq_enable);
static const struct ptp_clock_info ptp_qoriq_caps = { static const struct ptp_clock_info ptp_qoriq_caps = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -354,7 +358,7 @@ static const struct ptp_clock_info ptp_qoriq_caps = { ...@@ -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 * reference clock frequency
* *
* @clk_src: reference clock frequency * @clk_src: reference clock frequency
...@@ -365,7 +369,7 @@ static const struct ptp_clock_info ptp_qoriq_caps = { ...@@ -365,7 +369,7 @@ static const struct ptp_clock_info ptp_qoriq_caps = {
* *
* Return the nominal frequency * 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; u32 remainder = 0;
...@@ -385,9 +389,9 @@ static u32 qoriq_ptp_nominal_freq(u32 clk_src) ...@@ -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 * @node: pointer to device_node
* *
* If below dts properties are not provided, this function will be * If below dts properties are not provided, this function will be
...@@ -401,7 +405,7 @@ static u32 qoriq_ptp_nominal_freq(u32 clk_src) ...@@ -401,7 +405,7 @@ static u32 qoriq_ptp_nominal_freq(u32 clk_src)
* *
* Return 0 if success * 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 device_node *node)
{ {
struct clk *clk; struct clk *clk;
...@@ -411,7 +415,7 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp, ...@@ -411,7 +415,7 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
u32 remainder = 0; u32 remainder = 0;
u32 clk_src = 0; u32 clk_src = 0;
qoriq_ptp->cksel = DEFAULT_CKSEL; ptp_qoriq->cksel = DEFAULT_CKSEL;
clk = of_clk_get(node, 0); clk = of_clk_get(node, 0);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
...@@ -424,12 +428,12 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp, ...@@ -424,12 +428,12 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
return -EINVAL; return -EINVAL;
} }
nominal_freq = qoriq_ptp_nominal_freq(clk_src); nominal_freq = ptp_qoriq_nominal_freq(clk_src);
if (!nominal_freq) if (!nominal_freq)
return -EINVAL; return -EINVAL;
qoriq_ptp->tclk_period = 1000000000UL / nominal_freq; ptp_qoriq->tclk_period = 1000000000UL / nominal_freq;
qoriq_ptp->tmr_prsc = DEFAULT_TMR_PRSC; ptp_qoriq->tmr_prsc = DEFAULT_TMR_PRSC;
/* Calculate initial frequency compensation value for TMR_ADD register. /* Calculate initial frequency compensation value for TMR_ADD register.
* freq_comp = ceil(2^32 / freq_ratio) * freq_comp = ceil(2^32 / freq_ratio)
...@@ -440,172 +444,193 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp, ...@@ -440,172 +444,193 @@ static int qoriq_ptp_auto_config(struct qoriq_ptp *qoriq_ptp,
if (remainder) if (remainder)
freq_comp++; freq_comp++;
qoriq_ptp->tmr_add = freq_comp; ptp_qoriq->tmr_add = freq_comp;
qoriq_ptp->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - qoriq_ptp->tclk_period; ptp_qoriq->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - ptp_qoriq->tclk_period;
qoriq_ptp->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - qoriq_ptp->tclk_period; ptp_qoriq->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - ptp_qoriq->tclk_period;
/* max_adj = 1000000000 * (freq_ratio - 1.0) - 1 /* max_adj = 1000000000 * (freq_ratio - 1.0) - 1
* freq_ratio = reference_clock_freq / nominal_freq * freq_ratio = reference_clock_freq / nominal_freq
*/ */
max_adj = 1000000000ULL * (clk_src - nominal_freq); max_adj = 1000000000ULL * (clk_src - nominal_freq);
max_adj = div_u64(max_adj, nominal_freq) - 1; 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; 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 device_node *node = ptp_qoriq->dev->of_node;
struct qoriq_ptp *qoriq_ptp; struct ptp_qoriq_registers *regs;
struct qoriq_ptp_registers *regs;
struct timespec64 now; struct timespec64 now;
int err = -ENOMEM;
u32 tmr_ctrl;
unsigned long flags; unsigned long flags;
void __iomem *base; u32 tmr_ctrl;
qoriq_ptp = kzalloc(sizeof(*qoriq_ptp), GFP_KERNEL);
if (!qoriq_ptp)
goto no_memory;
err = -EINVAL;
qoriq_ptp->dev = &dev->dev; ptp_qoriq->base = base;
qoriq_ptp->caps = ptp_qoriq_caps; ptp_qoriq->caps = caps;
if (of_property_read_u32(node, "fsl,cksel", &qoriq_ptp->cksel)) if (of_property_read_u32(node, "fsl,cksel", &ptp_qoriq->cksel))
qoriq_ptp->cksel = DEFAULT_CKSEL; ptp_qoriq->cksel = DEFAULT_CKSEL;
if (of_property_read_bool(node, "fsl,extts-fifo")) if (of_property_read_bool(node, "fsl,extts-fifo"))
qoriq_ptp->extts_fifo_support = true; ptp_qoriq->extts_fifo_support = true;
else else
qoriq_ptp->extts_fifo_support = false; ptp_qoriq->extts_fifo_support = false;
if (of_property_read_u32(node, 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, of_property_read_u32(node,
"fsl,tmr-prsc", &qoriq_ptp->tmr_prsc) || "fsl,tmr-prsc", &ptp_qoriq->tmr_prsc) ||
of_property_read_u32(node, of_property_read_u32(node,
"fsl,tmr-add", &qoriq_ptp->tmr_add) || "fsl,tmr-add", &ptp_qoriq->tmr_add) ||
of_property_read_u32(node, of_property_read_u32(node,
"fsl,tmr-fiper1", &qoriq_ptp->tmr_fiper1) || "fsl,tmr-fiper1", &ptp_qoriq->tmr_fiper1) ||
of_property_read_u32(node, of_property_read_u32(node,
"fsl,tmr-fiper2", &qoriq_ptp->tmr_fiper2) || "fsl,tmr-fiper2", &ptp_qoriq->tmr_fiper2) ||
of_property_read_u32(node, 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"); pr_warn("device tree node missing required elements, try automatic configuration\n");
if (qoriq_ptp_auto_config(qoriq_ptp, node)) if (ptp_qoriq_auto_config(ptp_qoriq, node))
goto no_config; return -ENODEV;
} }
err = -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(&regs->ctrl_regs->tmr_ctrl, tmr_ctrl);
ptp_qoriq->write(&regs->ctrl_regs->tmr_add, ptp_qoriq->tmr_add);
ptp_qoriq->write(&regs->ctrl_regs->tmr_prsc, ptp_qoriq->tmr_prsc);
ptp_qoriq->write(&regs->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
ptp_qoriq->write(&regs->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
set_alarm(ptp_qoriq);
ptp_qoriq->write(&regs->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(&regs->ctrl_regs->tmr_temask, 0);
ptp_qoriq->write(&regs->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);
qoriq_ptp->irq = platform_get_irq(dev, 0); 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;
if (qoriq_ptp->irq < 0) { err = -ENODEV;
ptp_qoriq->irq = platform_get_irq(dev, 0);
if (ptp_qoriq->irq < 0) {
pr_err("irq not in device tree\n"); pr_err("irq not in device tree\n");
goto no_node; 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"); pr_err("request_irq failed\n");
goto no_node; goto no_node;
} }
qoriq_ptp->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0); ptp_qoriq->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!qoriq_ptp->rsrc) { if (!ptp_qoriq->rsrc) {
pr_err("no resource\n"); pr_err("no resource\n");
goto no_resource; goto no_resource;
} }
if (request_resource(&iomem_resource, qoriq_ptp->rsrc)) { if (request_resource(&iomem_resource, ptp_qoriq->rsrc)) {
pr_err("resource busy\n"); pr_err("resource busy\n");
goto no_resource; goto no_resource;
} }
spin_lock_init(&qoriq_ptp->lock); base = ioremap(ptp_qoriq->rsrc->start,
resource_size(ptp_qoriq->rsrc));
base = ioremap(qoriq_ptp->rsrc->start,
resource_size(qoriq_ptp->rsrc));
if (!base) { if (!base) {
pr_err("ioremap ptp registers failed\n"); pr_err("ioremap ptp registers failed\n");
goto no_ioremap; goto no_ioremap;
} }
qoriq_ptp->base = base; err = ptp_qoriq_init(ptp_qoriq, base, ptp_qoriq_caps);
if (err)
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(&regs->ctrl_regs->tmr_ctrl, tmr_ctrl);
qoriq_write(&regs->ctrl_regs->tmr_add, qoriq_ptp->tmr_add);
qoriq_write(&regs->ctrl_regs->tmr_prsc, qoriq_ptp->tmr_prsc);
qoriq_write(&regs->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
qoriq_write(&regs->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
set_alarm(qoriq_ptp);
qoriq_write(&regs->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);
goto no_clock; 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; return 0;
no_clock: no_clock:
iounmap(qoriq_ptp->base); iounmap(ptp_qoriq->base);
no_ioremap: no_ioremap:
release_resource(qoriq_ptp->rsrc); release_resource(ptp_qoriq->rsrc);
no_resource: no_resource:
free_irq(qoriq_ptp->irq, qoriq_ptp); free_irq(ptp_qoriq->irq, ptp_qoriq);
no_config:
no_node: no_node:
kfree(qoriq_ptp); kfree(ptp_qoriq);
no_memory: no_memory:
return err; 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 ptp_qoriq *ptp_qoriq = platform_get_drvdata(dev);
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
qoriq_write(&regs->ctrl_regs->tmr_temask, 0);
qoriq_write(&regs->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);
ptp_qoriq_free(ptp_qoriq);
release_resource(ptp_qoriq->rsrc);
kfree(ptp_qoriq);
return 0; return 0;
} }
...@@ -616,16 +641,16 @@ static const struct of_device_id match_table[] = { ...@@ -616,16 +641,16 @@ static const struct of_device_id match_table[] = {
}; };
MODULE_DEVICE_TABLE(of, match_table); MODULE_DEVICE_TABLE(of, match_table);
static struct platform_driver qoriq_ptp_driver = { static struct platform_driver ptp_qoriq_driver = {
.driver = { .driver = {
.name = "ptp_qoriq", .name = "ptp_qoriq",
.of_match_table = match_table, .of_match_table = match_table,
}, },
.probe = qoriq_ptp_probe, .probe = ptp_qoriq_probe,
.remove = qoriq_ptp_remove, .remove = ptp_qoriq_remove,
}; };
module_platform_driver(qoriq_ptp_driver); module_platform_driver(ptp_qoriq_driver);
MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>"); MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
MODULE_DESCRIPTION("PTP clock for Freescale QorIQ 1588 timer"); MODULE_DESCRIPTION("PTP clock for Freescale QorIQ 1588 timer");
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val) static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val)
{ {
struct qoriq_ptp *qoriq_ptp = data; struct ptp_qoriq *ptp_qoriq = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl; u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl); ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
*val = ctrl & PP1L ? 1 : 0; *val = ctrl & PP1L ? 1 : 0;
return 0; return 0;
...@@ -19,17 +19,17 @@ static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val) ...@@ -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) static int ptp_qoriq_fiper1_lpbk_set(void *data, u64 val)
{ {
struct qoriq_ptp *qoriq_ptp = data; struct ptp_qoriq *ptp_qoriq = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl; u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl); ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
if (val == 0) if (val == 0)
ctrl &= ~PP1L; ctrl &= ~PP1L;
else else
ctrl |= PP1L; ctrl |= PP1L;
qoriq_write(&regs->ctrl_regs->tmr_ctrl, ctrl); ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, ctrl);
return 0; return 0;
} }
...@@ -38,11 +38,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper1_fops, ptp_qoriq_fiper1_lpbk_get, ...@@ -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) static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val)
{ {
struct qoriq_ptp *qoriq_ptp = data; struct ptp_qoriq *ptp_qoriq = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl; u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl); ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
*val = ctrl & PP2L ? 1 : 0; *val = ctrl & PP2L ? 1 : 0;
return 0; return 0;
...@@ -50,52 +50,52 @@ static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val) ...@@ -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) static int ptp_qoriq_fiper2_lpbk_set(void *data, u64 val)
{ {
struct qoriq_ptp *qoriq_ptp = data; struct ptp_qoriq *ptp_qoriq = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs; struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl; u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl); ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
if (val == 0) if (val == 0)
ctrl &= ~PP2L; ctrl &= ~PP2L;
else else
ctrl |= PP2L; ctrl |= PP2L;
qoriq_write(&regs->ctrl_regs->tmr_ctrl, ctrl); ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, ctrl);
return 0; return 0;
} }
DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper2_fops, ptp_qoriq_fiper2_lpbk_get, DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper2_fops, ptp_qoriq_fiper2_lpbk_get,
ptp_qoriq_fiper2_lpbk_set, "%llu\n"); 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; 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)) if (IS_ERR(root))
return; return;
if (!root) if (!root)
goto err_root; goto err_root;
qoriq_ptp->debugfs_root = root; ptp_qoriq->debugfs_root = root;
if (!debugfs_create_file_unsafe("fiper1-loopback", 0600, 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; goto err_node;
if (!debugfs_create_file_unsafe("fiper2-loopback", 0600, root, if (!debugfs_create_file_unsafe("fiper2-loopback", 0600, root,
qoriq_ptp, &ptp_qoriq_fiper2_fops)) ptp_qoriq, &ptp_qoriq_fiper2_fops))
goto err_node; goto err_node;
return; return;
err_node: err_node:
debugfs_remove_recursive(root); debugfs_remove_recursive(root);
qoriq_ptp->debugfs_root = NULL; ptp_qoriq->debugfs_root = NULL;
err_root: 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); debugfs_remove_recursive(ptp_qoriq->debugfs_root);
qoriq_ptp->debugfs_root = NULL; ptp_qoriq->debugfs_root = NULL;
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define __PTP_QORIQ_H__ #define __PTP_QORIQ_H__
#include <linux/io.h> #include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
/* /*
...@@ -49,7 +50,7 @@ struct etts_regs { ...@@ -49,7 +50,7 @@ struct etts_regs {
u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */ 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 ctrl_regs __iomem *ctrl_regs;
struct alarm_regs __iomem *alarm_regs; struct alarm_regs __iomem *alarm_regs;
struct fiper_regs __iomem *fiper_regs; struct fiper_regs __iomem *fiper_regs;
...@@ -57,15 +58,15 @@ struct qoriq_ptp_registers { ...@@ -57,15 +58,15 @@ struct qoriq_ptp_registers {
}; };
/* Offset definitions for the four register groups */ /* Offset definitions for the four register groups */
#define CTRL_REGS_OFFSET 0x0 #define ETSEC_CTRL_REGS_OFFSET 0x0
#define ALARM_REGS_OFFSET 0x40 #define ETSEC_ALARM_REGS_OFFSET 0x40
#define FIPER_REGS_OFFSET 0x80 #define ETSEC_FIPER_REGS_OFFSET 0x80
#define ETTS_REGS_OFFSET 0xa0 #define ETSEC_ETTS_REGS_OFFSET 0xa0
#define FMAN_CTRL_REGS_OFFSET 0x80 #define CTRL_REGS_OFFSET 0x80
#define FMAN_ALARM_REGS_OFFSET 0xb8 #define ALARM_REGS_OFFSET 0xb8
#define FMAN_FIPER_REGS_OFFSET 0xd0 #define FIPER_REGS_OFFSET 0xd0
#define FMAN_ETTS_REGS_OFFSET 0xe0 #define ETTS_REGS_OFFSET 0xe0
/* Bit definitions for the TMR_CTRL register */ /* Bit definitions for the TMR_CTRL register */
...@@ -136,9 +137,9 @@ struct qoriq_ptp_registers { ...@@ -136,9 +137,9 @@ struct qoriq_ptp_registers {
#define DEFAULT_FIPER1_PERIOD 1000000000 #define DEFAULT_FIPER1_PERIOD 1000000000
#define DEFAULT_FIPER2_PERIOD 100000 #define DEFAULT_FIPER2_PERIOD 100000
struct qoriq_ptp { struct ptp_qoriq {
void __iomem *base; void __iomem *base;
struct qoriq_ptp_registers regs; struct ptp_qoriq_registers regs;
spinlock_t lock; /* protects regs */ spinlock_t lock; /* protects regs */
struct ptp_clock *clock; struct ptp_clock *clock;
struct ptp_clock_info caps; struct ptp_clock_info caps;
...@@ -156,28 +157,48 @@ struct qoriq_ptp { ...@@ -156,28 +157,48 @@ struct qoriq_ptp {
u32 cksel; u32 cksel;
u32 tmr_fiper1; u32 tmr_fiper1;
u32 tmr_fiper2; 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; return ioread32be(addr);
val = ioread32be(addr);
return val;
} }
static inline void qoriq_write(unsigned __iomem *addr, u32 val) static inline void qoriq_write_be(unsigned __iomem *addr, u32 val)
{ {
iowrite32be(val, addr); 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 #ifdef CONFIG_DEBUG_FS
void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp); void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq);
void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp); void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq);
#else #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 #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment