Commit 851013e9 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde
Browse files

Merge patch series "Add support for RZ/G3E CANFD"

Biju Das <biju.das.jz@bp.renesas.com> says:

The CAN-FD module on RZ/G3E is very similar to the one on both R-Car V4H
and RZ/G2L, but differs in some hardware parameters:
 * No external clock, but instead has ram clock.
 * Support up to 6 channels.
 * 20 interrupts.

v8->v9:
 * Collected tags.
 * Added missing header bitfield.h.
 * Fixed logical error ch->BIT(ch) in rcar_canfd_global_error().
 * Removed unneeded double space in rcar_canfd_setrnc().
 * Updated commit description in patch#15.
v7->v8:
 * Collected tags.
 * Updated commit description for patch#{5,9,15,16,17}.
 * Replaced the macro RCANFD_GERFL_EEF0_7->RCANFD_GERFL_EEF.
 * Dropped the redundant macro RCANFD_GERFL_EEF(ch).
 * Added patch for dropping the mask operation in RCANFD_GAFLCFG_SETRNC
   macro.
 * Converted RCANFD_GAFLCFG_SETRNC->rcar_canfd_setrnc().
 * Updated RCANFD_GAFLCFG macro by replacing the parameter ch->w, where w
   is the GAFLCFG index used in the hardware manual.
 * Renamed the parameter x->page_num in RCANFD_GAFLECTR_AFLPN macro to
   make it clear.
 * Renamed the parameter x->cftml in RCANFD_CFCC_CFTML macro to make it
   clear.
 * Updated {rzg2l,car_gen3_hw_info} with ch_interface_mode = 0.
 * Updated {rzg2l,rcar_gen3}_hw_info with shared_can_regs = 0.
 * Started using struct rcanfd_regs instead of LUT for reg offsets.
 * Started using struct rcar_canfd_shift_data instead of LUT for shift
   data.
 * Renamed only_internal_clks->external_clk to avoid negation.
 * Updated rcar_canfd_hw_info tables with external_clk entries.
 * Replaced 10->sizeof(name) in scnprintf().
v6->v7:
 * Collected tags
 * Replaced 'aswell'->'as well' in patch#11 commit description.
v5->v6:
 * Replaced RCANFD_RNC_PER_REG macro with rnc_stride variable.
 * Updated commit description for patch#7 and #8
 * Dropped mask_table:
     AFLPN_MASK is replaced by max_aflpn variable.
     CFTML_MASK is replaced by max_cftml variable.
     BITTIMING MASK's are replaced by {nom,data}_bittiming variables.
 * Collected tag from Geert.
v4->v5:
 * Collected tag from Geert.
 * The rules for R-Car Gen3/4 could be kept together, reducing the number
   of lines. Similar change for rzg2l-canfd aswell.
 * Keeping interrupts and resets together allows to keep a clear
   separation between RZ/G2L and RZ/G3E, at the expense of only
   a single line.
 * Retained the tags for binding patches as it is trivial changes.
 * Dropped the unused macro RCANFD_GAFLCFG_GETRNC.
 * Updated macro RCANFD_GERFL_ERR by using gpriv->channels_mask and
   dropped unused macro RCANFD_GERFL_EEF0_7.
 * Replaced RNC mask in RCANFD_GAFLCFG_SETRNC macro by using
   info->num_supported_rules variable.
 * Updated the macro RCANFD_GAFLCFG by using info->rnc_field_width
   variable.
 * Updated shift value in RCANFD_GAFLCFG_SETRNC macro by using a formula
   (32 - (n % rnc_per_reg + 1) * field_width).
 * Replaced the variable name shared_can_reg->shared_can_regs.
 * Improved commit description for patch{#11,#12}by replacing has->have.
 * Dropped RCANFD_EEF_MASK and RCANFD_RNC_MASK as it is taken
   care by gpriv->channels_mask and info->num_supported_rules.
 * Dropped RCANFD_FIRST_RNC_SH and RCANFD_SECOND_RNC_SH by using a
   formula (32 - (n % rnc_per_reg + 1) * rnc_field_width.
 * Improved commit description by "All SoCs supports extenal clock"->
   "All existing SoCs support an external clock".
 * Updated error description in probe as "cannot get enabled ram clock"
 * Updated r9a09g047_hw_info table.
v3->v4:
 * Added Rb tag from Rob for patch#2.
 * Added prefix RCANFD_* to enum rcar_canfd_reg_offset_id.
 * Added prefix RCANFD_* to enum rcar_canfd_mask_id.
 * Added prefix RCANFD_* to enum rcar_canfd_shift_id.
v2->v3:
 * Collected tags.
 * Dropped reg_gen4() and is_gen4() by adding mask_table, shift_table,
   regs, ch_interface_mode and shared_can_reg variables to
   struct rcar_canfd_hw_info.
v1->v2:
 * Split the series with fixes patch separately.
 * Added patch for Simplify rcar_canfd_probe() using
   of_get_available_child_by_name() as dependency patch hit on can-next.
 * Added Rb tag from Vincent Mailhol.
 * Dropped redundant comment from commit description for patch#3.

Link: https://patch.msgid.link/20250417054320.14100-1-biju.das.jz@bp.renesas.com


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 9ab0ac0e be53aa05
Loading
Loading
Loading
Loading
+128 −43
Original line number Diff line number Diff line
@@ -42,19 +42,80 @@ properties:
              - renesas,r9a07g054-canfd    # RZ/V2L
          - const: renesas,rzg2l-canfd     # RZ/G2L family

      - const: renesas,r9a09g047-canfd     # RZ/G3E

  reg:
    maxItems: 1

  interrupts: true
  interrupts:
    oneOf:
      - items:
          - description: Channel interrupt
          - description: Global interrupt
      - items:
          - description: CAN global error interrupt
          - description: CAN receive FIFO interrupt
          - description: CAN0 error interrupt
          - description: CAN0 transmit interrupt
          - description: CAN0 transmit/receive FIFO receive completion interrupt
          - description: CAN1 error interrupt
          - description: CAN1 transmit interrupt
          - description: CAN1 transmit/receive FIFO receive completion interrupt
          - description: CAN2 error interrupt
          - description: CAN2 transmit interrupt
          - description: CAN2 transmit/receive FIFO receive completion interrupt
          - description: CAN3 error interrupt
          - description: CAN3 transmit interrupt
          - description: CAN3 transmit/receive FIFO receive completion interrupt
          - description: CAN4 error interrupt
          - description: CAN4 transmit interrupt
          - description: CAN4 transmit/receive FIFO receive completion interrupt
          - description: CAN5 error interrupt
          - description: CAN5 transmit interrupt
          - description: CAN5 transmit/receive FIFO receive completion interrupt
        minItems: 8

  interrupt-names:
    oneOf:
      - items:
          - const: ch_int
          - const: g_int
      - items:
          - const: g_err
          - const: g_recc
          - const: ch0_err
          - const: ch0_rec
          - const: ch0_trx
          - const: ch1_err
          - const: ch1_rec
          - const: ch1_trx
          - const: ch2_err
          - const: ch2_rec
          - const: ch2_trx
          - const: ch3_err
          - const: ch3_rec
          - const: ch3_trx
          - const: ch4_err
          - const: ch4_rec
          - const: ch4_trx
          - const: ch5_err
          - const: ch5_rec
          - const: ch5_trx
        minItems: 8

  clocks:
    maxItems: 3

  clock-names:
    items:
    oneOf:
      - items:
          - const: fck
          - const: canfd
          - const: can_clk
      - items:
          - const: fck
          - const: ram_clk
          - const: can_clk

  power-domains:
    maxItems: 1
@@ -117,52 +178,77 @@ allOf:
    then:
      properties:
        interrupts:
          items:
            - description: CAN global error interrupt
            - description: CAN receive FIFO interrupt
            - description: CAN0 error interrupt
            - description: CAN0 transmit interrupt
            - description: CAN0 transmit/receive FIFO receive completion interrupt
            - description: CAN1 error interrupt
            - description: CAN1 transmit interrupt
            - description: CAN1 transmit/receive FIFO receive completion interrupt
          maxItems: 8

        interrupt-names:
          items:
            - const: g_err
            - const: g_recc
            - const: ch0_err
            - const: ch0_rec
            - const: ch0_trx
            - const: ch1_err
            - const: ch1_rec
            - const: ch1_trx
          maxItems: 8

        resets:
          minItems: 2
          maxItems: 2

        reset-names:
          items:
            - const: rstp_n
            - const: rstc_n
          minItems: 2
          maxItems: 2

      required:
        - reset-names
    else:

  - if:
      properties:
        compatible:
          contains:
            enum:
              - renesas,rcar-gen3-canfd
              - renesas,rcar-gen4-canfd
    then:
      properties:
        interrupts:
          items:
            - description: Channel interrupt
            - description: Global interrupt
          minItems: 2
          maxItems: 2

        interrupt-names:
          items:
            - const: ch_int
            - const: g_int
          minItems: 2
          maxItems: 2

        resets:
          maxItems: 1

  - if:
      properties:
        compatible:
          contains:
            const: renesas,r9a09g047-canfd
    then:
      properties:
        interrupts:
          minItems: 20

        interrupt-names:
          minItems: 20

        resets:
          minItems: 2
          maxItems: 2

        reset-names:
          minItems: 2
          maxItems: 2

      required:
        - reset-names

  - if:
      properties:
        compatible:
          contains:
            enum:
              - renesas,rcar-gen3-canfd
              - renesas,rzg2l-canfd
    then:
      patternProperties:
        "^channel[2-7]$": false

  - if:
      properties:
        compatible:
@@ -171,16 +257,15 @@ allOf:
    then:
      patternProperties:
        "^channel[4-7]$": false
    else:
      if:
        not:

  - if:
      properties:
        compatible:
          contains:
                const: renesas,rcar-gen4-canfd
            const: renesas,r9a09g047-canfd
    then:
      patternProperties:
          "^channel[2-7]$": false
        "^channel[6-7]$": false

unevaluatedProperties: false

+212 −66
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
 * wherever it is modified to a readable name.
 */

#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/can/dev.h>
@@ -74,33 +75,24 @@
#define RCANFD_GSTS_GNOPM		(BIT(0) | BIT(1) | BIT(2) | BIT(3))

/* RSCFDnCFDGERFL / RSCFDnGERFL */
#define RCANFD_GERFL_EEF0_7		GENMASK(23, 16)
#define RCANFD_GERFL_EEF(ch)		BIT(16 + (ch))
#define RCANFD_GERFL_EEF		GENMASK(23, 16)
#define RCANFD_GERFL_CMPOF		BIT(3)	/* CAN FD only */
#define RCANFD_GERFL_THLES		BIT(2)
#define RCANFD_GERFL_MES		BIT(1)
#define RCANFD_GERFL_DEF		BIT(0)

#define RCANFD_GERFL_ERR(gpriv, x) \
	((x) & (reg_gen4(gpriv, RCANFD_GERFL_EEF0_7, \
			 RCANFD_GERFL_EEF(0) | RCANFD_GERFL_EEF(1)) | \
		RCANFD_GERFL_MES | \
		((gpriv)->fdmode ? RCANFD_GERFL_CMPOF : 0)))
({\
	typeof(gpriv) (_gpriv) = (gpriv); \
	((x) & ((FIELD_PREP(RCANFD_GERFL_EEF, (_gpriv)->channels_mask)) | \
		RCANFD_GERFL_MES | ((_gpriv)->fdmode ? RCANFD_GERFL_CMPOF : 0))); \
})

/* AFL Rx rules registers */

/* RSCFDnCFDGAFLCFG0 / RSCFDnGAFLCFG0 */
#define RCANFD_GAFLCFG_SETRNC(gpriv, n, x) \
	(((x) & reg_gen4(gpriv, 0x1ff, 0xff)) << \
	 (reg_gen4(gpriv, 16, 24) - ((n) & 1) * reg_gen4(gpriv, 16, 8)))

#define RCANFD_GAFLCFG_GETRNC(gpriv, n, x) \
	(((x) >> (reg_gen4(gpriv, 16, 24) - ((n) & 1) * reg_gen4(gpriv, 16, 8))) & \
	 reg_gen4(gpriv, 0x1ff, 0xff))

/* RSCFDnCFDGAFLECTR / RSCFDnGAFLECTR */
#define RCANFD_GAFLECTR_AFLDAE		BIT(8)
#define RCANFD_GAFLECTR_AFLPN(gpriv, x)	((x) & reg_gen4(gpriv, 0x7f, 0x1f))
#define RCANFD_GAFLECTR_AFLPN(gpriv, page_num)	((page_num) & (gpriv)->info->max_aflpn)

/* RSCFDnCFDGAFLIDj / RSCFDnGAFLIDj */
#define RCANFD_GAFLID_GAFLLB		BIT(29)
@@ -118,13 +110,13 @@

/* RSCFDnCFDCmNCFG - CAN FD only */
#define RCANFD_NCFG_NTSEG2(gpriv, x) \
	(((x) & reg_gen4(gpriv, 0x7f, 0x1f)) << reg_gen4(gpriv, 25, 24))
	(((x) & ((gpriv)->info->nom_bittiming->tseg2_max - 1)) << (gpriv)->info->sh->ntseg2)

#define RCANFD_NCFG_NTSEG1(gpriv, x) \
	(((x) & reg_gen4(gpriv, 0xff, 0x7f)) << reg_gen4(gpriv, 17, 16))
	(((x) & ((gpriv)->info->nom_bittiming->tseg1_max - 1)) << (gpriv)->info->sh->ntseg1)

#define RCANFD_NCFG_NSJW(gpriv, x) \
	(((x) & reg_gen4(gpriv, 0x7f, 0x1f)) << reg_gen4(gpriv, 10, 11))
	(((x) & ((gpriv)->info->nom_bittiming->sjw_max - 1)) << (gpriv)->info->sh->nsjw)

#define RCANFD_NCFG_NBRP(x)		(((x) & 0x3ff) << 0)

@@ -186,13 +178,13 @@
#define RCANFD_CERFL_ERR(x)		((x) & (0x7fff)) /* above bits 14:0 */

/* RSCFDnCFDCmDCFG */
#define RCANFD_DCFG_DSJW(gpriv, x)	(((x) & reg_gen4(gpriv, 0xf, 0x7)) << 24)
#define RCANFD_DCFG_DSJW(gpriv, x)	(((x) & ((gpriv)->info->data_bittiming->sjw_max - 1)) << 24)

#define RCANFD_DCFG_DTSEG2(gpriv, x) \
	(((x) & reg_gen4(gpriv, 0x0f, 0x7)) << reg_gen4(gpriv, 16, 20))
	(((x) & ((gpriv)->info->data_bittiming->tseg2_max - 1)) << (gpriv)->info->sh->dtseg2)

#define RCANFD_DCFG_DTSEG1(gpriv, x) \
	(((x) & reg_gen4(gpriv, 0x1f, 0xf)) << reg_gen4(gpriv, 8, 16))
	(((x) & ((gpriv)->info->data_bittiming->tseg1_max - 1)) << (gpriv)->info->sh->dtseg1)

#define RCANFD_DCFG_DBRP(x)		(((x) & 0xff) << 0)

@@ -233,11 +225,14 @@
/* Common FIFO bits */

/* RSCFDnCFDCFCCk */
#define RCANFD_CFCC_CFTML(gpriv, x)	\
	(((x) & reg_gen4(gpriv, 0x1f, 0xf)) << reg_gen4(gpriv, 16, 20))
#define RCANFD_CFCC_CFM(gpriv, x)	(((x) & 0x3) << reg_gen4(gpriv,  8, 16))
#define RCANFD_CFCC_CFTML(gpriv, cftml) \
({\
	typeof(gpriv) (_gpriv) = (gpriv); \
	(((cftml) & (_gpriv)->info->max_cftml) << (_gpriv)->info->sh->cftml); \
})
#define RCANFD_CFCC_CFM(gpriv, x)	(((x) & 0x3) << (gpriv)->info->sh->cfm)
#define RCANFD_CFCC_CFIM		BIT(12)
#define RCANFD_CFCC_CFDC(gpriv, x)	(((x) & 0x7) << reg_gen4(gpriv, 21,  8))
#define RCANFD_CFCC_CFDC(gpriv, x)	(((x) & 0x7) << (gpriv)->info->sh->cfdc)
#define RCANFD_CFCC_CFPLS(x)		(((x) & 0x7) << 4)
#define RCANFD_CFCC_CFTXIE		BIT(2)
#define RCANFD_CFCC_CFE			BIT(0)
@@ -298,14 +293,14 @@
/* RSCFDnCFDGAFLECTR / RSCFDnGAFLECTR */
#define RCANFD_GAFLECTR			(0x0098)
/* RSCFDnCFDGAFLCFG / RSCFDnGAFLCFG */
#define RCANFD_GAFLCFG(ch)		(0x009c + (0x04 * ((ch) / 2)))
#define RCANFD_GAFLCFG(w)		(0x009c + (0x04 * (w)))
/* RSCFDnCFDRMNB / RSCFDnRMNB */
#define RCANFD_RMNB			(0x00a4)
/* RSCFDnCFDRMND / RSCFDnRMND */
#define RCANFD_RMND(y)			(0x00a8 + (0x04 * (y)))

/* RSCFDnCFDRFCCx / RSCFDnRFCCx */
#define RCANFD_RFCC(gpriv, x)		(reg_gen4(gpriv, 0x00c0, 0x00b8) + (0x04 * (x)))
#define RCANFD_RFCC(gpriv, x)		((gpriv)->info->regs->rfcc + (0x04 * (x)))
/* RSCFDnCFDRFSTSx / RSCFDnRFSTSx */
#define RCANFD_RFSTS(gpriv, x)		(RCANFD_RFCC(gpriv, x) + 0x20)
/* RSCFDnCFDRFPCTRx / RSCFDnRFPCTRx */
@@ -315,13 +310,13 @@

/* RSCFDnCFDCFCCx / RSCFDnCFCCx */
#define RCANFD_CFCC(gpriv, ch, idx) \
	(reg_gen4(gpriv, 0x0120, 0x0118) + (0x0c * (ch)) + (0x04 * (idx)))
	((gpriv)->info->regs->cfcc + (0x0c * (ch)) + (0x04 * (idx)))
/* RSCFDnCFDCFSTSx / RSCFDnCFSTSx */
#define RCANFD_CFSTS(gpriv, ch, idx) \
	(reg_gen4(gpriv, 0x01e0, 0x0178) + (0x0c * (ch)) + (0x04 * (idx)))
	((gpriv)->info->regs->cfsts + (0x0c * (ch)) + (0x04 * (idx)))
/* RSCFDnCFDCFPCTRx / RSCFDnCFPCTRx */
#define RCANFD_CFPCTR(gpriv, ch, idx) \
	(reg_gen4(gpriv, 0x0240, 0x01d8) + (0x0c * (ch)) + (0x04 * (idx)))
	((gpriv)->info->regs->cfpctr + (0x0c * (ch)) + (0x04 * (idx)))

/* RSCFDnCFDFESTS / RSCFDnFESTS */
#define RCANFD_FESTS			(0x0238)
@@ -437,7 +432,7 @@
/* CAN FD mode specific register map */

/* RSCFDnCFDCmXXX -> RCANFD_F_XXX(m) */
#define RCANFD_F_DCFG(gpriv, m)		(reg_gen4(gpriv, 0x1400, 0x0500) + (0x20 * (m)))
#define RCANFD_F_DCFG(gpriv, m)		((gpriv)->info->regs->f_dcfg + (0x20 * (m)))
#define RCANFD_F_CFDCFG(m)		(0x0504 + (0x20 * (m)))
#define RCANFD_F_CFDCTR(m)		(0x0508 + (0x20 * (m)))
#define RCANFD_F_CFDSTS(m)		(0x050c + (0x20 * (m)))
@@ -453,7 +448,7 @@
#define RCANFD_F_RMDF(q, b)		(0x200c + (0x04 * (b)) + (0x20 * (q)))

/* RSCFDnCFDRFXXx -> RCANFD_F_RFXX(x) */
#define RCANFD_F_RFOFFSET(gpriv)	reg_gen4(gpriv, 0x6000, 0x3000)
#define RCANFD_F_RFOFFSET(gpriv)	((gpriv)->info->regs->rfoffset)
#define RCANFD_F_RFID(gpriv, x)		(RCANFD_F_RFOFFSET(gpriv) + (0x80 * (x)))
#define RCANFD_F_RFPTR(gpriv, x)	(RCANFD_F_RFOFFSET(gpriv) + 0x04 + (0x80 * (x)))
#define RCANFD_F_RFFDSTS(gpriv, x)	(RCANFD_F_RFOFFSET(gpriv) + 0x08 + (0x80 * (x)))
@@ -461,7 +456,7 @@
	(RCANFD_F_RFOFFSET(gpriv) + 0x0c + (0x80 * (x)) + (0x04 * (df)))

/* RSCFDnCFDCFXXk -> RCANFD_F_CFXX(ch, k) */
#define RCANFD_F_CFOFFSET(gpriv)	reg_gen4(gpriv, 0x6400, 0x3400)
#define RCANFD_F_CFOFFSET(gpriv)	((gpriv)->info->regs->cfoffset)

#define RCANFD_F_CFID(gpriv, ch, idx) \
	(RCANFD_F_CFOFFSET(gpriv) + (0x180 * (ch)) + (0x80 * (idx)))
@@ -510,12 +505,43 @@

struct rcar_canfd_global;

struct rcar_canfd_regs {
	u16 rfcc;	/* RX FIFO Configuration/Control Register */
	u16 cfcc;	/* Common FIFO Configuration/Control Register */
	u16 cfsts;	/* Common FIFO Status Register */
	u16 cfpctr;	/* Common FIFO Pointer Control Register */
	u16 f_dcfg;	/* Global FD Configuration Register */
	u16 rfoffset;	/* Receive FIFO buffer access ID register */
	u16 cfoffset;	/* Transmit/receive FIFO buffer access ID register */
};

struct rcar_canfd_shift_data {
	u8 ntseg2;	/* Nominal Bit Rate Time Segment 2 Control */
	u8 ntseg1;	/* Nominal Bit Rate Time Segment 1 Control */
	u8 nsjw;	/* Nominal Bit Rate Resynchronization Jump Width Control */
	u8 dtseg2;	/* Data Bit Rate Time Segment 2 Control */
	u8 dtseg1;	/* Data Bit Rate Time Segment 1 Control */
	u8 cftml;	/* Common FIFO TX Message Buffer Link */
	u8 cfm;		/* Common FIFO Mode */
	u8 cfdc;	/* Common FIFO Depth Configuration */
};

struct rcar_canfd_hw_info {
	const struct can_bittiming_const *nom_bittiming;
	const struct can_bittiming_const *data_bittiming;
	const struct rcar_canfd_regs *regs;
	const struct rcar_canfd_shift_data *sh;
	u8 rnc_field_width;
	u8 max_aflpn;
	u8 max_cftml;
	u8 max_channels;
	u8 postdiv;
	/* hardware features */
	unsigned shared_global_irqs:1;	/* Has shared global irqs */
	unsigned multi_channel_irqs:1;	/* Has multiple channel irqs */
	unsigned ch_interface_mode:1;	/* Has channel interface mode */
	unsigned shared_can_regs:1;	/* Has shared classical can registers */
	unsigned external_clk:1;	/* Has external clock */
};

/* Channel priv data */
@@ -548,7 +574,7 @@ struct rcar_canfd_global {
};

/* CAN FD mode nominal rate constants */
static const struct can_bittiming_const rcar_canfd_nom_bittiming_const = {
static const struct can_bittiming_const rcar_canfd_gen3_nom_bittiming_const = {
	.name = RCANFD_DRV_NAME,
	.tseg1_min = 2,
	.tseg1_max = 128,
@@ -560,8 +586,20 @@ static const struct can_bittiming_const rcar_canfd_nom_bittiming_const = {
	.brp_inc = 1,
};

static const struct can_bittiming_const rcar_canfd_gen4_nom_bittiming_const = {
	.name = RCANFD_DRV_NAME,
	.tseg1_min = 2,
	.tseg1_max = 256,
	.tseg2_min = 2,
	.tseg2_max = 128,
	.sjw_max = 128,
	.brp_min = 1,
	.brp_max = 1024,
	.brp_inc = 1,
};

/* CAN FD mode data rate constants */
static const struct can_bittiming_const rcar_canfd_data_bittiming_const = {
static const struct can_bittiming_const rcar_canfd_gen3_data_bittiming_const = {
	.name = RCANFD_DRV_NAME,
	.tseg1_min = 2,
	.tseg1_max = 16,
@@ -573,6 +611,18 @@ static const struct can_bittiming_const rcar_canfd_data_bittiming_const = {
	.brp_inc = 1,
};

static const struct can_bittiming_const rcar_canfd_gen4_data_bittiming_const = {
	.name = RCANFD_DRV_NAME,
	.tseg1_min = 2,
	.tseg1_max = 32,
	.tseg2_min = 2,
	.tseg2_max = 16,
	.sjw_max = 16,
	.brp_min = 1,
	.brp_max = 256,
	.brp_inc = 1,
};

/* Classical CAN mode bitrate constants */
static const struct can_bittiming_const rcar_canfd_bittiming_const = {
	.name = RCANFD_DRV_NAME,
@@ -586,36 +636,113 @@ static const struct can_bittiming_const rcar_canfd_bittiming_const = {
	.brp_inc = 1,
};

static const struct rcar_canfd_regs rcar_gen3_regs = {
	.rfcc = 0x00b8,
	.cfcc = 0x0118,
	.cfsts = 0x0178,
	.cfpctr = 0x01d8,
	.f_dcfg = 0x0500,
	.rfoffset = 0x3000,
	.cfoffset = 0x3400,
};

static const struct rcar_canfd_regs rcar_gen4_regs = {
	.rfcc = 0x00c0,
	.cfcc = 0x0120,
	.cfsts = 0x01e0,
	.cfpctr = 0x0240,
	.f_dcfg = 0x1400,
	.rfoffset = 0x6000,
	.cfoffset = 0x6400,
};

static const struct rcar_canfd_shift_data rcar_gen3_shift_data = {
	.ntseg2 = 24,
	.ntseg1 = 16,
	.nsjw = 11,
	.dtseg2 = 20,
	.dtseg1 = 16,
	.cftml = 20,
	.cfm = 16,
	.cfdc = 8,
};

static const struct rcar_canfd_shift_data rcar_gen4_shift_data = {
	.ntseg2 = 25,
	.ntseg1 = 17,
	.nsjw = 10,
	.dtseg2 = 16,
	.dtseg1 = 8,
	.cftml = 16,
	.cfm = 8,
	.cfdc = 21,
};

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,
	.regs = &rcar_gen3_regs,
	.sh = &rcar_gen3_shift_data,
	.rnc_field_width = 8,
	.max_aflpn = 31,
	.max_cftml = 15,
	.max_channels = 2,
	.postdiv = 2,
	.shared_global_irqs = 1,
	.ch_interface_mode = 0,
	.shared_can_regs = 0,
	.external_clk = 1,
};

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,
	.regs = &rcar_gen4_regs,
	.sh = &rcar_gen4_shift_data,
	.rnc_field_width = 16,
	.max_aflpn = 127,
	.max_cftml = 31,
	.max_channels = 8,
	.postdiv = 2,
	.shared_global_irqs = 1,
	.ch_interface_mode = 1,
	.shared_can_regs = 1,
	.external_clk = 1,
};

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,
	.regs = &rcar_gen3_regs,
	.sh = &rcar_gen3_shift_data,
	.rnc_field_width = 8,
	.max_aflpn = 31,
	.max_cftml = 15,
	.max_channels = 2,
	.postdiv = 1,
	.multi_channel_irqs = 1,
	.ch_interface_mode = 0,
	.shared_can_regs = 0,
	.external_clk = 1,
};

/* Helper functions */
static inline bool is_gen4(struct rcar_canfd_global *gpriv)
{
	return gpriv->info == &rcar_gen4_hw_info;
}

static inline u32 reg_gen4(struct rcar_canfd_global *gpriv,
			   u32 gen4, u32 not_gen4)
{
	return is_gen4(gpriv) ? gen4 : not_gen4;
}
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,
	.regs = &rcar_gen4_regs,
	.sh = &rcar_gen4_shift_data,
	.rnc_field_width = 16,
	.max_aflpn = 63,
	.max_cftml = 31,
	.max_channels = 6,
	.postdiv = 1,
	.multi_channel_irqs = 1,
	.ch_interface_mode = 1,
	.shared_can_regs = 1,
	.external_clk = 0,
};

/* Helper functions */
static inline void rcar_canfd_update(u32 mask, u32 val, u32 __iomem *reg)
{
	u32 data = readl(reg);
@@ -681,9 +808,20 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev)
		can_free_echo_skb(ndev, i, NULL);
}

static void rcar_canfd_setrnc(struct rcar_canfd_global *gpriv, unsigned int ch,
			      unsigned int num_rules)
{
	unsigned int rnc_stride = 32 / gpriv->info->rnc_field_width;
	unsigned int shift = 32 - (ch % rnc_stride + 1) * gpriv->info->rnc_field_width;
	unsigned int w = ch / rnc_stride;
	u32 rnc = num_rules << shift;

	rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG(w), rnc);
}

static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv)
{
	if (is_gen4(gpriv)) {
	if (gpriv->info->ch_interface_mode) {
		u32 ch, val = gpriv->fdmode ? RCANFD_GEN4_FDCFG_FDOE
					    : RCANFD_GEN4_FDCFG_CLOE;

@@ -789,7 +927,7 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
					   u32 ch, u32 rule_entry)
{
	int offset, page, num_rules = RCANFD_CHANNEL_NUMRULES;
	unsigned int offset, page, num_rules = RCANFD_CHANNEL_NUMRULES;
	u32 rule_entry_index = rule_entry % 16;
	u32 ridx = ch + RCANFD_RFFIFO_IDX;

@@ -800,9 +938,8 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
			    RCANFD_GAFLECTR_AFLDAE));

	/* Write number of rules for channel */
	rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG(ch),
			   RCANFD_GAFLCFG_SETRNC(gpriv, ch, num_rules));
	if (is_gen4(gpriv))
	rcar_canfd_setrnc(gpriv, ch, num_rules);
	if (gpriv->info->shared_can_regs)
		offset = RCANFD_GEN4_GAFL_OFFSET;
	else if (gpriv->fdmode)
		offset = RCANFD_F_GAFL_OFFSET;
@@ -942,7 +1079,7 @@ static void rcar_canfd_global_error(struct net_device *ndev)
	u32 ridx = ch + RCANFD_RFFIFO_IDX;

	gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL);
	if (gerfl & RCANFD_GERFL_EEF(ch)) {
	if (gerfl & FIELD_PREP(RCANFD_GERFL_EEF, BIT(ch))) {
		netdev_dbg(ndev, "Ch%u: ECC Error flag\n", ch);
		stats->tx_dropped++;
	}
@@ -1338,7 +1475,7 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
			   brp, sjw, tseg1, tseg2);
	} else {
		/* Classical CAN only mode */
		if (is_gen4(gpriv)) {
		if (gpriv->info->shared_can_regs) {
			cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) |
			       RCANFD_NCFG_NBRP(brp) |
			       RCANFD_NCFG_NSJW(gpriv, sjw) |
@@ -1503,7 +1640,7 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,

	dlc = RCANFD_CFPTR_CFDLC(can_fd_len2dlc(cf->len));

	if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || is_gen4(gpriv)) {
	if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || gpriv->info->shared_can_regs) {
		rcar_canfd_write(priv->base,
				 RCANFD_F_CFID(gpriv, ch, RCANFD_CFFIFO_IDX), id);
		rcar_canfd_write(priv->base,
@@ -1562,7 +1699,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
	u32 ch = priv->channel;
	u32 ridx = ch + RCANFD_RFFIFO_IDX;

	if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || is_gen4(gpriv)) {
	if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || gpriv->info->shared_can_regs) {
		id = rcar_canfd_read(priv->base, RCANFD_F_RFID(gpriv, ridx));
		dlc = rcar_canfd_read(priv->base, RCANFD_F_RFPTR(gpriv, ridx));

@@ -1613,7 +1750,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
		cf->len = can_cc_dlc2len(RCANFD_RFPTR_RFDLC(dlc));
		if (id & RCANFD_RFID_RFRTR)
			cf->can_id |= CAN_RTR_FLAG;
		else if (is_gen4(gpriv))
		else if (gpriv->info->shared_can_regs)
			rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(gpriv, ridx, 0));
		else
			rcar_canfd_get_data(priv, cf, RCANFD_C_RFDF(ridx, 0));
@@ -1736,16 +1873,19 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,

	if (info->multi_channel_irqs) {
		char *irq_name;
		char name[10];
		int err_irq;
		int tx_irq;

		err_irq = platform_get_irq_byname(pdev, ch == 0 ? "ch0_err" : "ch1_err");
		scnprintf(name, sizeof(name), "ch%u_err", ch);
		err_irq = platform_get_irq_byname(pdev, name);
		if (err_irq < 0) {
			err = err_irq;
			goto fail;
		}

		tx_irq = platform_get_irq_byname(pdev, ch == 0 ? "ch0_trx" : "ch1_trx");
		scnprintf(name, sizeof(name), "ch%u_trx", ch);
		tx_irq = platform_get_irq_byname(pdev, name);
		if (tx_irq < 0) {
			err = tx_irq;
			goto fail;
@@ -1782,9 +1922,8 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
	}

	if (gpriv->fdmode) {
		priv->can.bittiming_const = &rcar_canfd_nom_bittiming_const;
		priv->can.data_bittiming_const =
			&rcar_canfd_data_bittiming_const;
		priv->can.bittiming_const = gpriv->info->nom_bittiming;
		priv->can.data_bittiming_const = gpriv->info->data_bittiming;

		/* Controller starts in CAN FD only mode */
		err = can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
@@ -1846,6 +1985,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
	u32 rule_entry = 0;
	bool fdmode = true;			/* CAN FD only mode - default */
	char name[9] = "channelX";
	struct clk *clk_ram;
	int i;

	info = of_device_get_match_data(dev);
@@ -1855,13 +1995,13 @@ static int rcar_canfd_probe(struct platform_device *pdev)

	for (i = 0; i < info->max_channels; ++i) {
		name[7] = '0' + i;
		of_child = of_get_child_by_name(dev->of_node, name);
		if (of_child && of_device_is_available(of_child)) {
		of_child = of_get_available_child_by_name(dev->of_node, name);
		if (of_child) {
			channels_mask |= BIT(i);
			transceivers[i] = devm_of_phy_optional_get(dev,
							of_child, NULL);
		}
			of_node_put(of_child);
		}
		if (IS_ERR(transceivers[i]))
			return PTR_ERR(transceivers[i]);
	}
@@ -1932,9 +2072,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)
		fcan_freq = clk_get_rate(gpriv->can_clk) / info->postdiv;
	} else {
		fcan_freq = clk_get_rate(gpriv->can_clk);
		gpriv->extclk = true;
		gpriv->extclk = gpriv->info->external_clk;
	}

	clk_ram = devm_clk_get_optional_enabled(dev, "ram_clk");
	if (IS_ERR(clk_ram))
		return dev_err_probe(dev, PTR_ERR(clk_ram),
				     "cannot get enabled ram clock\n");

	addr = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(addr)) {
		err = PTR_ERR(addr);
@@ -2097,6 +2242,7 @@ static SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,

static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
	{ .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
	{ .compatible = "renesas,r9a09g047-canfd", .data = &r9a09g047_hw_info },
	{ .compatible = "renesas,rcar-gen3-canfd", .data = &rcar_gen3_hw_info },
	{ .compatible = "renesas,rcar-gen4-canfd", .data = &rcar_gen4_hw_info },
	{ .compatible = "renesas,rzg2l-canfd", .data = &rzg2l_hw_info },