mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-06 21:14:18 +00:00
net: ethernet: renesas: rswitch: Add R-Car Gen4 gPTP support
Add R-Car Gen4 gPTP support into the rswitch driver. Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3590918b5d
commit
6c6fa1a00a
@ -9,6 +9,6 @@ ravb-objs := ravb_main.o ravb_ptp.o
|
|||||||
|
|
||||||
obj-$(CONFIG_RAVB) += ravb.o
|
obj-$(CONFIG_RAVB) += ravb.o
|
||||||
|
|
||||||
rswitch_drv-objs := rswitch.o
|
rswitch_drv-objs := rswitch.o rcar_gen4_ptp.o
|
||||||
|
|
||||||
obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch_drv.o
|
obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch_drv.o
|
||||||
|
181
drivers/net/ethernet/renesas/rcar_gen4_ptp.c
Normal file
181
drivers/net/ethernet/renesas/rcar_gen4_ptp.c
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Renesas R-Car Gen4 gPTP device driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Renesas Electronics Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "rcar_gen4_ptp.h"
|
||||||
|
#define ptp_to_priv(ptp) container_of(ptp, struct rcar_gen4_ptp_private, info)
|
||||||
|
|
||||||
|
static const struct rcar_gen4_ptp_reg_offset s4_offs = {
|
||||||
|
.enable = PTPTMEC,
|
||||||
|
.disable = PTPTMDC,
|
||||||
|
.increment = PTPTIVC0,
|
||||||
|
.config_t0 = PTPTOVC00,
|
||||||
|
.config_t1 = PTPTOVC10,
|
||||||
|
.config_t2 = PTPTOVC20,
|
||||||
|
.monitor_t0 = PTPGPTPTM00,
|
||||||
|
.monitor_t1 = PTPGPTPTM10,
|
||||||
|
.monitor_t2 = PTPGPTPTM20,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rcar_gen4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
|
||||||
|
bool neg_adj = scaled_ppm < 0 ? true : false;
|
||||||
|
s64 addend = ptp_priv->default_addend;
|
||||||
|
s64 diff;
|
||||||
|
|
||||||
|
if (neg_adj)
|
||||||
|
scaled_ppm = -scaled_ppm;
|
||||||
|
diff = div_s64(addend * scaled_ppm_to_ppb(scaled_ppm), NSEC_PER_SEC);
|
||||||
|
addend = neg_adj ? addend - diff : addend + diff;
|
||||||
|
|
||||||
|
iowrite32(addend, ptp_priv->addr + ptp_priv->offs->increment);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caller must hold the lock */
|
||||||
|
static void _rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
|
||||||
|
struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
|
||||||
|
|
||||||
|
ts->tv_nsec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t0);
|
||||||
|
ts->tv_sec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t1) |
|
||||||
|
((s64)ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t2) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
|
||||||
|
struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ptp_priv->lock, flags);
|
||||||
|
_rcar_gen4_ptp_gettime(ptp, ts);
|
||||||
|
spin_unlock_irqrestore(&ptp_priv->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caller must hold the lock */
|
||||||
|
static void _rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
|
||||||
|
const struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
|
||||||
|
|
||||||
|
iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
|
||||||
|
iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t2);
|
||||||
|
iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t1);
|
||||||
|
iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t0);
|
||||||
|
iowrite32(1, ptp_priv->addr + ptp_priv->offs->enable);
|
||||||
|
iowrite32(ts->tv_sec >> 32, ptp_priv->addr + ptp_priv->offs->config_t2);
|
||||||
|
iowrite32(ts->tv_sec, ptp_priv->addr + ptp_priv->offs->config_t1);
|
||||||
|
iowrite32(ts->tv_nsec, ptp_priv->addr + ptp_priv->offs->config_t0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
|
||||||
|
const struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ptp_priv->lock, flags);
|
||||||
|
_rcar_gen4_ptp_settime(ptp, ts);
|
||||||
|
spin_unlock_irqrestore(&ptp_priv->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
|
||||||
|
struct timespec64 ts;
|
||||||
|
unsigned long flags;
|
||||||
|
s64 now;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ptp_priv->lock, flags);
|
||||||
|
_rcar_gen4_ptp_gettime(ptp, &ts);
|
||||||
|
now = ktime_to_ns(timespec64_to_ktime(ts));
|
||||||
|
ts = ns_to_timespec64(now + delta);
|
||||||
|
_rcar_gen4_ptp_settime(ptp, &ts);
|
||||||
|
spin_unlock_irqrestore(&ptp_priv->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen4_ptp_enable(struct ptp_clock_info *ptp,
|
||||||
|
struct ptp_clock_request *rq, int on)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ptp_clock_info rcar_gen4_ptp_info = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.name = "rcar_gen4_ptp",
|
||||||
|
.max_adj = 50000000,
|
||||||
|
.adjfine = rcar_gen4_ptp_adjfine,
|
||||||
|
.adjtime = rcar_gen4_ptp_adjtime,
|
||||||
|
.gettime64 = rcar_gen4_ptp_gettime,
|
||||||
|
.settime64 = rcar_gen4_ptp_settime,
|
||||||
|
.enable = rcar_gen4_ptp_enable,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv,
|
||||||
|
enum rcar_gen4_ptp_reg_layout layout)
|
||||||
|
{
|
||||||
|
WARN_ON(layout != RCAR_GEN4_PTP_REG_LAYOUT_S4);
|
||||||
|
|
||||||
|
ptp_priv->offs = &s4_offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
|
||||||
|
enum rcar_gen4_ptp_reg_layout layout, u32 clock)
|
||||||
|
{
|
||||||
|
if (ptp_priv->initialized)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spin_lock_init(&ptp_priv->lock);
|
||||||
|
|
||||||
|
rcar_gen4_ptp_set_offs(ptp_priv, layout);
|
||||||
|
|
||||||
|
ptp_priv->default_addend = clock;
|
||||||
|
iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment);
|
||||||
|
ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL);
|
||||||
|
if (IS_ERR(ptp_priv->clock))
|
||||||
|
return PTR_ERR(ptp_priv->clock);
|
||||||
|
|
||||||
|
iowrite32(0x01, ptp_priv->addr + ptp_priv->offs->enable);
|
||||||
|
ptp_priv->initialized = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv)
|
||||||
|
{
|
||||||
|
iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
|
||||||
|
|
||||||
|
return ptp_clock_unregister(ptp_priv->clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rcar_gen4_ptp_private *ptp;
|
||||||
|
|
||||||
|
ptp = devm_kzalloc(&pdev->dev, sizeof(*ptp), GFP_KERNEL);
|
||||||
|
if (!ptp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptp->info = rcar_gen4_ptp_info;
|
||||||
|
|
||||||
|
return ptp;
|
||||||
|
}
|
72
drivers/net/ethernet/renesas/rcar_gen4_ptp.h
Normal file
72
drivers/net/ethernet/renesas/rcar_gen4_ptp.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/* Renesas R-Car Gen4 gPTP device driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Renesas Electronics Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RCAR_GEN4_PTP_H__
|
||||||
|
#define __RCAR_GEN4_PTP_H__
|
||||||
|
|
||||||
|
#include <linux/ptp_clock_kernel.h>
|
||||||
|
|
||||||
|
#define PTPTIVC_INIT 0x19000000 /* 320MHz */
|
||||||
|
#define RCAR_GEN4_PTP_CLOCK_S4 PTPTIVC_INIT
|
||||||
|
#define RCAR_GEN4_GPTP_OFFSET_S4 0x00018000
|
||||||
|
|
||||||
|
/* for rcar_gen4_ptp_init */
|
||||||
|
enum rcar_gen4_ptp_reg_layout {
|
||||||
|
RCAR_GEN4_PTP_REG_LAYOUT_S4
|
||||||
|
};
|
||||||
|
|
||||||
|
/* driver's definitions */
|
||||||
|
#define RCAR_GEN4_RXTSTAMP_ENABLED BIT(0)
|
||||||
|
#define RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT BIT(1)
|
||||||
|
#define RCAR_GEN4_RXTSTAMP_TYPE_ALL (RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT | BIT(2))
|
||||||
|
#define RCAR_GEN4_RXTSTAMP_TYPE RCAR_GEN4_RXTSTAMP_TYPE_ALL
|
||||||
|
|
||||||
|
#define RCAR_GEN4_TXTSTAMP_ENABLED BIT(0)
|
||||||
|
|
||||||
|
#define PTPRO 0
|
||||||
|
|
||||||
|
enum rcar_gen4_ptp_reg_s4 {
|
||||||
|
PTPTMEC = PTPRO + 0x0010,
|
||||||
|
PTPTMDC = PTPRO + 0x0014,
|
||||||
|
PTPTIVC0 = PTPRO + 0x0020,
|
||||||
|
PTPTOVC00 = PTPRO + 0x0030,
|
||||||
|
PTPTOVC10 = PTPRO + 0x0034,
|
||||||
|
PTPTOVC20 = PTPRO + 0x0038,
|
||||||
|
PTPGPTPTM00 = PTPRO + 0x0050,
|
||||||
|
PTPGPTPTM10 = PTPRO + 0x0054,
|
||||||
|
PTPGPTPTM20 = PTPRO + 0x0058,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcar_gen4_ptp_reg_offset {
|
||||||
|
u16 enable;
|
||||||
|
u16 disable;
|
||||||
|
u16 increment;
|
||||||
|
u16 config_t0;
|
||||||
|
u16 config_t1;
|
||||||
|
u16 config_t2;
|
||||||
|
u16 monitor_t0;
|
||||||
|
u16 monitor_t1;
|
||||||
|
u16 monitor_t2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rcar_gen4_ptp_private {
|
||||||
|
void __iomem *addr;
|
||||||
|
struct ptp_clock *clock;
|
||||||
|
struct ptp_clock_info info;
|
||||||
|
const struct rcar_gen4_ptp_reg_offset *offs;
|
||||||
|
spinlock_t lock; /* For multiple registers access */
|
||||||
|
u32 tstamp_tx_ctrl;
|
||||||
|
u32 tstamp_rx_ctrl;
|
||||||
|
s64 default_addend;
|
||||||
|
bool initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
|
||||||
|
enum rcar_gen4_ptp_reg_layout layout, u32 clock);
|
||||||
|
int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv);
|
||||||
|
struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev);
|
||||||
|
|
||||||
|
#endif /* #ifndef __RCAR_GEN4_PTP_H__ */
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/net_tstamp.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
@ -123,6 +124,13 @@ static void rswitch_fwd_init(struct rswitch_private *priv)
|
|||||||
iowrite32(GENMASK(RSWITCH_NUM_PORTS - 1, 0), priv->addr + FWPBFC(priv->gwca.index));
|
iowrite32(GENMASK(RSWITCH_NUM_PORTS - 1, 0), priv->addr + FWPBFC(priv->gwca.index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* gPTP timer (gPTP) */
|
||||||
|
static void rswitch_get_timestamp(struct rswitch_private *priv,
|
||||||
|
struct timespec64 *ts)
|
||||||
|
{
|
||||||
|
priv->ptp_priv->info.gettime64(&priv->ptp_priv->info, ts);
|
||||||
|
}
|
||||||
|
|
||||||
/* Gateway CPU agent block (GWCA) */
|
/* Gateway CPU agent block (GWCA) */
|
||||||
static int rswitch_gwca_change_mode(struct rswitch_private *priv,
|
static int rswitch_gwca_change_mode(struct rswitch_private *priv,
|
||||||
enum rswitch_gwca_mode mode)
|
enum rswitch_gwca_mode mode)
|
||||||
@ -663,6 +671,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
|
|||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
dma_addr_t dma_addr;
|
dma_addr_t dma_addr;
|
||||||
u16 pkt_len;
|
u16 pkt_len;
|
||||||
|
u32 get_ts;
|
||||||
|
|
||||||
boguscnt = min_t(int, gq->ring_size, *quota);
|
boguscnt = min_t(int, gq->ring_size, *quota);
|
||||||
limit = boguscnt;
|
limit = boguscnt;
|
||||||
@ -677,6 +686,17 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
|
|||||||
gq->skbs[gq->cur] = NULL;
|
gq->skbs[gq->cur] = NULL;
|
||||||
dma_addr = rswitch_desc_get_dptr(&desc->desc);
|
dma_addr = rswitch_desc_get_dptr(&desc->desc);
|
||||||
dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, DMA_FROM_DEVICE);
|
dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, DMA_FROM_DEVICE);
|
||||||
|
get_ts = rdev->priv->ptp_priv->tstamp_rx_ctrl & RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT;
|
||||||
|
if (get_ts) {
|
||||||
|
struct skb_shared_hwtstamps *shhwtstamps;
|
||||||
|
struct timespec64 ts;
|
||||||
|
|
||||||
|
shhwtstamps = skb_hwtstamps(skb);
|
||||||
|
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
|
||||||
|
ts.tv_sec = __le32_to_cpu(desc->ts_sec);
|
||||||
|
ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff));
|
||||||
|
shhwtstamps->hwtstamp = timespec64_to_ktime(ts);
|
||||||
|
}
|
||||||
skb_put(skb, pkt_len);
|
skb_put(skb, pkt_len);
|
||||||
skb->protocol = eth_type_trans(skb, ndev);
|
skb->protocol = eth_type_trans(skb, ndev);
|
||||||
netif_receive_skb(skb);
|
netif_receive_skb(skb);
|
||||||
@ -725,6 +745,15 @@ static int rswitch_tx_free(struct net_device *ndev, bool free_txed_only)
|
|||||||
size = le16_to_cpu(desc->desc.info_ds) & TX_DS;
|
size = le16_to_cpu(desc->desc.info_ds) & TX_DS;
|
||||||
skb = gq->skbs[gq->dirty];
|
skb = gq->skbs[gq->dirty];
|
||||||
if (skb) {
|
if (skb) {
|
||||||
|
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
|
||||||
|
struct skb_shared_hwtstamps shhwtstamps;
|
||||||
|
struct timespec64 ts;
|
||||||
|
|
||||||
|
rswitch_get_timestamp(rdev->priv, &ts);
|
||||||
|
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
|
||||||
|
shhwtstamps.hwtstamp = timespec64_to_ktime(ts);
|
||||||
|
skb_tstamp_tx(skb, &shhwtstamps);
|
||||||
|
}
|
||||||
dma_addr = rswitch_desc_get_dptr(&desc->desc);
|
dma_addr = rswitch_desc_get_dptr(&desc->desc);
|
||||||
dma_unmap_single(ndev->dev.parent, dma_addr,
|
dma_unmap_single(ndev->dev.parent, dma_addr,
|
||||||
size, DMA_TO_DEVICE);
|
size, DMA_TO_DEVICE);
|
||||||
@ -1412,6 +1441,75 @@ static struct net_device_stats *rswitch_get_stats(struct net_device *ndev)
|
|||||||
return &ndev->stats;
|
return &ndev->stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rswitch_hwstamp_get(struct net_device *ndev, struct ifreq *req)
|
||||||
|
{
|
||||||
|
struct rswitch_device *rdev = netdev_priv(ndev);
|
||||||
|
struct rcar_gen4_ptp_private *ptp_priv;
|
||||||
|
struct hwtstamp_config config;
|
||||||
|
|
||||||
|
ptp_priv = rdev->priv->ptp_priv;
|
||||||
|
|
||||||
|
config.flags = 0;
|
||||||
|
config.tx_type = ptp_priv->tstamp_tx_ctrl ? HWTSTAMP_TX_ON :
|
||||||
|
HWTSTAMP_TX_OFF;
|
||||||
|
switch (ptp_priv->tstamp_rx_ctrl & RCAR_GEN4_RXTSTAMP_TYPE) {
|
||||||
|
case RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT:
|
||||||
|
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
|
||||||
|
break;
|
||||||
|
case RCAR_GEN4_RXTSTAMP_TYPE_ALL:
|
||||||
|
config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy_to_user(req->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rswitch_hwstamp_set(struct net_device *ndev, struct ifreq *req)
|
||||||
|
{
|
||||||
|
struct rswitch_device *rdev = netdev_priv(ndev);
|
||||||
|
u32 tstamp_rx_ctrl = RCAR_GEN4_RXTSTAMP_ENABLED;
|
||||||
|
struct hwtstamp_config config;
|
||||||
|
u32 tstamp_tx_ctrl;
|
||||||
|
|
||||||
|
if (copy_from_user(&config, req->ifr_data, sizeof(config)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (config.flags)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (config.tx_type) {
|
||||||
|
case HWTSTAMP_TX_OFF:
|
||||||
|
tstamp_tx_ctrl = 0;
|
||||||
|
break;
|
||||||
|
case HWTSTAMP_TX_ON:
|
||||||
|
tstamp_tx_ctrl = RCAR_GEN4_TXTSTAMP_ENABLED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (config.rx_filter) {
|
||||||
|
case HWTSTAMP_FILTER_NONE:
|
||||||
|
tstamp_rx_ctrl = 0;
|
||||||
|
break;
|
||||||
|
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
|
||||||
|
tstamp_rx_ctrl |= RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||||
|
tstamp_rx_ctrl |= RCAR_GEN4_RXTSTAMP_TYPE_ALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdev->priv->ptp_priv->tstamp_tx_ctrl = tstamp_tx_ctrl;
|
||||||
|
rdev->priv->ptp_priv->tstamp_rx_ctrl = tstamp_rx_ctrl;
|
||||||
|
|
||||||
|
return copy_to_user(req->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int rswitch_eth_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
|
static int rswitch_eth_ioctl(struct net_device *ndev, struct ifreq *req, int cmd)
|
||||||
{
|
{
|
||||||
struct rswitch_device *rdev = netdev_priv(ndev);
|
struct rswitch_device *rdev = netdev_priv(ndev);
|
||||||
@ -1419,7 +1517,14 @@ static int rswitch_eth_ioctl(struct net_device *ndev, struct ifreq *req, int cmd
|
|||||||
if (!netif_running(ndev))
|
if (!netif_running(ndev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return phylink_mii_ioctl(rdev->phylink, req, cmd);
|
switch (cmd) {
|
||||||
|
case SIOCGHWTSTAMP:
|
||||||
|
return rswitch_hwstamp_get(ndev, req);
|
||||||
|
case SIOCSHWTSTAMP:
|
||||||
|
return rswitch_hwstamp_set(ndev, req);
|
||||||
|
default:
|
||||||
|
return phylink_mii_ioctl(rdev->phylink, req, cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops rswitch_netdev_ops = {
|
static const struct net_device_ops rswitch_netdev_ops = {
|
||||||
@ -1432,6 +1537,27 @@ static const struct net_device_ops rswitch_netdev_ops = {
|
|||||||
.ndo_set_mac_address = eth_mac_addr,
|
.ndo_set_mac_address = eth_mac_addr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int rswitch_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info)
|
||||||
|
{
|
||||||
|
struct rswitch_device *rdev = netdev_priv(ndev);
|
||||||
|
|
||||||
|
info->phc_index = ptp_clock_index(rdev->priv->ptp_priv->clock);
|
||||||
|
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||||
|
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||||
|
SOF_TIMESTAMPING_SOFTWARE |
|
||||||
|
SOF_TIMESTAMPING_TX_HARDWARE |
|
||||||
|
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||||
|
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||||
|
info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
|
||||||
|
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ethtool_ops rswitch_ethtool_ops = {
|
||||||
|
.get_ts_info = rswitch_get_ts_info,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id renesas_eth_sw_of_table[] = {
|
static const struct of_device_id renesas_eth_sw_of_table[] = {
|
||||||
{ .compatible = "renesas,r8a779f0-ether-switch", },
|
{ .compatible = "renesas,r8a779f0-ether-switch", },
|
||||||
{ }
|
{ }
|
||||||
@ -1476,6 +1602,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, int index)
|
|||||||
ndev->base_addr = (unsigned long)rdev->addr;
|
ndev->base_addr = (unsigned long)rdev->addr;
|
||||||
snprintf(ndev->name, IFNAMSIZ, "tsn%d", index);
|
snprintf(ndev->name, IFNAMSIZ, "tsn%d", index);
|
||||||
ndev->netdev_ops = &rswitch_netdev_ops;
|
ndev->netdev_ops = &rswitch_netdev_ops;
|
||||||
|
ndev->ethtool_ops = &rswitch_ethtool_ops;
|
||||||
|
|
||||||
netif_napi_add(ndev, &rdev->napi, rswitch_poll);
|
netif_napi_add(ndev, &rdev->napi, rswitch_poll);
|
||||||
|
|
||||||
@ -1560,6 +1687,11 @@ static int rswitch_init(struct rswitch_private *priv)
|
|||||||
|
|
||||||
rswitch_fwd_init(priv);
|
rswitch_fwd_init(priv);
|
||||||
|
|
||||||
|
err = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT_S4,
|
||||||
|
RCAR_GEN4_PTP_CLOCK_S4);
|
||||||
|
if (err < 0)
|
||||||
|
goto err_ptp_register;
|
||||||
|
|
||||||
err = rswitch_gwca_request_irqs(priv);
|
err = rswitch_gwca_request_irqs(priv);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_gwca_request_irq;
|
goto err_gwca_request_irq;
|
||||||
@ -1595,6 +1727,9 @@ static int rswitch_init(struct rswitch_private *priv)
|
|||||||
|
|
||||||
err_gwca_hw_init:
|
err_gwca_hw_init:
|
||||||
err_gwca_request_irq:
|
err_gwca_request_irq:
|
||||||
|
rcar_gen4_ptp_unregister(priv->ptp_priv);
|
||||||
|
|
||||||
|
err_ptp_register:
|
||||||
for (i = 0; i < RSWITCH_NUM_PORTS; i++)
|
for (i = 0; i < RSWITCH_NUM_PORTS; i++)
|
||||||
rswitch_device_free(priv, i);
|
rswitch_device_free(priv, i);
|
||||||
|
|
||||||
@ -1620,12 +1755,18 @@ static int renesas_eth_sw_probe(struct platform_device *pdev)
|
|||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->ptp_priv = rcar_gen4_ptp_alloc(pdev);
|
||||||
|
if (!priv->ptp_priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, priv);
|
platform_set_drvdata(pdev, priv);
|
||||||
priv->pdev = pdev;
|
priv->pdev = pdev;
|
||||||
priv->addr = devm_ioremap_resource(&pdev->dev, res);
|
priv->addr = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(priv->addr))
|
if (IS_ERR(priv->addr))
|
||||||
return PTR_ERR(priv->addr);
|
return PTR_ERR(priv->addr);
|
||||||
|
|
||||||
|
priv->ptp_priv->addr = priv->addr + RCAR_GEN4_GPTP_OFFSET_S4;
|
||||||
|
|
||||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
|
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||||
@ -1656,6 +1797,7 @@ static void rswitch_deinit(struct rswitch_private *priv)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
rswitch_gwca_hw_deinit(priv);
|
rswitch_gwca_hw_deinit(priv);
|
||||||
|
rcar_gen4_ptp_unregister(priv->ptp_priv);
|
||||||
|
|
||||||
for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
|
for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
|
||||||
struct rswitch_device *rdev = priv->rdev[i];
|
struct rswitch_device *rdev = priv->rdev[i];
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define __RSWITCH_H__
|
#define __RSWITCH_H__
|
||||||
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include "rcar_gen4_ptp.h"
|
||||||
|
|
||||||
#define RSWITCH_MAX_NUM_QUEUES 128
|
#define RSWITCH_MAX_NUM_QUEUES 128
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user