105 lines
3.2 KiB
C
105 lines
3.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
//
|
|
// Copyright (c) 2023, 2024 Pengutronix,
|
|
// Marc Kleine-Budde <kernel@pengutronix.de>
|
|
//
|
|
|
|
#include <linux/clocksource.h>
|
|
|
|
#include "rockchip_canfd.h"
|
|
|
|
static u64 rkcanfd_timestamp_read(const struct cyclecounter *cc)
|
|
{
|
|
const struct rkcanfd_priv *priv = container_of(cc, struct rkcanfd_priv, cc);
|
|
|
|
return rkcanfd_get_timestamp(priv);
|
|
}
|
|
|
|
void rkcanfd_skb_set_timestamp(const struct rkcanfd_priv *priv,
|
|
struct sk_buff *skb, const u32 timestamp)
|
|
{
|
|
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
|
|
u64 ns;
|
|
|
|
ns = timecounter_cyc2time(&priv->tc, timestamp);
|
|
|
|
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
|
}
|
|
|
|
static void rkcanfd_timestamp_work(struct work_struct *work)
|
|
{
|
|
const struct delayed_work *delayed_work = to_delayed_work(work);
|
|
struct rkcanfd_priv *priv;
|
|
|
|
priv = container_of(delayed_work, struct rkcanfd_priv, timestamp);
|
|
timecounter_read(&priv->tc);
|
|
|
|
schedule_delayed_work(&priv->timestamp, priv->work_delay_jiffies);
|
|
}
|
|
|
|
void rkcanfd_timestamp_init(struct rkcanfd_priv *priv)
|
|
{
|
|
const struct can_bittiming *dbt = &priv->can.data_bittiming;
|
|
const struct can_bittiming *bt = &priv->can.bittiming;
|
|
struct cyclecounter *cc = &priv->cc;
|
|
u32 bitrate, div, reg, rate;
|
|
u64 work_delay_ns;
|
|
u64 max_cycles;
|
|
|
|
/* At the standard clock rate of 300Mhz on the rk3658, the 32
|
|
* bit timer overflows every 14s. This means that we have to
|
|
* poll it quite often to avoid missing a wrap around.
|
|
*
|
|
* Divide it down to a reasonable rate, at least twice the bit
|
|
* rate.
|
|
*/
|
|
bitrate = max(bt->bitrate, dbt->bitrate);
|
|
div = min(DIV_ROUND_UP(priv->can.clock.freq, bitrate * 2),
|
|
FIELD_MAX(RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_PRESCALE) + 1);
|
|
|
|
reg = FIELD_PREP(RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_PRESCALE,
|
|
div - 1) |
|
|
RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_ENABLE;
|
|
rkcanfd_write(priv, RKCANFD_REG_TIMESTAMP_CTRL, reg);
|
|
|
|
cc->read = rkcanfd_timestamp_read;
|
|
cc->mask = CYCLECOUNTER_MASK(32);
|
|
|
|
rate = priv->can.clock.freq / div;
|
|
clocks_calc_mult_shift(&cc->mult, &cc->shift, rate, NSEC_PER_SEC,
|
|
RKCANFD_TIMESTAMP_WORK_MAX_DELAY_SEC);
|
|
|
|
max_cycles = div_u64(ULLONG_MAX, cc->mult);
|
|
max_cycles = min(max_cycles, cc->mask);
|
|
work_delay_ns = clocksource_cyc2ns(max_cycles, cc->mult, cc->shift);
|
|
priv->work_delay_jiffies = div_u64(work_delay_ns, 3u * NSEC_PER_SEC / HZ);
|
|
INIT_DELAYED_WORK(&priv->timestamp, rkcanfd_timestamp_work);
|
|
|
|
netdev_dbg(priv->ndev, "clock=%lu.%02luMHz bitrate=%lu.%02luMBit/s div=%u rate=%lu.%02luMHz mult=%u shift=%u delay=%lus\n",
|
|
priv->can.clock.freq / MEGA,
|
|
priv->can.clock.freq % MEGA / KILO / 10,
|
|
bitrate / MEGA,
|
|
bitrate % MEGA / KILO / 100,
|
|
div,
|
|
rate / MEGA,
|
|
rate % MEGA / KILO / 10,
|
|
cc->mult, cc->shift,
|
|
priv->work_delay_jiffies / HZ);
|
|
}
|
|
|
|
void rkcanfd_timestamp_start(struct rkcanfd_priv *priv)
|
|
{
|
|
timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns());
|
|
|
|
schedule_delayed_work(&priv->timestamp, priv->work_delay_jiffies);
|
|
}
|
|
|
|
void rkcanfd_timestamp_stop(struct rkcanfd_priv *priv)
|
|
{
|
|
cancel_delayed_work(&priv->timestamp);
|
|
}
|
|
|
|
void rkcanfd_timestamp_stop_sync(struct rkcanfd_priv *priv)
|
|
{
|
|
cancel_delayed_work_sync(&priv->timestamp);
|
|
}
|