diff mbox series

[2/6] can: rcar_canfd: Add support for RZ/G2L family

Message ID 20210715182123.23372-3-prabhakar.mahadev-lad.rj@bp.renesas.com
State New
Headers show
Series Renesas RZ/G2L CANFD support | expand

Commit Message

Prabhakar Mahadev Lad July 15, 2021, 6:21 p.m. UTC
CANFD block on RZ/G2L SoC is almost identical to one found on
R-Car Gen3 SoC's.

On RZ/G2L SoC interrupt sources for each channel are split into
different sources, irq handlers for the same are added.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
---
 drivers/net/can/rcar/rcar_canfd.c | 275 ++++++++++++++++++++++++++----
 1 file changed, 244 insertions(+), 31 deletions(-)

Comments

Geert Uytterhoeven July 16, 2021, 7:47 a.m. UTC | #1
Hi Prabhakar,

On Thu, Jul 15, 2021 at 8:21 PM Lad Prabhakar
<prabhakar.mahadev-lad.rj@bp.renesas.com> wrote:
> CANFD block on RZ/G2L SoC is almost identical to one found on

> R-Car Gen3 SoC's.

>

> On RZ/G2L SoC interrupt sources for each channel are split into

> different sources, irq handlers for the same are added.

>

> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>


Thanks for your patch!

> --- a/drivers/net/can/rcar/rcar_canfd.c

> +++ b/drivers/net/can/rcar/rcar_canfd.c

> @@ -1070,6 +1077,56 @@ static void rcar_canfd_tx_done(struct net_device *ndev)

>         can_led_event(ndev, CAN_LED_EVENT_TX);

>  }

>

> +static irqreturn_t rcar_canfd_global_err_interrupt(int irq, void *dev_id)

> +{


> +static irqreturn_t rcar_canfd_global_recieve_fifo_interrupt(int irq, void *dev_id)

> +{


>  static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)

>  {

>         struct rcar_canfd_global *gpriv = dev_id;

> @@ -1139,6 +1196,56 @@ static void rcar_canfd_state_change(struct net_device *ndev,

>         }

>  }

>

> +static irqreturn_t rcar_canfd_channel_tx_interrupt(int irq, void *dev_id)

> +{


> +static irqreturn_t rcar_canfd_channel_err_interrupt(int irq, void *dev_id)

> +{


It looks like the new split interrupt handlers duplicate code from
the existing unified interrupt handlers.  Perhaps the latter can be
made to call the former instead?

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Lad, Prabhakar July 16, 2021, 8:32 a.m. UTC | #2
Hi Geert,

On Fri, Jul 16, 2021 at 8:47 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>

> Hi Prabhakar,

>

> On Thu, Jul 15, 2021 at 8:21 PM Lad Prabhakar

> <prabhakar.mahadev-lad.rj@bp.renesas.com> wrote:

> > CANFD block on RZ/G2L SoC is almost identical to one found on

> > R-Car Gen3 SoC's.

> >

> > On RZ/G2L SoC interrupt sources for each channel are split into

> > different sources, irq handlers for the same are added.

> >

> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

> > Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>

>

> Thanks for your patch!

>

> > --- a/drivers/net/can/rcar/rcar_canfd.c

> > +++ b/drivers/net/can/rcar/rcar_canfd.c

> > @@ -1070,6 +1077,56 @@ static void rcar_canfd_tx_done(struct net_device *ndev)

> >         can_led_event(ndev, CAN_LED_EVENT_TX);

> >  }

> >

> > +static irqreturn_t rcar_canfd_global_err_interrupt(int irq, void *dev_id)

> > +{

>

> > +static irqreturn_t rcar_canfd_global_recieve_fifo_interrupt(int irq, void *dev_id)

> > +{

>

> >  static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)

> >  {

> >         struct rcar_canfd_global *gpriv = dev_id;

> > @@ -1139,6 +1196,56 @@ static void rcar_canfd_state_change(struct net_device *ndev,

> >         }

> >  }

> >

> > +static irqreturn_t rcar_canfd_channel_tx_interrupt(int irq, void *dev_id)

> > +{

>

> > +static irqreturn_t rcar_canfd_channel_err_interrupt(int irq, void *dev_id)

> > +{

>

> It looks like the new split interrupt handlers duplicate code from

> the existing unified interrupt handlers.  Perhaps the latter can be

> made to call the former instead?

>

Agreed.

Cheers,
Prabhakar

> Gr{oetje,eeting}s,

>

>                         Geert

>

> --

> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

>

> In personal conversations with technical people, I call myself a hacker. But

> when I'm talking to journalists I just say "programmer" or something like that.

>                                 -- Linus Torvalds
Marc Kleine-Budde July 16, 2021, 10:10 a.m. UTC | #3
On 15.07.2021 19:21:19, Lad Prabhakar wrote:
> CANFD block on RZ/G2L SoC is almost identical to one found on

> R-Car Gen3 SoC's.

> 

> On RZ/G2L SoC interrupt sources for each channel are split into

> different sources, irq handlers for the same are added.

> 

> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>


Thanks for the patch! Some nitpicks inline, Geert already commented to
use the same IRQ handler for all interrutps.

> ---

>  drivers/net/can/rcar/rcar_canfd.c | 275 ++++++++++++++++++++++++++----

>  1 file changed, 244 insertions(+), 31 deletions(-)

> 

> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c

> index 311e6ca3bdc4..5dfbc5fa2d81 100644

> --- a/drivers/net/can/rcar/rcar_canfd.c

> +++ b/drivers/net/can/rcar/rcar_canfd.c

> @@ -37,9 +37,13 @@

>  #include <linux/bitmap.h>

>  #include <linux/bitops.h>

>  #include <linux/iopoll.h>

> +#include <linux/reset.h>

>  

>  #define RCANFD_DRV_NAME			"rcar_canfd"

>  

> +#define RENESAS_RCAR_GEN3	0

> +#define RENESAS_RZG2L		1

> +


Please make this an enum.

>  /* Global register bits */

>  

>  /* RSCFDnCFDGRMCFG */

> @@ -513,6 +517,9 @@ struct rcar_canfd_global {

>  	enum rcar_canfd_fcanclk fcan;	/* CANFD or Ext clock */

>  	unsigned long channels_mask;	/* Enabled channels mask */

>  	bool fdmode;			/* CAN FD or Classical CAN only mode */

> +	struct reset_control *rstc1;     /* Pointer to reset source1 */

> +	struct reset_control *rstc2;     /* Pointer to reset source2 */

> +	unsigned int chip_id;


enum here, too

>  };

>  

>  /* CAN FD mode nominal rate constants */

> @@ -1070,6 +1077,56 @@ static void rcar_canfd_tx_done(struct net_device *ndev)

>  	can_led_event(ndev, CAN_LED_EVENT_TX);

>  }

>  

[...]

> @@ -1635,8 +1784,11 @@ static int rcar_canfd_probe(struct platform_device *pdev)

>  	struct rcar_canfd_global *gpriv;

>  	struct device_node *of_child;

>  	unsigned long channels_mask = 0;

> -	int err, ch_irq, g_irq;

> +	int err, ch_irq, g_irq, g_rx_irq;

>  	bool fdmode = true;			/* CAN FD only mode - default */

> +	unsigned int chip_id;

> +

> +	chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev);


The cast looks wrong.

>  

>  	if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd"))

>  		fdmode = false;			/* Classical CAN only mode */

> @@ -1649,27 +1801,56 @@ static int rcar_canfd_probe(struct platform_device *pdev)

>  	if (of_child && of_device_is_available(of_child))

>  		channels_mask |= BIT(1);	/* Channel 1 */

>  

> -	ch_irq = platform_get_irq(pdev, 0);

> -	if (ch_irq < 0) {

> -		err = ch_irq;

> -		goto fail_dev;

> -	}

> +	if (chip_id == RENESAS_RCAR_GEN3) {

> +		ch_irq = platform_get_irq(pdev, 0);

> +		if (ch_irq < 0)

> +			return ch_irq;

>  

> -	g_irq = platform_get_irq(pdev, 1);

> -	if (g_irq < 0) {

> -		err = g_irq;

> -		goto fail_dev;

> +		g_irq = platform_get_irq(pdev, 1);

> +		if (g_irq < 0)

> +			return g_irq;

> +	} else {

> +		g_irq = platform_get_irq(pdev, 0);

> +		if (g_irq < 0)

> +			return g_irq;

> +

> +		g_rx_irq = platform_get_irq(pdev, 1);

> +		if (g_rx_irq < 0)

> +			return g_rx_irq;

>  	}

>  

>  	/* Global controller context */

>  	gpriv = devm_kzalloc(&pdev->dev, sizeof(*gpriv), GFP_KERNEL);

> -	if (!gpriv) {

> -		err = -ENOMEM;

> -		goto fail_dev;

> -	}

> +	if (!gpriv)

> +		return -ENOMEM;

> +

>  	gpriv->pdev = pdev;

>  	gpriv->channels_mask = channels_mask;

>  	gpriv->fdmode = fdmode;

> +	gpriv->chip_id = chip_id;

> +

> +	if (gpriv->chip_id == RENESAS_RZG2L) {

> +		gpriv->rstc1 = devm_reset_control_get_exclusive_by_index(&pdev->dev, 0);

> +		if (IS_ERR(gpriv->rstc1)) {

> +			dev_err(&pdev->dev, "failed to get reset index 0\n");

> +			return PTR_ERR(gpriv->rstc1);

> +		}

> +

> +		err = reset_control_reset(gpriv->rstc1);

> +		if (err)

> +			return err;

> +

> +		gpriv->rstc2 = devm_reset_control_get_exclusive_by_index(&pdev->dev, 1);

> +		if (IS_ERR(gpriv->rstc2)) {

> +			dev_err(&pdev->dev, "failed to get reset index 1\n");

> +			return PTR_ERR(gpriv->rstc2);

> +		}

> +		err = reset_control_reset(gpriv->rstc2);

> +		if (err) {

> +			reset_control_assert(gpriv->rstc1);

> +			return err;

> +		}

> +	}

>  

>  	/* Peripheral clock */

>  	gpriv->clkp = devm_clk_get(&pdev->dev, "fck");

> @@ -1699,7 +1880,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)

>  	}

>  	fcan_freq = clk_get_rate(gpriv->can_clk);

>  

> -	if (gpriv->fcan == RCANFD_CANFDCLK)

> +	if (gpriv->fcan == RCANFD_CANFDCLK && gpriv->chip_id == RENESAS_RCAR_GEN3)

>  		/* CANFD clock is further divided by (1/2) within the IP */

>  		fcan_freq /= 2;

>  

> @@ -1711,21 +1892,43 @@ static int rcar_canfd_probe(struct platform_device *pdev)

>  	gpriv->base = addr;

>  

>  	/* Request IRQ that's common for both channels */

> -	err = devm_request_irq(&pdev->dev, ch_irq,

> -			       rcar_canfd_channel_interrupt, 0,

> -			       "canfd.chn", gpriv);

> -	if (err) {

> -		dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",

> -			ch_irq, err);

> -		goto fail_dev;

> -	}

> -	err = devm_request_irq(&pdev->dev, g_irq,

> -			       rcar_canfd_global_interrupt, 0,

> -			       "canfd.gbl", gpriv);

> -	if (err) {

> -		dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",

> -			g_irq, err);

> -		goto fail_dev;

> +	if (gpriv->chip_id == RENESAS_RCAR_GEN3) {

> +		err = devm_request_irq(&pdev->dev, ch_irq,

> +				       rcar_canfd_channel_interrupt, 0,

> +				       "canfd.chn", gpriv);

> +		if (err) {

> +			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",

> +				ch_irq, err);

> +			goto fail_dev;

> +		}

> +

> +		err = devm_request_irq(&pdev->dev, g_irq,

> +				       rcar_canfd_global_interrupt, 0,

> +				       "canfd.gbl", gpriv);

> +		if (err) {

> +			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",

> +				g_irq, err);

> +			goto fail_dev;

> +		}

> +	} else {

> +		err = devm_request_irq(&pdev->dev, g_rx_irq,

> +				       rcar_canfd_global_recieve_fifo_interrupt, 0,

> +				       "canfd.gblrx", gpriv);

> +

> +		if (err) {

> +			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",

> +				g_rx_irq, err);

> +			goto fail_dev;

> +		}

> +

> +		err = devm_request_irq(&pdev->dev, g_irq,

> +				       rcar_canfd_global_err_interrupt, 0,

> +				       "canfd.gblerr", gpriv);

> +		if (err) {

> +			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",

> +				g_irq, err);

> +			goto fail_dev;

> +		}

>  	}

>  

>  	/* Enable peripheral clock for register access */

> @@ -1791,6 +1994,10 @@ static int rcar_canfd_probe(struct platform_device *pdev)

>  fail_clk:

>  	clk_disable_unprepare(gpriv->clkp);

>  fail_dev:

> +	if (gpriv->chip_id == RENESAS_RZG2L) {

> +		reset_control_assert(gpriv->rstc1);

> +		reset_control_assert(gpriv->rstc2);


reset_control_assert() can handle NULL pointers

> +	}

>  	return err;

>  }

>  

> @@ -1810,6 +2017,11 @@ static int rcar_canfd_remove(struct platform_device *pdev)

>  	/* Enter global sleep mode */

>  	rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);

>  	clk_disable_unprepare(gpriv->clkp);

> +	if (gpriv->chip_id == RENESAS_RZG2L) {

> +		reset_control_assert(gpriv->rstc1);

> +		reset_control_assert(gpriv->rstc2);

> +	}


same here

> +

>  	return 0;

>  }

>  

> @@ -1827,7 +2039,8 @@ static SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,

>  			 rcar_canfd_resume);

>  

>  static const struct of_device_id rcar_canfd_of_table[] = {

> -	{ .compatible = "renesas,rcar-gen3-canfd" },

> +	{ .compatible = "renesas,rcar-gen3-canfd", .data = (void *)RENESAS_RCAR_GEN3 },

> +	{ .compatible = "renesas,rzg2l-canfd", .data = (void *)RENESAS_RZG2L },

>  	{ }

>  };


Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde           |
Embedded Linux                   | https://www.pengutronix.de  |
Vertretung West/Dortmund         | Phone: +49-231-2826-924     |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-5555 |
diff mbox series

Patch

diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 311e6ca3bdc4..5dfbc5fa2d81 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -37,9 +37,13 @@ 
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/iopoll.h>
+#include <linux/reset.h>
 
 #define RCANFD_DRV_NAME			"rcar_canfd"
 
+#define RENESAS_RCAR_GEN3	0
+#define RENESAS_RZG2L		1
+
 /* Global register bits */
 
 /* RSCFDnCFDGRMCFG */
@@ -513,6 +517,9 @@  struct rcar_canfd_global {
 	enum rcar_canfd_fcanclk fcan;	/* CANFD or Ext clock */
 	unsigned long channels_mask;	/* Enabled channels mask */
 	bool fdmode;			/* CAN FD or Classical CAN only mode */
+	struct reset_control *rstc1;     /* Pointer to reset source1 */
+	struct reset_control *rstc2;     /* Pointer to reset source2 */
+	unsigned int chip_id;
 };
 
 /* CAN FD mode nominal rate constants */
@@ -1070,6 +1077,56 @@  static void rcar_canfd_tx_done(struct net_device *ndev)
 	can_led_event(ndev, CAN_LED_EVENT_TX);
 }
 
+static irqreturn_t rcar_canfd_global_err_interrupt(int irq, void *dev_id)
+{
+	struct rcar_canfd_global *gpriv = dev_id;
+	struct net_device *ndev;
+	struct rcar_canfd_channel *priv;
+	u32 gerfl;
+	u32 ch, ridx;
+
+	/* Global error interrupts still indicate a condition specific to a channel. */
+	for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
+		priv = gpriv->ch[ch];
+		ndev = priv->ndev;
+		ridx = ch + RCANFD_RFFIFO_IDX;
+
+		/* Global error interrupts */
+		gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL);
+		if (unlikely(RCANFD_GERFL_ERR(gpriv, gerfl)))
+			rcar_canfd_global_error(ndev);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rcar_canfd_global_recieve_fifo_interrupt(int irq, void *dev_id)
+{
+	struct rcar_canfd_global *gpriv = dev_id;
+	struct net_device *ndev;
+	struct rcar_canfd_channel *priv;
+	u32 sts;
+	u32 ch, ridx;
+
+	for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
+		priv = gpriv->ch[ch];
+		ndev = priv->ndev;
+		ridx = ch + RCANFD_RFFIFO_IDX;
+
+		/* Handle Rx interrupts */
+		sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx));
+		if (likely(sts & RCANFD_RFSTS_RFIF)) {
+			if (napi_schedule_prep(&priv->napi)) {
+				/* Disable Rx FIFO interrupts */
+				rcar_canfd_clear_bit(priv->base,
+						     RCANFD_RFCC(ridx),
+						     RCANFD_RFCC_RFIE);
+				__napi_schedule(&priv->napi);
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
 {
 	struct rcar_canfd_global *gpriv = dev_id;
@@ -1139,6 +1196,56 @@  static void rcar_canfd_state_change(struct net_device *ndev,
 	}
 }
 
+static irqreturn_t rcar_canfd_channel_tx_interrupt(int irq, void *dev_id)
+{
+	struct rcar_canfd_global *gpriv = dev_id;
+	struct net_device *ndev;
+	struct rcar_canfd_channel *priv;
+	u32 sts, ch;
+
+	/* Common FIFO is a per channel resource */
+	for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
+		priv = gpriv->ch[ch];
+		ndev = priv->ndev;
+
+		/* Handle Tx interrupts */
+		sts = rcar_canfd_read(priv->base,
+				      RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX));
+		if (likely(sts & RCANFD_CFSTS_CFTXIF))
+			rcar_canfd_tx_done(ndev);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rcar_canfd_channel_err_interrupt(int irq, void *dev_id)
+{
+	struct rcar_canfd_global *gpriv = dev_id;
+	struct net_device *ndev;
+	struct rcar_canfd_channel *priv;
+	u32 sts, ch, cerfl;
+	u16 txerr, rxerr;
+
+	/* Common FIFO is a per channel resource */
+	for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
+		priv = gpriv->ch[ch];
+		ndev = priv->ndev;
+
+		/* Channel error interrupts */
+		cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch));
+		sts = rcar_canfd_read(priv->base, RCANFD_CSTS(ch));
+		txerr = RCANFD_CSTS_TECCNT(sts);
+		rxerr = RCANFD_CSTS_RECCNT(sts);
+		if (unlikely(RCANFD_CERFL_ERR(cerfl)))
+			rcar_canfd_error(ndev, cerfl, txerr, rxerr);
+
+		/* Handle state change to lower states */
+		if (unlikely(priv->can.state != CAN_STATE_ERROR_ACTIVE &&
+			     priv->can.state != CAN_STATE_BUS_OFF))
+			rcar_canfd_state_change(ndev, txerr, rxerr);
+	}
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
 {
 	struct rcar_canfd_global *gpriv = dev_id;
@@ -1560,6 +1667,10 @@  static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
 	struct rcar_canfd_channel *priv;
 	struct net_device *ndev;
 	int err = -ENODEV;
+	char *irq_name;
+	int err_irq;
+	int tx_irq;
+	int i;
 
 	ndev = alloc_candev(sizeof(*priv), RCANFD_FIFO_DEPTH);
 	if (!ndev) {
@@ -1577,6 +1688,44 @@  static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
 	priv->can.clock.freq = fcan_freq;
 	dev_info(&pdev->dev, "can_clk rate is %u\n", priv->can.clock.freq);
 
+	if (gpriv->chip_id == RENESAS_RZG2L) {
+		if (!ch)
+			i = 2;
+		else
+			i = 5;
+		err_irq = platform_get_irq(pdev, i++);
+		if (err_irq < 0) {
+			err = err_irq;
+			goto fail;
+		}
+		tx_irq = platform_get_irq(pdev, i);
+		if (tx_irq < 0) {
+			err = tx_irq;
+			goto fail;
+		}
+
+		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					  "canfd.chnerr%d", ch);
+		err = devm_request_irq(&pdev->dev, err_irq,
+				       rcar_canfd_channel_err_interrupt, 0,
+				       irq_name, gpriv);
+		if (err) {
+			dev_err(&pdev->dev, "devm_request_irq CH Err(%d) failed, error %d\n",
+				err_irq, err);
+			goto fail;
+		}
+		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					  "canfd.chntx%d", ch);
+		err = devm_request_irq(&pdev->dev, tx_irq,
+				       rcar_canfd_channel_tx_interrupt, 0,
+				       irq_name, gpriv);
+		if (err) {
+			dev_err(&pdev->dev, "devm_request_irq Tx (%d) failed, error %d\n",
+				tx_irq, err);
+			goto fail;
+		}
+	}
+
 	if (gpriv->fdmode) {
 		priv->can.bittiming_const = &rcar_canfd_nom_bittiming_const;
 		priv->can.data_bittiming_const =
@@ -1635,8 +1784,11 @@  static int rcar_canfd_probe(struct platform_device *pdev)
 	struct rcar_canfd_global *gpriv;
 	struct device_node *of_child;
 	unsigned long channels_mask = 0;
-	int err, ch_irq, g_irq;
+	int err, ch_irq, g_irq, g_rx_irq;
 	bool fdmode = true;			/* CAN FD only mode - default */
+	unsigned int chip_id;
+
+	chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
 
 	if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd"))
 		fdmode = false;			/* Classical CAN only mode */
@@ -1649,27 +1801,56 @@  static int rcar_canfd_probe(struct platform_device *pdev)
 	if (of_child && of_device_is_available(of_child))
 		channels_mask |= BIT(1);	/* Channel 1 */
 
-	ch_irq = platform_get_irq(pdev, 0);
-	if (ch_irq < 0) {
-		err = ch_irq;
-		goto fail_dev;
-	}
+	if (chip_id == RENESAS_RCAR_GEN3) {
+		ch_irq = platform_get_irq(pdev, 0);
+		if (ch_irq < 0)
+			return ch_irq;
 
-	g_irq = platform_get_irq(pdev, 1);
-	if (g_irq < 0) {
-		err = g_irq;
-		goto fail_dev;
+		g_irq = platform_get_irq(pdev, 1);
+		if (g_irq < 0)
+			return g_irq;
+	} else {
+		g_irq = platform_get_irq(pdev, 0);
+		if (g_irq < 0)
+			return g_irq;
+
+		g_rx_irq = platform_get_irq(pdev, 1);
+		if (g_rx_irq < 0)
+			return g_rx_irq;
 	}
 
 	/* Global controller context */
 	gpriv = devm_kzalloc(&pdev->dev, sizeof(*gpriv), GFP_KERNEL);
-	if (!gpriv) {
-		err = -ENOMEM;
-		goto fail_dev;
-	}
+	if (!gpriv)
+		return -ENOMEM;
+
 	gpriv->pdev = pdev;
 	gpriv->channels_mask = channels_mask;
 	gpriv->fdmode = fdmode;
+	gpriv->chip_id = chip_id;
+
+	if (gpriv->chip_id == RENESAS_RZG2L) {
+		gpriv->rstc1 = devm_reset_control_get_exclusive_by_index(&pdev->dev, 0);
+		if (IS_ERR(gpriv->rstc1)) {
+			dev_err(&pdev->dev, "failed to get reset index 0\n");
+			return PTR_ERR(gpriv->rstc1);
+		}
+
+		err = reset_control_reset(gpriv->rstc1);
+		if (err)
+			return err;
+
+		gpriv->rstc2 = devm_reset_control_get_exclusive_by_index(&pdev->dev, 1);
+		if (IS_ERR(gpriv->rstc2)) {
+			dev_err(&pdev->dev, "failed to get reset index 1\n");
+			return PTR_ERR(gpriv->rstc2);
+		}
+		err = reset_control_reset(gpriv->rstc2);
+		if (err) {
+			reset_control_assert(gpriv->rstc1);
+			return err;
+		}
+	}
 
 	/* Peripheral clock */
 	gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
@@ -1699,7 +1880,7 @@  static int rcar_canfd_probe(struct platform_device *pdev)
 	}
 	fcan_freq = clk_get_rate(gpriv->can_clk);
 
-	if (gpriv->fcan == RCANFD_CANFDCLK)
+	if (gpriv->fcan == RCANFD_CANFDCLK && gpriv->chip_id == RENESAS_RCAR_GEN3)
 		/* CANFD clock is further divided by (1/2) within the IP */
 		fcan_freq /= 2;
 
@@ -1711,21 +1892,43 @@  static int rcar_canfd_probe(struct platform_device *pdev)
 	gpriv->base = addr;
 
 	/* Request IRQ that's common for both channels */
-	err = devm_request_irq(&pdev->dev, ch_irq,
-			       rcar_canfd_channel_interrupt, 0,
-			       "canfd.chn", gpriv);
-	if (err) {
-		dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
-			ch_irq, err);
-		goto fail_dev;
-	}
-	err = devm_request_irq(&pdev->dev, g_irq,
-			       rcar_canfd_global_interrupt, 0,
-			       "canfd.gbl", gpriv);
-	if (err) {
-		dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
-			g_irq, err);
-		goto fail_dev;
+	if (gpriv->chip_id == RENESAS_RCAR_GEN3) {
+		err = devm_request_irq(&pdev->dev, ch_irq,
+				       rcar_canfd_channel_interrupt, 0,
+				       "canfd.chn", gpriv);
+		if (err) {
+			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
+				ch_irq, err);
+			goto fail_dev;
+		}
+
+		err = devm_request_irq(&pdev->dev, g_irq,
+				       rcar_canfd_global_interrupt, 0,
+				       "canfd.gbl", gpriv);
+		if (err) {
+			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
+				g_irq, err);
+			goto fail_dev;
+		}
+	} else {
+		err = devm_request_irq(&pdev->dev, g_rx_irq,
+				       rcar_canfd_global_recieve_fifo_interrupt, 0,
+				       "canfd.gblrx", gpriv);
+
+		if (err) {
+			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
+				g_rx_irq, err);
+			goto fail_dev;
+		}
+
+		err = devm_request_irq(&pdev->dev, g_irq,
+				       rcar_canfd_global_err_interrupt, 0,
+				       "canfd.gblerr", gpriv);
+		if (err) {
+			dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
+				g_irq, err);
+			goto fail_dev;
+		}
 	}
 
 	/* Enable peripheral clock for register access */
@@ -1791,6 +1994,10 @@  static int rcar_canfd_probe(struct platform_device *pdev)
 fail_clk:
 	clk_disable_unprepare(gpriv->clkp);
 fail_dev:
+	if (gpriv->chip_id == RENESAS_RZG2L) {
+		reset_control_assert(gpriv->rstc1);
+		reset_control_assert(gpriv->rstc2);
+	}
 	return err;
 }
 
@@ -1810,6 +2017,11 @@  static int rcar_canfd_remove(struct platform_device *pdev)
 	/* Enter global sleep mode */
 	rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
 	clk_disable_unprepare(gpriv->clkp);
+	if (gpriv->chip_id == RENESAS_RZG2L) {
+		reset_control_assert(gpriv->rstc1);
+		reset_control_assert(gpriv->rstc2);
+	}
+
 	return 0;
 }
 
@@ -1827,7 +2039,8 @@  static SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
 			 rcar_canfd_resume);
 
 static const struct of_device_id rcar_canfd_of_table[] = {
-	{ .compatible = "renesas,rcar-gen3-canfd" },
+	{ .compatible = "renesas,rcar-gen3-canfd", .data = (void *)RENESAS_RCAR_GEN3 },
+	{ .compatible = "renesas,rzg2l-canfd", .data = (void *)RENESAS_RZG2L },
 	{ }
 };