|
@@ -182,22 +182,23 @@
|
|
/* FLEXCAN hardware feature flags
|
|
/* FLEXCAN hardware feature flags
|
|
*
|
|
*
|
|
* Below is some version info we got:
|
|
* Below is some version info we got:
|
|
- * SOC Version IP-Version Glitch- [TR]WRN_INT Memory err RTR re-
|
|
|
|
- * Filter? connected? detection ception in MB
|
|
|
|
- * MX25 FlexCAN2 03.00.00.00 no no no no
|
|
|
|
- * MX28 FlexCAN2 03.00.04.00 yes yes no no
|
|
|
|
- * MX35 FlexCAN2 03.00.00.00 no no no no
|
|
|
|
- * MX53 FlexCAN2 03.00.00.00 yes no no no
|
|
|
|
- * MX6s FlexCAN3 10.00.12.00 yes yes no yes
|
|
|
|
- * VF610 FlexCAN3 ? no yes yes yes?
|
|
|
|
|
|
+ * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR re-
|
|
|
|
+ * Filter? connected? Passive detection ception in MB
|
|
|
|
+ * MX25 FlexCAN2 03.00.00.00 no no ? no no
|
|
|
|
+ * MX28 FlexCAN2 03.00.04.00 yes yes no no no
|
|
|
|
+ * MX35 FlexCAN2 03.00.00.00 no no ? no no
|
|
|
|
+ * MX53 FlexCAN2 03.00.00.00 yes no no no no
|
|
|
|
+ * MX6s FlexCAN3 10.00.12.00 yes yes no no yes
|
|
|
|
+ * VF610 FlexCAN3 ? no yes ? yes yes?
|
|
*
|
|
*
|
|
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
|
|
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
|
|
*/
|
|
*/
|
|
-#define FLEXCAN_QUIRK_BROKEN_ERR_STATE BIT(1) /* [TR]WRN_INT not connected */
|
|
|
|
|
|
+#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) /* [TR]WRN_INT not connected */
|
|
#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */
|
|
#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */
|
|
#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) /* Enable EACEN and RRS bit in ctrl2 */
|
|
#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) /* Enable EACEN and RRS bit in ctrl2 */
|
|
#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable Memory error detection */
|
|
#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) /* Disable Memory error detection */
|
|
#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */
|
|
#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */
|
|
|
|
+#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */
|
|
|
|
|
|
/* Structure of the message buffer */
|
|
/* Structure of the message buffer */
|
|
struct flexcan_mb {
|
|
struct flexcan_mb {
|
|
@@ -281,14 +282,17 @@ struct flexcan_priv {
|
|
};
|
|
};
|
|
|
|
|
|
static const struct flexcan_devtype_data fsl_p1010_devtype_data = {
|
|
static const struct flexcan_devtype_data fsl_p1010_devtype_data = {
|
|
- .quirks = FLEXCAN_QUIRK_BROKEN_ERR_STATE,
|
|
|
|
|
|
+ .quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE |
|
|
|
|
+ FLEXCAN_QUIRK_BROKEN_PERR_STATE,
|
|
};
|
|
};
|
|
|
|
|
|
-static const struct flexcan_devtype_data fsl_imx28_devtype_data;
|
|
|
|
|
|
+static const struct flexcan_devtype_data fsl_imx28_devtype_data = {
|
|
|
|
+ .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE,
|
|
|
|
+};
|
|
|
|
|
|
static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
|
|
static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
|
|
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
|
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
|
- FLEXCAN_QUIRK_USE_OFF_TIMESTAMP,
|
|
|
|
|
|
+ FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE,
|
|
};
|
|
};
|
|
|
|
|
|
static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
|
|
static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
|
|
@@ -335,6 +339,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv)
|
|
|
|
+{
|
|
|
|
+ struct flexcan_regs __iomem *regs = priv->regs;
|
|
|
|
+ u32 reg_ctrl = (priv->reg_ctrl_default | FLEXCAN_CTRL_ERR_MSK);
|
|
|
|
+
|
|
|
|
+ flexcan_write(reg_ctrl, ®s->ctrl);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void flexcan_error_irq_disable(const struct flexcan_priv *priv)
|
|
|
|
+{
|
|
|
|
+ struct flexcan_regs __iomem *regs = priv->regs;
|
|
|
|
+ u32 reg_ctrl = (priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_MSK);
|
|
|
|
+
|
|
|
|
+ flexcan_write(reg_ctrl, ®s->ctrl);
|
|
|
|
+}
|
|
|
|
+
|
|
static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
|
|
static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
|
|
{
|
|
{
|
|
if (!priv->reg_xceiver)
|
|
if (!priv->reg_xceiver)
|
|
@@ -713,6 +733,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|
struct flexcan_regs __iomem *regs = priv->regs;
|
|
struct flexcan_regs __iomem *regs = priv->regs;
|
|
irqreturn_t handled = IRQ_NONE;
|
|
irqreturn_t handled = IRQ_NONE;
|
|
u32 reg_iflag1, reg_esr;
|
|
u32 reg_iflag1, reg_esr;
|
|
|
|
+ enum can_state last_state = priv->can.state;
|
|
|
|
|
|
reg_iflag1 = flexcan_read(®s->iflag1);
|
|
reg_iflag1 = flexcan_read(®s->iflag1);
|
|
|
|
|
|
@@ -765,8 +786,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|
flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr);
|
|
flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr);
|
|
}
|
|
}
|
|
|
|
|
|
- /* state change interrupt */
|
|
|
|
- if (reg_esr & FLEXCAN_ESR_ERR_STATE)
|
|
|
|
|
|
+ /* state change interrupt or broken error state quirk fix is enabled */
|
|
|
|
+ if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
|
|
|
|
+ (priv->devtype_data->quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE |
|
|
|
|
+ FLEXCAN_QUIRK_BROKEN_PERR_STATE)))
|
|
flexcan_irq_state(dev, reg_esr);
|
|
flexcan_irq_state(dev, reg_esr);
|
|
|
|
|
|
/* bus error IRQ - handle if bus error reporting is activated */
|
|
/* bus error IRQ - handle if bus error reporting is activated */
|
|
@@ -774,6 +797,44 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|
(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
|
|
(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
|
|
flexcan_irq_bus_err(dev, reg_esr);
|
|
flexcan_irq_bus_err(dev, reg_esr);
|
|
|
|
|
|
|
|
+ /* availability of error interrupt among state transitions in case
|
|
|
|
+ * bus error reporting is de-activated and
|
|
|
|
+ * FLEXCAN_QUIRK_BROKEN_PERR_STATE is enabled:
|
|
|
|
+ * +--------------------------------------------------------------+
|
|
|
|
+ * | +----------------------------------------------+ [stopped / |
|
|
|
|
+ * | | | sleeping] -+
|
|
|
|
+ * +-+-> active <-> warning <-> passive -> bus off -+
|
|
|
|
+ * ___________^^^^^^^^^^^^_______________________________
|
|
|
|
+ * disabled(1) enabled disabled
|
|
|
|
+ *
|
|
|
|
+ * (1): enabled if FLEXCAN_QUIRK_BROKEN_WERR_STATE is enabled
|
|
|
|
+ */
|
|
|
|
+ if ((last_state != priv->can.state) &&
|
|
|
|
+ (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_PERR_STATE) &&
|
|
|
|
+ !(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) {
|
|
|
|
+ switch (priv->can.state) {
|
|
|
|
+ case CAN_STATE_ERROR_ACTIVE:
|
|
|
|
+ if (priv->devtype_data->quirks &
|
|
|
|
+ FLEXCAN_QUIRK_BROKEN_WERR_STATE)
|
|
|
|
+ flexcan_error_irq_enable(priv);
|
|
|
|
+ else
|
|
|
|
+ flexcan_error_irq_disable(priv);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case CAN_STATE_ERROR_WARNING:
|
|
|
|
+ flexcan_error_irq_enable(priv);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case CAN_STATE_ERROR_PASSIVE:
|
|
|
|
+ case CAN_STATE_BUS_OFF:
|
|
|
|
+ flexcan_error_irq_disable(priv);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return handled;
|
|
return handled;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -887,7 +948,7 @@ static int flexcan_chip_start(struct net_device *dev)
|
|
* on most Flexcan cores, too. Otherwise we don't get
|
|
* on most Flexcan cores, too. Otherwise we don't get
|
|
* any error warning or passive interrupts.
|
|
* any error warning or passive interrupts.
|
|
*/
|
|
*/
|
|
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_ERR_STATE ||
|
|
|
|
|
|
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_WERR_STATE ||
|
|
priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
|
priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
|
reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
|
|
reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
|
|
else
|
|
else
|