Commit 586d5eec authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Marc Kleine-Budde
Browse files

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: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: default avatarVincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://patch.msgid.link/69db727d5f728d679ba691d20854e7d963d0f323.1749655315.git.geert+renesas@glider.be


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 0acd4619
Loading
Loading
Loading
Loading
+82 −3
Original line number Diff line number Diff line
@@ -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;