162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * CAN bus driver for IFI CANFD controller
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2016 Marek Vasut <marex@denx.de>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Details about this controller can be found at
762306a36Sopenharmony_ci * http://www.ifi-pld.de/IP/CANFD/canfd.html
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
1062306a36Sopenharmony_ci * License version 2. This program is licensed "as is" without any
1162306a36Sopenharmony_ci * warranty of any kind, whether express or implied.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/ethtool.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/io.h>
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/netdevice.h>
2262306a36Sopenharmony_ci#include <linux/of.h>
2362306a36Sopenharmony_ci#include <linux/platform_device.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/can/dev.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define IFI_CANFD_STCMD				0x0
2862306a36Sopenharmony_ci#define IFI_CANFD_STCMD_HARDRESET		0xDEADCAFD
2962306a36Sopenharmony_ci#define IFI_CANFD_STCMD_ENABLE			BIT(0)
3062306a36Sopenharmony_ci#define IFI_CANFD_STCMD_ERROR_ACTIVE		BIT(2)
3162306a36Sopenharmony_ci#define IFI_CANFD_STCMD_ERROR_PASSIVE		BIT(3)
3262306a36Sopenharmony_ci#define IFI_CANFD_STCMD_BUSOFF			BIT(4)
3362306a36Sopenharmony_ci#define IFI_CANFD_STCMD_ERROR_WARNING		BIT(5)
3462306a36Sopenharmony_ci#define IFI_CANFD_STCMD_BUSMONITOR		BIT(16)
3562306a36Sopenharmony_ci#define IFI_CANFD_STCMD_LOOPBACK		BIT(18)
3662306a36Sopenharmony_ci#define IFI_CANFD_STCMD_DISABLE_CANFD		BIT(24)
3762306a36Sopenharmony_ci#define IFI_CANFD_STCMD_ENABLE_ISO		BIT(25)
3862306a36Sopenharmony_ci#define IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING	BIT(26)
3962306a36Sopenharmony_ci#define IFI_CANFD_STCMD_NORMAL_MODE		((u32)BIT(31))
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define IFI_CANFD_RXSTCMD			0x4
4262306a36Sopenharmony_ci#define IFI_CANFD_RXSTCMD_REMOVE_MSG		BIT(0)
4362306a36Sopenharmony_ci#define IFI_CANFD_RXSTCMD_RESET			BIT(7)
4462306a36Sopenharmony_ci#define IFI_CANFD_RXSTCMD_EMPTY			BIT(8)
4562306a36Sopenharmony_ci#define IFI_CANFD_RXSTCMD_OVERFLOW		BIT(13)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD			0x8
4862306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD_ADD_MSG		BIT(0)
4962306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD_HIGH_PRIO		BIT(1)
5062306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD_RESET			BIT(7)
5162306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD_EMPTY			BIT(8)
5262306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD_FULL			BIT(12)
5362306a36Sopenharmony_ci#define IFI_CANFD_TXSTCMD_OVERFLOW		BIT(13)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT			0xc
5662306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_ERROR_BUSOFF	BIT(0)
5762306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_ERROR_WARNING	BIT(1)
5862306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG	BIT(2)
5962306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC	BIT(3)
6062306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_ERROR_COUNTER	BIT(10)
6162306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY	BIT(16)
6262306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE	BIT(22)
6362306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY	BIT(24)
6462306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER	BIT(25)
6562306a36Sopenharmony_ci#define IFI_CANFD_INTERRUPT_SET_IRQ		((u32)BIT(31))
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK			0x10
6862306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_ERROR_BUSOFF		BIT(0)
6962306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_ERROR_WARNING		BIT(1)
7062306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_ERROR_STATE_CHG	BIT(2)
7162306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC	BIT(3)
7262306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_SET_ERR		BIT(7)
7362306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_SET_TS		BIT(15)
7462306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY		BIT(16)
7562306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_SET_TX		BIT(23)
7662306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY		BIT(24)
7762306a36Sopenharmony_ci#define IFI_CANFD_IRQMASK_SET_RX		((u32)BIT(31))
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define IFI_CANFD_TIME				0x14
8062306a36Sopenharmony_ci#define IFI_CANFD_FTIME				0x18
8162306a36Sopenharmony_ci#define IFI_CANFD_TIME_TIMEB_OFF		0
8262306a36Sopenharmony_ci#define IFI_CANFD_TIME_TIMEA_OFF		8
8362306a36Sopenharmony_ci#define IFI_CANFD_TIME_PRESCALE_OFF		16
8462306a36Sopenharmony_ci#define IFI_CANFD_TIME_SJW_OFF_7_9_8_8		25
8562306a36Sopenharmony_ci#define IFI_CANFD_TIME_SJW_OFF_4_12_6_6		28
8662306a36Sopenharmony_ci#define IFI_CANFD_TIME_SET_SJW_4_12_6_6		BIT(6)
8762306a36Sopenharmony_ci#define IFI_CANFD_TIME_SET_TIMEB_4_12_6_6	BIT(7)
8862306a36Sopenharmony_ci#define IFI_CANFD_TIME_SET_PRESC_4_12_6_6	BIT(14)
8962306a36Sopenharmony_ci#define IFI_CANFD_TIME_SET_TIMEA_4_12_6_6	BIT(15)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define IFI_CANFD_TDELAY			0x1c
9262306a36Sopenharmony_ci#define IFI_CANFD_TDELAY_DEFAULT		0xb
9362306a36Sopenharmony_ci#define IFI_CANFD_TDELAY_MASK			0x3fff
9462306a36Sopenharmony_ci#define IFI_CANFD_TDELAY_ABS			BIT(14)
9562306a36Sopenharmony_ci#define IFI_CANFD_TDELAY_EN			BIT(15)
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define IFI_CANFD_ERROR				0x20
9862306a36Sopenharmony_ci#define IFI_CANFD_ERROR_TX_OFFSET		0
9962306a36Sopenharmony_ci#define IFI_CANFD_ERROR_TX_MASK			0xff
10062306a36Sopenharmony_ci#define IFI_CANFD_ERROR_RX_OFFSET		16
10162306a36Sopenharmony_ci#define IFI_CANFD_ERROR_RX_MASK			0xff
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define IFI_CANFD_ERRCNT			0x24
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define IFI_CANFD_SUSPEND			0x28
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define IFI_CANFD_REPEAT			0x2c
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define IFI_CANFD_TRAFFIC			0x30
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define IFI_CANFD_TSCONTROL			0x34
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define IFI_CANFD_TSC				0x38
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define IFI_CANFD_TST				0x3c
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define IFI_CANFD_RES1				0x40
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR			0x44
12062306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC	0x21302899
12162306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST	BIT(0)
12262306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST	BIT(1)
12362306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST	BIT(2)
12462306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST	BIT(3)
12562306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST	BIT(4)
12662306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST	BIT(5)
12762306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST	BIT(6)
12862306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL	BIT(8)
12962306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL	BIT(9)
13062306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL	BIT(10)
13162306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL	BIT(11)
13262306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL	BIT(12)
13362306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL	BIT(13)
13462306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL	BIT(14)
13562306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET	16
13662306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK	0xff
13762306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_ER_RESET		BIT(30)
13862306a36Sopenharmony_ci#define IFI_CANFD_ERROR_CTR_ER_ENABLE		((u32)BIT(31))
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci#define IFI_CANFD_PAR				0x48
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#define IFI_CANFD_CANCLOCK			0x4c
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define IFI_CANFD_SYSCLOCK			0x50
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define IFI_CANFD_VER				0x54
14762306a36Sopenharmony_ci#define IFI_CANFD_VER_REV_MASK			0xff
14862306a36Sopenharmony_ci#define IFI_CANFD_VER_REV_MIN_SUPPORTED		0x15
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define IFI_CANFD_IP_ID				0x58
15162306a36Sopenharmony_ci#define IFI_CANFD_IP_ID_VALUE			0xD073CAFD
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define IFI_CANFD_TEST				0x5c
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_TS_63_32		0x60
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_TS_31_0		0x64
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC			0x68
16062306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET		0
16162306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_DLC_MASK		0xf
16262306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_RTR		BIT(4)
16362306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_EDL		BIT(5)
16462306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_BRS		BIT(6)
16562306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_ESI		BIT(7)
16662306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET		8
16762306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK		0x1ff
16862306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET		24
16962306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DLC_FNR_MASK		0xff
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID			0x6c
17262306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_OFFSET		0
17362306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK		CAN_SFF_MASK
17462306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_STD_OFFSET	0
17562306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_STD_WIDTH	10
17662306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK		CAN_EFF_MASK
17762306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET	11
17862306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH	18
17962306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_ID_IDE			BIT(29)
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define IFI_CANFD_RXFIFO_DATA			0x70	/* 0x70..0xac */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_SUSPEND_US		0xb0
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_REPEATCOUNT		0xb4
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC			0xb8
18862306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET		0
18962306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_DLC_MASK		0xf
19062306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_RTR		BIT(4)
19162306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_EDL		BIT(5)
19262306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_BRS		BIT(6)
19362306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET		24
19462306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DLC_FNR_MASK		0xff
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID			0xbc
19762306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_OFFSET		0
19862306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK		CAN_SFF_MASK
19962306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_STD_OFFSET	0
20062306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_STD_WIDTH	10
20162306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK		CAN_EFF_MASK
20262306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET	11
20362306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH	18
20462306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_ID_IDE			BIT(29)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci#define IFI_CANFD_TXFIFO_DATA			0xc0	/* 0xb0..0xfc */
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#define IFI_CANFD_FILTER_MASK(n)		(0x800 + ((n) * 8) + 0)
20962306a36Sopenharmony_ci#define IFI_CANFD_FILTER_MASK_EXT		BIT(29)
21062306a36Sopenharmony_ci#define IFI_CANFD_FILTER_MASK_EDL		BIT(30)
21162306a36Sopenharmony_ci#define IFI_CANFD_FILTER_MASK_VALID		((u32)BIT(31))
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci#define IFI_CANFD_FILTER_IDENT(n)		(0x800 + ((n) * 8) + 4)
21462306a36Sopenharmony_ci#define IFI_CANFD_FILTER_IDENT_IDE		BIT(29)
21562306a36Sopenharmony_ci#define IFI_CANFD_FILTER_IDENT_CANFD		BIT(30)
21662306a36Sopenharmony_ci#define IFI_CANFD_FILTER_IDENT_VALID		((u32)BIT(31))
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/* IFI CANFD private data structure */
21962306a36Sopenharmony_cistruct ifi_canfd_priv {
22062306a36Sopenharmony_ci	struct can_priv		can;	/* must be the first member */
22162306a36Sopenharmony_ci	struct napi_struct	napi;
22262306a36Sopenharmony_ci	struct net_device	*ndev;
22362306a36Sopenharmony_ci	void __iomem		*base;
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
22962306a36Sopenharmony_ci	u32 enirq = 0;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (enable) {
23262306a36Sopenharmony_ci		enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
23362306a36Sopenharmony_ci			IFI_CANFD_IRQMASK_RXFIFO_NEMPTY |
23462306a36Sopenharmony_ci			IFI_CANFD_IRQMASK_ERROR_STATE_CHG |
23562306a36Sopenharmony_ci			IFI_CANFD_IRQMASK_ERROR_WARNING |
23662306a36Sopenharmony_ci			IFI_CANFD_IRQMASK_ERROR_BUSOFF;
23762306a36Sopenharmony_ci		if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
23862306a36Sopenharmony_ci			enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	writel(IFI_CANFD_IRQMASK_SET_ERR |
24262306a36Sopenharmony_ci	       IFI_CANFD_IRQMASK_SET_TS |
24362306a36Sopenharmony_ci	       IFI_CANFD_IRQMASK_SET_TX |
24462306a36Sopenharmony_ci	       IFI_CANFD_IRQMASK_SET_RX | enirq,
24562306a36Sopenharmony_ci	       priv->base + IFI_CANFD_IRQMASK);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void ifi_canfd_read_fifo(struct net_device *ndev)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
25162306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
25262306a36Sopenharmony_ci	struct canfd_frame *cf;
25362306a36Sopenharmony_ci	struct sk_buff *skb;
25462306a36Sopenharmony_ci	const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
25562306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
25662306a36Sopenharmony_ci	u32 rxdlc, rxid;
25762306a36Sopenharmony_ci	u32 dlc, id;
25862306a36Sopenharmony_ci	int i;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	rxdlc = readl(priv->base + IFI_CANFD_RXFIFO_DLC);
26162306a36Sopenharmony_ci	if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
26262306a36Sopenharmony_ci		skb = alloc_canfd_skb(ndev, &cf);
26362306a36Sopenharmony_ci	else
26462306a36Sopenharmony_ci		skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (!skb) {
26762306a36Sopenharmony_ci		stats->rx_dropped++;
26862306a36Sopenharmony_ci		return;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
27262306a36Sopenharmony_ci	      IFI_CANFD_RXFIFO_DLC_DLC_MASK;
27362306a36Sopenharmony_ci	if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
27462306a36Sopenharmony_ci		cf->len = can_fd_dlc2len(dlc);
27562306a36Sopenharmony_ci	else
27662306a36Sopenharmony_ci		cf->len = can_cc_dlc2len(dlc);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
27962306a36Sopenharmony_ci	id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
28062306a36Sopenharmony_ci	if (id & IFI_CANFD_RXFIFO_ID_IDE) {
28162306a36Sopenharmony_ci		id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
28262306a36Sopenharmony_ci		/*
28362306a36Sopenharmony_ci		 * In case the Extended ID frame is received, the standard
28462306a36Sopenharmony_ci		 * and extended part of the ID are swapped in the register,
28562306a36Sopenharmony_ci		 * so swap them back to obtain the correct ID.
28662306a36Sopenharmony_ci		 */
28762306a36Sopenharmony_ci		id = (id >> IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET) |
28862306a36Sopenharmony_ci		     ((id & IFI_CANFD_RXFIFO_ID_ID_STD_MASK) <<
28962306a36Sopenharmony_ci		       IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH);
29062306a36Sopenharmony_ci		id |= CAN_EFF_FLAG;
29162306a36Sopenharmony_ci	} else {
29262306a36Sopenharmony_ci		id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci	cf->can_id = id;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
29762306a36Sopenharmony_ci		cf->flags |= CANFD_ESI;
29862306a36Sopenharmony_ci		netdev_dbg(ndev, "ESI Error\n");
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!(rxdlc & IFI_CANFD_RXFIFO_DLC_EDL) &&
30262306a36Sopenharmony_ci	    (rxdlc & IFI_CANFD_RXFIFO_DLC_RTR)) {
30362306a36Sopenharmony_ci		cf->can_id |= CAN_RTR_FLAG;
30462306a36Sopenharmony_ci	} else {
30562306a36Sopenharmony_ci		if (rxdlc & IFI_CANFD_RXFIFO_DLC_BRS)
30662306a36Sopenharmony_ci			cf->flags |= CANFD_BRS;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		for (i = 0; i < cf->len; i += 4) {
30962306a36Sopenharmony_ci			*(u32 *)(cf->data + i) =
31062306a36Sopenharmony_ci				readl(priv->base + IFI_CANFD_RXFIFO_DATA + i);
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		stats->rx_bytes += cf->len;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci	stats->rx_packets++;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Remove the packet from FIFO */
31862306a36Sopenharmony_ci	writel(IFI_CANFD_RXSTCMD_REMOVE_MSG, priv->base + IFI_CANFD_RXSTCMD);
31962306a36Sopenharmony_ci	writel(rx_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	netif_receive_skb(skb);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
32762306a36Sopenharmony_ci	u32 pkts = 0;
32862306a36Sopenharmony_ci	u32 rxst;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
33162306a36Sopenharmony_ci	if (rxst & IFI_CANFD_RXSTCMD_EMPTY) {
33262306a36Sopenharmony_ci		netdev_dbg(ndev, "No messages in RX FIFO\n");
33362306a36Sopenharmony_ci		return 0;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	for (;;) {
33762306a36Sopenharmony_ci		if (rxst & IFI_CANFD_RXSTCMD_EMPTY)
33862306a36Sopenharmony_ci			break;
33962306a36Sopenharmony_ci		if (quota <= 0)
34062306a36Sopenharmony_ci			break;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		ifi_canfd_read_fifo(ndev);
34362306a36Sopenharmony_ci		quota--;
34462306a36Sopenharmony_ci		pkts++;
34562306a36Sopenharmony_ci		rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return pkts;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic int ifi_canfd_handle_lost_msg(struct net_device *ndev)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
35462306a36Sopenharmony_ci	struct sk_buff *skb;
35562306a36Sopenharmony_ci	struct can_frame *frame;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	netdev_err(ndev, "RX FIFO overflow, message(s) lost.\n");
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	stats->rx_errors++;
36062306a36Sopenharmony_ci	stats->rx_over_errors++;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	skb = alloc_can_err_skb(ndev, &frame);
36362306a36Sopenharmony_ci	if (unlikely(!skb))
36462306a36Sopenharmony_ci		return 0;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	frame->can_id |= CAN_ERR_CRTL;
36762306a36Sopenharmony_ci	frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	netif_receive_skb(skb);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return 1;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic int ifi_canfd_handle_lec_err(struct net_device *ndev)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
37762306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
37862306a36Sopenharmony_ci	struct can_frame *cf;
37962306a36Sopenharmony_ci	struct sk_buff *skb;
38062306a36Sopenharmony_ci	u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
38162306a36Sopenharmony_ci	const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST |
38262306a36Sopenharmony_ci			    IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST |
38362306a36Sopenharmony_ci			    IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST |
38462306a36Sopenharmony_ci			    IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST |
38562306a36Sopenharmony_ci			    IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST |
38662306a36Sopenharmony_ci			    IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST |
38762306a36Sopenharmony_ci			    IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (!(errctr & errmask))	/* No error happened. */
39062306a36Sopenharmony_ci		return 0;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	priv->can.can_stats.bus_error++;
39362306a36Sopenharmony_ci	stats->rx_errors++;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* Propagate the error condition to the CAN stack. */
39662306a36Sopenharmony_ci	skb = alloc_can_err_skb(ndev, &cf);
39762306a36Sopenharmony_ci	if (unlikely(!skb))
39862306a36Sopenharmony_ci		return 0;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Read the error counter register and check for new errors. */
40162306a36Sopenharmony_ci	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST)
40462306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST)
40762306a36Sopenharmony_ci		cf->data[3] = CAN_ERR_PROT_LOC_ACK;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST)
41062306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_BIT0;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST)
41362306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_BIT1;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST)
41662306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_STUFF;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST)
41962306a36Sopenharmony_ci		cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST)
42262306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_FORM;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Reset the error counter, ack the IRQ and re-enable the counter. */
42562306a36Sopenharmony_ci	writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
42662306a36Sopenharmony_ci	writel(IFI_CANFD_INTERRUPT_ERROR_COUNTER,
42762306a36Sopenharmony_ci	       priv->base + IFI_CANFD_INTERRUPT);
42862306a36Sopenharmony_ci	writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	netif_receive_skb(skb);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return 1;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int ifi_canfd_get_berr_counter(const struct net_device *ndev,
43662306a36Sopenharmony_ci				      struct can_berr_counter *bec)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
43962306a36Sopenharmony_ci	u32 err;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	err = readl(priv->base + IFI_CANFD_ERROR);
44262306a36Sopenharmony_ci	bec->rxerr = (err >> IFI_CANFD_ERROR_RX_OFFSET) &
44362306a36Sopenharmony_ci		     IFI_CANFD_ERROR_RX_MASK;
44462306a36Sopenharmony_ci	bec->txerr = (err >> IFI_CANFD_ERROR_TX_OFFSET) &
44562306a36Sopenharmony_ci		     IFI_CANFD_ERROR_TX_MASK;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	return 0;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic int ifi_canfd_handle_state_change(struct net_device *ndev,
45162306a36Sopenharmony_ci					 enum can_state new_state)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
45462306a36Sopenharmony_ci	struct can_frame *cf;
45562306a36Sopenharmony_ci	struct sk_buff *skb;
45662306a36Sopenharmony_ci	struct can_berr_counter bec;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	switch (new_state) {
45962306a36Sopenharmony_ci	case CAN_STATE_ERROR_ACTIVE:
46062306a36Sopenharmony_ci		/* error active state */
46162306a36Sopenharmony_ci		priv->can.can_stats.error_warning++;
46262306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_ACTIVE;
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	case CAN_STATE_ERROR_WARNING:
46562306a36Sopenharmony_ci		/* error warning state */
46662306a36Sopenharmony_ci		priv->can.can_stats.error_warning++;
46762306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_WARNING;
46862306a36Sopenharmony_ci		break;
46962306a36Sopenharmony_ci	case CAN_STATE_ERROR_PASSIVE:
47062306a36Sopenharmony_ci		/* error passive state */
47162306a36Sopenharmony_ci		priv->can.can_stats.error_passive++;
47262306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_PASSIVE;
47362306a36Sopenharmony_ci		break;
47462306a36Sopenharmony_ci	case CAN_STATE_BUS_OFF:
47562306a36Sopenharmony_ci		/* bus-off state */
47662306a36Sopenharmony_ci		priv->can.state = CAN_STATE_BUS_OFF;
47762306a36Sopenharmony_ci		ifi_canfd_irq_enable(ndev, 0);
47862306a36Sopenharmony_ci		priv->can.can_stats.bus_off++;
47962306a36Sopenharmony_ci		can_bus_off(ndev);
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci	default:
48262306a36Sopenharmony_ci		break;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* propagate the error condition to the CAN stack */
48662306a36Sopenharmony_ci	skb = alloc_can_err_skb(ndev, &cf);
48762306a36Sopenharmony_ci	if (unlikely(!skb))
48862306a36Sopenharmony_ci		return 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ifi_canfd_get_berr_counter(ndev, &bec);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	switch (new_state) {
49362306a36Sopenharmony_ci	case CAN_STATE_ERROR_WARNING:
49462306a36Sopenharmony_ci		/* error warning state */
49562306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
49662306a36Sopenharmony_ci		cf->data[1] = (bec.txerr > bec.rxerr) ?
49762306a36Sopenharmony_ci			CAN_ERR_CRTL_TX_WARNING :
49862306a36Sopenharmony_ci			CAN_ERR_CRTL_RX_WARNING;
49962306a36Sopenharmony_ci		cf->data[6] = bec.txerr;
50062306a36Sopenharmony_ci		cf->data[7] = bec.rxerr;
50162306a36Sopenharmony_ci		break;
50262306a36Sopenharmony_ci	case CAN_STATE_ERROR_PASSIVE:
50362306a36Sopenharmony_ci		/* error passive state */
50462306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
50562306a36Sopenharmony_ci		cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
50662306a36Sopenharmony_ci		if (bec.txerr > 127)
50762306a36Sopenharmony_ci			cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
50862306a36Sopenharmony_ci		cf->data[6] = bec.txerr;
50962306a36Sopenharmony_ci		cf->data[7] = bec.rxerr;
51062306a36Sopenharmony_ci		break;
51162306a36Sopenharmony_ci	case CAN_STATE_BUS_OFF:
51262306a36Sopenharmony_ci		/* bus-off state */
51362306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_BUSOFF;
51462306a36Sopenharmony_ci		break;
51562306a36Sopenharmony_ci	default:
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	netif_receive_skb(skb);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return 1;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic int ifi_canfd_handle_state_errors(struct net_device *ndev)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
52762306a36Sopenharmony_ci	u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
52862306a36Sopenharmony_ci	int work_done = 0;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) &&
53162306a36Sopenharmony_ci	    (priv->can.state != CAN_STATE_ERROR_ACTIVE)) {
53262306a36Sopenharmony_ci		netdev_dbg(ndev, "Error, entered active state\n");
53362306a36Sopenharmony_ci		work_done += ifi_canfd_handle_state_change(ndev,
53462306a36Sopenharmony_ci						CAN_STATE_ERROR_ACTIVE);
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if ((stcmd & IFI_CANFD_STCMD_ERROR_WARNING) &&
53862306a36Sopenharmony_ci	    (priv->can.state != CAN_STATE_ERROR_WARNING)) {
53962306a36Sopenharmony_ci		netdev_dbg(ndev, "Error, entered warning state\n");
54062306a36Sopenharmony_ci		work_done += ifi_canfd_handle_state_change(ndev,
54162306a36Sopenharmony_ci						CAN_STATE_ERROR_WARNING);
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	if ((stcmd & IFI_CANFD_STCMD_ERROR_PASSIVE) &&
54562306a36Sopenharmony_ci	    (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
54662306a36Sopenharmony_ci		netdev_dbg(ndev, "Error, entered passive state\n");
54762306a36Sopenharmony_ci		work_done += ifi_canfd_handle_state_change(ndev,
54862306a36Sopenharmony_ci						CAN_STATE_ERROR_PASSIVE);
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if ((stcmd & IFI_CANFD_STCMD_BUSOFF) &&
55262306a36Sopenharmony_ci	    (priv->can.state != CAN_STATE_BUS_OFF)) {
55362306a36Sopenharmony_ci		netdev_dbg(ndev, "Error, entered bus-off state\n");
55462306a36Sopenharmony_ci		work_done += ifi_canfd_handle_state_change(ndev,
55562306a36Sopenharmony_ci						CAN_STATE_BUS_OFF);
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return work_done;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int ifi_canfd_poll(struct napi_struct *napi, int quota)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	struct net_device *ndev = napi->dev;
56462306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
56562306a36Sopenharmony_ci	u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD);
56662306a36Sopenharmony_ci	int work_done = 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/* Handle bus state changes */
56962306a36Sopenharmony_ci	work_done += ifi_canfd_handle_state_errors(ndev);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* Handle lost messages on RX */
57262306a36Sopenharmony_ci	if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
57362306a36Sopenharmony_ci		work_done += ifi_canfd_handle_lost_msg(ndev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* Handle lec errors on the bus */
57662306a36Sopenharmony_ci	if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
57762306a36Sopenharmony_ci		work_done += ifi_canfd_handle_lec_err(ndev);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* Handle normal messages on RX */
58062306a36Sopenharmony_ci	if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
58162306a36Sopenharmony_ci		work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (work_done < quota) {
58462306a36Sopenharmony_ci		napi_complete_done(napi, work_done);
58562306a36Sopenharmony_ci		ifi_canfd_irq_enable(ndev, 1);
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	return work_done;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct net_device *ndev = (struct net_device *)dev_id;
59462306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
59562306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
59662306a36Sopenharmony_ci	const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
59762306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER |
59862306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_ERROR_COUNTER |
59962306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_ERROR_STATE_CHG |
60062306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_ERROR_WARNING |
60162306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_ERROR_BUSOFF;
60262306a36Sopenharmony_ci	const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
60362306a36Sopenharmony_ci				IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
60462306a36Sopenharmony_ci	const u32 clr_irq_mask = ~((u32)IFI_CANFD_INTERRUPT_SET_IRQ);
60562306a36Sopenharmony_ci	u32 isr;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	isr = readl(priv->base + IFI_CANFD_INTERRUPT);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* No interrupt */
61062306a36Sopenharmony_ci	if (isr == 0)
61162306a36Sopenharmony_ci		return IRQ_NONE;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Clear all pending interrupts but ErrWarn */
61462306a36Sopenharmony_ci	writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* RX IRQ or bus warning, start NAPI */
61762306a36Sopenharmony_ci	if (isr & rx_irq_mask) {
61862306a36Sopenharmony_ci		ifi_canfd_irq_enable(ndev, 0);
61962306a36Sopenharmony_ci		napi_schedule(&priv->napi);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* TX IRQ */
62362306a36Sopenharmony_ci	if (isr & IFI_CANFD_INTERRUPT_TXFIFO_REMOVE) {
62462306a36Sopenharmony_ci		stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL);
62562306a36Sopenharmony_ci		stats->tx_packets++;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (isr & tx_irq_mask)
62962306a36Sopenharmony_ci		netif_wake_queue(ndev);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return IRQ_HANDLED;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic const struct can_bittiming_const ifi_canfd_bittiming_const = {
63562306a36Sopenharmony_ci	.name		= KBUILD_MODNAME,
63662306a36Sopenharmony_ci	.tseg1_min	= 1,	/* Time segment 1 = prop_seg + phase_seg1 */
63762306a36Sopenharmony_ci	.tseg1_max	= 256,
63862306a36Sopenharmony_ci	.tseg2_min	= 2,	/* Time segment 2 = phase_seg2 */
63962306a36Sopenharmony_ci	.tseg2_max	= 256,
64062306a36Sopenharmony_ci	.sjw_max	= 128,
64162306a36Sopenharmony_ci	.brp_min	= 2,
64262306a36Sopenharmony_ci	.brp_max	= 512,
64362306a36Sopenharmony_ci	.brp_inc	= 1,
64462306a36Sopenharmony_ci};
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic void ifi_canfd_set_bittiming(struct net_device *ndev)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
64962306a36Sopenharmony_ci	const struct can_bittiming *bt = &priv->can.bittiming;
65062306a36Sopenharmony_ci	const struct can_bittiming *dbt = &priv->can.data_bittiming;
65162306a36Sopenharmony_ci	u16 brp, sjw, tseg1, tseg2, tdc;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* Configure bit timing */
65462306a36Sopenharmony_ci	brp = bt->brp - 2;
65562306a36Sopenharmony_ci	sjw = bt->sjw - 1;
65662306a36Sopenharmony_ci	tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
65762306a36Sopenharmony_ci	tseg2 = bt->phase_seg2 - 2;
65862306a36Sopenharmony_ci	writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
65962306a36Sopenharmony_ci	       (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
66062306a36Sopenharmony_ci	       (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
66162306a36Sopenharmony_ci	       (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8),
66262306a36Sopenharmony_ci	       priv->base + IFI_CANFD_TIME);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* Configure data bit timing */
66562306a36Sopenharmony_ci	brp = dbt->brp - 2;
66662306a36Sopenharmony_ci	sjw = dbt->sjw - 1;
66762306a36Sopenharmony_ci	tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
66862306a36Sopenharmony_ci	tseg2 = dbt->phase_seg2 - 2;
66962306a36Sopenharmony_ci	writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
67062306a36Sopenharmony_ci	       (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
67162306a36Sopenharmony_ci	       (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
67262306a36Sopenharmony_ci	       (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8),
67362306a36Sopenharmony_ci	       priv->base + IFI_CANFD_FTIME);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Configure transmitter delay */
67662306a36Sopenharmony_ci	tdc = dbt->brp * (dbt->prop_seg + dbt->phase_seg1);
67762306a36Sopenharmony_ci	tdc &= IFI_CANFD_TDELAY_MASK;
67862306a36Sopenharmony_ci	writel(IFI_CANFD_TDELAY_EN | tdc, priv->base + IFI_CANFD_TDELAY);
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic void ifi_canfd_set_filter(struct net_device *ndev, const u32 id,
68262306a36Sopenharmony_ci				 const u32 mask, const u32 ident)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id));
68762306a36Sopenharmony_ci	writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id));
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic void ifi_canfd_set_filters(struct net_device *ndev)
69162306a36Sopenharmony_ci{
69262306a36Sopenharmony_ci	/* Receive all CAN frames (standard ID) */
69362306a36Sopenharmony_ci	ifi_canfd_set_filter(ndev, 0,
69462306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_VALID |
69562306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_EXT,
69662306a36Sopenharmony_ci			     IFI_CANFD_FILTER_IDENT_VALID);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* Receive all CAN frames (extended ID) */
69962306a36Sopenharmony_ci	ifi_canfd_set_filter(ndev, 1,
70062306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_VALID |
70162306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_EXT,
70262306a36Sopenharmony_ci			     IFI_CANFD_FILTER_IDENT_VALID |
70362306a36Sopenharmony_ci			     IFI_CANFD_FILTER_IDENT_IDE);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* Receive all CANFD frames */
70662306a36Sopenharmony_ci	ifi_canfd_set_filter(ndev, 2,
70762306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_VALID |
70862306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_EDL |
70962306a36Sopenharmony_ci			     IFI_CANFD_FILTER_MASK_EXT,
71062306a36Sopenharmony_ci			     IFI_CANFD_FILTER_IDENT_VALID |
71162306a36Sopenharmony_ci			     IFI_CANFD_FILTER_IDENT_CANFD |
71262306a36Sopenharmony_ci			     IFI_CANFD_FILTER_IDENT_IDE);
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic void ifi_canfd_start(struct net_device *ndev)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
71862306a36Sopenharmony_ci	u32 stcmd;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	/* Reset the IP */
72162306a36Sopenharmony_ci	writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
72262306a36Sopenharmony_ci	writel(IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING,
72362306a36Sopenharmony_ci	       priv->base + IFI_CANFD_STCMD);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	ifi_canfd_set_bittiming(ndev);
72662306a36Sopenharmony_ci	ifi_canfd_set_filters(ndev);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* Reset FIFOs */
72962306a36Sopenharmony_ci	writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD);
73062306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_RXSTCMD);
73162306a36Sopenharmony_ci	writel(IFI_CANFD_TXSTCMD_RESET, priv->base + IFI_CANFD_TXSTCMD);
73262306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_TXSTCMD);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* Repeat transmission until successful */
73562306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_REPEAT);
73662306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_SUSPEND);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	/* Clear all pending interrupts */
73962306a36Sopenharmony_ci	writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
74062306a36Sopenharmony_ci	       priv->base + IFI_CANFD_INTERRUPT);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE |
74362306a36Sopenharmony_ci		IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
74662306a36Sopenharmony_ci		stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
74962306a36Sopenharmony_ci		stcmd |= IFI_CANFD_STCMD_LOOPBACK;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) &&
75262306a36Sopenharmony_ci	    !(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
75362306a36Sopenharmony_ci		stcmd |= IFI_CANFD_STCMD_ENABLE_ISO;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD))
75662306a36Sopenharmony_ci		stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	priv->can.state = CAN_STATE_ERROR_ACTIVE;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	ifi_canfd_irq_enable(ndev, 1);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* Unlock, reset and enable the error counter. */
76362306a36Sopenharmony_ci	writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC,
76462306a36Sopenharmony_ci	       priv->base + IFI_CANFD_ERROR_CTR);
76562306a36Sopenharmony_ci	writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
76662306a36Sopenharmony_ci	writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* Enable controller */
76962306a36Sopenharmony_ci	writel(stcmd, priv->base + IFI_CANFD_STCMD);
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic void ifi_canfd_stop(struct net_device *ndev)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	/* Reset and disable the error counter. */
77762306a36Sopenharmony_ci	writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
77862306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_ERROR_CTR);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	/* Reset the IP */
78162306a36Sopenharmony_ci	writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	/* Mask all interrupts */
78462306a36Sopenharmony_ci	writel(~0, priv->base + IFI_CANFD_IRQMASK);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	/* Clear all pending interrupts */
78762306a36Sopenharmony_ci	writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
78862306a36Sopenharmony_ci	       priv->base + IFI_CANFD_INTERRUPT);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	/* Set the state as STOPPED */
79162306a36Sopenharmony_ci	priv->can.state = CAN_STATE_STOPPED;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cistatic int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	switch (mode) {
79762306a36Sopenharmony_ci	case CAN_MODE_START:
79862306a36Sopenharmony_ci		ifi_canfd_start(ndev);
79962306a36Sopenharmony_ci		netif_wake_queue(ndev);
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	default:
80262306a36Sopenharmony_ci		return -EOPNOTSUPP;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic int ifi_canfd_open(struct net_device *ndev)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
81162306a36Sopenharmony_ci	int ret;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	ret = open_candev(ndev);
81462306a36Sopenharmony_ci	if (ret) {
81562306a36Sopenharmony_ci		netdev_err(ndev, "Failed to open CAN device\n");
81662306a36Sopenharmony_ci		return ret;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/* Register interrupt handler */
82062306a36Sopenharmony_ci	ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED,
82162306a36Sopenharmony_ci			  ndev->name, ndev);
82262306a36Sopenharmony_ci	if (ret < 0) {
82362306a36Sopenharmony_ci		netdev_err(ndev, "Failed to request interrupt\n");
82462306a36Sopenharmony_ci		goto err_irq;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	ifi_canfd_start(ndev);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	napi_enable(&priv->napi);
83062306a36Sopenharmony_ci	netif_start_queue(ndev);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	return 0;
83362306a36Sopenharmony_cierr_irq:
83462306a36Sopenharmony_ci	close_candev(ndev);
83562306a36Sopenharmony_ci	return ret;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic int ifi_canfd_close(struct net_device *ndev)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	netif_stop_queue(ndev);
84362306a36Sopenharmony_ci	napi_disable(&priv->napi);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	ifi_canfd_stop(ndev);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	free_irq(ndev->irq, ndev);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	close_candev(ndev);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	return 0;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
85562306a36Sopenharmony_ci					struct net_device *ndev)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct ifi_canfd_priv *priv = netdev_priv(ndev);
85862306a36Sopenharmony_ci	struct canfd_frame *cf = (struct canfd_frame *)skb->data;
85962306a36Sopenharmony_ci	u32 txst, txid, txdlc;
86062306a36Sopenharmony_ci	int i;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (can_dev_dropped_skb(ndev, skb))
86362306a36Sopenharmony_ci		return NETDEV_TX_OK;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* Check if the TX buffer is full */
86662306a36Sopenharmony_ci	txst = readl(priv->base + IFI_CANFD_TXSTCMD);
86762306a36Sopenharmony_ci	if (txst & IFI_CANFD_TXSTCMD_FULL) {
86862306a36Sopenharmony_ci		netif_stop_queue(ndev);
86962306a36Sopenharmony_ci		netdev_err(ndev, "BUG! TX FIFO full when queue awake!\n");
87062306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	netif_stop_queue(ndev);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if (cf->can_id & CAN_EFF_FLAG) {
87662306a36Sopenharmony_ci		txid = cf->can_id & CAN_EFF_MASK;
87762306a36Sopenharmony_ci		/*
87862306a36Sopenharmony_ci		 * In case the Extended ID frame is transmitted, the
87962306a36Sopenharmony_ci		 * standard and extended part of the ID are swapped
88062306a36Sopenharmony_ci		 * in the register, so swap them back to send the
88162306a36Sopenharmony_ci		 * correct ID.
88262306a36Sopenharmony_ci		 */
88362306a36Sopenharmony_ci		txid = (txid >> IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH) |
88462306a36Sopenharmony_ci		       ((txid & IFI_CANFD_TXFIFO_ID_ID_XTD_MASK) <<
88562306a36Sopenharmony_ci		         IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET);
88662306a36Sopenharmony_ci		txid |= IFI_CANFD_TXFIFO_ID_IDE;
88762306a36Sopenharmony_ci	} else {
88862306a36Sopenharmony_ci		txid = cf->can_id & CAN_SFF_MASK;
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	txdlc = can_fd_len2dlc(cf->len);
89262306a36Sopenharmony_ci	if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) {
89362306a36Sopenharmony_ci		txdlc |= IFI_CANFD_TXFIFO_DLC_EDL;
89462306a36Sopenharmony_ci		if (cf->flags & CANFD_BRS)
89562306a36Sopenharmony_ci			txdlc |= IFI_CANFD_TXFIFO_DLC_BRS;
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (cf->can_id & CAN_RTR_FLAG)
89962306a36Sopenharmony_ci		txdlc |= IFI_CANFD_TXFIFO_DLC_RTR;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* message ram configuration */
90262306a36Sopenharmony_ci	writel(txid, priv->base + IFI_CANFD_TXFIFO_ID);
90362306a36Sopenharmony_ci	writel(txdlc, priv->base + IFI_CANFD_TXFIFO_DLC);
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	for (i = 0; i < cf->len; i += 4) {
90662306a36Sopenharmony_ci		writel(*(u32 *)(cf->data + i),
90762306a36Sopenharmony_ci		       priv->base + IFI_CANFD_TXFIFO_DATA + i);
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_TXFIFO_REPEATCOUNT);
91162306a36Sopenharmony_ci	writel(0, priv->base + IFI_CANFD_TXFIFO_SUSPEND_US);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	can_put_echo_skb(skb, ndev, 0, 0);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* Start the transmission */
91662306a36Sopenharmony_ci	writel(IFI_CANFD_TXSTCMD_ADD_MSG, priv->base + IFI_CANFD_TXSTCMD);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return NETDEV_TX_OK;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic const struct net_device_ops ifi_canfd_netdev_ops = {
92262306a36Sopenharmony_ci	.ndo_open	= ifi_canfd_open,
92362306a36Sopenharmony_ci	.ndo_stop	= ifi_canfd_close,
92462306a36Sopenharmony_ci	.ndo_start_xmit	= ifi_canfd_start_xmit,
92562306a36Sopenharmony_ci	.ndo_change_mtu	= can_change_mtu,
92662306a36Sopenharmony_ci};
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic const struct ethtool_ops ifi_canfd_ethtool_ops = {
92962306a36Sopenharmony_ci	.get_ts_info = ethtool_op_get_ts_info,
93062306a36Sopenharmony_ci};
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic int ifi_canfd_plat_probe(struct platform_device *pdev)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
93562306a36Sopenharmony_ci	struct net_device *ndev;
93662306a36Sopenharmony_ci	struct ifi_canfd_priv *priv;
93762306a36Sopenharmony_ci	void __iomem *addr;
93862306a36Sopenharmony_ci	int irq, ret;
93962306a36Sopenharmony_ci	u32 id, rev;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	addr = devm_platform_ioremap_resource(pdev, 0);
94262306a36Sopenharmony_ci	if (IS_ERR(addr))
94362306a36Sopenharmony_ci		return PTR_ERR(addr);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
94662306a36Sopenharmony_ci	if (irq < 0)
94762306a36Sopenharmony_ci		return -EINVAL;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	id = readl(addr + IFI_CANFD_IP_ID);
95062306a36Sopenharmony_ci	if (id != IFI_CANFD_IP_ID_VALUE) {
95162306a36Sopenharmony_ci		dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id);
95262306a36Sopenharmony_ci		return -EINVAL;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	rev = readl(addr + IFI_CANFD_VER) & IFI_CANFD_VER_REV_MASK;
95662306a36Sopenharmony_ci	if (rev < IFI_CANFD_VER_REV_MIN_SUPPORTED) {
95762306a36Sopenharmony_ci		dev_err(dev, "This block is too old (rev %i), minimum supported is rev %i\n",
95862306a36Sopenharmony_ci			rev, IFI_CANFD_VER_REV_MIN_SUPPORTED);
95962306a36Sopenharmony_ci		return -EINVAL;
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	ndev = alloc_candev(sizeof(*priv), 1);
96362306a36Sopenharmony_ci	if (!ndev)
96462306a36Sopenharmony_ci		return -ENOMEM;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	ndev->irq = irq;
96762306a36Sopenharmony_ci	ndev->flags |= IFF_ECHO;	/* we support local echo */
96862306a36Sopenharmony_ci	ndev->netdev_ops = &ifi_canfd_netdev_ops;
96962306a36Sopenharmony_ci	ndev->ethtool_ops = &ifi_canfd_ethtool_ops;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	priv = netdev_priv(ndev);
97262306a36Sopenharmony_ci	priv->ndev = ndev;
97362306a36Sopenharmony_ci	priv->base = addr;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	netif_napi_add(ndev, &priv->napi, ifi_canfd_poll);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	priv->can.state = CAN_STATE_STOPPED;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	priv->can.bittiming_const	= &ifi_canfd_bittiming_const;
98262306a36Sopenharmony_ci	priv->can.data_bittiming_const	= &ifi_canfd_bittiming_const;
98362306a36Sopenharmony_ci	priv->can.do_set_mode		= ifi_canfd_set_mode;
98462306a36Sopenharmony_ci	priv->can.do_get_berr_counter	= ifi_canfd_get_berr_counter;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	/* IFI CANFD can do both Bosch FD and ISO FD */
98762306a36Sopenharmony_ci	priv->can.ctrlmode = CAN_CTRLMODE_FD;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* IFI CANFD can do both Bosch FD and ISO FD */
99062306a36Sopenharmony_ci	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
99162306a36Sopenharmony_ci				       CAN_CTRLMODE_LISTENONLY |
99262306a36Sopenharmony_ci				       CAN_CTRLMODE_FD |
99362306a36Sopenharmony_ci				       CAN_CTRLMODE_FD_NON_ISO |
99462306a36Sopenharmony_ci				       CAN_CTRLMODE_BERR_REPORTING;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
99762306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, dev);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	ret = register_candev(ndev);
100062306a36Sopenharmony_ci	if (ret) {
100162306a36Sopenharmony_ci		dev_err(dev, "Failed to register (ret=%d)\n", ret);
100262306a36Sopenharmony_ci		goto err_reg;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n",
100662306a36Sopenharmony_ci		 priv->base, ndev->irq, priv->can.clock.freq);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	return 0;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_cierr_reg:
101162306a36Sopenharmony_ci	free_candev(ndev);
101262306a36Sopenharmony_ci	return ret;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic void ifi_canfd_plat_remove(struct platform_device *pdev)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	unregister_candev(ndev);
102062306a36Sopenharmony_ci	platform_set_drvdata(pdev, NULL);
102162306a36Sopenharmony_ci	free_candev(ndev);
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic const struct of_device_id ifi_canfd_of_table[] = {
102562306a36Sopenharmony_ci	{ .compatible = "ifi,canfd-1.0", .data = NULL },
102662306a36Sopenharmony_ci	{ /* sentinel */ },
102762306a36Sopenharmony_ci};
102862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ifi_canfd_of_table);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic struct platform_driver ifi_canfd_plat_driver = {
103162306a36Sopenharmony_ci	.driver = {
103262306a36Sopenharmony_ci		.name		= KBUILD_MODNAME,
103362306a36Sopenharmony_ci		.of_match_table	= ifi_canfd_of_table,
103462306a36Sopenharmony_ci	},
103562306a36Sopenharmony_ci	.probe	= ifi_canfd_plat_probe,
103662306a36Sopenharmony_ci	.remove_new = ifi_canfd_plat_remove,
103762306a36Sopenharmony_ci};
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cimodule_platform_driver(ifi_canfd_plat_driver);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marex@denx.de>");
104262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
104362306a36Sopenharmony_ciMODULE_DESCRIPTION("CAN bus driver for IFI CANFD controller");
1044