Hi All,
This patch series adds CANFD support to Renesas RZ/G2L family.
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 individual sources.
Cheers,
Prabhakar
Changes for v3:
* Dropped core clock addition patches from this series (its queued
up already in renesas-clk-for-v5.15)
* Added reset-names in binding doc as suggested by Philipp
* Updated interrupt names in binding doc as suggested by Geert
* Updated the driver to handle the above DT binding changes
Changes for v2:
* Added interrupt-names property and marked it as required for
RZ/G2L family
* Added descriptions for reset property
* Re-used irq handlers on RZ/G2L SoC
* Added new enum for chip_id
* Dropped R9A07G044_LAST_CORE_CLK
* Dropped patch (clk: renesas: r9a07g044-cpg: Add clock and reset
entries for CANFD) as its been merged into renesas tree
Lad Prabhakar (3):
dt-bindings: net: can: renesas,rcar-canfd: Document RZ/G2L SoC
can: rcar_canfd: Add support for RZ/G2L family
arm64: dts: renesas: r9a07g044: Add CANFD node
.../bindings/net/can/renesas,rcar-canfd.yaml | 69 ++++++-
arch/arm64/boot/dts/renesas/r9a07g044.dtsi | 41 +++++
drivers/net/can/rcar/rcar_canfd.c | 173 +++++++++++++++---
3 files changed, 253 insertions(+), 30 deletions(-)
--
2.17.1
@@ -13,6 +13,13 @@#address-cells=<2>;#size-cells=<2>;+/* External CAN clock - to be overridden by boards that provide it */+can_clk:can{+compatible="fixed-clock";+#clock-cells=<0>;+clock-frequency=<0>;+};+/* clock can be either from exclk or crystal oscillator (XIN/XOUT) */extal_clk:extal{compatible="fixed-clock";
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 and the IP doesn't divide (1/2)
CANFD clock within the IP.
This patch adds compatible string for RZ/G2L family and registers
the irq handlers required for CANFD operation. IRQ numbers are now
fetched based on names instead of indices. For backward compatibility
on non RZ/G2L SoC's we fallback reading based on indices.
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 | 173 +++++++++++++++++++++++++-----
1 file changed, 149 insertions(+), 24 deletions(-)
@@ -1636,7 +1692,11 @@ static int rcar_canfd_probe(struct platform_device *pdev)structdevice_node*of_child;unsignedlongchannels_mask=0;interr,ch_irq,g_irq;+intg_err_irq,g_recc_irq;boolfdmode=true;/* CAN FD only mode - default */+enumrcanfd_chip_idchip_id;++chip_id=(enumrcanfd_chip_id)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,16 +1709,30 @@ 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;-gotofail_dev;-}+if(chip_id==RENESAS_RCAR_GEN3){+ch_irq=platform_get_irq_byname_optional(pdev,"ch_int");+if(ch_irq<0){+/* For backward compatibility get irq by index */+ch_irq=platform_get_irq(pdev,0);+if(ch_irq<0)+returnch_irq;+}-g_irq=platform_get_irq(pdev,1);-if(g_irq<0){-err=g_irq;-gotofail_dev;+g_irq=platform_get_irq_byname_optional(pdev,"g_int");+if(g_irq<0){+/* For backward compatibility get irq by index */+g_irq=platform_get_irq(pdev,1);+if(g_irq<0)+returng_irq;+}+}else{+g_err_irq=platform_get_irq_byname(pdev,"g_err");+if(g_err_irq<0)+returng_err_irq;++g_recc_irq=platform_get_irq_byname(pdev,"g_recc");+if(g_recc_irq<0)+returng_recc_irq;}/* Global controller context */
@@ -1670,6 +1744,19 @@ static int rcar_canfd_probe(struct platform_device *pdev)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(&pdev->dev,"rstp_n");+if(IS_ERR(gpriv->rstc1))+returndev_err_probe(&pdev->dev,PTR_ERR(gpriv->rstc1),+"failed to get rstp_n\n");++gpriv->rstc2=devm_reset_control_get_exclusive(&pdev->dev,"rstc_n");+if(IS_ERR(gpriv->rstc2))+returndev_err_probe(&pdev->dev,PTR_ERR(gpriv->rstc2),+"failed to get rstc_n\n");+}/* Peripheral clock */gpriv->clkp=devm_clk_get(&pdev->dev,"fck");
@@ -1699,7 +1786,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,20 +1798,51 @@ 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);-gotofail_dev;+if(gpriv->chip_id==RENESAS_RCAR_GEN3){+err=devm_request_irq(&pdev->dev,ch_irq,+rcar_canfd_channel_interrupt,0,+"canfd.ch_int",gpriv);+if(err){+dev_err(&pdev->dev,"devm_request_irq(%d) failed, error %d\n",+ch_irq,err);+gotofail_dev;+}++err=devm_request_irq(&pdev->dev,g_irq,+rcar_canfd_global_interrupt,0,+"canfd.g_int",gpriv);+if(err){+dev_err(&pdev->dev,"devm_request_irq(%d) failed, error %d\n",+g_irq,err);+gotofail_dev;+}+}else{+err=devm_request_irq(&pdev->dev,g_recc_irq,+rcar_canfd_global_interrupt,0,+"canfd.g_recc",gpriv);++if(err){+dev_err(&pdev->dev,"devm_request_irq(%d) failed, error %d\n",+g_recc_irq,err);+gotofail_dev;+}++err=devm_request_irq(&pdev->dev,g_err_irq,+rcar_canfd_global_interrupt,0,+"canfd.g_err",gpriv);+if(err){+dev_err(&pdev->dev,"devm_request_irq(%d) failed, error %d\n",+g_err_irq,err);+gotofail_dev;+}}-err=devm_request_irq(&pdev->dev,g_irq,-rcar_canfd_global_interrupt,0,-"canfd.gbl",gpriv);++err=reset_control_reset(gpriv->rstc1);+if(err)+gotofail_dev;+err=reset_control_reset(gpriv->rstc2);if(err){-dev_err(&pdev->dev,"devm_request_irq(%d) failed, error %d\n",-g_irq,err);+reset_control_assert(gpriv->rstc1);gotofail_dev;}
@@ -1733,7 +1851,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)if(err){dev_err(&pdev->dev,"failed to enable peripheral clock, error %d\n",err);-gotofail_dev;+gotofail_reset;}err=rcar_canfd_reset_controller(gpriv);
@@ -1790,6 +1908,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)rcar_canfd_disable_global_interrupts(gpriv);fail_clk:clk_disable_unprepare(gpriv->clkp);+fail_reset:+reset_control_assert(gpriv->rstc1);+reset_control_assert(gpriv->rstc2);fail_dev:returnerr;}
@@ -1810,6 +1931,9 @@ 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);+reset_control_assert(gpriv->rstc1);+reset_control_assert(gpriv->rstc2);+return0;}
drivers/net/can/rcar/rcar_canfd.c:1699:12: warning: cast to smaller integer type 'enum rcanfd_chip_id' from 'const void *' [-Wvoid-pointer-to-enum-cast]
chip_id = (enum rcanfd_chip_id)of_device_get_match_data(&pdev->dev);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
vim +1699 drivers/net/can/rcar/rcar_canfd.c
1686
1687 static int rcar_canfd_probe(struct platform_device *pdev)
1688 {
1689 void __iomem *addr;
1690 u32 sts, ch, fcan_freq;
1691 struct rcar_canfd_global *gpriv;
1692 struct device_node *of_child;
1693 unsigned long channels_mask = 0;
1694 int err, ch_irq, g_irq;
1695 int g_err_irq, g_recc_irq;
1696 bool fdmode = true; /* CAN FD only mode - default */
1697 enum rcanfd_chip_id chip_id;
1698
drivers/net/can/rcar/rcar_canfd.c:1699:12: warning: cast to smaller integer type 'enum rcanfd_chip_id' from 'const void *' [-Wvoid-pointer-to-enum-cast]
Seems we need the cast (uintptr_t), that I asked you to remove. Can you
test if
| chip_id = (enum rcanfd_chip_id)(uintptr_t)of_device_get_match_data(&pdev->dev);
works?
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 |
drivers/net/can/rcar/rcar_canfd.c:1699:12: warning: cast to smaller integer type 'enum rcanfd_chip_id' from 'const void *' [-Wvoid-pointer-to-enum-cast]
Seems we need the cast (uintptr_t), that I asked you to remove. Can you
Bummer, I had seen your comment while reading email on my phone,
but forgot to reply when I got back to my computer...
test if
| chip_id = (enum rcanfd_chip_id)(uintptr_t)of_device_get_match_data(&pdev->dev);
works?
Just
chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
should be fine.
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
Hi Prabhakar,
On Wed, Jul 21, 2021 at 9:50 PM Lad Prabhakar
[off-list ref] 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 and the IP doesn't divide (1/2)
CANFD clock within the IP.
This patch adds compatible string for RZ/G2L family and registers
the irq handlers required for CANFD operation. IRQ numbers are now
fetched based on names instead of indices. For backward compatibility
on non RZ/G2L SoC's we fallback reading based on indices.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Thanks for the update!
I think you misunderstood my comment on v1 about the interrupt
handlers, cfr. below.
I did not object to having fine-grained interrupt handlers on RZ/G2L.
I did object to duplicating code in global and fine-grained interrupt
handlers.
The trick to have both is to let the global interrupt handlers call
(conditionally) into the fine-grained handlers. In pseudo-code:
global_interrupt_handler()
{
if (...)
fine_grained_handler1();
if (...)
fine_grained_handler2();
...
}
On R-Car Gen3, you register the global interrupt handlers, as before.
On RZ/G2L, you register the fine-grained interrupt handlers 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
drivers/net/can/rcar/rcar_canfd.c:1699:12: warning: cast to smaller integer type 'enum rcanfd_chip_id' from 'const void *' [-Wvoid-pointer-to-enum-cast]
Seems we need the cast (uintptr_t), that I asked you to remove. Can you
Bummer, I had seen your comment while reading email on my phone,
but forgot to reply when I got back to my computer...
quoted
test if
| chip_id = (enum rcanfd_chip_id)(uintptr_t)of_device_get_match_data(&pdev->dev);
works?
Just
chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev);
should be fine.
Above works, cast is not required.
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
Hi Geert,
Thank you for the review.
On Mon, Jul 26, 2021 at 10:53 AM Geert Uytterhoeven
[off-list ref] wrote:
Hi Prabhakar,
On Wed, Jul 21, 2021 at 9:50 PM Lad Prabhakar
[off-list ref] wrote:
quoted
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 and the IP doesn't divide (1/2)
CANFD clock within the IP.
This patch adds compatible string for RZ/G2L family and registers
the irq handlers required for CANFD operation. IRQ numbers are now
fetched based on names instead of indices. For backward compatibility
on non RZ/G2L SoC's we fallback reading based on indices.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Thanks for the update!
I think you misunderstood my comment on v1 about the interrupt
handlers, cfr. below.
I did not object to having fine-grained interrupt handlers on RZ/G2L.
I did object to duplicating code in global and fine-grained interrupt
handlers.
The trick to have both is to let the global interrupt handlers call
(conditionally) into the fine-grained handlers. In pseudo-code:
global_interrupt_handler()
{
if (...)
fine_grained_handler1();
if (...)
fine_grained_handler2();
...
}
On R-Car Gen3, you register the global interrupt handlers, as before.
On RZ/G2L, you register the fine-grained interrupt handlers instead.
Agreed will re-spin with the fine-grained version tomorrow.
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