* [PATCH] can: rcar_canfd: Add Classical CAN only mode support
@ 2016-06-20 14:46 Ramesh Shanmugasundaram
2016-06-21 13:29 ` Rob Herring
2016-06-22 12:31 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Ramesh Shanmugasundaram
0 siblings, 2 replies; 7+ messages in thread
From: Ramesh Shanmugasundaram @ 2016-06-20 14:46 UTC (permalink / raw)
To: mkl-bIcnvbaLZ9MEGnE8C9+IrQ, wg-5Yr1BZd7O62+XT7JhA+gdA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ
Cc: ulrich.hecht+renesas-Re5JQEeQqe8AvxtiuMwx3w,
horms-/R6kz+dDXgpPR4JQBCEnsQ,
linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-can-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
chris.paterson2-zM6kxYcvzFBBDgjK7y7TUQ,
magnus.damm-Re5JQEeQqe8AvxtiuMwx3w,
socketcan-fJ+pQTUTwRTk1uMJSBkQmQ, Ramesh Shanmugasundaram
The controller can operate in one of the two global modes
- CAN FD only mode (default)
- Classical CAN (CAN2.0) only mode
This patch adds support for Classical CAN only mode. It can be enabled
by defining the optional device tree property "renesas,can-nofd" of this
node.
Note: R-Car Gen3 h/w manual v0.51E shows bit6 of RSCFDnCFDGCFG as
reserved, which is incorrect. This bit is same as RSCFDnGCFG.
Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram-kTT6dE0pTRh9uiUsa/gSgQ@public.gmane.org>
---
Hi Marc, All,
This patch is based on top of can-next(tag:linux-can-next-for-4.8-20160617).
Thanks,
Ramesh.
---
.../devicetree/bindings/net/can/rcar_canfd.txt | 9 +-
drivers/net/can/rcar/rcar_canfd.c | 355 ++++++++++++++-------
2 files changed, 249 insertions(+), 115 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
index d45182b..a343359 100644
--- a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
+++ b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
@@ -32,6 +32,12 @@ below properties.
- assigned-clocks: phandle of canfd clock.
- assigned-clock-rates: maximum frequency of this clock.
+Optional property:
+The controller can operate in either CAN FD only mode (default) or
+Classical CAN only mode. The mode is global to both the channels. In order to
+enable the later, define the following optional property.
+ - renesas,can-nofd: puts the controller in Classical CAN only mode.
+
Example
-------
@@ -63,11 +69,12 @@ SoC common .dtsi file:
Board specific .dts file:
-E.g. below enables Channel 1 alone in the board.
+E.g. below enables Channel 1 alone in the board in Classical CAN only mode.
&canfd {
pinctrl-0 = <&canfd1_pins>;
pinctrl-names = "default";
+ renesas,can-nofd;
status = "okay";
channel1 {
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index a39d922..747e576b 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -16,8 +16,9 @@
* mode, the controller acts as a CAN FD node that can also interoperate with
* CAN 2.0 nodes.
*
- * As of now, this driver does not support the Classical CAN (CAN 2.0) mode,
- * which is handled by a different register map compared to CAN FD only mode.
+ * To switch the controller to Classical CAN (CAN 2.0) only mode, add
+ * "renesas,can-nofd" optional property to the device tree node. A h/w reset is
+ * also required to switch modes.
*
* Note: The h/w manual register naming convention is clumsy and not acceptable
* to use as it is in the driver. However, those names are added as comments
@@ -48,15 +49,16 @@
/* RSCFDnCFDGRMCFG */
#define RCANFD_GRMCFG_RCMC BIT(0)
-/* RSCFDnCFDGCFG */
-#define RCANFD_GCFG_CMPOC BIT(5)
+/* RSCFDnCFDGCFG / RSCFDnGCFG */
+#define RCANFD_GCFG_EEFE BIT(6)
+#define RCANFD_GCFG_CMPOC BIT(5) /* CAN FD only */
#define RCANFD_GCFG_DCS BIT(4)
#define RCANFD_GCFG_DCE BIT(1)
#define RCANFD_GCFG_TPRI BIT(0)
-/* RSCFDnCFDGCTR */
+/* RSCFDnCFDGCTR / RSCFDnGCTR */
#define RCANFD_GCTR_TSRST BIT(16)
-#define RCANFD_GCTR_CFMPOFIE BIT(11)
+#define RCANFD_GCTR_CFMPOFIE BIT(11) /* CAN FD only */
#define RCANFD_GCTR_THLEIE BIT(10)
#define RCANFD_GCTR_MEIE BIT(9)
#define RCANFD_GCTR_DEIE BIT(8)
@@ -66,7 +68,7 @@
#define RCANFD_GCTR_GMDC_GRESET (0x1)
#define RCANFD_GCTR_GMDC_GTEST (0x2)
-/* RSCFDnCFDGSTS */
+/* RSCFDnCFDGSTS / RSCFDnGSTS */
#define RCANFD_GSTS_GRAMINIT BIT(3)
#define RCANFD_GSTS_GSLPSTS BIT(2)
#define RCANFD_GSTS_GHLTSTS BIT(1)
@@ -74,44 +76,50 @@
/* Non-operational status */
#define RCANFD_GSTS_GNOPM (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-/* RSCFDnCFDGERFL */
+/* RSCFDnCFDGERFL / RSCFDnGERFL */
#define RCANFD_GERFL_EEF1 BIT(17)
#define RCANFD_GERFL_EEF0 BIT(16)
-#define RCANFD_GERFL_CMPOF BIT(3)
+#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(x) ((x) & (RCANFD_GERFL_EEF1 |\
- RCANFD_GERFL_EEF0 |\
- RCANFD_GERFL_MES |\
- RCANFD_GERFL_CMPOF))
+#define RCANFD_GERFL_ERR(gpriv, x) ((x) & (RCANFD_GERFL_EEF1 |\
+ RCANFD_GERFL_EEF0 | RCANFD_GERFL_MES |\
+ (gpriv->fdmode ?\
+ RCANFD_GERFL_CMPOF : 0)))
/* AFL Rx rules registers */
-/* RSCFDnCFDGAFLCFG0 */
+/* RSCFDnCFDGAFLCFG0 / RSCFDnGAFLCFG0 */
#define RCANFD_GAFLCFG_SETRNC(n, x) (((x) & 0xff) << (24 - n * 8))
#define RCANFD_GAFLCFG_GETRNC(n, x) (((x) >> (24 - n * 8)) & 0xff)
-/* RSCFDnCFDGAFLECTR */
+/* RSCFDnCFDGAFLECTR / RSCFDnGAFLECTR */
#define RCANFD_GAFLECTR_AFLDAE BIT(8)
#define RCANFD_GAFLECTR_AFLPN(x) ((x) & 0x1f)
-/* RSCFDnCFDGAFLIDj */
+/* RSCFDnCFDGAFLIDj / RSCFDnGAFLIDj */
#define RCANFD_GAFLID_GAFLLB BIT(29)
-/* RSCFDnCFDGAFLP1_j */
+/* RSCFDnCFDGAFLP1_j / RSCFDnGAFLP1_j */
#define RCANFD_GAFLP1_GAFLFDP(x) (1 << (x))
/* Channel register bits */
-/* RSCFDnCFDCmNCFG */
+/* RSCFDnCmCFG - Classical CAN only */
+#define RCANFD_CFG_SJW(x) (((x) & 0x3) << 24)
+#define RCANFD_CFG_TSEG2(x) (((x) & 0x7) << 20)
+#define RCANFD_CFG_TSEG1(x) (((x) & 0xf) << 16)
+#define RCANFD_CFG_BRP(x) (((x) & 0x3ff) << 0)
+
+/* RSCFDnCFDCmNCFG - CAN FD only */
#define RCANFD_NCFG_NTSEG2(x) (((x) & 0x1f) << 24)
#define RCANFD_NCFG_NTSEG1(x) (((x) & 0x7f) << 16)
#define RCANFD_NCFG_NSJW(x) (((x) & 0x1f) << 11)
#define RCANFD_NCFG_NBRP(x) (((x) & 0x3ff) << 0)
-/* RSCFDnCFDCmCTR */
+/* RSCFDnCFDCmCTR / RSCFDnCmCTR */
#define RCANFD_CCTR_CTME BIT(24)
#define RCANFD_CCTR_ERRD BIT(23)
#define RCANFD_CCTR_BOM_MASK (0x3 << 21)
@@ -136,7 +144,7 @@
#define RCANFD_CCTR_CHDMC_CRESET (0x1)
#define RCANFD_CCTR_CHDMC_CHLT (0x2)
-/* RSCFDnCFDCmSTS */
+/* RSCFDnCFDCmSTS / RSCFDnCmSTS */
#define RCANFD_CSTS_COMSTS BIT(7)
#define RCANFD_CSTS_RECSTS BIT(6)
#define RCANFD_CSTS_TRMSTS BIT(5)
@@ -149,7 +157,7 @@
#define RCANFD_CSTS_TECCNT(x) (((x) >> 24) & 0xff)
#define RCANFD_CSTS_RECCNT(x) (((x) >> 16) & 0xff)
-/* RSCFDnCFDCmERFL */
+/* RSCFDnCFDCmERFL / RSCFDnCmERFL */
#define RCANFD_CERFL_ADERR BIT(14)
#define RCANFD_CERFL_B0ERR BIT(13)
#define RCANFD_CERFL_B1ERR BIT(12)
@@ -239,14 +247,14 @@
#define RCANFD_CFFDCSTS_CFBRS BIT(1)
#define RCANFD_CFFDCSTS_CFESI BIT(0)
-/* This controller supports classical CAN only mode or CAN FD only mode. These
- * modes are supported in two separate set of register maps & names. However,
- * some of the register offsets are common for both modes. Those offsets are
- * listed below as Common registers.
+/* This controller supports either Classical CAN only mode or CAN FD only mode.
+ * These modes are supported in two separate set of register maps & names.
+ * However, some of the register offsets are common for both modes. Those
+ * offsets are listed below as Common registers.
*
- * The CAN FD only specific registers are listed separately and their names
- * starts with RCANFD_F_xxx names. When classical CAN only specific registers
- * are added, those specific registers can be prefixed as RCANFD_C_xxx.
+ * The CAN FD only mode specific registers & Classical CAN only mode specific
+ * registers are listed separately. Their register names starts with
+ * RCANFD_F_xxx & RCANFD_C_xxx respectively.
*/
/* Common registers */
@@ -353,7 +361,7 @@
#define RCANFD_GTSTCTR (0x046c)
/* RSCFDnCFDGLOCKK / RSCFDnGLOCKK */
#define RCANFD_GLOCKK (0x047c)
-/* RSCFDnCFDGRMCFG / RSCFDnGRMCFG */
+/* RSCFDnCFDGRMCFG */
#define RCANFD_GRMCFG (0x04fc)
/* RSCFDnCFDGAFLIDj / RSCFDnGAFLIDj */
@@ -365,6 +373,46 @@
/* RSCFDnCFDGAFLP1j / RSCFDnGAFLP1j */
#define RCANFD_GAFLP1(offset, j) ((offset) + 0x0c + (0x10 * (j)))
+/* Classical CAN only mode register map */
+
+/* RSCFDnGAFLXXXj offset */
+#define RCANFD_C_GAFL_OFFSET (0x0500)
+
+/* RSCFDnRMXXXq -> RCANFD_C_RMXXX(q) */
+#define RCANFD_C_RMID(q) (0x0600 + (0x10 * (q)))
+#define RCANFD_C_RMPTR(q) (0x0604 + (0x10 * (q)))
+#define RCANFD_C_RMDF0(q) (0x0608 + (0x10 * (q)))
+#define RCANFD_C_RMDF1(q) (0x060c + (0x10 * (q)))
+
+/* RSCFDnRFXXx -> RCANFD_C_RFXX(x) */
+#define RCANFD_C_RFOFFSET (0x0e00)
+#define RCANFD_C_RFID(x) (RCANFD_C_RFOFFSET + (0x10 * (x)))
+#define RCANFD_C_RFPTR(x) (RCANFD_C_RFOFFSET + 0x04 + \
+ (0x10 * (x)))
+#define RCANFD_C_RFDF(x, df) (RCANFD_C_RFOFFSET + 0x08 + \
+ (0x10 * (x)) + (0x04 * (df)))
+
+/* RSCFDnCFXXk -> RCANFD_C_CFXX(ch, k) */
+#define RCANFD_C_CFOFFSET (0x0e80)
+#define RCANFD_C_CFID(ch, idx) (RCANFD_C_CFOFFSET + (0x30 * (ch)) + \
+ (0x10 * (idx)))
+#define RCANFD_C_CFPTR(ch, idx) (RCANFD_C_CFOFFSET + 0x04 + \
+ (0x30 * (ch)) + (0x10 * (idx)))
+#define RCANFD_C_CFDF(ch, idx, df) (RCANFD_C_CFOFFSET + 0x08 + \
+ (0x30 * (ch)) + (0x10 * (idx)) + \
+ (0x04 * (df)))
+
+/* RSCFDnTMXXp -> RCANFD_C_TMXX(p) */
+#define RCANFD_C_TMID(p) (0x1000 + (0x10 * (p)))
+#define RCANFD_C_TMPTR(p) (0x1004 + (0x10 * (p)))
+#define RCANFD_C_TMDF0(p) (0x1008 + (0x10 * (p)))
+#define RCANFD_C_TMDF1(p) (0x100c + (0x10 * (p)))
+
+/* RSCFDnTHLACCm */
+#define RCANFD_C_THLACC(m) (0x1800 + (0x04 * (m)))
+/* RSCFDnRPGACCr */
+#define RCANFD_C_RPGACC(r) (0x1900 + (0x04 * (r)))
+
/* CAN FD mode specific regsiter map */
/* RSCFDnCFDCmXXX -> RCANFD_F_XXX(m) */
@@ -468,6 +516,7 @@ struct rcar_canfd_global {
struct clk *can_clk; /* fCAN clock */
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 */
};
/* CAN FD mode nominal rate constants */
@@ -496,6 +545,19 @@ static const struct can_bittiming_const rcar_canfd_data_bittiming_const = {
.brp_inc = 1,
};
+/* Classical CAN mode bitrate constants */
+static const struct can_bittiming_const rcar_canfd_bittiming_const = {
+ .name = RCANFD_DRV_NAME,
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
/* Helper functions */
static inline void rcar_canfd_update(u32 mask, u32 val, u32 __iomem *reg)
{
@@ -593,8 +655,13 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
/* Reset Global error flags */
rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0);
- /* Set the controller into FD mode */
- rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG, RCANFD_GRMCFG_RCMC);
+ /* Set the controller into appropriate mode */
+ if (gpriv->fdmode)
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
+ RCANFD_GRMCFG_RCMC);
+ else
+ rcar_canfd_clear_bit(gpriv->base, RCANFD_GRMCFG,
+ RCANFD_GRMCFG_RCMC);
/* Transition all Channels to reset mode */
for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
@@ -624,8 +691,12 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
/* Global configuration settings */
- /* Truncate payload to configured message size RFPLS */
- cfg = RCANFD_GCFG_CMPOC;
+ /* ECC Error flag Enable */
+ cfg = RCANFD_GCFG_EEFE;
+
+ if (gpriv->fdmode)
+ /* Truncate payload to configured message size RFPLS */
+ cfg |= RCANFD_GCFG_CMPOC;
/* Set External Clock if selected */
if (gpriv->fcan != RCANFD_CANFDCLK)
@@ -647,7 +718,7 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
u32 ch)
{
u32 cfg;
- int start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
+ int offset, start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
u32 ridx = ch + RCANFD_RFFIFO_IDX;
if (ch == 0) {
@@ -667,19 +738,19 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
/* Write number of rules for channel */
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG0,
RCANFD_GAFLCFG_SETRNC(ch, num_rules));
+ if (gpriv->fdmode)
+ offset = RCANFD_F_GAFL_OFFSET;
+ else
+ offset = RCANFD_C_GAFL_OFFSET;
/* Accept all IDs */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLID(RCANFD_F_GAFL_OFFSET, start), 0);
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, start), 0);
/* IDE or RTR is not considered for matching */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLM(RCANFD_F_GAFL_OFFSET, start), 0);
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, start), 0);
/* Any data length accepted */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLP0(RCANFD_F_GAFL_OFFSET, start), 0);
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, start), 0);
/* Place the msg in corresponding Rx FIFO entry */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLP1(RCANFD_F_GAFL_OFFSET, start),
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLP1(offset, start),
RCANFD_GAFLP1_GAFLFDP(ridx));
/* Disable write access to page */
@@ -697,7 +768,10 @@ static void rcar_canfd_configure_rx(struct rcar_canfd_global *gpriv, u32 ch)
u32 ridx = ch + RCANFD_RFFIFO_IDX;
rfdc = 2; /* b010 - 8 messages Rx FIFO depth */
- rfpls = 7; /* b111 - Max 64 bytes payload */
+ if (gpriv->fdmode)
+ rfpls = 7; /* b111 - Max 64 bytes payload */
+ else
+ rfpls = 0; /* b000 - Max 8 bytes payload */
cfg = (RCANFD_RFCC_RFIM | RCANFD_RFCC_RFDC(rfdc) |
RCANFD_RFCC_RFPLS(rfpls) | RCANFD_RFCC_RFIE);
@@ -718,16 +792,20 @@ static void rcar_canfd_configure_tx(struct rcar_canfd_global *gpriv, u32 ch)
cftml = 0; /* 0th buffer */
cfm = 1; /* b01 - Transmit mode */
cfdc = 2; /* b010 - 8 messages Tx FIFO depth */
- cfpls = 7; /* b111 - Max 64 bytes payload */
+ if (gpriv->fdmode)
+ cfpls = 7; /* b111 - Max 64 bytes payload */
+ else
+ cfpls = 0; /* b000 - Max 8 bytes payload */
cfg = (RCANFD_CFCC_CFTML(cftml) | RCANFD_CFCC_CFM(cfm) |
RCANFD_CFCC_CFIM | RCANFD_CFCC_CFDC(cfdc) |
RCANFD_CFCC_CFPLS(cfpls) | RCANFD_CFCC_CFTXIE);
rcar_canfd_write(gpriv->base, RCANFD_CFCC(ch, RCANFD_CFFIFO_IDX), cfg);
- /* Clear FD mode specific control/status register */
- rcar_canfd_write(gpriv->base,
- RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX), 0);
+ if (gpriv->fdmode)
+ /* Clear FD mode specific control/status register */
+ rcar_canfd_write(gpriv->base,
+ RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX), 0);
}
static void rcar_canfd_enable_global_interrupts(struct rcar_canfd_global *gpriv)
@@ -739,7 +817,8 @@ static void rcar_canfd_enable_global_interrupts(struct rcar_canfd_global *gpriv)
/* Global interrupts setup */
ctr = RCANFD_GCTR_MEIE;
- ctr |= RCANFD_GCTR_CFMPOFIE;
+ if (gpriv->fdmode)
+ ctr |= RCANFD_GCTR_CFMPOFIE;
rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, ctr);
}
@@ -790,6 +869,7 @@ static void rcar_canfd_disable_channel_interrupts(struct rcar_canfd_channel
static void rcar_canfd_global_error(struct net_device *ndev)
{
struct rcar_canfd_channel *priv = netdev_priv(ndev);
+ struct rcar_canfd_global *gpriv = priv->gpriv;
struct net_device_stats *stats = &ndev->stats;
u32 ch = priv->channel;
u32 gerfl, sts;
@@ -823,7 +903,7 @@ static void rcar_canfd_global_error(struct net_device *ndev)
sts & ~RCANFD_RFSTS_RFMLT);
}
}
- if (gerfl & RCANFD_GERFL_CMPOF) {
+ if (gpriv->fdmode && gerfl & RCANFD_GERFL_CMPOF) {
/* Message Lost flag will be set for respective channel
* when this condition happens with counters and flags
* already updated.
@@ -1018,7 +1098,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 (RCANFD_GERFL_ERR(gerfl))
+ if (RCANFD_GERFL_ERR(gpriv, gerfl))
rcar_canfd_global_error(ndev);
/* Handle Rx interrupts */
@@ -1077,25 +1157,37 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
tseg2 = bt->phase_seg2 - 1;
- cfg = (RCANFD_NCFG_NTSEG1(tseg1) | RCANFD_NCFG_NBRP(brp) |
- RCANFD_NCFG_NSJW(sjw) | RCANFD_NCFG_NTSEG2(tseg2));
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ /* CAN FD only mode */
+ cfg = (RCANFD_NCFG_NTSEG1(tseg1) | RCANFD_NCFG_NBRP(brp) |
+ RCANFD_NCFG_NSJW(sjw) | RCANFD_NCFG_NTSEG2(tseg2));
- rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg);
- netdev_dbg(priv->ndev, "nrate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
- brp, sjw, tseg1, tseg2);
+ rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg);
+ netdev_dbg(priv->ndev, "nrate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
+ brp, sjw, tseg1, tseg2);
- /* Data bit timing settings */
- brp = dbt->brp - 1;
- sjw = dbt->sjw - 1;
- tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
- tseg2 = dbt->phase_seg2 - 1;
+ /* Data bit timing settings */
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
- cfg = (RCANFD_DCFG_DTSEG1(tseg1) | RCANFD_DCFG_DBRP(brp) |
- RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(tseg2));
+ cfg = (RCANFD_DCFG_DTSEG1(tseg1) | RCANFD_DCFG_DBRP(brp) |
+ RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(tseg2));
- rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
- netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
- brp, sjw, tseg1, tseg2);
+ rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
+ netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
+ brp, sjw, tseg1, tseg2);
+ } else {
+ /* Classical CAN only mode */
+ cfg = (RCANFD_CFG_TSEG1(tseg1) | RCANFD_CFG_BRP(brp) |
+ RCANFD_CFG_SJW(sjw) | RCANFD_CFG_TSEG2(tseg2));
+
+ rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg);
+ netdev_dbg(priv->ndev,
+ "rate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
+ brp, sjw, tseg1, tseg2);
+ }
}
static int rcar_canfd_start(struct net_device *ndev)
@@ -1233,27 +1325,37 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
if (cf->can_id & CAN_RTR_FLAG)
id |= RCANFD_CFID_CFRTR;
- rcar_canfd_write(priv->base,
- RCANFD_F_CFID(ch, RCANFD_CFFIFO_IDX), id);
dlc = RCANFD_CFPTR_CFDLC(can_len2dlc(cf->len));
- rcar_canfd_write(priv->base,
- RCANFD_F_CFPTR(ch, RCANFD_CFFIFO_IDX), dlc);
- if (can_is_canfd_skb(skb)) {
- /* CAN FD frame format */
- sts |= RCANFD_CFFDCSTS_CFFDF;
- if (cf->flags & CANFD_BRS)
- sts |= RCANFD_CFFDCSTS_CFBRS;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ rcar_canfd_write(priv->base,
+ RCANFD_F_CFID(ch, RCANFD_CFFIFO_IDX), id);
+ rcar_canfd_write(priv->base,
+ RCANFD_F_CFPTR(ch, RCANFD_CFFIFO_IDX), dlc);
- if (priv->can.state == CAN_STATE_ERROR_PASSIVE)
- sts |= RCANFD_CFFDCSTS_CFESI;
- }
+ if (can_is_canfd_skb(skb)) {
+ /* CAN FD frame format */
+ sts |= RCANFD_CFFDCSTS_CFFDF;
+ if (cf->flags & CANFD_BRS)
+ sts |= RCANFD_CFFDCSTS_CFBRS;
- rcar_canfd_write(priv->base, RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX),
- sts);
+ if (priv->can.state == CAN_STATE_ERROR_PASSIVE)
+ sts |= RCANFD_CFFDCSTS_CFESI;
+ }
+
+ rcar_canfd_write(priv->base,
+ RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX), sts);
- rcar_canfd_put_data(priv, cf,
- RCANFD_F_CFDF(ch, RCANFD_CFFIFO_IDX, 0));
+ rcar_canfd_put_data(priv, cf,
+ RCANFD_F_CFDF(ch, RCANFD_CFFIFO_IDX, 0));
+ } else {
+ rcar_canfd_write(priv->base,
+ RCANFD_C_CFID(ch, RCANFD_CFFIFO_IDX), id);
+ rcar_canfd_write(priv->base,
+ RCANFD_C_CFPTR(ch, RCANFD_CFFIFO_IDX), dlc);
+ rcar_canfd_put_data(priv, cf,
+ RCANFD_C_CFDF(ch, RCANFD_CFFIFO_IDX, 0));
+ }
priv->tx_len[priv->tx_head % RCANFD_FIFO_DEPTH] = cf->len;
can_put_echo_skb(skb, ndev, priv->tx_head % RCANFD_FIFO_DEPTH);
@@ -1280,47 +1382,61 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
struct net_device_stats *stats = &priv->ndev->stats;
struct canfd_frame *cf;
struct sk_buff *skb;
- u32 sts = 0, id, ptr;
+ u32 sts = 0, id, dlc;
u32 ch = priv->channel;
u32 ridx = ch + RCANFD_RFFIFO_IDX;
- id = rcar_canfd_read(priv->base, RCANFD_F_RFID(ridx));
- ptr = rcar_canfd_read(priv->base, RCANFD_F_RFPTR(ridx));
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ id = rcar_canfd_read(priv->base, RCANFD_F_RFID(ridx));
+ dlc = rcar_canfd_read(priv->base, RCANFD_F_RFPTR(ridx));
- sts = rcar_canfd_read(priv->base, RCANFD_F_RFFDSTS(ridx));
- if (sts & RCANFD_RFFDSTS_RFFDF)
- skb = alloc_canfd_skb(priv->ndev, &cf);
- else
- skb = alloc_can_skb(priv->ndev,
- (struct can_frame **)&cf);
+ sts = rcar_canfd_read(priv->base, RCANFD_F_RFFDSTS(ridx));
+ if (sts & RCANFD_RFFDSTS_RFFDF)
+ skb = alloc_canfd_skb(priv->ndev, &cf);
+ else
+ skb = alloc_can_skb(priv->ndev,
+ (struct can_frame **)&cf);
+ } else {
+ id = rcar_canfd_read(priv->base, RCANFD_C_RFID(ridx));
+ dlc = rcar_canfd_read(priv->base, RCANFD_C_RFPTR(ridx));
+ skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cf);
+ }
if (!skb) {
stats->rx_dropped++;
return;
}
- if (sts & RCANFD_RFFDSTS_RFFDF)
- cf->len = can_dlc2len(RCANFD_RFPTR_RFDLC(ptr));
- else
- cf->len = get_can_dlc(RCANFD_RFPTR_RFDLC(ptr));
-
- if (sts & RCANFD_RFFDSTS_RFESI) {
- cf->flags |= CANFD_ESI;
- netdev_dbg(priv->ndev, "ESI Error\n");
- }
-
if (id & RCANFD_RFID_RFIDE)
cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = id & CAN_SFF_MASK;
- if (!(sts & RCANFD_RFFDSTS_RFFDF) && (id & RCANFD_RFID_RFRTR)) {
- cf->can_id |= CAN_RTR_FLAG;
- } else {
- if (sts & RCANFD_RFFDSTS_RFBRS)
- cf->flags |= CANFD_BRS;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ if (sts & RCANFD_RFFDSTS_RFFDF)
+ cf->len = can_dlc2len(RCANFD_RFPTR_RFDLC(dlc));
+ else
+ cf->len = get_can_dlc(RCANFD_RFPTR_RFDLC(dlc));
+
+ if (sts & RCANFD_RFFDSTS_RFESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_dbg(priv->ndev, "ESI Error\n");
+ }
+
+ if (!(sts & RCANFD_RFFDSTS_RFFDF) && (id & RCANFD_RFID_RFRTR)) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ if (sts & RCANFD_RFFDSTS_RFBRS)
+ cf->flags |= CANFD_BRS;
- rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(ridx, 0));
+ rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(ridx, 0));
+ }
+ } else {
+ cf->len = get_can_dlc(RCANFD_RFPTR_RFDLC(dlc));
+ if (id & RCANFD_RFID_RFRTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ rcar_canfd_get_data(priv, cf, RCANFD_C_RFDF(ridx, 0));
}
/* Write 0xff to RFPC to increment the CPU-side
@@ -1428,13 +1544,19 @@ 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);
- priv->can.bittiming_const = &rcar_canfd_nom_bittiming_const;
- priv->can.data_bittiming_const =
- &rcar_canfd_data_bittiming_const;
+ if (gpriv->fdmode) {
+ priv->can.bittiming_const = &rcar_canfd_nom_bittiming_const;
+ priv->can.data_bittiming_const =
+ &rcar_canfd_data_bittiming_const;
- /* Controller starts in CAN FD only mode */
- can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
- priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+ /* Controller starts in CAN FD only mode */
+ can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+ } else {
+ /* Controller starts in Classical CAN only mode */
+ priv->can.bittiming_const = &rcar_canfd_bittiming_const;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+ }
priv->can.do_set_mode = rcar_canfd_do_set_mode;
priv->can.do_get_berr_counter = rcar_canfd_get_berr_counter;
@@ -1482,6 +1604,10 @@ static int rcar_canfd_probe(struct platform_device *pdev)
struct device_node *of_child;
unsigned long channels_mask = 0;
int err, ch_irq, g_irq;
+ bool fdmode = true; /* CAN FD only mode - default */
+
+ if (of_property_read_bool(pdev->dev.of_node, "renesas,can-nofd"))
+ fdmode = false; /* Classical CAN only mode */
of_child = of_get_child_by_name(pdev->dev.of_node, "channel0");
if (of_child && of_device_is_available(of_child))
@@ -1513,6 +1639,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
}
gpriv->pdev = pdev;
gpriv->channels_mask = channels_mask;
+ gpriv->fdmode = fdmode;
/* Peripheral clock */
gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
@@ -1623,8 +1750,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, gpriv);
- dev_info(&pdev->dev, "global operational state (clk %d)\n",
- gpriv->fcan);
+ dev_info(&pdev->dev, "global operational state (clk %d, fdmode %d)\n",
+ gpriv->fcan, gpriv->fdmode);
return 0;
fail_channel:
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] can: rcar_canfd: Add Classical CAN only mode support
2016-06-20 14:46 [PATCH] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
@ 2016-06-21 13:29 ` Rob Herring
2016-06-22 12:31 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Ramesh Shanmugasundaram
1 sibling, 0 replies; 7+ messages in thread
From: Rob Herring @ 2016-06-21 13:29 UTC (permalink / raw)
To: Ramesh Shanmugasundaram
Cc: mark.rutland, devicetree, chris.paterson2, pawel.moll,
ijc+devicetree, socketcan, magnus.damm, linux-can,
linux-renesas-soc, horms, mkl, linux-arm-kernel, galak,
ulrich.hecht+renesas, wg
On Mon, Jun 20, 2016 at 03:46:47PM +0100, Ramesh Shanmugasundaram wrote:
> The controller can operate in one of the two global modes
> - CAN FD only mode (default)
> - Classical CAN (CAN2.0) only mode
>
> This patch adds support for Classical CAN only mode. It can be enabled
> by defining the optional device tree property "renesas,can-nofd" of this
> node.
>
> Note: R-Car Gen3 h/w manual v0.51E shows bit6 of RSCFDnCFDGCFG as
> reserved, which is incorrect. This bit is same as RSCFDnGCFG.
>
> Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
> ---
> Hi Marc, All,
>
> This patch is based on top of can-next(tag:linux-can-next-for-4.8-20160617).
>
> Thanks,
> Ramesh.
> ---
> .../devicetree/bindings/net/can/rcar_canfd.txt | 9 +-
> drivers/net/can/rcar/rcar_canfd.c | 355 ++++++++++++++-------
> 2 files changed, 249 insertions(+), 115 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
> index d45182b..a343359 100644
> --- a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
> +++ b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
> @@ -32,6 +32,12 @@ below properties.
> - assigned-clocks: phandle of canfd clock.
> - assigned-clock-rates: maximum frequency of this clock.
>
> +Optional property:
> +The controller can operate in either CAN FD only mode (default) or
> +Classical CAN only mode. The mode is global to both the channels. In order to
> +enable the later, define the following optional property.
> + - renesas,can-nofd: puts the controller in Classical CAN only mode.
renesas,no-can-fd would be a bit more readable.
> +
> Example
> -------
>
> @@ -63,11 +69,12 @@ SoC common .dtsi file:
>
> Board specific .dts file:
>
> -E.g. below enables Channel 1 alone in the board.
> +E.g. below enables Channel 1 alone in the board in Classical CAN only mode.
>
> &canfd {
> pinctrl-0 = <&canfd1_pins>;
> pinctrl-names = "default";
> + renesas,can-nofd;
Now we have a mixture of tabs and spaces.
> status = "okay";
>
> channel1 {
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support
2016-06-20 14:46 [PATCH] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
2016-06-21 13:29 ` Rob Herring
@ 2016-06-22 12:31 ` Ramesh Shanmugasundaram
2016-06-22 12:31 ` [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
` (2 more replies)
1 sibling, 3 replies; 7+ messages in thread
From: Ramesh Shanmugasundaram @ 2016-06-22 12:31 UTC (permalink / raw)
To: mkl, wg, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak
Cc: devicetree, chris.paterson2, socketcan, magnus.damm, linux-can,
linux-renesas-soc, horms, ulrich.hecht+renesas,
Ramesh Shanmugasundaram, linux-arm-kernel
This patch is based on latest can-next(tag:linux-can-next-for-4.8-20160617).
Changes since v1:
- property named changed from "can-nofd" to "no-can-fd" (Rob H)
- added new patch(0002) that support lower state transitions (Wolfgang G)
(http://marc.info/?l=linux-can&m=146650325116971&w=2)
Ramesh Shanmugasundaram (2):
can: rcar_canfd: Add Classical CAN only mode support
can: rcar_canfd: Add back-to-error-active support
.../devicetree/bindings/net/can/rcar_canfd.txt | 21 +-
drivers/net/can/rcar/rcar_canfd.c | 429 ++++++++++++++-------
2 files changed, 310 insertions(+), 140 deletions(-)
--
1.9.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support
2016-06-22 12:31 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Ramesh Shanmugasundaram
@ 2016-06-22 12:31 ` Ramesh Shanmugasundaram
2016-06-24 16:12 ` Rob Herring
2016-06-22 12:31 ` [PATCH v2 2/2] can: rcar_canfd: Add back-to-error-active support Ramesh Shanmugasundaram
2016-06-22 20:34 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Marc Kleine-Budde
2 siblings, 1 reply; 7+ messages in thread
From: Ramesh Shanmugasundaram @ 2016-06-22 12:31 UTC (permalink / raw)
To: mkl, wg, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak
Cc: devicetree, chris.paterson2, socketcan, magnus.damm, linux-can,
linux-renesas-soc, horms, ulrich.hecht+renesas,
Ramesh Shanmugasundaram, linux-arm-kernel
The controller can operate in one of the two global modes
- CAN FD only mode (default)
- Classical CAN (CAN2.0) only mode
This patch adds support for Classical CAN only mode. It can be enabled
by defining the optional device tree property "renesas,no-can-fd" of this
node.
Note: R-Car Gen3 h/w manual v0.51E shows bit6 of RSCFDnCFDGCFG as
reserved, which is incorrect. This bit is same as RSCFDnGCFG.
Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
---
.../devicetree/bindings/net/can/rcar_canfd.txt | 21 +-
drivers/net/can/rcar/rcar_canfd.c | 355 ++++++++++++++-------
2 files changed, 255 insertions(+), 121 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
index d45182b..22a6f10 100644
--- a/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
+++ b/Documentation/devicetree/bindings/net/can/rcar_canfd.txt
@@ -32,6 +32,12 @@ below properties.
- assigned-clocks: phandle of canfd clock.
- assigned-clock-rates: maximum frequency of this clock.
+Optional property:
+The controller can operate in either CAN FD only mode (default) or
+Classical CAN only mode. The mode is global to both the channels. In order to
+enable the later, define the following optional property.
+ - renesas,no-can-fd: puts the controller in Classical CAN only mode.
+
Example
-------
@@ -63,12 +69,13 @@ SoC common .dtsi file:
Board specific .dts file:
-E.g. below enables Channel 1 alone in the board.
+E.g. below enables Channel 1 alone in the board in Classical CAN only mode.
&canfd {
- pinctrl-0 = <&canfd1_pins>;
- pinctrl-names = "default";
- status = "okay";
+ pinctrl-0 = <&canfd1_pins>;
+ pinctrl-names = "default";
+ renesas,no-can-fd;
+ status = "okay";
channel1 {
status = "okay";
@@ -79,9 +86,9 @@ E.g. below enables Channel 0 alone in the board using External clock
as fCAN clock.
&canfd {
- pinctrl-0 = <&canfd0_pins &can_clk_pins>;
- pinctrl-names = "default";
- status = "okay";
+ pinctrl-0 = <&canfd0_pins &can_clk_pins>;
+ pinctrl-names = "default";
+ status = "okay";
channel0 {
status = "okay";
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index a39d922..6bcc474 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -16,8 +16,9 @@
* mode, the controller acts as a CAN FD node that can also interoperate with
* CAN 2.0 nodes.
*
- * As of now, this driver does not support the Classical CAN (CAN 2.0) mode,
- * which is handled by a different register map compared to CAN FD only mode.
+ * To switch the controller to Classical CAN (CAN 2.0) only mode, add
+ * "renesas,no-can-fd" optional property to the device tree node. A h/w reset is
+ * also required to switch modes.
*
* Note: The h/w manual register naming convention is clumsy and not acceptable
* to use as it is in the driver. However, those names are added as comments
@@ -48,15 +49,16 @@
/* RSCFDnCFDGRMCFG */
#define RCANFD_GRMCFG_RCMC BIT(0)
-/* RSCFDnCFDGCFG */
-#define RCANFD_GCFG_CMPOC BIT(5)
+/* RSCFDnCFDGCFG / RSCFDnGCFG */
+#define RCANFD_GCFG_EEFE BIT(6)
+#define RCANFD_GCFG_CMPOC BIT(5) /* CAN FD only */
#define RCANFD_GCFG_DCS BIT(4)
#define RCANFD_GCFG_DCE BIT(1)
#define RCANFD_GCFG_TPRI BIT(0)
-/* RSCFDnCFDGCTR */
+/* RSCFDnCFDGCTR / RSCFDnGCTR */
#define RCANFD_GCTR_TSRST BIT(16)
-#define RCANFD_GCTR_CFMPOFIE BIT(11)
+#define RCANFD_GCTR_CFMPOFIE BIT(11) /* CAN FD only */
#define RCANFD_GCTR_THLEIE BIT(10)
#define RCANFD_GCTR_MEIE BIT(9)
#define RCANFD_GCTR_DEIE BIT(8)
@@ -66,7 +68,7 @@
#define RCANFD_GCTR_GMDC_GRESET (0x1)
#define RCANFD_GCTR_GMDC_GTEST (0x2)
-/* RSCFDnCFDGSTS */
+/* RSCFDnCFDGSTS / RSCFDnGSTS */
#define RCANFD_GSTS_GRAMINIT BIT(3)
#define RCANFD_GSTS_GSLPSTS BIT(2)
#define RCANFD_GSTS_GHLTSTS BIT(1)
@@ -74,44 +76,50 @@
/* Non-operational status */
#define RCANFD_GSTS_GNOPM (BIT(0) | BIT(1) | BIT(2) | BIT(3))
-/* RSCFDnCFDGERFL */
+/* RSCFDnCFDGERFL / RSCFDnGERFL */
#define RCANFD_GERFL_EEF1 BIT(17)
#define RCANFD_GERFL_EEF0 BIT(16)
-#define RCANFD_GERFL_CMPOF BIT(3)
+#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(x) ((x) & (RCANFD_GERFL_EEF1 |\
- RCANFD_GERFL_EEF0 |\
- RCANFD_GERFL_MES |\
- RCANFD_GERFL_CMPOF))
+#define RCANFD_GERFL_ERR(gpriv, x) ((x) & (RCANFD_GERFL_EEF1 |\
+ RCANFD_GERFL_EEF0 | RCANFD_GERFL_MES |\
+ (gpriv->fdmode ?\
+ RCANFD_GERFL_CMPOF : 0)))
/* AFL Rx rules registers */
-/* RSCFDnCFDGAFLCFG0 */
+/* RSCFDnCFDGAFLCFG0 / RSCFDnGAFLCFG0 */
#define RCANFD_GAFLCFG_SETRNC(n, x) (((x) & 0xff) << (24 - n * 8))
#define RCANFD_GAFLCFG_GETRNC(n, x) (((x) >> (24 - n * 8)) & 0xff)
-/* RSCFDnCFDGAFLECTR */
+/* RSCFDnCFDGAFLECTR / RSCFDnGAFLECTR */
#define RCANFD_GAFLECTR_AFLDAE BIT(8)
#define RCANFD_GAFLECTR_AFLPN(x) ((x) & 0x1f)
-/* RSCFDnCFDGAFLIDj */
+/* RSCFDnCFDGAFLIDj / RSCFDnGAFLIDj */
#define RCANFD_GAFLID_GAFLLB BIT(29)
-/* RSCFDnCFDGAFLP1_j */
+/* RSCFDnCFDGAFLP1_j / RSCFDnGAFLP1_j */
#define RCANFD_GAFLP1_GAFLFDP(x) (1 << (x))
/* Channel register bits */
-/* RSCFDnCFDCmNCFG */
+/* RSCFDnCmCFG - Classical CAN only */
+#define RCANFD_CFG_SJW(x) (((x) & 0x3) << 24)
+#define RCANFD_CFG_TSEG2(x) (((x) & 0x7) << 20)
+#define RCANFD_CFG_TSEG1(x) (((x) & 0xf) << 16)
+#define RCANFD_CFG_BRP(x) (((x) & 0x3ff) << 0)
+
+/* RSCFDnCFDCmNCFG - CAN FD only */
#define RCANFD_NCFG_NTSEG2(x) (((x) & 0x1f) << 24)
#define RCANFD_NCFG_NTSEG1(x) (((x) & 0x7f) << 16)
#define RCANFD_NCFG_NSJW(x) (((x) & 0x1f) << 11)
#define RCANFD_NCFG_NBRP(x) (((x) & 0x3ff) << 0)
-/* RSCFDnCFDCmCTR */
+/* RSCFDnCFDCmCTR / RSCFDnCmCTR */
#define RCANFD_CCTR_CTME BIT(24)
#define RCANFD_CCTR_ERRD BIT(23)
#define RCANFD_CCTR_BOM_MASK (0x3 << 21)
@@ -136,7 +144,7 @@
#define RCANFD_CCTR_CHDMC_CRESET (0x1)
#define RCANFD_CCTR_CHDMC_CHLT (0x2)
-/* RSCFDnCFDCmSTS */
+/* RSCFDnCFDCmSTS / RSCFDnCmSTS */
#define RCANFD_CSTS_COMSTS BIT(7)
#define RCANFD_CSTS_RECSTS BIT(6)
#define RCANFD_CSTS_TRMSTS BIT(5)
@@ -149,7 +157,7 @@
#define RCANFD_CSTS_TECCNT(x) (((x) >> 24) & 0xff)
#define RCANFD_CSTS_RECCNT(x) (((x) >> 16) & 0xff)
-/* RSCFDnCFDCmERFL */
+/* RSCFDnCFDCmERFL / RSCFDnCmERFL */
#define RCANFD_CERFL_ADERR BIT(14)
#define RCANFD_CERFL_B0ERR BIT(13)
#define RCANFD_CERFL_B1ERR BIT(12)
@@ -239,14 +247,14 @@
#define RCANFD_CFFDCSTS_CFBRS BIT(1)
#define RCANFD_CFFDCSTS_CFESI BIT(0)
-/* This controller supports classical CAN only mode or CAN FD only mode. These
- * modes are supported in two separate set of register maps & names. However,
- * some of the register offsets are common for both modes. Those offsets are
- * listed below as Common registers.
+/* This controller supports either Classical CAN only mode or CAN FD only mode.
+ * These modes are supported in two separate set of register maps & names.
+ * However, some of the register offsets are common for both modes. Those
+ * offsets are listed below as Common registers.
*
- * The CAN FD only specific registers are listed separately and their names
- * starts with RCANFD_F_xxx names. When classical CAN only specific registers
- * are added, those specific registers can be prefixed as RCANFD_C_xxx.
+ * The CAN FD only mode specific registers & Classical CAN only mode specific
+ * registers are listed separately. Their register names starts with
+ * RCANFD_F_xxx & RCANFD_C_xxx respectively.
*/
/* Common registers */
@@ -353,7 +361,7 @@
#define RCANFD_GTSTCTR (0x046c)
/* RSCFDnCFDGLOCKK / RSCFDnGLOCKK */
#define RCANFD_GLOCKK (0x047c)
-/* RSCFDnCFDGRMCFG / RSCFDnGRMCFG */
+/* RSCFDnCFDGRMCFG */
#define RCANFD_GRMCFG (0x04fc)
/* RSCFDnCFDGAFLIDj / RSCFDnGAFLIDj */
@@ -365,6 +373,46 @@
/* RSCFDnCFDGAFLP1j / RSCFDnGAFLP1j */
#define RCANFD_GAFLP1(offset, j) ((offset) + 0x0c + (0x10 * (j)))
+/* Classical CAN only mode register map */
+
+/* RSCFDnGAFLXXXj offset */
+#define RCANFD_C_GAFL_OFFSET (0x0500)
+
+/* RSCFDnRMXXXq -> RCANFD_C_RMXXX(q) */
+#define RCANFD_C_RMID(q) (0x0600 + (0x10 * (q)))
+#define RCANFD_C_RMPTR(q) (0x0604 + (0x10 * (q)))
+#define RCANFD_C_RMDF0(q) (0x0608 + (0x10 * (q)))
+#define RCANFD_C_RMDF1(q) (0x060c + (0x10 * (q)))
+
+/* RSCFDnRFXXx -> RCANFD_C_RFXX(x) */
+#define RCANFD_C_RFOFFSET (0x0e00)
+#define RCANFD_C_RFID(x) (RCANFD_C_RFOFFSET + (0x10 * (x)))
+#define RCANFD_C_RFPTR(x) (RCANFD_C_RFOFFSET + 0x04 + \
+ (0x10 * (x)))
+#define RCANFD_C_RFDF(x, df) (RCANFD_C_RFOFFSET + 0x08 + \
+ (0x10 * (x)) + (0x04 * (df)))
+
+/* RSCFDnCFXXk -> RCANFD_C_CFXX(ch, k) */
+#define RCANFD_C_CFOFFSET (0x0e80)
+#define RCANFD_C_CFID(ch, idx) (RCANFD_C_CFOFFSET + (0x30 * (ch)) + \
+ (0x10 * (idx)))
+#define RCANFD_C_CFPTR(ch, idx) (RCANFD_C_CFOFFSET + 0x04 + \
+ (0x30 * (ch)) + (0x10 * (idx)))
+#define RCANFD_C_CFDF(ch, idx, df) (RCANFD_C_CFOFFSET + 0x08 + \
+ (0x30 * (ch)) + (0x10 * (idx)) + \
+ (0x04 * (df)))
+
+/* RSCFDnTMXXp -> RCANFD_C_TMXX(p) */
+#define RCANFD_C_TMID(p) (0x1000 + (0x10 * (p)))
+#define RCANFD_C_TMPTR(p) (0x1004 + (0x10 * (p)))
+#define RCANFD_C_TMDF0(p) (0x1008 + (0x10 * (p)))
+#define RCANFD_C_TMDF1(p) (0x100c + (0x10 * (p)))
+
+/* RSCFDnTHLACCm */
+#define RCANFD_C_THLACC(m) (0x1800 + (0x04 * (m)))
+/* RSCFDnRPGACCr */
+#define RCANFD_C_RPGACC(r) (0x1900 + (0x04 * (r)))
+
/* CAN FD mode specific regsiter map */
/* RSCFDnCFDCmXXX -> RCANFD_F_XXX(m) */
@@ -468,6 +516,7 @@ struct rcar_canfd_global {
struct clk *can_clk; /* fCAN clock */
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 */
};
/* CAN FD mode nominal rate constants */
@@ -496,6 +545,19 @@ static const struct can_bittiming_const rcar_canfd_data_bittiming_const = {
.brp_inc = 1,
};
+/* Classical CAN mode bitrate constants */
+static const struct can_bittiming_const rcar_canfd_bittiming_const = {
+ .name = RCANFD_DRV_NAME,
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
/* Helper functions */
static inline void rcar_canfd_update(u32 mask, u32 val, u32 __iomem *reg)
{
@@ -593,8 +655,13 @@ static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
/* Reset Global error flags */
rcar_canfd_write(gpriv->base, RCANFD_GERFL, 0x0);
- /* Set the controller into FD mode */
- rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG, RCANFD_GRMCFG_RCMC);
+ /* Set the controller into appropriate mode */
+ if (gpriv->fdmode)
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
+ RCANFD_GRMCFG_RCMC);
+ else
+ rcar_canfd_clear_bit(gpriv->base, RCANFD_GRMCFG,
+ RCANFD_GRMCFG_RCMC);
/* Transition all Channels to reset mode */
for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
@@ -624,8 +691,12 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
/* Global configuration settings */
- /* Truncate payload to configured message size RFPLS */
- cfg = RCANFD_GCFG_CMPOC;
+ /* ECC Error flag Enable */
+ cfg = RCANFD_GCFG_EEFE;
+
+ if (gpriv->fdmode)
+ /* Truncate payload to configured message size RFPLS */
+ cfg |= RCANFD_GCFG_CMPOC;
/* Set External Clock if selected */
if (gpriv->fcan != RCANFD_CANFDCLK)
@@ -647,7 +718,7 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
u32 ch)
{
u32 cfg;
- int start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
+ int offset, start, page, num_rules = RCANFD_CHANNEL_NUMRULES;
u32 ridx = ch + RCANFD_RFFIFO_IDX;
if (ch == 0) {
@@ -667,19 +738,19 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
/* Write number of rules for channel */
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG0,
RCANFD_GAFLCFG_SETRNC(ch, num_rules));
+ if (gpriv->fdmode)
+ offset = RCANFD_F_GAFL_OFFSET;
+ else
+ offset = RCANFD_C_GAFL_OFFSET;
/* Accept all IDs */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLID(RCANFD_F_GAFL_OFFSET, start), 0);
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLID(offset, start), 0);
/* IDE or RTR is not considered for matching */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLM(RCANFD_F_GAFL_OFFSET, start), 0);
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLM(offset, start), 0);
/* Any data length accepted */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLP0(RCANFD_F_GAFL_OFFSET, start), 0);
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLP0(offset, start), 0);
/* Place the msg in corresponding Rx FIFO entry */
- rcar_canfd_write(gpriv->base,
- RCANFD_GAFLP1(RCANFD_F_GAFL_OFFSET, start),
+ rcar_canfd_write(gpriv->base, RCANFD_GAFLP1(offset, start),
RCANFD_GAFLP1_GAFLFDP(ridx));
/* Disable write access to page */
@@ -697,7 +768,10 @@ static void rcar_canfd_configure_rx(struct rcar_canfd_global *gpriv, u32 ch)
u32 ridx = ch + RCANFD_RFFIFO_IDX;
rfdc = 2; /* b010 - 8 messages Rx FIFO depth */
- rfpls = 7; /* b111 - Max 64 bytes payload */
+ if (gpriv->fdmode)
+ rfpls = 7; /* b111 - Max 64 bytes payload */
+ else
+ rfpls = 0; /* b000 - Max 8 bytes payload */
cfg = (RCANFD_RFCC_RFIM | RCANFD_RFCC_RFDC(rfdc) |
RCANFD_RFCC_RFPLS(rfpls) | RCANFD_RFCC_RFIE);
@@ -718,16 +792,20 @@ static void rcar_canfd_configure_tx(struct rcar_canfd_global *gpriv, u32 ch)
cftml = 0; /* 0th buffer */
cfm = 1; /* b01 - Transmit mode */
cfdc = 2; /* b010 - 8 messages Tx FIFO depth */
- cfpls = 7; /* b111 - Max 64 bytes payload */
+ if (gpriv->fdmode)
+ cfpls = 7; /* b111 - Max 64 bytes payload */
+ else
+ cfpls = 0; /* b000 - Max 8 bytes payload */
cfg = (RCANFD_CFCC_CFTML(cftml) | RCANFD_CFCC_CFM(cfm) |
RCANFD_CFCC_CFIM | RCANFD_CFCC_CFDC(cfdc) |
RCANFD_CFCC_CFPLS(cfpls) | RCANFD_CFCC_CFTXIE);
rcar_canfd_write(gpriv->base, RCANFD_CFCC(ch, RCANFD_CFFIFO_IDX), cfg);
- /* Clear FD mode specific control/status register */
- rcar_canfd_write(gpriv->base,
- RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX), 0);
+ if (gpriv->fdmode)
+ /* Clear FD mode specific control/status register */
+ rcar_canfd_write(gpriv->base,
+ RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX), 0);
}
static void rcar_canfd_enable_global_interrupts(struct rcar_canfd_global *gpriv)
@@ -739,7 +817,8 @@ static void rcar_canfd_enable_global_interrupts(struct rcar_canfd_global *gpriv)
/* Global interrupts setup */
ctr = RCANFD_GCTR_MEIE;
- ctr |= RCANFD_GCTR_CFMPOFIE;
+ if (gpriv->fdmode)
+ ctr |= RCANFD_GCTR_CFMPOFIE;
rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, ctr);
}
@@ -790,6 +869,7 @@ static void rcar_canfd_disable_channel_interrupts(struct rcar_canfd_channel
static void rcar_canfd_global_error(struct net_device *ndev)
{
struct rcar_canfd_channel *priv = netdev_priv(ndev);
+ struct rcar_canfd_global *gpriv = priv->gpriv;
struct net_device_stats *stats = &ndev->stats;
u32 ch = priv->channel;
u32 gerfl, sts;
@@ -823,7 +903,7 @@ static void rcar_canfd_global_error(struct net_device *ndev)
sts & ~RCANFD_RFSTS_RFMLT);
}
}
- if (gerfl & RCANFD_GERFL_CMPOF) {
+ if (gpriv->fdmode && gerfl & RCANFD_GERFL_CMPOF) {
/* Message Lost flag will be set for respective channel
* when this condition happens with counters and flags
* already updated.
@@ -1018,7 +1098,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 (RCANFD_GERFL_ERR(gerfl))
+ if (RCANFD_GERFL_ERR(gpriv, gerfl))
rcar_canfd_global_error(ndev);
/* Handle Rx interrupts */
@@ -1077,25 +1157,37 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
tseg2 = bt->phase_seg2 - 1;
- cfg = (RCANFD_NCFG_NTSEG1(tseg1) | RCANFD_NCFG_NBRP(brp) |
- RCANFD_NCFG_NSJW(sjw) | RCANFD_NCFG_NTSEG2(tseg2));
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ /* CAN FD only mode */
+ cfg = (RCANFD_NCFG_NTSEG1(tseg1) | RCANFD_NCFG_NBRP(brp) |
+ RCANFD_NCFG_NSJW(sjw) | RCANFD_NCFG_NTSEG2(tseg2));
- rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg);
- netdev_dbg(priv->ndev, "nrate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
- brp, sjw, tseg1, tseg2);
+ rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg);
+ netdev_dbg(priv->ndev, "nrate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
+ brp, sjw, tseg1, tseg2);
- /* Data bit timing settings */
- brp = dbt->brp - 1;
- sjw = dbt->sjw - 1;
- tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
- tseg2 = dbt->phase_seg2 - 1;
+ /* Data bit timing settings */
+ brp = dbt->brp - 1;
+ sjw = dbt->sjw - 1;
+ tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+ tseg2 = dbt->phase_seg2 - 1;
- cfg = (RCANFD_DCFG_DTSEG1(tseg1) | RCANFD_DCFG_DBRP(brp) |
- RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(tseg2));
+ cfg = (RCANFD_DCFG_DTSEG1(tseg1) | RCANFD_DCFG_DBRP(brp) |
+ RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(tseg2));
- rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
- netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
- brp, sjw, tseg1, tseg2);
+ rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
+ netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
+ brp, sjw, tseg1, tseg2);
+ } else {
+ /* Classical CAN only mode */
+ cfg = (RCANFD_CFG_TSEG1(tseg1) | RCANFD_CFG_BRP(brp) |
+ RCANFD_CFG_SJW(sjw) | RCANFD_CFG_TSEG2(tseg2));
+
+ rcar_canfd_write(priv->base, RCANFD_CCFG(ch), cfg);
+ netdev_dbg(priv->ndev,
+ "rate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
+ brp, sjw, tseg1, tseg2);
+ }
}
static int rcar_canfd_start(struct net_device *ndev)
@@ -1233,27 +1325,37 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
if (cf->can_id & CAN_RTR_FLAG)
id |= RCANFD_CFID_CFRTR;
- rcar_canfd_write(priv->base,
- RCANFD_F_CFID(ch, RCANFD_CFFIFO_IDX), id);
dlc = RCANFD_CFPTR_CFDLC(can_len2dlc(cf->len));
- rcar_canfd_write(priv->base,
- RCANFD_F_CFPTR(ch, RCANFD_CFFIFO_IDX), dlc);
- if (can_is_canfd_skb(skb)) {
- /* CAN FD frame format */
- sts |= RCANFD_CFFDCSTS_CFFDF;
- if (cf->flags & CANFD_BRS)
- sts |= RCANFD_CFFDCSTS_CFBRS;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ rcar_canfd_write(priv->base,
+ RCANFD_F_CFID(ch, RCANFD_CFFIFO_IDX), id);
+ rcar_canfd_write(priv->base,
+ RCANFD_F_CFPTR(ch, RCANFD_CFFIFO_IDX), dlc);
- if (priv->can.state == CAN_STATE_ERROR_PASSIVE)
- sts |= RCANFD_CFFDCSTS_CFESI;
- }
+ if (can_is_canfd_skb(skb)) {
+ /* CAN FD frame format */
+ sts |= RCANFD_CFFDCSTS_CFFDF;
+ if (cf->flags & CANFD_BRS)
+ sts |= RCANFD_CFFDCSTS_CFBRS;
- rcar_canfd_write(priv->base, RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX),
- sts);
+ if (priv->can.state == CAN_STATE_ERROR_PASSIVE)
+ sts |= RCANFD_CFFDCSTS_CFESI;
+ }
+
+ rcar_canfd_write(priv->base,
+ RCANFD_F_CFFDCSTS(ch, RCANFD_CFFIFO_IDX), sts);
- rcar_canfd_put_data(priv, cf,
- RCANFD_F_CFDF(ch, RCANFD_CFFIFO_IDX, 0));
+ rcar_canfd_put_data(priv, cf,
+ RCANFD_F_CFDF(ch, RCANFD_CFFIFO_IDX, 0));
+ } else {
+ rcar_canfd_write(priv->base,
+ RCANFD_C_CFID(ch, RCANFD_CFFIFO_IDX), id);
+ rcar_canfd_write(priv->base,
+ RCANFD_C_CFPTR(ch, RCANFD_CFFIFO_IDX), dlc);
+ rcar_canfd_put_data(priv, cf,
+ RCANFD_C_CFDF(ch, RCANFD_CFFIFO_IDX, 0));
+ }
priv->tx_len[priv->tx_head % RCANFD_FIFO_DEPTH] = cf->len;
can_put_echo_skb(skb, ndev, priv->tx_head % RCANFD_FIFO_DEPTH);
@@ -1280,47 +1382,61 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
struct net_device_stats *stats = &priv->ndev->stats;
struct canfd_frame *cf;
struct sk_buff *skb;
- u32 sts = 0, id, ptr;
+ u32 sts = 0, id, dlc;
u32 ch = priv->channel;
u32 ridx = ch + RCANFD_RFFIFO_IDX;
- id = rcar_canfd_read(priv->base, RCANFD_F_RFID(ridx));
- ptr = rcar_canfd_read(priv->base, RCANFD_F_RFPTR(ridx));
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ id = rcar_canfd_read(priv->base, RCANFD_F_RFID(ridx));
+ dlc = rcar_canfd_read(priv->base, RCANFD_F_RFPTR(ridx));
- sts = rcar_canfd_read(priv->base, RCANFD_F_RFFDSTS(ridx));
- if (sts & RCANFD_RFFDSTS_RFFDF)
- skb = alloc_canfd_skb(priv->ndev, &cf);
- else
- skb = alloc_can_skb(priv->ndev,
- (struct can_frame **)&cf);
+ sts = rcar_canfd_read(priv->base, RCANFD_F_RFFDSTS(ridx));
+ if (sts & RCANFD_RFFDSTS_RFFDF)
+ skb = alloc_canfd_skb(priv->ndev, &cf);
+ else
+ skb = alloc_can_skb(priv->ndev,
+ (struct can_frame **)&cf);
+ } else {
+ id = rcar_canfd_read(priv->base, RCANFD_C_RFID(ridx));
+ dlc = rcar_canfd_read(priv->base, RCANFD_C_RFPTR(ridx));
+ skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cf);
+ }
if (!skb) {
stats->rx_dropped++;
return;
}
- if (sts & RCANFD_RFFDSTS_RFFDF)
- cf->len = can_dlc2len(RCANFD_RFPTR_RFDLC(ptr));
- else
- cf->len = get_can_dlc(RCANFD_RFPTR_RFDLC(ptr));
-
- if (sts & RCANFD_RFFDSTS_RFESI) {
- cf->flags |= CANFD_ESI;
- netdev_dbg(priv->ndev, "ESI Error\n");
- }
-
if (id & RCANFD_RFID_RFIDE)
cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = id & CAN_SFF_MASK;
- if (!(sts & RCANFD_RFFDSTS_RFFDF) && (id & RCANFD_RFID_RFRTR)) {
- cf->can_id |= CAN_RTR_FLAG;
- } else {
- if (sts & RCANFD_RFFDSTS_RFBRS)
- cf->flags |= CANFD_BRS;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ if (sts & RCANFD_RFFDSTS_RFFDF)
+ cf->len = can_dlc2len(RCANFD_RFPTR_RFDLC(dlc));
+ else
+ cf->len = get_can_dlc(RCANFD_RFPTR_RFDLC(dlc));
+
+ if (sts & RCANFD_RFFDSTS_RFESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_dbg(priv->ndev, "ESI Error\n");
+ }
+
+ if (!(sts & RCANFD_RFFDSTS_RFFDF) && (id & RCANFD_RFID_RFRTR)) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ if (sts & RCANFD_RFFDSTS_RFBRS)
+ cf->flags |= CANFD_BRS;
- rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(ridx, 0));
+ rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(ridx, 0));
+ }
+ } else {
+ cf->len = get_can_dlc(RCANFD_RFPTR_RFDLC(dlc));
+ if (id & RCANFD_RFID_RFRTR)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ rcar_canfd_get_data(priv, cf, RCANFD_C_RFDF(ridx, 0));
}
/* Write 0xff to RFPC to increment the CPU-side
@@ -1428,13 +1544,19 @@ 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);
- priv->can.bittiming_const = &rcar_canfd_nom_bittiming_const;
- priv->can.data_bittiming_const =
- &rcar_canfd_data_bittiming_const;
+ if (gpriv->fdmode) {
+ priv->can.bittiming_const = &rcar_canfd_nom_bittiming_const;
+ priv->can.data_bittiming_const =
+ &rcar_canfd_data_bittiming_const;
- /* Controller starts in CAN FD only mode */
- can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
- priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+ /* Controller starts in CAN FD only mode */
+ can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+ } else {
+ /* Controller starts in Classical CAN only mode */
+ priv->can.bittiming_const = &rcar_canfd_bittiming_const;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING;
+ }
priv->can.do_set_mode = rcar_canfd_do_set_mode;
priv->can.do_get_berr_counter = rcar_canfd_get_berr_counter;
@@ -1482,6 +1604,10 @@ static int rcar_canfd_probe(struct platform_device *pdev)
struct device_node *of_child;
unsigned long channels_mask = 0;
int err, ch_irq, g_irq;
+ bool fdmode = true; /* CAN FD only mode - default */
+
+ if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd"))
+ fdmode = false; /* Classical CAN only mode */
of_child = of_get_child_by_name(pdev->dev.of_node, "channel0");
if (of_child && of_device_is_available(of_child))
@@ -1513,6 +1639,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
}
gpriv->pdev = pdev;
gpriv->channels_mask = channels_mask;
+ gpriv->fdmode = fdmode;
/* Peripheral clock */
gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
@@ -1623,8 +1750,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, gpriv);
- dev_info(&pdev->dev, "global operational state (clk %d)\n",
- gpriv->fcan);
+ dev_info(&pdev->dev, "global operational state (clk %d, fdmode %d)\n",
+ gpriv->fcan, gpriv->fdmode);
return 0;
fail_channel:
--
1.9.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] can: rcar_canfd: Add back-to-error-active support
2016-06-22 12:31 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Ramesh Shanmugasundaram
2016-06-22 12:31 ` [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
@ 2016-06-22 12:31 ` Ramesh Shanmugasundaram
2016-06-22 20:34 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Marc Kleine-Budde
2 siblings, 0 replies; 7+ messages in thread
From: Ramesh Shanmugasundaram @ 2016-06-22 12:31 UTC (permalink / raw)
To: mkl, wg, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak
Cc: devicetree, chris.paterson2, socketcan, magnus.damm, linux-can,
linux-renesas-soc, horms, ulrich.hecht+renesas,
Ramesh Shanmugasundaram, linux-arm-kernel
As per Wolfgang G, all new drivers should support decreasing state
transition(back-to-error-active). This patch adds this support.
This driver configures the controller to halt on bus-off entry. Hence,
when in error states less than bus off state, the TEC/REC counters
are checked for lower state transition eligibility and action.
Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
---
drivers/net/can/rcar/rcar_canfd.c | 76 ++++++++++++++++++++++++++++-----------
1 file changed, 56 insertions(+), 20 deletions(-)
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 6bcc474..43cdd55 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -917,16 +917,17 @@ static void rcar_canfd_global_error(struct net_device *ndev)
rcar_canfd_write(priv->base, RCANFD_GERFL, 0);
}
-static void rcar_canfd_error(struct net_device *ndev)
+static void rcar_canfd_error(struct net_device *ndev, u32 cerfl,
+ u16 txerr, u16 rxerr)
{
struct rcar_canfd_channel *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
struct can_frame *cf;
struct sk_buff *skb;
- u32 cerfl, csts;
- u32 txerr = 0, rxerr = 0;
u32 ch = priv->channel;
+ netdev_dbg(ndev, "ch erfl %x txerr %u rxerr %u\n", cerfl, txerr, rxerr);
+
/* Propagate the error condition to the CAN stack */
skb = alloc_can_err_skb(ndev, &cf);
if (!skb) {
@@ -934,15 +935,7 @@ static void rcar_canfd_error(struct net_device *ndev)
return;
}
- /* Channel error interrupt */
- cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch));
- csts = rcar_canfd_read(priv->base, RCANFD_CSTS(ch));
- txerr = RCANFD_CSTS_TECCNT(csts);
- rxerr = RCANFD_CSTS_RECCNT(csts);
-
- netdev_dbg(ndev, "ch erfl %x sts %x txerr %u rxerr %u\n",
- cerfl, csts, txerr, rxerr);
-
+ /* Channel error interrupts */
if (cerfl & RCANFD_CERFL_BEF) {
netdev_dbg(ndev, "Bus error\n");
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
@@ -1032,8 +1025,9 @@ static void rcar_canfd_error(struct net_device *ndev)
cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
}
- /* Clear all channel error interrupts */
- rcar_canfd_write(priv->base, RCANFD_CERFL(ch), 0);
+ /* Clear channel error interrupts that are handled */
+ rcar_canfd_write(priv->base, RCANFD_CERFL(ch),
+ RCANFD_CERFL_ERR(~cerfl));
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
@@ -1098,12 +1092,12 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
/* Global error interrupts */
gerfl = rcar_canfd_read(priv->base, RCANFD_GERFL);
- if (RCANFD_GERFL_ERR(gpriv, gerfl))
+ if (unlikely(RCANFD_GERFL_ERR(gpriv, gerfl)))
rcar_canfd_global_error(ndev);
/* Handle Rx interrupts */
sts = rcar_canfd_read(priv->base, RCANFD_RFSTS(ridx));
- if (sts & RCANFD_RFSTS_RFIF) {
+ if (likely(sts & RCANFD_RFSTS_RFIF)) {
if (napi_schedule_prep(&priv->napi)) {
/* Disable Rx FIFO interrupts */
rcar_canfd_clear_bit(priv->base,
@@ -1116,12 +1110,46 @@ static irqreturn_t rcar_canfd_global_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void rcar_canfd_state_change(struct net_device *ndev,
+ u16 txerr, u16 rxerr)
+{
+ struct rcar_canfd_channel *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ enum can_state rx_state, tx_state, state = priv->can.state;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /* Handle transition from error to normal states */
+ if (txerr < 96 && rxerr < 96)
+ state = CAN_STATE_ERROR_ACTIVE;
+ else if (txerr < 128 && rxerr < 128)
+ state = CAN_STATE_ERROR_WARNING;
+
+ if (state != priv->can.state) {
+ netdev_dbg(ndev, "state: new %d, old %d: txerr %u, rxerr %u\n",
+ state, priv->can.state, txerr, rxerr);
+ skb = alloc_can_err_skb(ndev, &cf);
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+ tx_state = txerr >= rxerr ? state : 0;
+ rx_state = txerr <= rxerr ? state : 0;
+
+ can_change_state(ndev, cf, tx_state, rx_state);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_rx(skb);
+ }
+}
+
static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
{
struct rcar_canfd_global *gpriv = dev_id;
struct net_device *ndev;
struct rcar_canfd_channel *priv;
- u32 sts, cerfl, ch;
+ 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) {
@@ -1130,13 +1158,21 @@ static irqreturn_t rcar_canfd_channel_interrupt(int irq, void *dev_id)
/* Channel error interrupts */
cerfl = rcar_canfd_read(priv->base, RCANFD_CERFL(ch));
- if (RCANFD_CERFL_ERR(cerfl))
- rcar_canfd_error(ndev);
+ 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);
/* Handle Tx interrupts */
sts = rcar_canfd_read(priv->base,
RCANFD_CFSTS(ch, RCANFD_CFFIFO_IDX));
- if (sts & RCANFD_CFSTS_CFTXIF)
+ if (likely(sts & RCANFD_CFSTS_CFTXIF))
rcar_canfd_tx_done(ndev);
}
return IRQ_HANDLED;
--
1.9.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support
2016-06-22 12:31 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Ramesh Shanmugasundaram
2016-06-22 12:31 ` [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
2016-06-22 12:31 ` [PATCH v2 2/2] can: rcar_canfd: Add back-to-error-active support Ramesh Shanmugasundaram
@ 2016-06-22 20:34 ` Marc Kleine-Budde
2 siblings, 0 replies; 7+ messages in thread
From: Marc Kleine-Budde @ 2016-06-22 20:34 UTC (permalink / raw)
To: Ramesh Shanmugasundaram, wg, robh+dt, pawel.moll, mark.rutland,
ijc+devicetree, galak
Cc: ulrich.hecht+renesas, horms, linux-renesas-soc, devicetree,
linux-can, linux-arm-kernel, chris.paterson2, magnus.damm,
socketcan
[-- Attachment #1.1: Type: text/plain, Size: 1039 bytes --]
On 06/22/2016 02:31 PM, Ramesh Shanmugasundaram wrote:
> This patch is based on latest can-next(tag:linux-can-next-for-4.8-20160617).
>
> Changes since v1:
> - property named changed from "can-nofd" to "no-can-fd" (Rob H)
> - added new patch(0002) that support lower state transitions (Wolfgang G)
> (http://marc.info/?l=linux-can&m=146650325116971&w=2)
>
> Ramesh Shanmugasundaram (2):
> can: rcar_canfd: Add Classical CAN only mode support
> can: rcar_canfd: Add back-to-error-active support
>
> .../devicetree/bindings/net/can/rcar_canfd.txt | 21 +-
> drivers/net/can/rcar/rcar_canfd.c | 429 ++++++++++++++-------
> 2 files changed, 310 insertions(+), 140 deletions(-)
Applied to can-next.
Tnx,
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support
2016-06-22 12:31 ` [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
@ 2016-06-24 16:12 ` Rob Herring
0 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2016-06-24 16:12 UTC (permalink / raw)
To: Ramesh Shanmugasundaram
Cc: mkl, wg, pawel.moll, mark.rutland, ijc+devicetree, galak,
ulrich.hecht+renesas, horms, linux-renesas-soc, devicetree,
linux-can, linux-arm-kernel, chris.paterson2, magnus.damm,
socketcan
On Wed, Jun 22, 2016 at 01:31:46PM +0100, Ramesh Shanmugasundaram wrote:
> The controller can operate in one of the two global modes
> - CAN FD only mode (default)
> - Classical CAN (CAN2.0) only mode
>
> This patch adds support for Classical CAN only mode. It can be enabled
> by defining the optional device tree property "renesas,no-can-fd" of this
> node.
>
> Note: R-Car Gen3 h/w manual v0.51E shows bit6 of RSCFDnCFDGCFG as
> reserved, which is incorrect. This bit is same as RSCFDnGCFG.
>
> Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
> ---
> .../devicetree/bindings/net/can/rcar_canfd.txt | 21 +-
Acked-by: Rob Herring <robh@kernel.org>
> drivers/net/can/rcar/rcar_canfd.c | 355 ++++++++++++++-------
> 2 files changed, 255 insertions(+), 121 deletions(-)
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-06-24 16:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-20 14:46 [PATCH] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
2016-06-21 13:29 ` Rob Herring
2016-06-22 12:31 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Ramesh Shanmugasundaram
2016-06-22 12:31 ` [PATCH v2 1/2] can: rcar_canfd: Add Classical CAN only mode support Ramesh Shanmugasundaram
2016-06-24 16:12 ` Rob Herring
2016-06-22 12:31 ` [PATCH v2 2/2] can: rcar_canfd: Add back-to-error-active support Ramesh Shanmugasundaram
2016-06-22 20:34 ` [PATCH v2 0/2] can: rcar_canfd: Add Classical CAN & lower state transition support Marc Kleine-Budde
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).