提交 1d7229dd 编写于 作者: D David S. Miller

Merge branch 'DPAA-PTP-clock-and-timestamping'

Yangbo Lu says:

====================
Support DPAA PTP clock and timestamping

This patchset is to support DPAA FMAN PTP clock and HW timestamping.
It had been verified on both ARM platform and PPC platform.
- The patch #1 to patch #5 are to support DPAA FMAN 1588 timer in
  ptp_qoriq driver.
- The patch #6 to patch #10 are to add HW timestamping support in
  DPAA ethernet driver.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -356,30 +356,7 @@ ethernet@e0000 {
============================================================================
FMan IEEE 1588 Node
DESCRIPTION
The FMan interface to support IEEE 1588
PROPERTIES
- compatible
Usage: required
Value type: <stringlist>
Definition: A standard property.
Must include "fsl,fman-ptp-timer".
- reg
Usage: required
Value type: <prop-encoded-array>
Definition: A standard property.
EXAMPLE
ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
Refer to Documentation/devicetree/bindings/ptp/ptp-qoriq.txt
=============================================================================
FMan MDIO Node
......
......@@ -2,7 +2,8 @@
General Properties:
- compatible Should be "fsl,etsec-ptp"
- compatible Should be "fsl,etsec-ptp" for eTSEC
Should be "fsl,fman-ptp-timer" for DPAA FMan
- reg Offset and length of the register set for the device
- interrupts There should be at least two interrupts. Some devices
have as many as four PTP related interrupts.
......@@ -43,14 +44,22 @@ Clock Properties:
value, which will be directly written in those bits, that is why,
according to reference manual, the next clock sources can be used:
For eTSEC,
<0> - external high precision timer reference clock (TSEC_TMR_CLK
input is used for this purpose);
<1> - eTSEC system clock;
<2> - eTSEC1 transmit clock;
<3> - RTC clock input.
When this attribute is not used, eTSEC system clock will serve as
IEEE 1588 timer reference clock.
For DPAA FMan,
<0> - external high precision timer reference clock (TMR_1588_CLK)
<1> - MAC system clock (1/2 FMan clock)
<2> - reserved
<3> - RTC clock oscillator
When this attribute is not used, the IEEE 1588 timer reference clock
will use the eTSEC system clock (for Gianfar) or the MAC system
clock (for DPAA).
Example:
......
......@@ -11,13 +11,14 @@ fman0: fman@1a00000 {
#size-cells = <1>;
cell-index = <0>;
compatible = "fsl,fman";
ranges = <0x0 0x0 0x1a00000 0x100000>;
reg = <0x0 0x1a00000 0x0 0x100000>;
ranges = <0x0 0x0 0x1a00000 0xfe000>;
reg = <0x0 0x1a00000 0x0 0xfe000>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clockgen 3 0>;
clock-names = "fmanclk";
fsl,qman-channel-range = <0x800 0x10>;
ptimer-handle = <&ptp_timer0>;
muram@0 {
compatible = "fsl,fman-muram";
......@@ -73,9 +74,10 @@ xmdio0: mdio@fd000 {
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
reg = <0xfd000 0x1000>;
};
};
ptp_timer0: ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
ptp_timer0: ptp-timer@1afe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0x0 0x1afe000 0x0 0x1000>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
};
......@@ -37,12 +37,13 @@ fman0: fman@400000 {
#size-cells = <1>;
cell-index = <0>;
compatible = "fsl,fman";
ranges = <0 0x400000 0x100000>;
reg = <0x400000 0x100000>;
ranges = <0 0x400000 0xfe000>;
reg = <0x400000 0xfe000>;
interrupts = <96 2 0 0>, <16 2 1 1>;
clocks = <&clockgen 3 0>;
clock-names = "fmanclk";
fsl,qman-channel-range = <0x40 0xc>;
ptimer-handle = <&ptp_timer0>;
muram@0 {
compatible = "fsl,fman-muram";
......@@ -93,9 +94,10 @@ fman0_oh_0x7: port@87000 {
reg = <0x87000 0x1000>;
status = "disabled";
};
};
ptp_timer0: ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
ptp_timer0: ptp-timer@4fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0x4fe000 0x1000>;
interrupts = <96 2 0 0>;
};
......@@ -37,12 +37,13 @@ fman1: fman@500000 {
#size-cells = <1>;
cell-index = <1>;
compatible = "fsl,fman";
ranges = <0 0x500000 0x100000>;
reg = <0x500000 0x100000>;
ranges = <0 0x500000 0xfe000>;
reg = <0x500000 0xfe000>;
interrupts = <97 2 0 0>, <16 2 1 0>;
clocks = <&clockgen 3 1>;
clock-names = "fmanclk";
fsl,qman-channel-range = <0x60 0xc>;
ptimer-handle = <&ptp_timer1>;
muram@0 {
compatible = "fsl,fman-muram";
......@@ -93,9 +94,10 @@ fman1_oh_0x7: port@87000 {
reg = <0x87000 0x1000>;
status = "disabled";
};
};
ptp_timer1: ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
ptp_timer1: ptp-timer@5fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0x5fe000 0x1000>;
interrupts = <97 2 0 0>;
};
......@@ -37,12 +37,13 @@ fman0: fman@400000 {
#size-cells = <1>;
cell-index = <0>;
compatible = "fsl,fman";
ranges = <0 0x400000 0x100000>;
reg = <0x400000 0x100000>;
ranges = <0 0x400000 0xfe000>;
reg = <0x400000 0xfe000>;
interrupts = <96 2 0 0>, <16 2 1 1>;
clocks = <&clockgen 3 0>;
clock-names = "fmanclk";
fsl,qman-channel-range = <0x800 0x10>;
ptimer-handle = <&ptp_timer0>;
muram@0 {
compatible = "fsl,fman-muram";
......@@ -98,9 +99,10 @@ xmdio0: mdio@fd000 {
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
reg = <0xfd000 0x1000>;
};
};
ptp_timer0: ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
ptp_timer0: ptp-timer@4fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0x4fe000 0x1000>;
interrupts = <96 2 0 0>;
};
......@@ -37,12 +37,13 @@ fman1: fman@500000 {
#size-cells = <1>;
cell-index = <1>;
compatible = "fsl,fman";
ranges = <0 0x500000 0x100000>;
reg = <0x500000 0x100000>;
ranges = <0 0x500000 0xfe000>;
reg = <0x500000 0xfe000>;
interrupts = <97 2 0 0>, <16 2 1 0>;
clocks = <&clockgen 3 1>;
clock-names = "fmanclk";
fsl,qman-channel-range = <0x820 0x10>;
ptimer-handle = <&ptp_timer1>;
muram@0 {
compatible = "fsl,fman-muram";
......@@ -98,9 +99,10 @@ mdio@fd000 {
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
reg = <0xfd000 0x1000>;
};
};
ptp_timer1: ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
ptp_timer1: ptp-timer@5fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0x5fe000 0x1000>;
interrupts = <97 2 0 0>;
};
......@@ -37,12 +37,13 @@ fman0: fman@400000 {
#size-cells = <1>;
cell-index = <0>;
compatible = "fsl,fman";
ranges = <0 0x400000 0x100000>;
reg = <0x400000 0x100000>;
ranges = <0 0x400000 0xfe000>;
reg = <0x400000 0xfe000>;
interrupts = <96 2 0 0>, <16 2 1 1>;
clocks = <&clockgen 3 0>;
clock-names = "fmanclk";
fsl,qman-channel-range = <0x800 0x10>;
ptimer-handle = <&ptp_timer0>;
muram@0 {
compatible = "fsl,fman-muram";
......@@ -86,9 +87,10 @@ xmdio0: mdio@fd000 {
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
reg = <0xfd000 0x1000>;
};
};
ptp_timer0: ptp-timer@fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0xfe000 0x1000>;
};
ptp_timer0: ptp-timer@4fe000 {
compatible = "fsl,fman-ptp-timer";
reg = <0x4fe000 0x1000>;
interrupts = <96 2 0 0>;
};
......@@ -1168,7 +1168,7 @@ static int dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq,
buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
buf_prefix_content.pass_prs_result = true;
buf_prefix_content.pass_hash_result = true;
buf_prefix_content.pass_time_stamp = false;
buf_prefix_content.pass_time_stamp = true;
buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
params.specific_params.non_rx_params.err_fqid = errq->fqid;
......@@ -1210,7 +1210,7 @@ static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps,
buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
buf_prefix_content.pass_prs_result = true;
buf_prefix_content.pass_hash_result = true;
buf_prefix_content.pass_time_stamp = false;
buf_prefix_content.pass_time_stamp = true;
buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
rx_p = &params.specific_params.rx_params;
......@@ -1607,14 +1607,28 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
{
const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
struct device *dev = priv->net_dev->dev.parent;
struct skb_shared_hwtstamps shhwtstamps;
dma_addr_t addr = qm_fd_addr(fd);
const struct qm_sg_entry *sgt;
struct sk_buff **skbh, *skb;
int nr_frags, i;
u64 ns;
skbh = (struct sk_buff **)phys_to_virt(addr);
skb = *skbh;
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh,
&ns)) {
shhwtstamps.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(skb, &shhwtstamps);
} else {
dev_warn(dev, "fman_port_get_tstamp failed!\n");
}
}
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
nr_frags = skb_shinfo(skb)->nr_frags;
dma_unmap_single(dev, addr, qm_fd_get_offset(fd) +
......@@ -2086,6 +2100,11 @@ static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
if (unlikely(err < 0))
goto skb_to_fd_failed;
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
fd.cmd |= cpu_to_be32(FM_FD_CMD_UPD);
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
}
if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0))
return NETDEV_TX_OK;
......@@ -2227,6 +2246,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
struct qman_fq *fq,
const struct qm_dqrr_entry *dq)
{
struct skb_shared_hwtstamps *shhwtstamps;
struct rtnl_link_stats64 *percpu_stats;
struct dpaa_percpu_priv *percpu_priv;
const struct qm_fd *fd = &dq->fd;
......@@ -2240,6 +2260,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
struct sk_buff *skb;
int *count_ptr;
void *vaddr;
u64 ns;
fd_status = be32_to_cpu(fd->status);
fd_format = qm_fd_get_format(fd);
......@@ -2304,6 +2325,16 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
if (!skb)
return qman_cb_dqrr_consume;
if (priv->rx_tstamp) {
shhwtstamps = skb_hwtstamps(skb);
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
if (!fman_port_get_tstamp(priv->mac_dev->port[RX], vaddr, &ns))
shhwtstamps->hwtstamp = ns_to_ktime(ns);
else
dev_warn(net_dev->dev.parent, "fman_port_get_tstamp failed!\n");
}
skb->protocol = eth_type_trans(skb, net_dev);
if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use &&
......@@ -2523,11 +2554,58 @@ static int dpaa_eth_stop(struct net_device *net_dev)
return err;
}
static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct dpaa_priv *priv = netdev_priv(dev);
struct hwtstamp_config config;
if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
return -EFAULT;
switch (config.tx_type) {
case HWTSTAMP_TX_OFF:
/* Couldn't disable rx/tx timestamping separately.
* Do nothing here.
*/
priv->tx_tstamp = false;
break;
case HWTSTAMP_TX_ON:
priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac, true);
priv->tx_tstamp = true;
break;
default:
return -ERANGE;
}
if (config.rx_filter == HWTSTAMP_FILTER_NONE) {
/* Couldn't disable rx/tx timestamping separately.
* Do nothing here.
*/
priv->rx_tstamp = false;
} else {
priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac, true);
priv->rx_tstamp = true;
/* TS is set for all frame types, not only those requested */
config.rx_filter = HWTSTAMP_FILTER_ALL;
}
return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}
static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
{
if (!net_dev->phydev)
return -EINVAL;
return phy_mii_ioctl(net_dev->phydev, rq, cmd);
int ret = -EINVAL;
if (cmd == SIOCGMIIREG) {
if (net_dev->phydev)
return phy_mii_ioctl(net_dev->phydev, rq, cmd);
}
if (cmd == SIOCSHWTSTAMP)
return dpaa_ts_ioctl(net_dev, rq, cmd);
return ret;
}
static const struct net_device_ops dpaa_ops = {
......
......@@ -182,6 +182,9 @@ struct dpaa_priv {
struct dpaa_buffer_layout buf_layout[2];
u16 rx_headroom;
bool tx_tstamp; /* Tx timestamping enabled */
bool rx_tstamp; /* Rx timestamping enabled */
};
/* from dpaa_ethtool.c */
......
......@@ -32,6 +32,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/string.h>
#include <linux/of_platform.h>
#include <linux/net_tstamp.h>
#include <linux/fsl/ptp_qoriq.h>
#include "dpaa_eth.h"
#include "mac.h"
......@@ -515,6 +518,41 @@ static int dpaa_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}
static int dpaa_get_ts_info(struct net_device *net_dev,
struct ethtool_ts_info *info)
{
struct device *dev = net_dev->dev.parent;
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;
info->phc_index = -1;
fman_node = of_get_parent(mac_node);
if (fman_node)
ptp_node = of_parse_phandle(fman_node, "ptimer-handle", 0);
if (ptp_node)
ptp_dev = of_find_device_by_node(ptp_node);
if (ptp_dev)
ptp = platform_get_drvdata(ptp_dev);
if (ptp)
info->phc_index = ptp->phc_index;
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->tx_types = (1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_ALL);
return 0;
}
const struct ethtool_ops dpaa_ethtool_ops = {
.get_drvinfo = dpaa_get_drvinfo,
.get_msglevel = dpaa_get_msglevel,
......@@ -530,4 +568,5 @@ const struct ethtool_ops dpaa_ethtool_ops = {
.set_link_ksettings = dpaa_set_link_ksettings,
.get_rxnfc = dpaa_get_rxnfc,
.set_rxnfc = dpaa_set_rxnfc,
.get_ts_info = dpaa_get_ts_info,
};
......@@ -2801,7 +2801,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
of_node_put(muram_node);
of_node_put(fm_node);
err = devm_request_irq(&of_dev->dev, irq, fman_irq, 0, "fman", fman);
err = devm_request_irq(&of_dev->dev, irq, fman_irq, IRQF_SHARED,
"fman", fman);
if (err < 0) {
dev_err(&of_dev->dev, "%s: irq %d allocation failed (error = %d)\n",
__func__, irq, err);
......
......@@ -41,6 +41,7 @@
/* Frame queue Context Override */
#define FM_FD_CMD_FCO 0x80000000
#define FM_FD_CMD_RPD 0x40000000 /* Read Prepended Data */
#define FM_FD_CMD_UPD 0x20000000 /* Update Prepended Data */
#define FM_FD_CMD_DTC 0x10000000 /* Do L4 Checksum */
/* TX-Port: Unsupported Format */
......
......@@ -123,11 +123,13 @@
#define DTSEC_ECNTRL_R100M 0x00000008
#define DTSEC_ECNTRL_QSGMIIM 0x00000001
#define TCTRL_TTSE 0x00000040
#define TCTRL_GTS 0x00000020
#define RCTRL_PAL_MASK 0x001f0000
#define RCTRL_PAL_SHIFT 16
#define RCTRL_GHTX 0x00000400
#define RCTRL_RTSE 0x00000040
#define RCTRL_GRS 0x00000020
#define RCTRL_MPROM 0x00000008
#define RCTRL_RSF 0x00000004
......@@ -1136,6 +1138,31 @@ int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable)
return 0;
}
int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
u32 rctrl, tctrl;
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
rctrl = ioread32be(&regs->rctrl);
tctrl = ioread32be(&regs->tctrl);
if (enable) {
rctrl |= RCTRL_RTSE;
tctrl |= TCTRL_TTSE;
} else {
rctrl &= ~RCTRL_RTSE;
tctrl &= ~TCTRL_TTSE;
}
iowrite32be(rctrl, &regs->rctrl);
iowrite32be(tctrl, &regs->tctrl);
return 0;
}
int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr)
{
struct dtsec_regs __iomem *regs = dtsec->regs;
......
......@@ -56,5 +56,6 @@ int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr);
int dtsec_del_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr);
int dtsec_get_version(struct fman_mac *dtsec, u32 *mac_version);
int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable);
int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable);
#endif /* __DTSEC_H */
......@@ -964,6 +964,11 @@ int memac_set_allmulti(struct fman_mac *memac, bool enable)
return 0;
}
int memac_set_tstamp(struct fman_mac *memac, bool enable)
{
return 0; /* Always enabled. */
}
int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr)
{
struct memac_regs __iomem *regs = memac->regs;
......
......@@ -58,5 +58,6 @@ int memac_set_exception(struct fman_mac *memac,
int memac_add_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr);
int memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr);
int memac_set_allmulti(struct fman_mac *memac, bool enable);
int memac_set_tstamp(struct fman_mac *memac, bool enable);
#endif /* __MEMAC_H */
......@@ -1731,6 +1731,18 @@ int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset)
}
EXPORT_SYMBOL(fman_port_get_hash_result_offset);
int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp)
{
if (port->buffer_offsets.time_stamp_offset == ILLEGAL_BASE)
return -EINVAL;
*tstamp = be64_to_cpu(*(__be64 *)(data +
port->buffer_offsets.time_stamp_offset));
return 0;
}
EXPORT_SYMBOL(fman_port_get_tstamp);
static int fman_port_probe(struct platform_device *of_dev)
{
struct fman_port *port;
......
......@@ -153,6 +153,8 @@ u32 fman_port_get_qman_channel_id(struct fman_port *port);
int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset);
int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp);
struct fman_port *fman_port_bind(struct device *dev);
#endif /* __FMAN_PORT_H */
......@@ -44,6 +44,7 @@
#define TGEC_TX_IPG_LENGTH_MASK 0x000003ff
/* Command and Configuration Register (COMMAND_CONFIG) */
#define CMD_CFG_EN_TIMESTAMP 0x00100000
#define CMD_CFG_NO_LEN_CHK 0x00020000
#define CMD_CFG_PAUSE_IGNORE 0x00000100
#define CMF_CFG_CRC_FWD 0x00000040
......@@ -588,6 +589,26 @@ int tgec_set_allmulti(struct fman_mac *tgec, bool enable)
return 0;
}
int tgec_set_tstamp(struct fman_mac *tgec, bool enable)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (enable)
tmp |= CMD_CFG_EN_TIMESTAMP;
else
tmp &= ~CMD_CFG_EN_TIMESTAMP;
iowrite32be(tmp, &regs->command_config);
return 0;
}
int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr)
{
struct tgec_regs __iomem *regs = tgec->regs;
......
......@@ -52,5 +52,6 @@ int tgec_add_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr);
int tgec_del_hash_mac_address(struct fman_mac *tgec, enet_addr_t *eth_addr);
int tgec_get_version(struct fman_mac *tgec, u32 *mac_version);
int tgec_set_allmulti(struct fman_mac *tgec, bool enable);
int tgec_set_tstamp(struct fman_mac *tgec, bool enable);
#endif /* __TGEC_H */
......@@ -471,6 +471,7 @@ static void setup_dtsec(struct mac_device *mac_dev)
mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames;
mac_dev->set_exception = dtsec_set_exception;
mac_dev->set_allmulti = dtsec_set_allmulti;
mac_dev->set_tstamp = dtsec_set_tstamp;
mac_dev->set_multi = set_multi;
mac_dev->start = start;
mac_dev->stop = stop;
......@@ -490,6 +491,7 @@ static void setup_tgec(struct mac_device *mac_dev)
mac_dev->set_rx_pause = tgec_accept_rx_pause_frames;
mac_dev->set_exception = tgec_set_exception;
mac_dev->set_allmulti = tgec_set_allmulti;
mac_dev->set_tstamp = tgec_set_tstamp;
mac_dev->set_multi = set_multi;
mac_dev->start = start;
mac_dev->stop = stop;
......@@ -509,6 +511,7 @@ static void setup_memac(struct mac_device *mac_dev)
mac_dev->set_rx_pause = memac_accept_rx_pause_frames;
mac_dev->set_exception = memac_set_exception;
mac_dev->set_allmulti = memac_set_allmulti;
mac_dev->set_tstamp = memac_set_tstamp;
mac_dev->set_multi = set_multi;
mac_dev->start = start;
mac_dev->stop = stop;
......
......@@ -68,6 +68,7 @@ struct mac_device {
int (*set_promisc)(struct fman_mac *mac_dev, bool enable);
int (*change_addr)(struct fman_mac *mac_dev, enet_addr_t *enet_addr);
int (*set_allmulti)(struct fman_mac *mac_dev, bool enable);
int (*set_tstamp)(struct fman_mac *mac_dev, bool enable);
int (*set_multi)(struct net_device *net_dev,
struct mac_device *mac_dev);
int (*set_rx_pause)(struct fman_mac *mac_dev, bool en);
......
......@@ -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
depends on GIANFAR || FSL_DPAA_ETH
depends on PTP_1588_CLOCK
default y
help
......
......@@ -39,11 +39,12 @@
/* Caller must hold qoriq_ptp->lock. */
static u64 tmr_cnt_read(struct qoriq_ptp *qoriq_ptp)
{
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
u64 ns;
u32 lo, hi;
lo = qoriq_read(&qoriq_ptp->regs->tmr_cnt_l);
hi = qoriq_read(&qoriq_ptp->regs->tmr_cnt_h);
lo = qoriq_read(&regs->ctrl_regs->tmr_cnt_l);
hi = qoriq_read(&regs->ctrl_regs->tmr_cnt_h);
ns = ((u64) hi) << 32;
ns |= lo;
return ns;
......@@ -52,16 +53,18 @@ static u64 tmr_cnt_read(struct qoriq_ptp *qoriq_ptp)
/* Caller must hold qoriq_ptp->lock. */
static void tmr_cnt_write(struct qoriq_ptp *qoriq_ptp, u64 ns)
{
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
u32 hi = ns >> 32;
u32 lo = ns & 0xffffffff;
qoriq_write(&qoriq_ptp->regs->tmr_cnt_l, lo);
qoriq_write(&qoriq_ptp->regs->tmr_cnt_h, hi);
qoriq_write(&regs->ctrl_regs->tmr_cnt_l, lo);
qoriq_write(&regs->ctrl_regs->tmr_cnt_h, hi);
}
/* Caller must hold qoriq_ptp->lock. */
static void set_alarm(struct qoriq_ptp *qoriq_ptp)
{
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
u64 ns;
u32 lo, hi;
......@@ -70,16 +73,18 @@ static void set_alarm(struct qoriq_ptp *qoriq_ptp)
ns -= qoriq_ptp->tclk_period;
hi = ns >> 32;
lo = ns & 0xffffffff;
qoriq_write(&qoriq_ptp->regs->tmr_alarm1_l, lo);
qoriq_write(&qoriq_ptp->regs->tmr_alarm1_h, hi);
qoriq_write(&regs->alarm_regs->tmr_alarm1_l, lo);
qoriq_write(&regs->alarm_regs->tmr_alarm1_h, hi);
}
/* Caller must hold qoriq_ptp->lock. */
static void set_fipers(struct qoriq_ptp *qoriq_ptp)
{
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
set_alarm(qoriq_ptp);
qoriq_write(&qoriq_ptp->regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
qoriq_write(&qoriq_ptp->regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
qoriq_write(&regs->fiper_regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
qoriq_write(&regs->fiper_regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
}
/*
......@@ -89,16 +94,17 @@ static void set_fipers(struct qoriq_ptp *qoriq_ptp)
static irqreturn_t isr(int irq, void *priv)
{
struct qoriq_ptp *qoriq_ptp = priv;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
struct ptp_clock_event event;
u64 ns;
u32 ack = 0, lo, hi, mask, val;
val = qoriq_read(&qoriq_ptp->regs->tmr_tevent);
val = qoriq_read(&regs->ctrl_regs->tmr_tevent);
if (val & ETS1) {
ack |= ETS1;
hi = qoriq_read(&qoriq_ptp->regs->tmr_etts1_h);
lo = qoriq_read(&qoriq_ptp->regs->tmr_etts1_l);
hi = qoriq_read(&regs->etts_regs->tmr_etts1_h);
lo = qoriq_read(&regs->etts_regs->tmr_etts1_l);
event.type = PTP_CLOCK_EXTTS;
event.index = 0;
event.timestamp = ((u64) hi) << 32;
......@@ -108,8 +114,8 @@ static irqreturn_t isr(int irq, void *priv)
if (val & ETS2) {
ack |= ETS2;
hi = qoriq_read(&qoriq_ptp->regs->tmr_etts2_h);
lo = qoriq_read(&qoriq_ptp->regs->tmr_etts2_l);
hi = qoriq_read(&regs->etts_regs->tmr_etts2_h);
lo = qoriq_read(&regs->etts_regs->tmr_etts2_l);
event.type = PTP_CLOCK_EXTTS;
event.index = 1;
event.timestamp = ((u64) hi) << 32;
......@@ -130,16 +136,16 @@ static irqreturn_t isr(int irq, void *priv)
hi = ns >> 32;
lo = ns & 0xffffffff;
spin_lock(&qoriq_ptp->lock);
qoriq_write(&qoriq_ptp->regs->tmr_alarm2_l, lo);
qoriq_write(&qoriq_ptp->regs->tmr_alarm2_h, hi);
qoriq_write(&regs->alarm_regs->tmr_alarm2_l, lo);
qoriq_write(&regs->alarm_regs->tmr_alarm2_h, hi);
spin_unlock(&qoriq_ptp->lock);
qoriq_ptp->alarm_value = ns;
} else {
qoriq_write(&qoriq_ptp->regs->tmr_tevent, ALM2);
qoriq_write(&regs->ctrl_regs->tmr_tevent, ALM2);
spin_lock(&qoriq_ptp->lock);
mask = qoriq_read(&qoriq_ptp->regs->tmr_temask);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
mask &= ~ALM2EN;
qoriq_write(&qoriq_ptp->regs->tmr_temask, mask);
qoriq_write(&regs->ctrl_regs->tmr_temask, mask);
spin_unlock(&qoriq_ptp->lock);
qoriq_ptp->alarm_value = 0;
qoriq_ptp->alarm_interval = 0;
......@@ -153,7 +159,7 @@ static irqreturn_t isr(int irq, void *priv)
}
if (ack) {
qoriq_write(&qoriq_ptp->regs->tmr_tevent, ack);
qoriq_write(&regs->ctrl_regs->tmr_tevent, ack);
return IRQ_HANDLED;
} else
return IRQ_NONE;
......@@ -169,6 +175,7 @@ static int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
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;
if (scaled_ppm < 0) {
neg_adj = 1;
......@@ -186,7 +193,7 @@ 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(&qoriq_ptp->regs->tmr_add, tmr_add);
qoriq_write(&regs->ctrl_regs->tmr_add, tmr_add);
return 0;
}
......@@ -250,6 +257,7 @@ static 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;
unsigned long flags;
u32 bit, mask;
......@@ -266,23 +274,23 @@ static int ptp_qoriq_enable(struct ptp_clock_info *ptp,
return -EINVAL;
}
spin_lock_irqsave(&qoriq_ptp->lock, flags);
mask = qoriq_read(&qoriq_ptp->regs->tmr_temask);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
if (on)
mask |= bit;
else
mask &= ~bit;
qoriq_write(&qoriq_ptp->regs->tmr_temask, mask);
qoriq_write(&regs->ctrl_regs->tmr_temask, mask);
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
return 0;
case PTP_CLK_REQ_PPS:
spin_lock_irqsave(&qoriq_ptp->lock, flags);
mask = qoriq_read(&qoriq_ptp->regs->tmr_temask);
mask = qoriq_read(&regs->ctrl_regs->tmr_temask);
if (on)
mask |= PP1EN;
else
mask &= ~PP1EN;
qoriq_write(&qoriq_ptp->regs->tmr_temask, mask);
qoriq_write(&regs->ctrl_regs->tmr_temask, mask);
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
return 0;
......@@ -313,10 +321,12 @@ static int qoriq_ptp_probe(struct platform_device *dev)
{
struct device_node *node = dev->dev.of_node;
struct qoriq_ptp *qoriq_ptp;
struct qoriq_ptp_registers *regs;
struct timespec64 now;
int err = -ENOMEM;
u32 tmr_ctrl;
unsigned long flags;
void __iomem *base;
qoriq_ptp = kzalloc(sizeof(*qoriq_ptp), GFP_KERNEL);
if (!qoriq_ptp)
......@@ -351,7 +361,7 @@ static int qoriq_ptp_probe(struct platform_device *dev)
pr_err("irq not in device tree\n");
goto no_node;
}
if (request_irq(qoriq_ptp->irq, isr, 0, DRIVER, qoriq_ptp)) {
if (request_irq(qoriq_ptp->irq, isr, IRQF_SHARED, DRIVER, qoriq_ptp)) {
pr_err("request_irq failed\n");
goto no_node;
}
......@@ -368,12 +378,27 @@ static int qoriq_ptp_probe(struct platform_device *dev)
spin_lock_init(&qoriq_ptp->lock);
qoriq_ptp->regs = ioremap(qoriq_ptp->rsrc->start,
resource_size(qoriq_ptp->rsrc));
if (!qoriq_ptp->regs) {
base = ioremap(qoriq_ptp->rsrc->start,
resource_size(qoriq_ptp->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);
......@@ -383,13 +408,14 @@ static int qoriq_ptp_probe(struct platform_device *dev)
spin_lock_irqsave(&qoriq_ptp->lock, flags);
qoriq_write(&qoriq_ptp->regs->tmr_ctrl, tmr_ctrl);
qoriq_write(&qoriq_ptp->regs->tmr_add, qoriq_ptp->tmr_add);
qoriq_write(&qoriq_ptp->regs->tmr_prsc, qoriq_ptp->tmr_prsc);
qoriq_write(&qoriq_ptp->regs->tmr_fiper1, qoriq_ptp->tmr_fiper1);
qoriq_write(&qoriq_ptp->regs->tmr_fiper2, qoriq_ptp->tmr_fiper2);
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(&qoriq_ptp->regs->tmr_ctrl, tmr_ctrl|FIPERST|RTPE|TE|FRD);
qoriq_write(&regs->ctrl_regs->tmr_ctrl, tmr_ctrl|FIPERST|RTPE|TE|FRD);
spin_unlock_irqrestore(&qoriq_ptp->lock, flags);
......@@ -405,7 +431,7 @@ static int qoriq_ptp_probe(struct platform_device *dev)
return 0;
no_clock:
iounmap(qoriq_ptp->regs);
iounmap(qoriq_ptp->base);
no_ioremap:
release_resource(qoriq_ptp->rsrc);
no_resource:
......@@ -419,12 +445,13 @@ static int qoriq_ptp_probe(struct platform_device *dev)
static int qoriq_ptp_remove(struct platform_device *dev)
{
struct qoriq_ptp *qoriq_ptp = platform_get_drvdata(dev);
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
qoriq_write(&qoriq_ptp->regs->tmr_temask, 0);
qoriq_write(&qoriq_ptp->regs->tmr_ctrl, 0);
qoriq_write(&regs->ctrl_regs->tmr_temask, 0);
qoriq_write(&regs->ctrl_regs->tmr_ctrl, 0);
ptp_clock_unregister(qoriq_ptp->clock);
iounmap(qoriq_ptp->regs);
iounmap(qoriq_ptp->base);
release_resource(qoriq_ptp->rsrc);
free_irq(qoriq_ptp->irq, qoriq_ptp);
kfree(qoriq_ptp);
......@@ -434,6 +461,7 @@ static int qoriq_ptp_remove(struct platform_device *dev)
static const struct of_device_id match_table[] = {
{ .compatible = "fsl,etsec-ptp" },
{ .compatible = "fsl,fman-ptp-timer" },
{},
};
MODULE_DEVICE_TABLE(of, match_table);
......
......@@ -11,9 +11,8 @@
/*
* qoriq ptp registers
* Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010
*/
struct qoriq_ptp_registers {
struct ctrl_regs {
u32 tmr_ctrl; /* Timer control register */
u32 tmr_tevent; /* Timestamp event register */
u32 tmr_temask; /* Timer event mask register */
......@@ -28,22 +27,47 @@ struct qoriq_ptp_registers {
u8 res1[4];
u32 tmroff_h; /* Timer offset high */
u32 tmroff_l; /* Timer offset low */
u8 res2[8];
};
struct alarm_regs {
u32 tmr_alarm1_h; /* Timer alarm 1 high register */
u32 tmr_alarm1_l; /* Timer alarm 1 high register */
u32 tmr_alarm2_h; /* Timer alarm 2 high register */
u32 tmr_alarm2_l; /* Timer alarm 2 high register */
u8 res3[48];
};
struct fiper_regs {
u32 tmr_fiper1; /* Timer fixed period interval */
u32 tmr_fiper2; /* Timer fixed period interval */
u32 tmr_fiper3; /* Timer fixed period interval */
u8 res4[20];
};
struct etts_regs {
u32 tmr_etts1_h; /* Timestamp of general purpose external trigger */
u32 tmr_etts1_l; /* Timestamp of general purpose external trigger */
u32 tmr_etts2_h; /* Timestamp of general purpose external trigger */
u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */
};
struct qoriq_ptp_registers {
struct ctrl_regs __iomem *ctrl_regs;
struct alarm_regs __iomem *alarm_regs;
struct fiper_regs __iomem *fiper_regs;
struct etts_regs __iomem *etts_regs;
};
/* 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 FMAN_CTRL_REGS_OFFSET 0x80
#define FMAN_ALARM_REGS_OFFSET 0xb8
#define FMAN_FIPER_REGS_OFFSET 0xd0
#define FMAN_ETTS_REGS_OFFSET 0xe0
/* Bit definitions for the TMR_CTRL register */
#define ALM1P (1<<31) /* Alarm1 output polarity */
#define ALM2P (1<<30) /* Alarm2 output polarity */
......@@ -105,10 +129,10 @@ struct qoriq_ptp_registers {
#define DRIVER "ptp_qoriq"
#define DEFAULT_CKSEL 1
#define N_EXT_TS 2
#define REG_SIZE sizeof(struct qoriq_ptp_registers)
struct qoriq_ptp {
struct qoriq_ptp_registers __iomem *regs;
void __iomem *base;
struct qoriq_ptp_registers regs;
spinlock_t lock; /* protects regs */
struct ptp_clock *clock;
struct ptp_clock_info caps;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册