|
|
|
@ -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.
|
|
|
|
@ -837,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) {
|
|
|
|
@ -854,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;
|
|
|
|
@ -952,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);
|
|
|
|
@ -1018,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(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,
|
|
|
|
@ -1036,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) {
|
|
|
|
@ -1050,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;
|
|
|
|
@ -1077,25 +1193,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,28 +1361,38 @@ 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;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
} 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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
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 +1418,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));
|
|
|
|
|
|
|
|
|
|
rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(ridx, 0));
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
} 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 +1580,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 +1640,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 +1675,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 +1786,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:
|
|
|
|
|