mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
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:
parent
0acd46190e
commit
586d5eecdf
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user