can: rcar_canfd: Add support for Transceiver Delay Compensation

The Renesas CAN-FD hardware block supports configuring Transceiver Delay
Compensation, and reading back the Transceiver Delay Compensation
Result, which is needed to support high transfer rates like 8 Mbps.
The Secondary Sample Point is either the measured delay plus the
configured offset, or just the configured offset.

Fix the existing RCANFD_FDCFG_TDCO() macro for the intended use case
(writing instead of reading the field).  Add register definition bits
for the Channel n CAN-FD Status Register.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://patch.msgid.link/69db727d5f728d679ba691d20854e7d963d0f323.1749655315.git.geert+renesas@glider.be
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Geert Uytterhoeven 2025-06-11 17:37:39 +02:00 committed by Marc Kleine-Budde
parent 0acd46190e
commit 586d5eecdf

View File

@ -191,9 +191,19 @@
/* RSCFDnCFDCmFDCFG */
#define RCANFD_GEN4_FDCFG_CLOE BIT(30)
#define RCANFD_GEN4_FDCFG_FDOE BIT(28)
#define RCANFD_FDCFG_TDCO GENMASK(23, 16)
#define RCANFD_FDCFG_TDCE BIT(9)
#define RCANFD_FDCFG_TDCOC BIT(8)
#define RCANFD_FDCFG_TDCO(x) (((x) & 0x7f) >> 16)
/* RSCFDnCFDCmFDSTS */
#define RCANFD_FDSTS_SOC GENMASK(31, 24)
#define RCANFD_FDSTS_EOC GENMASK(23, 16)
#define RCANFD_GEN4_FDSTS_TDCVF BIT(15)
#define RCANFD_GEN4_FDSTS_PNSTS GENMASK(13, 12)
#define RCANFD_FDSTS_SOCO BIT(9)
#define RCANFD_FDSTS_EOCO BIT(8)
#define RCANFD_FDSTS_TDCVF BIT(7)
#define RCANFD_FDSTS_TDCR GENMASK(7, 0)
/* RSCFDnCFDRFCCx */
#define RCANFD_RFCC_RFIM BIT(12)
@ -520,6 +530,7 @@ struct rcar_canfd_shift_data {
struct rcar_canfd_hw_info {
const struct can_bittiming_const *nom_bittiming;
const struct can_bittiming_const *data_bittiming;
const struct can_tdc_const *tdc_const;
const struct rcar_canfd_regs *regs;
const struct rcar_canfd_shift_data *sh;
u8 rnc_field_width;
@ -627,6 +638,25 @@ static const struct can_bittiming_const rcar_canfd_bittiming_const = {
.brp_inc = 1,
};
/* CAN FD Transmission Delay Compensation constants */
static const struct can_tdc_const rcar_canfd_gen3_tdc_const = {
.tdcv_min = 1,
.tdcv_max = 128,
.tdco_min = 1,
.tdco_max = 128,
.tdcf_min = 0, /* Filter window not supported */
.tdcf_max = 0,
};
static const struct can_tdc_const rcar_canfd_gen4_tdc_const = {
.tdcv_min = 1,
.tdcv_max = 256,
.tdco_min = 1,
.tdco_max = 256,
.tdcf_min = 0, /* Filter window not supported */
.tdcf_max = 0,
};
static const struct rcar_canfd_regs rcar_gen3_regs = {
.rfcc = 0x00b8,
.cfcc = 0x0118,
@ -672,6 +702,7 @@ static const struct rcar_canfd_shift_data rcar_gen4_shift_data = {
static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
.nom_bittiming = &rcar_canfd_gen3_nom_bittiming_const,
.data_bittiming = &rcar_canfd_gen3_data_bittiming_const,
.tdc_const = &rcar_canfd_gen3_tdc_const,
.regs = &rcar_gen3_regs,
.sh = &rcar_gen3_shift_data,
.rnc_field_width = 8,
@ -688,6 +719,7 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
.nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
.data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
.tdc_const = &rcar_canfd_gen4_tdc_const,
.regs = &rcar_gen4_regs,
.sh = &rcar_gen4_shift_data,
.rnc_field_width = 16,
@ -704,6 +736,7 @@ static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
static const struct rcar_canfd_hw_info rzg2l_hw_info = {
.nom_bittiming = &rcar_canfd_gen3_nom_bittiming_const,
.data_bittiming = &rcar_canfd_gen3_data_bittiming_const,
.tdc_const = &rcar_canfd_gen3_tdc_const,
.regs = &rcar_gen3_regs,
.sh = &rcar_gen3_shift_data,
.rnc_field_width = 8,
@ -720,6 +753,7 @@ static const struct rcar_canfd_hw_info rzg2l_hw_info = {
static const struct rcar_canfd_hw_info r9a09g047_hw_info = {
.nom_bittiming = &rcar_canfd_gen4_nom_bittiming_const,
.data_bittiming = &rcar_canfd_gen4_data_bittiming_const,
.tdc_const = &rcar_canfd_gen4_tdc_const,
.regs = &rcar_gen4_regs,
.sh = &rcar_gen4_shift_data,
.rnc_field_width = 16,
@ -1460,12 +1494,15 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
static void rcar_canfd_set_bittiming(struct net_device *ndev)
{
u32 mask = RCANFD_FDCFG_TDCO | RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC;
struct rcar_canfd_channel *priv = netdev_priv(ndev);
struct rcar_canfd_global *gpriv = priv->gpriv;
const struct can_bittiming *bt = &priv->can.bittiming;
const struct can_bittiming *dbt = &priv->can.fd.data_bittiming;
const struct can_tdc_const *tdc_const = priv->can.fd.tdc_const;
const struct can_tdc *tdc = &priv->can.fd.tdc;
u32 cfg, tdcmode = 0, tdco = 0;
u16 brp, sjw, tseg1, tseg2;
u32 cfg;
u32 ch = priv->channel;
/* Nominal bit timing settings */
@ -1497,6 +1534,20 @@ static void rcar_canfd_set_bittiming(struct net_device *ndev)
RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
rcar_canfd_write(priv->base, rcar_canfd_f_dcfg(gpriv, ch), cfg);
/* Transceiver Delay Compensation */
if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_AUTO) {
/* TDC enabled, measured + offset */
tdcmode = RCANFD_FDCFG_TDCE;
tdco = tdc->tdco - 1;
} else if (priv->can.ctrlmode & CAN_CTRLMODE_TDC_MANUAL) {
/* TDC enabled, offset only */
tdcmode = RCANFD_FDCFG_TDCE | RCANFD_FDCFG_TDCOC;
tdco = min(tdc->tdcv + tdc->tdco, tdc_const->tdco_max) - 1;
}
rcar_canfd_update_bit(gpriv->base, rcar_canfd_f_cfdcfg(gpriv, ch), mask,
tdcmode | FIELD_PREP(RCANFD_FDCFG_TDCO, tdco));
}
static int rcar_canfd_start(struct net_device *ndev)
@ -1807,6 +1858,29 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota)
return num_pkts;
}
static unsigned int rcar_canfd_get_tdcr(struct rcar_canfd_global *gpriv,
unsigned int ch)
{
u32 sts = rcar_canfd_read(gpriv->base, rcar_canfd_f_cfdsts(gpriv, ch));
u32 tdcr = FIELD_GET(RCANFD_FDSTS_TDCR, sts);
return tdcr & (gpriv->info->tdc_const->tdcv_max - 1);
}
static int rcar_canfd_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv)
{
struct rcar_canfd_channel *priv = netdev_priv(ndev);
u32 tdco = priv->can.fd.tdc.tdco;
u32 tdcr;
/* Transceiver Delay Compensation Result */
tdcr = rcar_canfd_get_tdcr(priv->gpriv, priv->channel) + 1;
*tdcv = tdcr < tdco ? 0 : tdcr - tdco;
return 0;
}
static int rcar_canfd_do_set_mode(struct net_device *ndev, enum can_mode mode)
{
int err;
@ -1929,12 +2003,17 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
if (gpriv->fdmode) {
priv->can.bittiming_const = gpriv->info->nom_bittiming;
priv->can.fd.data_bittiming_const = gpriv->info->data_bittiming;
priv->can.fd.tdc_const = gpriv->info->tdc_const;
/* Controller starts in CAN FD only mode */
err = can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
if (err)
goto fail;
priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_TDC_AUTO |
CAN_CTRLMODE_TDC_MANUAL;
priv->can.fd.do_get_auto_tdcv = rcar_canfd_get_auto_tdcv;
} else {
/* Controller starts in Classical CAN only mode */
priv->can.bittiming_const = &rcar_canfd_bittiming_const;