All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bhupesh Sharma <bhupesh.sharma@freescale.com>
To: arnd@arndb.de, linux-can@vger.kernel.org, mkl@pengutronix.de
Cc: bhupesh.sharma@freescale.com, bhupesh.linux@gmail.com,
	linux-arm-kernel@lists.infradead.org, Sakar.Arora@freescale.com
Subject: [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO mode
Date: Thu, 14 May 2015 17:03:35 +0530	[thread overview]
Message-ID: <1431603215-25546-6-git-send-email-bhupesh.sharma@freescale.com> (raw)
In-Reply-To: <1431603215-25546-1-git-send-email-bhupesh.sharma@freescale.com>

This patch adds support for non RX-FIFO (legacy) mode in
the flexcan driver.

On certain SoCs, the RX-FIFO support might be broken, as
a result we need to fall-back on the legacy (non RX-FIFO)
mode to receive CAN frames.

Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
---
 drivers/net/can/flexcan.c |  188 +++++++++++++++++++++++++++++++++------------
 1 file changed, 138 insertions(+), 50 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index b0222ae..3240472 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -156,6 +156,9 @@
 #define FLEXCAN_IFLAG_DEFAULT \
 	(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
 	 FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#define FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE \
+	 (FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#define FLEXCAN_IFLAG_RX_MB_RXMASK	((1 << FLEXCAN_TX_BUF_RESERVED) - 1)
 
 /* FLEXCAN message buffers */
 #define FLEXCAN_MB_CNT_CODE(x)		(((x) & 0xf) << 24)
@@ -198,6 +201,8 @@
 #define FLEXCAN_HAS_V10_FEATURES	BIT(1) /* For core version >= 10 */
 #define FLEXCAN_HAS_BROKEN_ERR_STATE	BIT(2) /* [TR]WRN_INT not connected */
 #define FLEXCAN_HAS_MECR_FEATURES	BIT(3) /* Memory error detection */
+#define FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT \
+	 BIT(4) /* No RX FIFO mode support */
 
 /* Structure of the message buffer */
 struct flexcan_mb {
@@ -252,6 +257,7 @@ struct flexcan_priv {
 	void __iomem *base;
 	u32 reg_esr;
 	u32 reg_ctrl_default;
+	u32 rx_msg_buf;
 
 	struct clk *clk_ipg;
 	struct clk *clk_per;
@@ -303,8 +309,7 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
 	.brp_inc = 1,
 };
 
-/*
- * FlexCAN module is essentially modelled as a little-endian IP in most
+/* FlexCAN module is essentially modelled as a little-endian IP in most
  * SoCs, i.e the registers as well as the message buffer areas are
  * implemented in a little-endian fashion.
  *
@@ -646,12 +651,10 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
 	return 1;
 }
 
-static void flexcan_read_fifo(const struct net_device *dev,
-			      struct can_frame *cf)
+static void flexcan_read_can_frame(const struct flexcan_priv *priv,
+				   struct flexcan_mb __iomem *mb,
+				   struct can_frame *cf)
 {
-	const struct flexcan_priv *priv = netdev_priv(dev);
-	struct flexcan_regs __iomem *regs = priv->base;
-	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
 	u32 reg_ctrl, reg_id;
 
 	reg_ctrl = priv->read(&mb->can_ctrl);
@@ -667,14 +670,39 @@ static void flexcan_read_fifo(const struct net_device *dev,
 
 	*(__be32 *)(cf->data + 0) = cpu_to_be32(priv->read(&mb->data[0]));
 	*(__be32 *)(cf->data + 4) = cpu_to_be32(priv->read(&mb->data[1]));
+}
+
+static void flexcan_read_fifo(const struct net_device *dev,
+			      struct can_frame *cf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
+
+	flexcan_read_can_frame(priv, mb, cf);
 
 	/* mark as read */
 	priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
 	priv->read(&regs->timer);
 }
 
+static void flexcan_read_msg_buf(const struct net_device *dev,
+				 struct can_frame *cf, u32 msg_buf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[msg_buf];
+
+	flexcan_read_can_frame(priv, mb, cf);
+
+	/* mark as read */
+	priv->write(BIT(msg_buf), &regs->iflag1);
+	priv->read(&regs->timer);
+}
+
 static int flexcan_read_frame(struct net_device *dev)
 {
+	const struct flexcan_priv *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &dev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
@@ -685,7 +713,11 @@ static int flexcan_read_frame(struct net_device *dev)
 		return 0;
 	}
 
-	flexcan_read_fifo(dev, cf);
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		flexcan_read_msg_buf(dev, cf, priv->rx_msg_buf);
+	else
+		flexcan_read_fifo(dev, cf);
+
 	netif_receive_skb(skb);
 
 	stats->rx_packets++;
@@ -699,9 +731,10 @@ static int flexcan_read_frame(struct net_device *dev)
 static int flexcan_poll(struct napi_struct *napi, int quota)
 {
 	struct net_device *dev = napi->dev;
-	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->base;
 	u32 reg_iflag1, reg_esr;
+	unsigned long iflag1;
 	int work_done = 0;
 
 	/*
@@ -713,12 +746,25 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
 	/* handle state changes */
 	work_done += flexcan_poll_state(dev, reg_esr);
 
-	/* handle RX-FIFO */
 	reg_iflag1 = priv->read(&regs->iflag1);
-	while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
-	       work_done < quota) {
-		work_done += flexcan_read_frame(dev);
-		reg_iflag1 = priv->read(&regs->iflag1);
+
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		/* handle legacy RX mode */
+		iflag1 = reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK;
+		while ((reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK) &&
+		       work_done < quota) {
+			priv->rx_msg_buf = find_first_bit(&iflag1,
+						(FLEXCAN_TX_BUF_ID - 1));
+			work_done += flexcan_read_frame(dev);
+			reg_iflag1 = priv->read(&regs->iflag1);
+		}
+	} else {
+		/* handle RX-FIFO */
+		while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
+		       work_done < quota) {
+			work_done += flexcan_read_frame(dev);
+			reg_iflag1 = priv->read(&regs->iflag1);
+		}
 	}
 
 	/* report bus errors */
@@ -728,7 +774,13 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
 	if (work_done < quota) {
 		napi_complete(napi);
 		/* enable IRQs */
-		priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+		if (priv->devtype_data->features &
+		    FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+			priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE |
+				    FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+		else
+			priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+
 		priv->write(priv->reg_ctrl_default, &regs->ctrl);
 	}
 
@@ -755,26 +807,45 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
 	 * - state change IRQ
 	 * - bus error IRQ and bus error reporting is activated
 	 */
-	if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
-	    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
-	    flexcan_has_and_handle_berr(priv, reg_esr)) {
-		/*
-		 * The error bits are cleared on read,
-		 * save them for later use.
-		 */
-		priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
-		priv->write(FLEXCAN_IFLAG_DEFAULT &
-			~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
-		priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
-		       &regs->ctrl);
-		napi_schedule(&priv->napi);
-	}
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		if ((reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK) ||
+		    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+		    flexcan_has_and_handle_berr(priv, reg_esr)) {
+			/* The error bits are cleared on read,
+			 * save them for later use.
+			 */
+			priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+			priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE &
+				    ~FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+			priv->write(priv->reg_ctrl_default &
+				    ~FLEXCAN_CTRL_ERR_ALL, &regs->ctrl);
+
+			napi_schedule(&priv->napi);
+		}
+	} else {
+		if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
+		    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+		    flexcan_has_and_handle_berr(priv, reg_esr)) {
+			/*
+			 * The error bits are cleared on read,
+			 * save them for later use.
+			 */
+			priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+			priv->write(FLEXCAN_IFLAG_DEFAULT &
+				    ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
+				    &regs->imask1);
+			priv->write(priv->reg_ctrl_default &
+				    ~FLEXCAN_CTRL_ERR_ALL, &regs->ctrl);
+			napi_schedule(&priv->napi);
+		}
 
-	/* FIFO overflow */
-	if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
-		priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
-		dev->stats.rx_over_errors++;
-		dev->stats.rx_errors++;
+		/* FIFO overflow */
+		if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
+			priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW,
+				    &regs->iflag1);
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
+		}
 	}
 
 	/* transmission complete interrupt */
@@ -869,7 +940,12 @@ static int flexcan_chip_start(struct net_device *dev)
 	 */
 	reg_mcr = priv->read(&regs->mcr);
 	reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
-	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		reg_mcr &= ~FLEXCAN_MCR_FEN;
+	else
+		reg_mcr |= FLEXCAN_MCR_FEN;
+
+	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
 		FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
 		FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
 		FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
@@ -966,8 +1042,13 @@ static int flexcan_chip_start(struct net_device *dev)
 
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
-	/* enable FIFO interrupts */
-	priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		/* enable mb interrupts */
+		priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE |
+			    FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+	else
+		/* enable FIFO interrupts */
+		priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
 
 	/* print chip status */
 	netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
@@ -1125,22 +1206,29 @@ static int register_flexcandev(struct net_device *dev)
 	if (err)
 		goto out_chip_disable;
 
-	/* set freeze, halt and activate FIFO, restrict register access */
+	/* set freeze, halt and activate FIFO/legacy mode, restrict
+	 * register access
+	 */
 	reg = priv->read(&regs->mcr);
-	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
-		FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		reg &= ~FLEXCAN_MCR_FEN;
+	else
+		reg |= FLEXCAN_MCR_FEN;
+
+	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV;
 	priv->write(reg, &regs->mcr);
 
-	/*
-	 * Currently we only support newer versions of this core
-	 * featuring a RX FIFO. Older cores found on some Coldfire
-	 * derivates are not yet supported.
-	 */
-	reg = priv->read(&regs->mcr);
-	if (!(reg & FLEXCAN_MCR_FEN)) {
-		netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
-		err = -ENODEV;
-		goto out_chip_disable;
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		/* Legacy RX mode*/
+		netdev_info(dev, "Legacy mode (non RX-FIFO) enabled\n");
+	} else {
+		/* RX FIFO mode */
+		reg = priv->read(&regs->mcr);
+		if (!(reg & FLEXCAN_MCR_FEN)) {
+			netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
+			err = -ENODEV;
+			goto out_chip_disable;
+		}
 	}
 
 	err = register_candev(dev);
-- 
1.7.9.5

WARNING: multiple messages have this Message-ID (diff)
From: bhupesh.sharma@freescale.com (Bhupesh Sharma)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO mode
Date: Thu, 14 May 2015 17:03:35 +0530	[thread overview]
Message-ID: <1431603215-25546-6-git-send-email-bhupesh.sharma@freescale.com> (raw)
In-Reply-To: <1431603215-25546-1-git-send-email-bhupesh.sharma@freescale.com>

This patch adds support for non RX-FIFO (legacy) mode in
the flexcan driver.

On certain SoCs, the RX-FIFO support might be broken, as
a result we need to fall-back on the legacy (non RX-FIFO)
mode to receive CAN frames.

Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com>
Signed-off-by: Sakar Arora <Sakar.Arora@freescale.com>
---
 drivers/net/can/flexcan.c |  188 +++++++++++++++++++++++++++++++++------------
 1 file changed, 138 insertions(+), 50 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index b0222ae..3240472 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -156,6 +156,9 @@
 #define FLEXCAN_IFLAG_DEFAULT \
 	(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
 	 FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#define FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE \
+	 (FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+#define FLEXCAN_IFLAG_RX_MB_RXMASK	((1 << FLEXCAN_TX_BUF_RESERVED) - 1)
 
 /* FLEXCAN message buffers */
 #define FLEXCAN_MB_CNT_CODE(x)		(((x) & 0xf) << 24)
@@ -198,6 +201,8 @@
 #define FLEXCAN_HAS_V10_FEATURES	BIT(1) /* For core version >= 10 */
 #define FLEXCAN_HAS_BROKEN_ERR_STATE	BIT(2) /* [TR]WRN_INT not connected */
 #define FLEXCAN_HAS_MECR_FEATURES	BIT(3) /* Memory error detection */
+#define FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT \
+	 BIT(4) /* No RX FIFO mode support */
 
 /* Structure of the message buffer */
 struct flexcan_mb {
@@ -252,6 +257,7 @@ struct flexcan_priv {
 	void __iomem *base;
 	u32 reg_esr;
 	u32 reg_ctrl_default;
+	u32 rx_msg_buf;
 
 	struct clk *clk_ipg;
 	struct clk *clk_per;
@@ -303,8 +309,7 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
 	.brp_inc = 1,
 };
 
-/*
- * FlexCAN module is essentially modelled as a little-endian IP in most
+/* FlexCAN module is essentially modelled as a little-endian IP in most
  * SoCs, i.e the registers as well as the message buffer areas are
  * implemented in a little-endian fashion.
  *
@@ -646,12 +651,10 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
 	return 1;
 }
 
-static void flexcan_read_fifo(const struct net_device *dev,
-			      struct can_frame *cf)
+static void flexcan_read_can_frame(const struct flexcan_priv *priv,
+				   struct flexcan_mb __iomem *mb,
+				   struct can_frame *cf)
 {
-	const struct flexcan_priv *priv = netdev_priv(dev);
-	struct flexcan_regs __iomem *regs = priv->base;
-	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
 	u32 reg_ctrl, reg_id;
 
 	reg_ctrl = priv->read(&mb->can_ctrl);
@@ -667,14 +670,39 @@ static void flexcan_read_fifo(const struct net_device *dev,
 
 	*(__be32 *)(cf->data + 0) = cpu_to_be32(priv->read(&mb->data[0]));
 	*(__be32 *)(cf->data + 4) = cpu_to_be32(priv->read(&mb->data[1]));
+}
+
+static void flexcan_read_fifo(const struct net_device *dev,
+			      struct can_frame *cf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[0];
+
+	flexcan_read_can_frame(priv, mb, cf);
 
 	/* mark as read */
 	priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
 	priv->read(&regs->timer);
 }
 
+static void flexcan_read_msg_buf(const struct net_device *dev,
+				 struct can_frame *cf, u32 msg_buf)
+{
+	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_regs __iomem *regs = priv->base;
+	struct flexcan_mb __iomem *mb = &regs->cantxfg[msg_buf];
+
+	flexcan_read_can_frame(priv, mb, cf);
+
+	/* mark as read */
+	priv->write(BIT(msg_buf), &regs->iflag1);
+	priv->read(&regs->timer);
+}
+
 static int flexcan_read_frame(struct net_device *dev)
 {
+	const struct flexcan_priv *priv = netdev_priv(dev);
 	struct net_device_stats *stats = &dev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
@@ -685,7 +713,11 @@ static int flexcan_read_frame(struct net_device *dev)
 		return 0;
 	}
 
-	flexcan_read_fifo(dev, cf);
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		flexcan_read_msg_buf(dev, cf, priv->rx_msg_buf);
+	else
+		flexcan_read_fifo(dev, cf);
+
 	netif_receive_skb(skb);
 
 	stats->rx_packets++;
@@ -699,9 +731,10 @@ static int flexcan_read_frame(struct net_device *dev)
 static int flexcan_poll(struct napi_struct *napi, int quota)
 {
 	struct net_device *dev = napi->dev;
-	const struct flexcan_priv *priv = netdev_priv(dev);
+	struct flexcan_priv *priv = netdev_priv(dev);
 	struct flexcan_regs __iomem *regs = priv->base;
 	u32 reg_iflag1, reg_esr;
+	unsigned long iflag1;
 	int work_done = 0;
 
 	/*
@@ -713,12 +746,25 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
 	/* handle state changes */
 	work_done += flexcan_poll_state(dev, reg_esr);
 
-	/* handle RX-FIFO */
 	reg_iflag1 = priv->read(&regs->iflag1);
-	while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
-	       work_done < quota) {
-		work_done += flexcan_read_frame(dev);
-		reg_iflag1 = priv->read(&regs->iflag1);
+
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		/* handle legacy RX mode */
+		iflag1 = reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK;
+		while ((reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK) &&
+		       work_done < quota) {
+			priv->rx_msg_buf = find_first_bit(&iflag1,
+						(FLEXCAN_TX_BUF_ID - 1));
+			work_done += flexcan_read_frame(dev);
+			reg_iflag1 = priv->read(&regs->iflag1);
+		}
+	} else {
+		/* handle RX-FIFO */
+		while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
+		       work_done < quota) {
+			work_done += flexcan_read_frame(dev);
+			reg_iflag1 = priv->read(&regs->iflag1);
+		}
 	}
 
 	/* report bus errors */
@@ -728,7 +774,13 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
 	if (work_done < quota) {
 		napi_complete(napi);
 		/* enable IRQs */
-		priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+		if (priv->devtype_data->features &
+		    FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+			priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE |
+				    FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+		else
+			priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+
 		priv->write(priv->reg_ctrl_default, &regs->ctrl);
 	}
 
@@ -755,26 +807,45 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
 	 * - state change IRQ
 	 * - bus error IRQ and bus error reporting is activated
 	 */
-	if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
-	    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
-	    flexcan_has_and_handle_berr(priv, reg_esr)) {
-		/*
-		 * The error bits are cleared on read,
-		 * save them for later use.
-		 */
-		priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
-		priv->write(FLEXCAN_IFLAG_DEFAULT &
-			~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
-		priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
-		       &regs->ctrl);
-		napi_schedule(&priv->napi);
-	}
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		if ((reg_iflag1 & FLEXCAN_IFLAG_RX_MB_RXMASK) ||
+		    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+		    flexcan_has_and_handle_berr(priv, reg_esr)) {
+			/* The error bits are cleared on read,
+			 * save them for later use.
+			 */
+			priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+			priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE &
+				    ~FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+			priv->write(priv->reg_ctrl_default &
+				    ~FLEXCAN_CTRL_ERR_ALL, &regs->ctrl);
+
+			napi_schedule(&priv->napi);
+		}
+	} else {
+		if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
+		    (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
+		    flexcan_has_and_handle_berr(priv, reg_esr)) {
+			/*
+			 * The error bits are cleared on read,
+			 * save them for later use.
+			 */
+			priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
+			priv->write(FLEXCAN_IFLAG_DEFAULT &
+				    ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
+				    &regs->imask1);
+			priv->write(priv->reg_ctrl_default &
+				    ~FLEXCAN_CTRL_ERR_ALL, &regs->ctrl);
+			napi_schedule(&priv->napi);
+		}
 
-	/* FIFO overflow */
-	if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
-		priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
-		dev->stats.rx_over_errors++;
-		dev->stats.rx_errors++;
+		/* FIFO overflow */
+		if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
+			priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW,
+				    &regs->iflag1);
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
+		}
 	}
 
 	/* transmission complete interrupt */
@@ -869,7 +940,12 @@ static int flexcan_chip_start(struct net_device *dev)
 	 */
 	reg_mcr = priv->read(&regs->mcr);
 	reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
-	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		reg_mcr &= ~FLEXCAN_MCR_FEN;
+	else
+		reg_mcr |= FLEXCAN_MCR_FEN;
+
+	reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
 		FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
 		FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
 		FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
@@ -966,8 +1042,13 @@ static int flexcan_chip_start(struct net_device *dev)
 
 	priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
-	/* enable FIFO interrupts */
-	priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		/* enable mb interrupts */
+		priv->write(FLEXCAN_IFLAG_DEFAULT_RX_MB_MODE |
+			    FLEXCAN_IFLAG_RX_MB_RXMASK, &regs->imask1);
+	else
+		/* enable FIFO interrupts */
+		priv->write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
 
 	/* print chip status */
 	netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
@@ -1125,22 +1206,29 @@ static int register_flexcandev(struct net_device *dev)
 	if (err)
 		goto out_chip_disable;
 
-	/* set freeze, halt and activate FIFO, restrict register access */
+	/* set freeze, halt and activate FIFO/legacy mode, restrict
+	 * register access
+	 */
 	reg = priv->read(&regs->mcr);
-	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
-		FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT)
+		reg &= ~FLEXCAN_MCR_FEN;
+	else
+		reg |= FLEXCAN_MCR_FEN;
+
+	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV;
 	priv->write(reg, &regs->mcr);
 
-	/*
-	 * Currently we only support newer versions of this core
-	 * featuring a RX FIFO. Older cores found on some Coldfire
-	 * derivates are not yet supported.
-	 */
-	reg = priv->read(&regs->mcr);
-	if (!(reg & FLEXCAN_MCR_FEN)) {
-		netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
-		err = -ENODEV;
-		goto out_chip_disable;
+	if (priv->devtype_data->features & FLEXCAN_HAS_ONLY_LEGACY_RX_SUPPORT) {
+		/* Legacy RX mode*/
+		netdev_info(dev, "Legacy mode (non RX-FIFO) enabled\n");
+	} else {
+		/* RX FIFO mode */
+		reg = priv->read(&regs->mcr);
+		if (!(reg & FLEXCAN_MCR_FEN)) {
+			netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
+			err = -ENODEV;
+			goto out_chip_disable;
+		}
 	}
 
 	err = register_candev(dev);
-- 
1.7.9.5

  parent reply	other threads:[~2015-05-14 11:33 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-14 11:33 [PATCH v2 0/5] Add flexcan support for LS1021A SoCs Bhupesh Sharma
2015-05-14 11:33 ` Bhupesh Sharma
2015-05-14 11:33 ` [PATCH v2 1/5] doc/bindings: Add 'endianess' optional-property for FlexCAN controller Bhupesh Sharma
2015-05-14 11:33   ` Bhupesh Sharma
2015-05-14 11:33 ` [PATCH v2 2/5] arm/dts: Add nodes for flexcan devices present on LS1021A SoC Bhupesh Sharma
2015-05-14 11:33   ` Bhupesh Sharma
2015-05-14 11:33 ` [PATCH v2 3/5] can: flexcan: Add ls1021a flexcan device entry Bhupesh Sharma
2015-05-14 11:33   ` Bhupesh Sharma
2015-05-14 15:38   ` Marc Kleine-Budde
2015-05-14 15:38     ` Marc Kleine-Budde
2015-05-14 11:33 ` [PATCH v2 4/5] can: flexcan: Remodel FlexCAN register r/w APIs for BE instances Bhupesh Sharma
2015-05-14 11:33   ` Bhupesh Sharma
2015-05-18 16:17   ` Enrico Weigelt, metux IT consult
2015-05-18 16:17     ` Enrico Weigelt, metux IT consult
2015-05-18 16:37     ` Sharma Bhupesh
2015-05-18 16:37       ` Sharma Bhupesh
2015-05-14 11:33 ` Bhupesh Sharma [this message]
2015-05-14 11:33   ` [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO mode Bhupesh Sharma
2015-05-14 15:41   ` Marc Kleine-Budde
2015-05-14 15:41     ` Marc Kleine-Budde
2015-05-14 15:44     ` Sharma Bhupesh
2015-05-14 15:44       ` Sharma Bhupesh
2015-12-10 11:05       ` Sharma Bhupesh
2015-12-10 11:05         ` Sharma Bhupesh
2015-12-10 11:44         ` can: flexcan: Ancient Freescale Reference FlexCAN Driver and bug fixes so it works Tom Evans
2015-12-10 12:44           ` Marc Kleine-Budde
2015-12-10 12:44             ` Marc Kleine-Budde
2015-12-10 22:53             ` Tom Evans
2015-12-10 22:53               ` Tom Evans
2015-12-17  4:22               ` Tom Evans
2015-12-17  4:22                 ` Tom Evans
2015-12-23  0:53                 ` Tom Evans
2015-12-23  0:53                   ` Tom Evans
2015-12-10 12:19         ` [PATCH v2 5/5] can: flexcan: Add support for non RX-FIFO mode Marc Kleine-Budde
2015-12-10 12:19           ` Marc Kleine-Budde
2015-12-10 12:22           ` Sharma Bhupesh
2015-12-10 12:22             ` Sharma Bhupesh
2015-12-11 16:01             ` Robert Schwebel
2015-12-11 16:01               ` Robert Schwebel
2015-05-15  0:09     ` Tom Evans
2015-05-15  0:09       ` Tom Evans

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1431603215-25546-6-git-send-email-bhupesh.sharma@freescale.com \
    --to=bhupesh.sharma@freescale.com \
    --cc=Sakar.Arora@freescale.com \
    --cc=arnd@arndb.de \
    --cc=bhupesh.linux@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-can@vger.kernel.org \
    --cc=mkl@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.