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