aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDuy Dang <duy.dang.yw@renesas.com>2024-06-12 14:01:22 +0700
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2024-06-25 10:13:42 +0000
commitce55e2d760c3877ca754e24dfe76c16eb09ada68 (patch)
tree91edc6d70b58be42a59ea06144434f7d561d7863
parent2676c9fe38d813cfdb38ba67da2377e798559850 (diff)
s4sk: Add Linux CANFD driver
Add a patch to support CANFD driver for S4SK. Since CANFD does not work without bus protection unlock program running on G4MH, this feature is disabled by default. To enable this patch, add to local.conf: MACHINE_FEATURES:append = " canfd" Unlock program on TrampolineOS: https://github.com/renesas-rcar/whitebox-sdk/tree/wip/v5.x_CAN_unlock_app Please clone this repo and follow the guideline to build: - Download CC-RH compiler: https://www.renesas.com/us/en/software-tool/c-compiler-package-rh850-family#downloads - Move it to tool directory: $ cp CC-RH_V20500_setup-doc.zip ./whitebox-sdk/tool - Install compiler and tools: $ cd ./whitebox-sdk/tool $ ./setup_wine.sh $ ./setup_csp.sh CC-RH_V20500_setup-doc.zip - Build unlock program: $ cd ./whitebox-sdk/mcu/ $ ./build_trampoline.sh s4sk The output file is: whitebox-sdk/mcu/deploy/g4mh_can_unlock.srec Follow flashing guideline in: https://elinux.org/R-Car/Boards/S4SK#How_to_flash.2Fupdate_the_loader and replace the file dummy_g4mh_case0.srec with the output file. Bug-AGL: SPEC-5175 Change-Id: If43d857e7dbd6abe0fa928894e036ffedba80234 Signed-off-by: Duy Dang <duy.dang.yw@renesas.com> Reviewed-on: https://gerrit.automotivelinux.org/gerrit/c/AGL/meta-agl/+/29988 Reviewed-by: Jan-Simon Moeller <jsmoeller@linuxfoundation.org> Tested-by: Jenkins Job builder account ci-image-build: Jenkins Job builder account ci-image-boot-test: Jenkins Job builder account
-rw-r--r--meta-agl-bsp/conf/include/agl_s4sk.inc5
-rw-r--r--meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas/0001-Porting-to-support-device-driver-Canfd-from-Control-.patch1388
-rw-r--r--meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas_%.bbappend6
3 files changed, 1399 insertions, 0 deletions
diff --git a/meta-agl-bsp/conf/include/agl_s4sk.inc b/meta-agl-bsp/conf/include/agl_s4sk.inc
index 8f4a91b44..91a65d8b8 100644
--- a/meta-agl-bsp/conf/include/agl_s4sk.inc
+++ b/meta-agl-bsp/conf/include/agl_s4sk.inc
@@ -7,3 +7,8 @@ WKS_FILE = "singlepart-noloader.wks"
IMAGE_INSTALL:append = " \
kernel-devicetree \
"
+
+# For systemd CAN bus configuration
+#MACHINE_FEATURES:append = " canfd"
+CANBUS_NETWORK_CONFIG = "canbus-can-fd.network"
+
diff --git a/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas/0001-Porting-to-support-device-driver-Canfd-from-Control-.patch b/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas/0001-Porting-to-support-device-driver-Canfd-from-Control-.patch
new file mode 100644
index 000000000..69fb1ace2
--- /dev/null
+++ b/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas/0001-Porting-to-support-device-driver-Canfd-from-Control-.patch
@@ -0,0 +1,1388 @@
+From a7e7a8317d5b150a97a08270ddfb711a88168add Mon Sep 17 00:00:00 2001
+From: Phat Pham <phat.pham.zg@renesas.com>
+Date: Wed, 2 Aug 2023 17:12:09 +0700
+Subject: [PATCH] Porting to support device driver Canfd from Control Domain to
+ Application Domain
+
+- Update pinctrl support for 15 canfd channels in file pfc-r8a779f0.c.
+- Update device tree to support GPIO Group 4-7 on CA55 in file r8a779f0.dtsi and r8a779f0-spider.dts,
+r8a779f0-s4sk.dts.
+- Update Canfd device nodes in device tree R9A779F0.
+- Update Source code support canfd device in rcar-canfd.c.
+
+Signed-off-by: Phat Pham <phat.pham.zg@renesas.com>
+Signed-off-by: Duy Dang <duy.dang.yw@renesas.com>
+---
+ arch/arm64/boot/dts/renesas/r8a779f0-s4sk.dts | 28 ++
+ .../boot/dts/renesas/r8a779f0-spider.dts | 160 ++++++++++++
+ arch/arm64/boot/dts/renesas/r8a779f0.dtsi | 170 +++++++++++-
+ drivers/net/can/rcar/rcar_can.c | 28 +-
+ drivers/net/can/rcar/rcar_canfd.c | 211 +++++++++++----
+ drivers/pinctrl/renesas/pfc-r8a779f0.c | 246 ++++++++++++++++++
+ 6 files changed, 780 insertions(+), 63 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/renesas/r8a779f0-s4sk.dts b/arch/arm64/boot/dts/renesas/r8a779f0-s4sk.dts
+index b6c61a20cd0d..1288285b5a9d 100644
+--- a/arch/arm64/boot/dts/renesas/r8a779f0-s4sk.dts
++++ b/arch/arm64/boot/dts/renesas/r8a779f0-s4sk.dts
+@@ -109,6 +109,24 @@ &mmc0 {
+ status = "okay";
+ };
+
++&canfd0 {
++ pinctrl-0 = <&canfd0_pins>, <&canfd1_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++};
++
++&canfd1 {
++ status = "disabled";
++};
++
+ &pfc {
+ pinctrl-0 = <&scif_clk_pins>;
+ pinctrl-names = "default";
+@@ -203,6 +221,16 @@ pins_mdio {
+ power-source = <3300>;
+ };
+ };
++
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
+ };
+
+ &rwdt {
+diff --git a/arch/arm64/boot/dts/renesas/r8a779f0-spider.dts b/arch/arm64/boot/dts/renesas/r8a779f0-spider.dts
+index 538f413fbffd..0d6b21fe0c07 100644
+--- a/arch/arm64/boot/dts/renesas/r8a779f0-spider.dts
++++ b/arch/arm64/boot/dts/renesas/r8a779f0-spider.dts
+@@ -27,6 +27,86 @@ eeprom@51 {
+ };
+ };
+
++&canfd0 {
++ pinctrl-0 = <&canfd0_pins>, <&canfd1_pins>, <&canfd2_pins>,
++ <&canfd3_pins>, <&canfd4_pins>, <&canfd5_pins>,
++ <&canfd6_pins>, <&canfd7_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++
++ channel2 {
++ status = "okay";
++ };
++
++ channel3 {
++ status = "okay";
++ };
++
++ channel4 {
++ status = "okay";
++ };
++
++ channel5 {
++ status = "okay";
++ };
++
++ channel6 {
++ status = "okay";
++ };
++
++ channel7 {
++ status = "okay";
++ };
++};
++
++&canfd1 {
++ pinctrl-0 = <&canfd8_pins>,<&canfd9_pins>, <&canfd10_pins>,
++ <&canfd11_pins>, <&canfd12_pins>, <&canfd13_pins>,
++ <&canfd14_pins>, <&canfd15_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ channel0 {
++ status = "okay";
++ };
++
++ channel1 {
++ status = "okay";
++ };
++
++ channel2 {
++ status = "okay";
++ };
++
++ channel3 {
++ status = "okay";
++ };
++
++ channel4 {
++ status = "okay";
++ };
++
++ channel5 {
++ status = "okay";
++ };
++
++ channel6 {
++ status = "okay";
++ };
++
++ channel7 {
++ status = "okay";
++ };
++};
++
+ &pfc {
+ tsn0_pins: tsn0 {
+ mux {
+@@ -73,6 +153,86 @@ pins_mdio {
+ };
+ };
+
++ canfd0_pins: canfd0 {
++ groups = "canfd0_data";
++ function = "canfd0";
++ };
++
++ canfd1_pins: canfd1 {
++ groups = "canfd1_data";
++ function = "canfd1";
++ };
++
++ canfd2_pins: canfd2 {
++ groups = "canfd2_data";
++ function = "canfd2";
++ };
++
++ canfd3_pins: canfd3 {
++ groups = "canfd3_data";
++ function = "canfd3";
++ };
++
++ canfd4_pins: canfd4 {
++ groups = "canfd4_data";
++ function = "canfd4";
++ };
++
++ canfd5_pins: canfd5 {
++ groups = "canfd5_data";
++ function = "canfd5";
++ };
++
++ canfd6_pins: canfd6 {
++ groups = "canfd6_data";
++ function = "canfd6";
++ };
++
++ canfd7_pins: canfd7 {
++ groups = "canfd7_data";
++ function = "canfd7";
++ };
++
++ canfd8_pins: canfd8 {
++ groups = "canfd8_data";
++ function = "canfd8";
++ };
++
++ canfd9_pins: canfd9 {
++ groups = "canfd9_data";
++ function = "canfd9";
++ };
++
++ canfd10_pins: canfd10 {
++ groups = "canfd10_data";
++ function = "canfd10";
++ };
++
++ canfd11_pins: canfd11 {
++ groups = "canfd11_data";
++ function = "canfd11";
++ };
++
++ canfd12_pins: canfd12 {
++ groups = "canfd12_data";
++ function = "canfd12";
++ };
++
++ canfd13_pins: canfd13 {
++ groups = "canfd13_data";
++ function = "canfd13";
++ };
++
++ canfd14_pins: canfd14 {
++ groups = "canfd14_data";
++ function = "canfd14";
++ };
++
++ canfd15_pins: canfd15 {
++ groups = "canfd15_data";
++ function = "canfd15";
++ };
++
+ pcie0_pins: pcie0 {
+ groups = "pcie0_clkreq_n";
+ function = "pcie";
+diff --git a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
+index ddda2fc3acd0..b930b93ab3f7 100644
+--- a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
++++ b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
+@@ -23,6 +23,13 @@ aliases {
+ i2c5 = &i2c5;
+ };
+
++ /* External CAN clock - to be overridden by boards that provide it */
++ can_clk: can {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <40000000>;
++ };
++
+ cluster1_opp: opp_table10 {
+ compatible = "operating-points-v2";
+ opp-shared;
+@@ -329,7 +336,7 @@ pfc: pin-controller@e6050000 {
+ compatible = "renesas,pfc-r8a779f0";
+ reg = <0 0xe6050000 0 0x16c>, <0 0xe6050800 0 0x16c>,
+ <0 0xe6051000 0 0x16c>, <0 0xe6051800 0 0x16c>,
+- <0 0xdfd90000 0 0x16c>, <0 0xdfd90800 0 0x16c>,
++ <0 0xdfd90000 0 0x16c>, <0 0xdfd90800 0 0x16c>,
+ <0 0xdfd91000 0 0x16c>, <0 0xdfd91800 0 0x16c>;
+ };
+
+@@ -389,6 +396,63 @@ gpio3: gpio@e6051980 {
+ resets = <&cpg 915>;
+ };
+
++ /* Porting GPIO GP 4~7 from Control Domain to Application Domain */
++ gpio4: gpio@dfd90180 {
++ compatible = "renesas,gpio-r8a779f0";
++ reg = <0 0xdfd90180 0 0x54>;
++ interrupts = <GIC_SPI 826 IRQ_TYPE_LEVEL_HIGH>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ gpio-ranges = <&pfc 0 128 31>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ clocks = <&cpg CPG_MOD 915>;
++ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
++ resets = <&cpg 915>;
++ };
++
++ gpio5: gpio@dfd90980 {
++ compatible = "renesas,gpio-r8a779f0";
++ reg = <0 0xdfd90980 0 0x54>;
++ interrupts = <GIC_SPI 827 IRQ_TYPE_LEVEL_HIGH>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ gpio-ranges = <&pfc 0 160 20>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ clocks = <&cpg CPG_MOD 915>;
++ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
++ resets = <&cpg 915>;
++ };
++
++ gpio6: gpio@dfd91180 {
++ compatible = "renesas,gpio-r8a779f0";
++ reg = <0 0xdfd91180 0 0x54>;
++ interrupts = <GIC_SPI 828 IRQ_TYPE_LEVEL_HIGH>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ gpio-ranges = <&pfc 0 192 24>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ clocks = <&cpg CPG_MOD 915>;
++ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
++ resets = <&cpg 915>;
++ };
++
++ gpio7: gpio@dfd91980 {
++ compatible = "renesas,gpio-r8a779f0";
++ reg = <0 0xdfd91980 0 0x54>;
++ interrupts = <GIC_SPI 829 IRQ_TYPE_LEVEL_HIGH>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ gpio-ranges = <&pfc 0 224 32>;
++ #interrupt-cells = <2>;
++ interrupt-controller;
++ clocks = <&cpg CPG_MOD 915>;
++ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
++ resets = <&cpg 915>;
++ };
++
+ cpg: clock-controller@e6150000 {
+ compatible = "renesas,r8a779f0-cpg-mssr";
+ reg = <0 0xe6150000 0 0x4000>;
+@@ -410,6 +474,110 @@ sysc: system-controller@e6180000 {
+ #power-domain-cells = <1>;
+ };
+
++ canfd0: can@dff50000 {
++ compatible = "renesas,r8a779f0-canfd";
++ reg = <0 0xdff50000 0 0x8600>;
++ interrupts = <GIC_SPI 534 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 535 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 536 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 537 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 538 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 539 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 540 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 541 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 542 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&can_clk>;
++ clock-names = "can_clk";
++ assigned-clocks = <&can_clk>;
++ assigned-clock-rates = <40000000>;
++ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
++ status = "okay";
++
++ channel0 {
++ status = "disabled";
++ };
++
++ channel1 {
++ status = "disabled";
++ };
++
++ channel2 {
++ status = "disabled";
++ };
++
++ channel3 {
++ status = "disabled";
++ };
++
++ channel4 {
++ status = "disabled";
++ };
++
++ channel5 {
++ status = "disabled";
++ };
++
++ channel6 {
++ status = "disabled";
++ };
++
++ channel7 {
++ status = "disabled";
++ };
++ };
++
++ canfd1: can@dfd00000 {
++ compatible = "renesas,r8a779f0-canfd";
++ reg = <0 0xdfd00000 0 0x8600>;
++ interrupts = <GIC_SPI 543 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 544 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 545 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 546 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 547 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 548 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 549 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 550 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 551 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&can_clk>;
++ clock-names = "can_clk";
++ assigned-clocks = <&can_clk>;
++ assigned-clock-rates = <40000000>;
++ power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
++ status = "okay";
++
++ channel0 {
++ status = "disabled";
++ };
++
++ channel1 {
++ status = "disabled";
++ };
++
++ channel2 {
++ status = "disabled";
++ };
++
++ channel3 {
++ status = "disabled";
++ };
++
++ channel4 {
++ status = "disabled";
++ };
++
++ channel5 {
++ status = "disabled";
++ };
++
++ channel6 {
++ status = "disabled";
++ };
++
++ channel7 {
++ status = "disabled";
++ };
++ };
++
+ i2c0: i2c@e6500000 {
+ compatible = "renesas,i2c-r8a779f0",
+ "renesas,rcar-gen4-i2c";
+diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c
+index 48575900adb7..134eda66f0dc 100644
+--- a/drivers/net/can/rcar/rcar_can.c
++++ b/drivers/net/can/rcar/rcar_can.c
+@@ -235,11 +235,8 @@ static void rcar_can_error(struct net_device *ndev)
+ if (eifr & (RCAR_CAN_EIFR_EWIF | RCAR_CAN_EIFR_EPIF)) {
+ txerr = readb(&priv->regs->tecr);
+ rxerr = readb(&priv->regs->recr);
+- if (skb) {
++ if (skb)
+ cf->can_id |= CAN_ERR_CRTL;
+- cf->data[6] = txerr;
+- cf->data[7] = rxerr;
+- }
+ }
+ if (eifr & RCAR_CAN_EIFR_BEIF) {
+ int rx_errors = 0, tx_errors = 0;
+@@ -339,6 +336,9 @@ static void rcar_can_error(struct net_device *ndev)
+ can_bus_off(ndev);
+ if (skb)
+ cf->can_id |= CAN_ERR_BUSOFF;
++ } else if (skb) {
++ cf->data[6] = txerr;
++ cf->data[7] = rxerr;
+ }
+ if (eifr & RCAR_CAN_EIFR_ORIF) {
+ netdev_dbg(priv->ndev, "Receive overrun error interrupt\n");
+@@ -846,10 +846,12 @@ static int __maybe_unused rcar_can_suspend(struct device *dev)
+ struct rcar_can_priv *priv = netdev_priv(ndev);
+ u16 ctlr;
+
+- if (netif_running(ndev)) {
+- netif_stop_queue(ndev);
+- netif_device_detach(ndev);
+- }
++ if (!netif_running(ndev))
++ return 0;
++
++ netif_stop_queue(ndev);
++ netif_device_detach(ndev);
++
+ ctlr = readw(&priv->regs->ctlr);
+ ctlr |= RCAR_CAN_CTLR_CANM_HALT;
+ writew(ctlr, &priv->regs->ctlr);
+@@ -868,6 +870,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
+ u16 ctlr;
+ int err;
+
++ if (!netif_running(ndev))
++ return 0;
++
+ err = clk_enable(priv->clk);
+ if (err) {
+ netdev_err(ndev, "clk_enable() failed, error %d\n", err);
+@@ -881,10 +886,9 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
+ writew(ctlr, &priv->regs->ctlr);
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+- if (netif_running(ndev)) {
+- netif_device_attach(ndev);
+- netif_start_queue(ndev);
+- }
++ netif_device_attach(ndev);
++ netif_start_queue(ndev);
++
+ return 0;
+ }
+
+diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
+index b458b5fd7900..e4f820308954 100644
+--- a/drivers/net/can/rcar/rcar_canfd.c
++++ b/drivers/net/can/rcar/rcar_canfd.c
+@@ -203,7 +203,7 @@
+ #define RCANFD_FDCFG_FDOE BIT(28)
+ #define RCANFD_FDCFG_TDCE BIT(9)
+ #define RCANFD_FDCFG_TDCOC BIT(8)
+-#define RCANFD_FDCFG_TDCO(x) (((x) & 0x7f) >> 16)
++#define RCANFD_FDCFG_TDCO(x) (((x) & 0xff) << 16)
+
+ /* RSCFDnCFDRFCCx */
+ #define RCANFD_RFCC_RFIM BIT(12)
+@@ -506,6 +506,7 @@
+ /* R-Car V3U Classical and CAN FD mode specific register map */
+ #define RCANFD_V3U_CFDCFG (0x1314)
+ #define RCANFD_V3U_DCFG(m) (0x1400 + (0x20 * (m)))
++#define RCANFD_V3U_FDCFG(m) (0x1404 + (0x20 * (m)))
+
+ #define RCANFD_V3U_GAFL_OFFSET (0x1800)
+
+@@ -574,6 +575,7 @@ struct rcar_canfd_channel {
+
+ enum rcar_canfd_chip_id {
+ R8A779G0,
++ R8A779F0,
+ R8A779A0,
+ GEN3,
+ };
+@@ -734,13 +736,17 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
+ rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0);
+
+ /* Set the controller into appropriate mode */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ if (gpriv->fdmode)
+- rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_CFDCFG,
+- RCANFD_FDCFG_FDOE);
++ {
++ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
++ rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_FDCFG(ch),
++ RCANFD_FDCFG_FDOE);
++ }
+ else
+- rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_CFDCFG,
+- RCANFD_FDCFG_CLOE);
++ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->max_channels)
++ rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_FDCFG(ch),
++ RCANFD_FDCFG_CLOE);
+ } else {
+ if (gpriv->fdmode)
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
+@@ -801,7 +807,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 ch, int num_ch_enabled)
+ {
+ u32 cfg;
+ int offset, start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
+@@ -812,7 +818,7 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
+ } else {
+ /* Get number of Channel 0 rules and adjust */
+ cfg = rcar_canfd_read(gpriv->base, RCANFD_V3U_GAFLCFG(ch));
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ start = ch * num_rules;
+ else
+ start = RCANFD_GAFLCFG_GETRNC(0, cfg);
+@@ -821,24 +827,28 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
+ /* Enable write access to entry */
+ page = RCANFD_GAFL_PAGENUM(start);
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
++ {
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLECTR,
+ (RCANFD_V3U_GAFLECTR_AFLPN(page) |
+ RCANFD_GAFLECTR_AFLDAE));
++ }
+ else
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLECTR,
+ (RCANFD_GAFLECTR_AFLPN(page) |
+ RCANFD_GAFLECTR_AFLDAE));
+
+ /* Write number of rules for channel */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
++ {
+ rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_GAFLCFG(ch),
+ RCANFD_V3U_GAFLCFG_SETRNC(ch, num_rules));
++ }
+ else
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG0,
+ RCANFD_GAFLCFG_SETRNC(ch, num_rules));
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ offset = RCANFD_V3U_GAFL_OFFSET;
+ } else {
+ if (gpriv->fdmode)
+@@ -848,13 +858,13 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
+ }
+
+ /* Accept all IDs */
+- rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, start), 0);
++ rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, num_ch_enabled), 0);
+ /* IDE or RTR is not considered for matching */
+- rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, start), 0);
++ rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, num_ch_enabled), 0);
+ /* Any data length accepted */
+- rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, start), 0);
++ rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, num_ch_enabled), 0);
+ /* Place the msg in corresponding Rx FIFO entry */
+- rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, start),
++ rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLP1(offset, num_ch_enabled),
+ RCANFD_GAFLP1_GAFLFDP(ridx));
+
+ /* Disable write access to page */
+@@ -879,10 +889,14 @@ static void rcar_canfd_configure_rx(struct rcar_canfd_global *gpriv, u32 ch)
+
+ cfg = (RCANFD_RFCC_RFIM | RCANFD_RFCC_RFDC(rfdc) |
+ RCANFD_RFCC_RFPLS(rfpls) | RCANFD_RFCC_RFIE);
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
++ {
+ rcar_canfd_write(gpriv->base, RCANFD_V3U_RFCC(ridx), cfg);
++ }
+ else
++ {
+ rcar_canfd_write(gpriv->base, RCANFD_RFCC(ridx), cfg);
++ }
+ }
+
+ static void rcar_canfd_configure_tx(struct rcar_canfd_global *gpriv, u32 ch)
+@@ -904,7 +918,7 @@ static void rcar_canfd_configure_tx(struct rcar_canfd_global *gpriv, u32 ch)
+ else
+ cfpls = 0; /* b000 - Max 8 bytes payload */
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ cfg = (RCANFD_V3U_CFCC_CFTML(cftml) | RCANFD_V3U_CFCC_CFM(cfm) |
+ RCANFD_V3U_CFCC_CFIM | RCANFD_V3U_CFCC_CFDC(cfdc) |
+ RCANFD_V3U_CFCC_CFPLS(cfpls) | RCANFD_V3U_CFCC_CFTXIE);
+@@ -919,8 +933,10 @@ static void rcar_canfd_configure_tx(struct rcar_canfd_global *gpriv, u32 ch)
+ }
+ if (gpriv->fdmode) {
+ /* Clear FD mode specific control/status register */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
++ {
+ addr = RCANFD_V3U_CFFDCSTS(ch, RCANFD_CFFIFO_IDX);
++ }
+ else
+ addr = RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX);
+
+@@ -938,7 +954,9 @@ static void rcar_canfd_enable_global_interrupts(struct rcar_canfd_global *gpriv)
+ /* Global interrupts setup */
+ ctr = RCANFD_GCTR_MEIE;
+ if (gpriv->fdmode)
++ {
+ ctr |= RCANFD_GCTR_CFMPOFIE;
++ }
+
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, ctr);
+ }
+@@ -1005,7 +1023,7 @@ static void rcar_canfd_global_error(struct net_device *ndev)
+ stats->tx_dropped++;
+ }
+ if (gerfl & RCANFD_GERFL_MES) {
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ addr = RCANFD_V3U_CFSTS(ch, RCANFD_CFFIFO_IDX);
+ else
+ addr = RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX);
+@@ -1018,7 +1036,7 @@ static void rcar_canfd_global_error(struct net_device *ndev)
+ rcar_canfd_write(priv->base, addr,
+ sts & ~RCANFD_CFSTS_CFMLT);
+ }
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ addr = RCANFD_V3U_RFSTS(ridx);
+ else
+ addr = RCANFD_RFSTS(ridx);
+@@ -1171,8 +1189,10 @@ static void rcar_canfd_tx_done(struct net_device *ndev)
+ u32 ch = priv->channel;
+ struct rcar_canfd_global *gpriv = priv->gpriv;
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
++ {
+ addr = RCANFD_V3U_CFSTS(ch, RCANFD_CFFIFO_IDX);
++ }
+ else
+ addr = RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX);
+
+@@ -1227,7 +1247,7 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
+
+ /* Global error interrupts */
+ gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL);
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ if (unlikely(RCANFD_V3U_GERFL_ERR(gpriv, gerfl)))
+ rcar_canfd_global_error(ndev);
+ } else {
+@@ -1235,7 +1255,7 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
+ rcar_canfd_global_error(ndev);
+ }
+ /* Handle Rx interrupts */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ addr1 = RCANFD_V3U_RFSTS(ridx);
+ addr2 = RCANFD_V3U_RFCC(ridx);
+ } else {
+@@ -1307,6 +1327,7 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
+ 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);
+
+@@ -1316,19 +1337,57 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
+ rcar_canfd_state_change(ndev, txerr, rxerr);
+
+ /* Handle Tx interrupts */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
++ {
+ addr = RCANFD_V3U_CFSTS(ch, RCANFD_CFFIFO_IDX);
++ }
+ else
++ {
+ addr = RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX);
++ }
+
+ sts = rcar_canfd_read(priv->base, addr);
+
+ if (likely(sts & RCANFD_CFSTS_CFTXIF))
++ {
+ rcar_canfd_tx_done(ndev);
++ }
+ }
+ return IRQ_HANDLED;
+ }
+
++static void rcar_canfd_set_samplepoint(struct net_device *dev)
++{
++ struct rcar_canfd_channel *priv = netdev_priv(dev);
++ u32 ch = priv->channel;
++ u16 tdco;
++ u32 cfg;
++ struct rcar_canfd_global *gpriv = priv->gpriv;
++
++ /* Sample point settings */
++ tdco = 2; /* TDCO = 2Tq */
++
++ /* Transceiver Delay Compensation Offset Configuration */
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
++ cfg = (RCANFD_FDCFG_TDCE |
++ RCANFD_FDCFG_TDCO(tdco));
++ rcar_canfd_set_bit(priv->base, RCANFD_V3U_FDCFG(ch), cfg);
++ }
++}
++
++static void rcar_canfd_unset_samplepoint(struct net_device *dev)
++{
++ struct rcar_canfd_channel *priv = netdev_priv(dev);
++ u32 ch = priv->channel;
++ u32 cfg;
++ struct rcar_canfd_global *gpriv = priv->gpriv;
++
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
++ cfg = RCANFD_FDCFG_TDCE; /* Disable TDC */
++ rcar_canfd_clear_bit(priv->base, RCANFD_V3U_FDCFG(ch), cfg);
++ }
++}
++
+ static void rcar_canfd_set_bittiming(struct net_device *dev)
+ {
+ struct rcar_canfd_channel *priv = netdev_priv(dev);
+@@ -1342,12 +1401,12 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
+ /* Nominal bit timing settings */
+ brp = bt->brp - 1;
+ sjw = bt->sjw - 1;
+- tseg1 = bt->prop_seg + bt->phase_seg1 + 1;
++ tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+ tseg2 = bt->phase_seg2 - 1;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ /* CAN FD only mode */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ cfg = (RCANFD_V3U_NCFG_NTSEG1(tseg1) |
+ RCANFD_V3U_NCFG_NBRP(brp) |
+ RCANFD_V3U_NCFG_NSJW(sjw) |
+@@ -1365,10 +1424,16 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
+ /* Data bit timing settings */
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+- tseg1 = dbt->prop_seg + dbt->phase_seg1 + 1;
++ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ /* Set Secondary Sample Point for high baud rate */
++ if (brp == 0 && tseg1 <= 5 && tseg2 == 1)
++ rcar_canfd_set_samplepoint(dev);
++ else
++ rcar_canfd_unset_samplepoint(dev);
++
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ cfg = (RCANFD_V3U_DCFG_DTSEG1(tseg1) |
+ RCANFD_V3U_DCFG_DBRP(brp) |
+ RCANFD_V3U_DCFG_DSJW(sjw) |
+@@ -1387,7 +1452,7 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
+ brp, sjw, tseg1, tseg2);
+ } else {
+ /* Classical CAN only mode */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ cfg = (RCANFD_V3U_NCFG_NTSEG1(tseg1) |
+ RCANFD_V3U_NCFG_NBRP(brp) |
+ RCANFD_V3U_NCFG_NSJW(sjw) |
+@@ -1430,7 +1495,7 @@ static int rcar_canfd_start(struct net_device *ndev)
+ }
+
+ /* Enable Common & Rx FIFO */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ addr1 = RCANFD_V3U_CFCC(ch, RCANFD_CFFIFO_IDX);
+ addr2 = RCANFD_V3U_RFCC(ridx);
+ } else {
+@@ -1505,7 +1570,7 @@ static void rcar_canfd_stop(struct net_device *ndev)
+ rcar_canfd_disable_channel_interrupts(priv);
+
+ /* Disable Common & Rx FIFO */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ addr1 = RCANFD_V3U_CFCC(ch, RCANFD_CFFIFO_IDX);
+ addr2 = RCANFD_V3U_RFCC(ridx);
+ } else {
+@@ -1544,7 +1609,9 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
+ struct rcar_canfd_global *gpriv = priv->gpriv;
+
+ if (can_dropped_invalid_skb(ndev, skb))
++ {
+ return NETDEV_TX_OK;
++ }
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ id = cf->can_id & CAN_EFF_MASK;
+@@ -1554,11 +1621,13 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
+ }
+
+ if (cf->can_id & CAN_RTR_FLAG)
++ {
+ id |= RCANFD_CFID_CFRTR;
++ }
+
+ dlc = RCANFD_CFPTR_CFDLC(can_len2dlc(cf->len));
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ rcar_canfd_write(priv->base,
+ RCANFD_V3U_CFID(ch, RCANFD_CFFIFO_IDX), id);
+ rcar_canfd_write(priv->base,
+@@ -1622,7 +1691,7 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
+ /* Start Tx: Write 0xff to CFPC to increment the CPU-side
+ * pointer for the Common FIFO
+ */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ addr = RCANFD_V3U_CFPCTR(ch, RCANFD_CFFIFO_IDX);
+ else
+ addr = RCANFD_CFPCTR(ch, RCANFD_CFFIFO_IDX);
+@@ -1630,6 +1699,7 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
+ rcar_canfd_write(priv->base, addr, 0xff);
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
++
+ return NETDEV_TX_OK;
+ }
+
+@@ -1643,7 +1713,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
+ u32 ridx = ch + RCANFD_RFFIFO_IDX;
+ struct rcar_canfd_global *gpriv = priv->gpriv;
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ id = rcar_canfd_read(priv->base, RCANFD_V3U_RFID(ridx));
+ dlc = rcar_canfd_read(priv->base, RCANFD_V3U_RFPTR(ridx));
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+@@ -1707,7 +1777,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
+ if (sts & RCANFD_RFFDSTS_RFBRS)
+ cf->flags |= CANFD_BRS;
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ rcar_canfd_get_data(priv, cf,
+ RCANFD_V3U_RFDF(ridx, 0));
+ else
+@@ -1719,7 +1789,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
+ if (id & RCANFD_RFID_RFRTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ rcar_canfd_get_data(priv, cf,
+ RCANFD_V3U_RFDF(ridx, 0));
+ else
+@@ -1730,7 +1800,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
+ /* Write 0xff to RFPC to increment the CPU-side
+ * pointer of the Rx FIFO
+ */
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0))
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0)
+ rcar_canfd_write(priv->base, RCANFD_V3U_RFPCTR(ridx), 0xff);
+ else
+ rcar_canfd_write(priv->base, RCANFD_RFPCTR(ridx), 0xff);
+@@ -1752,7 +1822,7 @@ static int rcar_canfd_rx_poll(struct napi_struct *napi, int quota)
+ u32 ridx = ch + RCANFD_RFFIFO_IDX, addr1, addr2;
+ struct rcar_canfd_global *gpriv = priv->gpriv;
+
+- if ((gpriv->chip_id == R8A779A0) || (gpriv->chip_id == R8A779G0)) {
++ if (gpriv->chip_id == R8A779A0 || gpriv->chip_id == R8A779G0 || gpriv->chip_id == R8A779F0) {
+ addr1 = RCANFD_V3U_RFSTS(ridx);
+ addr2 = RCANFD_V3U_RFCC(ridx);
+ } else {
+@@ -1867,15 +1937,15 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
+
+ netif_napi_add(ndev, &priv->napi, rcar_canfd_rx_poll,
+ RCANFD_NAPI_WEIGHT);
++ spin_lock_init(&priv->tx_lock);
++ devm_can_led_init(ndev);
++ gpriv->ch[priv->channel] = priv;
+ err = register_candev(ndev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "register_candev() failed, error %d\n", err);
+ goto fail_candev;
+ }
+- spin_lock_init(&priv->tx_lock);
+- devm_can_led_init(ndev);
+- gpriv->ch[priv->channel] = priv;
+ dev_info(&pdev->dev, "device registered (channel %u)\n", priv->channel);
+ return 0;
+
+@@ -1904,7 +1974,8 @@ 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, i;
++ int err, g_irq, ch_irq, i, num_ch_enabled = 0;
++ int ch_irq_s4[RCANFD_NUM_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
+ bool fdmode = true; /* CAN FD only mode - default */
+ const struct rcar_canfd_of_data *of_data;
+ char *name[RCANFD_NUM_CHANNELS] = {
+@@ -1925,13 +1996,28 @@ static int rcar_canfd_probe(struct platform_device *pdev)
+ channels_mask |= BIT(i); /* Channel i */
+ }
+
+- ch_irq = platform_get_irq(pdev, 0);
++ /* ch_irq = platform_get_irq(pdev, 0);
+ if (ch_irq < 0) {
+ err = ch_irq;
+ goto fail_dev;
+ }
+
+ g_irq = platform_get_irq(pdev, 1);
++ if (g_irq < 0) {
++ err = g_irq;
++ goto fail_dev;
++ } */
++
++ /* Porting for R8A779F0 */
++ for (i = 0; i < RCANFD_NUM_CHANNELS; i++) {
++ ch_irq_s4[i] = platform_get_irq(pdev, i + 1);
++ if (ch_irq_s4[i] < 0) {
++ err = ch_irq_s4[i];
++ goto fail_dev;
++ }
++ }
++
++ g_irq = platform_get_irq(pdev, 0);
+ if (g_irq < 0) {
+ err = g_irq;
+ goto fail_dev;
+@@ -1950,13 +2036,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)
+ gpriv->max_channels = of_data->max_channels;
+
+ /* Peripheral clock */
+- gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
++ /* Porting for R8A779F0, not use fck */
++ /* gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
+ if (IS_ERR(gpriv->clkp)) {
+ err = PTR_ERR(gpriv->clkp);
+ dev_err(&pdev->dev, "cannot get peripheral clock, error %d\n",
+ err);
+ goto fail_dev;
+- }
++ } */
+
+ /* fCAN clock: Pick External clock. If not available fallback to
+ * CANFD clock
+@@ -1971,15 +2058,16 @@ static int rcar_canfd_probe(struct platform_device *pdev)
+ goto fail_dev;
+ }
+ gpriv->fcan = RCANFD_CANFDCLK;
+-
+ } else {
+ gpriv->fcan = RCANFD_EXTCLK;
+ }
+ fcan_freq = clk_get_rate(gpriv->can_clk);
+
+ if (gpriv->fcan == RCANFD_CANFDCLK)
++ {
+ /* CANFD clock is further divided by (1/2) within the IP */
+ fcan_freq /= 2;
++ }
+
+ addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(addr)) {
+@@ -1989,14 +2077,27 @@ 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);
++ /* 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;
++ } */
++
++ /* Porting for R8A779F0 */
++ for (i = 0; i < RCANFD_NUM_CHANNELS; i++) {
++ err = devm_request_irq(&pdev->dev, ch_irq_s4[i],
++ rcar_canfd_channel_interrupt, 0,
++ "canfd.chn", gpriv);
++ if (err) {
++ dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
++ ch_irq_s4[i], err);
++ goto fail_dev;
++ }
+ }
++
+ err = devm_request_irq(&pdev->dev, g_irq,
+ rcar_canfd_global_interrupt, 0,
+ "canfd.gbl", gpriv);
+@@ -2032,7 +2133,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
+ rcar_canfd_configure_tx(gpriv, ch);
+
+ /* Configure receive rules */
+- rcar_canfd_configure_afl_rules(gpriv, ch);
++ rcar_canfd_configure_afl_rules(gpriv, ch, num_ch_enabled);
++ num_ch_enabled++;
+ }
+
+ /* Configure common interrupts */
+@@ -2109,6 +2211,11 @@ static const struct rcar_canfd_of_data of_rcanfd_v4h_compatible = {
+ .max_channels = 8,
+ };
+
++static const struct rcar_canfd_of_data of_rcanfd_s4_compatible = {
++ .chip_id = R8A779F0,
++ .max_channels = 8,
++};
++
+ static const struct rcar_canfd_of_data of_rcanfd_v3u_compatible = {
+ .chip_id = R8A779A0,
+ .max_channels = 8,
+@@ -2124,6 +2231,10 @@ static const struct of_device_id rcar_canfd_of_table[] = {
+ .compatible = "renesas,r8a779g0-canfd",
+ .data = &of_rcanfd_v4h_compatible,
+ },
++ {
++ .compatible = "renesas,r8a779f0-canfd",
++ .data = &of_rcanfd_s4_compatible,
++ },
+ {
+ .compatible = "renesas,r8a779a0-canfd",
+ .data = &of_rcanfd_v3u_compatible,
+diff --git a/drivers/pinctrl/renesas/pfc-r8a779f0.c b/drivers/pinctrl/renesas/pfc-r8a779f0.c
+index de01d4d6b1b1..822b4f7e450f 100644
+--- a/drivers/pinctrl/renesas/pfc-r8a779f0.c
++++ b/drivers/pinctrl/renesas/pfc-r8a779f0.c
+@@ -11,8 +11,10 @@
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+
++#include "core.h"
+ #include "sh_pfc.h"
+
++#define ENABLE_ACCESS_TO_CONTROL_DOMAIN
+ #define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN)
+
+ #define CPU_ALL_GP(fn, sfx) \
+@@ -1170,6 +1172,150 @@ static const struct sh_pfc_pin pinmux_pins[] = {
+ PINMUX_GPIO_GP_ALL(),
+ };
+
++/* - CANFD0 ----------------------------------------------------------------- */
++static const unsigned int canfd0_data_pins[] = {
++ /* CANFD0_TX, CANFD0_RX */
++ RCAR_GP_PIN(7, 0), RCAR_GP_PIN(7, 1),
++};
++static const unsigned int canfd0_data_mux[] = {
++ CAN0TX_MARK, CAN0RX_INTP0_MARK,
++};
++
++/* - CANFD1 ----------------------------------------------------------------- */
++static const unsigned int canfd1_data_pins[] = {
++ /* CANFD1_TX, CANFD1_RX */
++ RCAR_GP_PIN(7, 2), RCAR_GP_PIN(7, 3),
++};
++static const unsigned int canfd1_data_mux[] = {
++ CAN1TX_MARK, CAN1RX_INTP1_MARK,
++};
++
++/* - CANFD2 ----------------------------------------------------------------- */
++static const unsigned int canfd2_data_pins[] = {
++ /* CANFD2_TX, CANFD2_RX */
++ RCAR_GP_PIN(7, 4), RCAR_GP_PIN(7, 5),
++};
++static const unsigned int canfd2_data_mux[] = {
++ CAN2TX_MARK, CAN2RX_INTP2_MARK,
++};
++
++/* - CANFD3 ----------------------------------------------------------------- */
++static const unsigned int canfd3_data_pins[] = {
++ /* CANFD2_TX, CANFD2_RX */
++ RCAR_GP_PIN(7, 6), RCAR_GP_PIN(7, 7),
++};
++static const unsigned int canfd3_data_mux[] = {
++ CAN3TX_MARK, CAN3RX_INTP3_MARK,
++};
++
++/* - CANFD4 ----------------------------------------------------------------- */
++static const unsigned int canfd4_data_pins[] = {
++ /* CANFD4_TX, CANFD4_RX */
++ RCAR_GP_PIN(7, 8), RCAR_GP_PIN(7, 9),
++};
++static const unsigned int canfd4_data_mux[] = {
++ CAN4TX_MARK, CAN4RX_INTP4_MARK,
++};
++
++/* - CANFD5 ----------------------------------------------------------------- */
++static const unsigned int canfd5_data_pins[] = {
++ /* CANFD5_TX, CANFD5_RX */
++ RCAR_GP_PIN(7, 10), RCAR_GP_PIN(7, 11),
++};
++static const unsigned int canfd5_data_mux[] = {
++ CAN5TX_MARK, CAN5RX_INTP5_MARK,
++};
++
++/* - CANFD6 ----------------------------------------------------------------- */
++static const unsigned int canfd6_data_pins[] = {
++ /* CANFD6_TX, CANFD6_RX */
++ RCAR_GP_PIN(7, 12), RCAR_GP_PIN(7, 13),
++};
++static const unsigned int canfd6_data_mux[] = {
++ CAN6TX_MARK, CAN6RX_INTP6_MARK,
++};
++
++/* - CANFD7 ----------------------------------------------------------------- */
++static const unsigned int canfd7_data_pins[] = {
++ /* CANFD7_TX, CANFD7_RX */
++ RCAR_GP_PIN(7, 14), RCAR_GP_PIN(7, 15),
++};
++static const unsigned int canfd7_data_mux[] = {
++ CAN7TX_MARK, CAN7RX_INTP7_MARK,
++};
++
++/* - CANFD8 ----------------------------------------------------------------- */
++static const unsigned int canfd8_data_pins[] = {
++ /* CANFD8_TX, CANFD8_RX */
++ RCAR_GP_PIN(7, 16), RCAR_GP_PIN(7, 17),
++};
++static const unsigned int canfd8_data_mux[] = {
++ CAN8TX_MARK, CAN8RX_INTP8_MARK,
++};
++
++/* - CANFD9 ----------------------------------------------------------------- */
++static const unsigned int canfd9_data_pins[] = {
++ /* CANFD9_TX, CANFD9_RX */
++ RCAR_GP_PIN(7, 18), RCAR_GP_PIN(7, 19),
++};
++static const unsigned int canfd9_data_mux[] = {
++ CAN9TX_MARK, CAN9RX_INTP9_MARK,
++};
++
++/* - CANFD10 ----------------------------------------------------------------- */
++static const unsigned int canfd10_data_pins[] = {
++ /* CANFD10_TX, CANFD10_RX */
++ RCAR_GP_PIN(7, 20), RCAR_GP_PIN(7, 21),
++};
++static const unsigned int canfd10_data_mux[] = {
++ CAN10TX_MARK, CAN10RX_INTP10_MARK,
++};
++
++/* - CANFD11 ----------------------------------------------------------------- */
++static const unsigned int canfd11_data_pins[] = {
++ /* CANFD11_TX, CANFD11_RX */
++ RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 23),
++};
++static const unsigned int canfd11_data_mux[] = {
++ CAN11TX_MARK, CAN11RX_INTP11_MARK,
++};
++
++/* - CANFD12 ----------------------------------------------------------------- */
++static const unsigned int canfd12_data_pins[] = {
++ /* CANFD12_TX, CANFD12_RX */
++ RCAR_GP_PIN(7, 24), RCAR_GP_PIN(7, 25),
++};
++static const unsigned int canfd12_data_mux[] = {
++ CAN12TX_MARK, CAN12RX_INTP12_MARK,
++};
++
++/* - CANFD13 ----------------------------------------------------------------- */
++static const unsigned int canfd13_data_pins[] = {
++ /* CANFD13_TX, CANFD13_RX */
++ RCAR_GP_PIN(7, 26), RCAR_GP_PIN(7, 27),
++};
++static const unsigned int canfd13_data_mux[] = {
++ CAN13TX_MARK, CAN13RX_INTP13_MARK,
++};
++
++/* - CANFD14 ----------------------------------------------------------------- */
++static const unsigned int canfd14_data_pins[] = {
++ /* CANFD14_TX, CANFD14_RX */
++ RCAR_GP_PIN(7, 28), RCAR_GP_PIN(7, 29),
++};
++static const unsigned int canfd14_data_mux[] = {
++ CAN14TX_MARK, CAN14RX_INTP14_MARK,
++};
++
++/* - CANFD15 ----------------------------------------------------------------- */
++static const unsigned int canfd15_data_pins[] = {
++ /* CANFD15_TX, CANFD15_RX */
++ RCAR_GP_PIN(7, 30), RCAR_GP_PIN(7, 31),
++};
++static const unsigned int canfd15_data_mux[] = {
++ CAN15TX_MARK, CAN15RX_INTP15_MARK,
++};
++
+ /* - TSN0 ------------------------------------------------ */
+ static const unsigned int tsn0_link_pins[] = {
+ /* TSN0_LINK */
+@@ -1893,6 +2039,88 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(taud1_pwm5),
+ SH_PFC_PIN_GROUP(taud1_pwm6),
+ SH_PFC_PIN_GROUP(taud1_pwm7),
++
++ SH_PFC_PIN_GROUP(canfd0_data),
++ SH_PFC_PIN_GROUP(canfd1_data),
++ SH_PFC_PIN_GROUP(canfd2_data),
++ SH_PFC_PIN_GROUP(canfd3_data),
++ SH_PFC_PIN_GROUP(canfd4_data),
++ SH_PFC_PIN_GROUP(canfd5_data),
++ SH_PFC_PIN_GROUP(canfd6_data),
++ SH_PFC_PIN_GROUP(canfd7_data),
++
++ SH_PFC_PIN_GROUP(canfd8_data),
++ SH_PFC_PIN_GROUP(canfd9_data),
++ SH_PFC_PIN_GROUP(canfd10_data),
++ SH_PFC_PIN_GROUP(canfd11_data),
++ SH_PFC_PIN_GROUP(canfd12_data),
++ SH_PFC_PIN_GROUP(canfd13_data),
++ SH_PFC_PIN_GROUP(canfd14_data),
++ SH_PFC_PIN_GROUP(canfd15_data),
++};
++
++static const char * const canfd0_groups[] = {
++ "canfd0_data",
++};
++
++static const char * const canfd1_groups[] = {
++ "canfd1_data",
++};
++
++static const char * const canfd2_groups[] = {
++ "canfd2_data",
++};
++
++static const char * const canfd3_groups[] = {
++ "canfd3_data",
++};
++
++static const char * const canfd4_groups[] = {
++ "canfd4_data",
++};
++
++static const char * const canfd5_groups[] = {
++ "canfd5_data",
++};
++
++static const char * const canfd6_groups[] = {
++ "canfd6_data",
++};
++
++static const char * const canfd7_groups[] = {
++ "canfd7_data",
++};
++
++static const char * const canfd8_groups[] = {
++ "canfd8_data",
++};
++
++static const char * const canfd9_groups[] = {
++ "canfd9_data",
++};
++
++static const char * const canfd10_groups[] = {
++ "canfd10_data",
++};
++
++static const char * const canfd11_groups[] = {
++ "canfd11_data",
++};
++
++static const char * const canfd12_groups[] = {
++ "canfd12_data",
++};
++
++static const char * const canfd13_groups[] = {
++ "canfd13_data",
++};
++
++static const char * const canfd14_groups[] = {
++ "canfd14_data",
++};
++
++static const char * const canfd15_groups[] = {
++ "canfd15_data",
+ };
+
+ static const char * const tsn0_groups[] = {
+@@ -2050,6 +2278,24 @@ static const char * const taud1_pwm_groups[] = {
+ };
+
+ static const struct sh_pfc_function pinmux_functions[] = {
++ SH_PFC_FUNCTION(canfd0),
++ SH_PFC_FUNCTION(canfd1),
++ SH_PFC_FUNCTION(canfd2),
++ SH_PFC_FUNCTION(canfd3),
++ SH_PFC_FUNCTION(canfd4),
++ SH_PFC_FUNCTION(canfd5),
++ SH_PFC_FUNCTION(canfd6),
++ SH_PFC_FUNCTION(canfd7),
++
++ SH_PFC_FUNCTION(canfd8),
++ SH_PFC_FUNCTION(canfd9),
++ SH_PFC_FUNCTION(canfd10),
++ SH_PFC_FUNCTION(canfd11),
++ SH_PFC_FUNCTION(canfd12),
++ SH_PFC_FUNCTION(canfd13),
++ SH_PFC_FUNCTION(canfd14),
++ SH_PFC_FUNCTION(canfd15),
++
+ SH_PFC_FUNCTION(tsn0),
+ SH_PFC_FUNCTION(tsn1),
+ SH_PFC_FUNCTION(tsn2),
+--
+2.25.1
+
diff --git a/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas_%.bbappend b/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas_%.bbappend
index d565da8ac..4baf07552 100644
--- a/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas_%.bbappend
+++ b/meta-agl-bsp/meta-rcar-gateway/recipes-kernel/linux/linux-renesas_%.bbappend
@@ -1,3 +1,9 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI:append = " \
+ ${@bb.utils.contains('MACHINE_FEATURES', 'canfd', 'file://0001-Porting-to-support-device-driver-Canfd-from-Control-.patch', '', d)} \
+"
+
do_install:append () {
# Remove firmware file that is not packaged in the kernel.