359 lines
9.4 KiB
C
359 lines
9.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Copyright (C) 2015 - 2016 Thomas Körper, esd electronic system design gmbh
|
|
* Copyright (C) 2017 - 2023 Stefan Mätje, esd electronics gmbh
|
|
*/
|
|
|
|
#include <linux/bits.h>
|
|
#include <linux/can/dev.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/units.h>
|
|
|
|
#define ACC_TS_FREQ_80MHZ (80 * HZ_PER_MHZ)
|
|
#define ACC_I2C_ADDON_DETECT_DELAY_MS 10
|
|
|
|
/* esdACC Overview Module */
|
|
#define ACC_OV_OF_PROBE 0x0000
|
|
#define ACC_OV_OF_VERSION 0x0004
|
|
#define ACC_OV_OF_INFO 0x0008
|
|
#define ACC_OV_OF_CANCORE_FREQ 0x000c
|
|
#define ACC_OV_OF_TS_FREQ_LO 0x0010
|
|
#define ACC_OV_OF_TS_FREQ_HI 0x0014
|
|
#define ACC_OV_OF_IRQ_STATUS_CORES 0x0018
|
|
#define ACC_OV_OF_TS_CURR_LO 0x001c
|
|
#define ACC_OV_OF_TS_CURR_HI 0x0020
|
|
#define ACC_OV_OF_IRQ_STATUS 0x0028
|
|
#define ACC_OV_OF_MODE 0x002c
|
|
#define ACC_OV_OF_BM_IRQ_COUNTER 0x0070
|
|
#define ACC_OV_OF_BM_IRQ_MASK 0x0074
|
|
#define ACC_OV_OF_MSI_DATA 0x0080
|
|
#define ACC_OV_OF_MSI_ADDRESSOFFSET 0x0084
|
|
|
|
/* Feature flags are contained in the upper 16 bit of the version
|
|
* register at ACC_OV_OF_VERSION but only used with these masks after
|
|
* extraction into an extra variable => (xx - 16).
|
|
*/
|
|
#define ACC_OV_REG_FEAT_MASK_CANFD BIT(27 - 16)
|
|
#define ACC_OV_REG_FEAT_MASK_NEW_PSC BIT(28 - 16)
|
|
#define ACC_OV_REG_FEAT_MASK_DAR BIT(30 - 16)
|
|
|
|
#define ACC_OV_REG_MODE_MASK_ENDIAN_LITTLE BIT(0)
|
|
#define ACC_OV_REG_MODE_MASK_BM_ENABLE BIT(1)
|
|
#define ACC_OV_REG_MODE_MASK_MODE_LED BIT(2)
|
|
#define ACC_OV_REG_MODE_MASK_TIMER_ENABLE BIT(4)
|
|
#define ACC_OV_REG_MODE_MASK_TIMER_ONE_SHOT BIT(5)
|
|
#define ACC_OV_REG_MODE_MASK_TIMER_ABSOLUTE BIT(6)
|
|
#define ACC_OV_REG_MODE_MASK_TIMER GENMASK(6, 4)
|
|
#define ACC_OV_REG_MODE_MASK_TS_SRC GENMASK(8, 7)
|
|
#define ACC_OV_REG_MODE_MASK_I2C_ENABLE BIT(11)
|
|
#define ACC_OV_REG_MODE_MASK_MSI_ENABLE BIT(14)
|
|
#define ACC_OV_REG_MODE_MASK_NEW_PSC_ENABLE BIT(15)
|
|
#define ACC_OV_REG_MODE_MASK_FPGA_RESET BIT(31)
|
|
|
|
/* esdACC CAN Core Module */
|
|
#define ACC_CORE_OF_CTRL 0x0000
|
|
#define ACC_CORE_OF_STATUS_IRQ 0x0008
|
|
#define ACC_CORE_OF_BRP 0x000c
|
|
#define ACC_CORE_OF_BTR 0x0010
|
|
#define ACC_CORE_OF_FBTR 0x0014
|
|
#define ACC_CORE_OF_STATUS 0x0030
|
|
#define ACC_CORE_OF_TXFIFO_CONFIG 0x0048
|
|
#define ACC_CORE_OF_TXFIFO_STATUS 0x004c
|
|
#define ACC_CORE_OF_TX_STATUS_IRQ 0x0050
|
|
#define ACC_CORE_OF_TX_ABORT_MASK 0x0054
|
|
#define ACC_CORE_OF_BM_IRQ_COUNTER 0x0070
|
|
#define ACC_CORE_OF_TXFIFO_ID 0x00c0
|
|
#define ACC_CORE_OF_TXFIFO_DLC 0x00c4
|
|
#define ACC_CORE_OF_TXFIFO_DATA_0 0x00c8
|
|
#define ACC_CORE_OF_TXFIFO_DATA_1 0x00cc
|
|
|
|
/* CTRL register layout */
|
|
#define ACC_REG_CTRL_MASK_RESETMODE BIT(0)
|
|
#define ACC_REG_CTRL_MASK_LOM BIT(1)
|
|
#define ACC_REG_CTRL_MASK_STM BIT(2)
|
|
#define ACC_REG_CTRL_MASK_TRANSEN BIT(5)
|
|
#define ACC_REG_CTRL_MASK_TS BIT(6)
|
|
#define ACC_REG_CTRL_MASK_SCHEDULE BIT(7)
|
|
|
|
#define ACC_REG_CTRL_MASK_IE_RXTX BIT(8)
|
|
#define ACC_REG_CTRL_MASK_IE_TXERROR BIT(9)
|
|
#define ACC_REG_CTRL_MASK_IE_ERRWARN BIT(10)
|
|
#define ACC_REG_CTRL_MASK_IE_OVERRUN BIT(11)
|
|
#define ACC_REG_CTRL_MASK_IE_TSI BIT(12)
|
|
#define ACC_REG_CTRL_MASK_IE_ERRPASS BIT(13)
|
|
#define ACC_REG_CTRL_MASK_IE_ALI BIT(14)
|
|
#define ACC_REG_CTRL_MASK_IE_BUSERR BIT(15)
|
|
|
|
/* BRP and BTR register layout for CAN-Classic version */
|
|
#define ACC_REG_BRP_CL_MASK_BRP GENMASK(8, 0)
|
|
#define ACC_REG_BTR_CL_MASK_TSEG1 GENMASK(3, 0)
|
|
#define ACC_REG_BTR_CL_MASK_TSEG2 GENMASK(18, 16)
|
|
#define ACC_REG_BTR_CL_MASK_SJW GENMASK(25, 24)
|
|
|
|
/* BRP and BTR register layout for CAN-FD version */
|
|
#define ACC_REG_BRP_FD_MASK_BRP GENMASK(7, 0)
|
|
#define ACC_REG_BTR_FD_MASK_TSEG1 GENMASK(7, 0)
|
|
#define ACC_REG_BTR_FD_MASK_TSEG2 GENMASK(22, 16)
|
|
#define ACC_REG_BTR_FD_MASK_SJW GENMASK(30, 24)
|
|
|
|
/* 256 BM_MSGs of 32 byte size */
|
|
#define ACC_CORE_DMAMSG_SIZE 32U
|
|
#define ACC_CORE_DMABUF_SIZE (256U * ACC_CORE_DMAMSG_SIZE)
|
|
|
|
enum acc_bmmsg_id {
|
|
BM_MSG_ID_RXTXDONE = 0x01,
|
|
BM_MSG_ID_TXABORT = 0x02,
|
|
BM_MSG_ID_OVERRUN = 0x03,
|
|
BM_MSG_ID_BUSERR = 0x04,
|
|
BM_MSG_ID_ERRPASSIVE = 0x05,
|
|
BM_MSG_ID_ERRWARN = 0x06,
|
|
BM_MSG_ID_TIMESLICE = 0x07,
|
|
BM_MSG_ID_HWTIMER = 0x08,
|
|
BM_MSG_ID_HOTPLUG = 0x09,
|
|
};
|
|
|
|
/* The struct acc_bmmsg_* structure declarations that follow here provide
|
|
* access to the ring buffer of bus master messages maintained by the FPGA
|
|
* bus master engine. All bus master messages have the same size of
|
|
* ACC_CORE_DMAMSG_SIZE and a minimum alignment of ACC_CORE_DMAMSG_SIZE in
|
|
* memory.
|
|
*
|
|
* All structure members are natural aligned. Therefore we should not need
|
|
* a __packed attribute. All struct acc_bmmsg_* declarations have at least
|
|
* reserved* members to fill the structure to the full ACC_CORE_DMAMSG_SIZE.
|
|
*
|
|
* A failure of this property due padding will be detected at compile time
|
|
* by static_assert(sizeof(union acc_bmmsg) == ACC_CORE_DMAMSG_SIZE).
|
|
*/
|
|
|
|
struct acc_bmmsg_rxtxdone {
|
|
u8 msg_id;
|
|
u8 txfifo_level;
|
|
u8 reserved1[2];
|
|
u8 txtsfifo_level;
|
|
u8 reserved2[3];
|
|
u32 id;
|
|
struct {
|
|
u8 len;
|
|
u8 txdfifo_idx;
|
|
u8 zeroes8;
|
|
u8 reserved;
|
|
} acc_dlc;
|
|
u8 data[CAN_MAX_DLEN];
|
|
/* Time stamps in struct acc_ov::timestamp_frequency ticks. */
|
|
u64 ts;
|
|
};
|
|
|
|
struct acc_bmmsg_txabort {
|
|
u8 msg_id;
|
|
u8 txfifo_level;
|
|
u16 abort_mask;
|
|
u8 txtsfifo_level;
|
|
u8 reserved2[1];
|
|
u16 abort_mask_txts;
|
|
u64 ts;
|
|
u32 reserved3[4];
|
|
};
|
|
|
|
struct acc_bmmsg_overrun {
|
|
u8 msg_id;
|
|
u8 txfifo_level;
|
|
u8 lost_cnt;
|
|
u8 reserved1;
|
|
u8 txtsfifo_level;
|
|
u8 reserved2[3];
|
|
u64 ts;
|
|
u32 reserved3[4];
|
|
};
|
|
|
|
struct acc_bmmsg_buserr {
|
|
u8 msg_id;
|
|
u8 txfifo_level;
|
|
u8 ecc;
|
|
u8 reserved1;
|
|
u8 txtsfifo_level;
|
|
u8 reserved2[3];
|
|
u64 ts;
|
|
u32 reg_status;
|
|
u32 reg_btr;
|
|
u32 reserved3[2];
|
|
};
|
|
|
|
struct acc_bmmsg_errstatechange {
|
|
u8 msg_id;
|
|
u8 txfifo_level;
|
|
u8 reserved1[2];
|
|
u8 txtsfifo_level;
|
|
u8 reserved2[3];
|
|
u64 ts;
|
|
u32 reg_status;
|
|
u32 reserved3[3];
|
|
};
|
|
|
|
struct acc_bmmsg_timeslice {
|
|
u8 msg_id;
|
|
u8 txfifo_level;
|
|
u8 reserved1[2];
|
|
u8 txtsfifo_level;
|
|
u8 reserved2[3];
|
|
u64 ts;
|
|
u32 reserved3[4];
|
|
};
|
|
|
|
struct acc_bmmsg_hwtimer {
|
|
u8 msg_id;
|
|
u8 reserved1[3];
|
|
u32 reserved2[1];
|
|
u64 timer;
|
|
u32 reserved3[4];
|
|
};
|
|
|
|
struct acc_bmmsg_hotplug {
|
|
u8 msg_id;
|
|
u8 reserved1[3];
|
|
u32 reserved2[7];
|
|
};
|
|
|
|
union acc_bmmsg {
|
|
u8 msg_id;
|
|
struct acc_bmmsg_rxtxdone rxtxdone;
|
|
struct acc_bmmsg_txabort txabort;
|
|
struct acc_bmmsg_overrun overrun;
|
|
struct acc_bmmsg_buserr buserr;
|
|
struct acc_bmmsg_errstatechange errstatechange;
|
|
struct acc_bmmsg_timeslice timeslice;
|
|
struct acc_bmmsg_hwtimer hwtimer;
|
|
};
|
|
|
|
/* Check size of union acc_bmmsg to be of expected size. */
|
|
static_assert(sizeof(union acc_bmmsg) == ACC_CORE_DMAMSG_SIZE);
|
|
|
|
struct acc_bmfifo {
|
|
const union acc_bmmsg *messages;
|
|
/* irq_cnt points to an u32 value where the esdACC FPGA deposits
|
|
* the bm_fifo head index in coherent DMA memory. Only bits 7..0
|
|
* are valid. Use READ_ONCE() to access this memory location.
|
|
*/
|
|
const u32 *irq_cnt;
|
|
u32 local_irq_cnt;
|
|
u32 msg_fifo_tail;
|
|
};
|
|
|
|
struct acc_core {
|
|
void __iomem *addr;
|
|
struct net_device *netdev;
|
|
struct acc_bmfifo bmfifo;
|
|
u8 tx_fifo_size;
|
|
u8 tx_fifo_head;
|
|
u8 tx_fifo_tail;
|
|
};
|
|
|
|
struct acc_ov {
|
|
void __iomem *addr;
|
|
struct acc_bmfifo bmfifo;
|
|
u32 timestamp_frequency;
|
|
u32 core_frequency;
|
|
u16 version;
|
|
u16 features;
|
|
u8 total_cores;
|
|
u8 active_cores;
|
|
};
|
|
|
|
struct acc_net_priv {
|
|
struct can_priv can; /* must be the first member! */
|
|
struct acc_core *core;
|
|
struct acc_ov *ov;
|
|
};
|
|
|
|
static inline u32 acc_read32(struct acc_core *core, unsigned short offs)
|
|
{
|
|
return ioread32be(core->addr + offs);
|
|
}
|
|
|
|
static inline void acc_write32(struct acc_core *core,
|
|
unsigned short offs, u32 v)
|
|
{
|
|
iowrite32be(v, core->addr + offs);
|
|
}
|
|
|
|
static inline void acc_write32_noswap(struct acc_core *core,
|
|
unsigned short offs, u32 v)
|
|
{
|
|
iowrite32(v, core->addr + offs);
|
|
}
|
|
|
|
static inline void acc_set_bits(struct acc_core *core,
|
|
unsigned short offs, u32 mask)
|
|
{
|
|
u32 v = acc_read32(core, offs);
|
|
|
|
v |= mask;
|
|
acc_write32(core, offs, v);
|
|
}
|
|
|
|
static inline void acc_clear_bits(struct acc_core *core,
|
|
unsigned short offs, u32 mask)
|
|
{
|
|
u32 v = acc_read32(core, offs);
|
|
|
|
v &= ~mask;
|
|
acc_write32(core, offs, v);
|
|
}
|
|
|
|
static inline int acc_resetmode_entered(struct acc_core *core)
|
|
{
|
|
u32 ctrl = acc_read32(core, ACC_CORE_OF_CTRL);
|
|
|
|
return (ctrl & ACC_REG_CTRL_MASK_RESETMODE) != 0;
|
|
}
|
|
|
|
static inline u32 acc_ov_read32(struct acc_ov *ov, unsigned short offs)
|
|
{
|
|
return ioread32be(ov->addr + offs);
|
|
}
|
|
|
|
static inline void acc_ov_write32(struct acc_ov *ov,
|
|
unsigned short offs, u32 v)
|
|
{
|
|
iowrite32be(v, ov->addr + offs);
|
|
}
|
|
|
|
static inline void acc_ov_set_bits(struct acc_ov *ov,
|
|
unsigned short offs, u32 b)
|
|
{
|
|
u32 v = acc_ov_read32(ov, offs);
|
|
|
|
v |= b;
|
|
acc_ov_write32(ov, offs, v);
|
|
}
|
|
|
|
static inline void acc_ov_clear_bits(struct acc_ov *ov,
|
|
unsigned short offs, u32 b)
|
|
{
|
|
u32 v = acc_ov_read32(ov, offs);
|
|
|
|
v &= ~b;
|
|
acc_ov_write32(ov, offs, v);
|
|
}
|
|
|
|
static inline void acc_reset_fpga(struct acc_ov *ov)
|
|
{
|
|
acc_ov_write32(ov, ACC_OV_OF_MODE, ACC_OV_REG_MODE_MASK_FPGA_RESET);
|
|
|
|
/* (Re-)start and wait for completion of addon detection on the I^2C bus */
|
|
acc_ov_set_bits(ov, ACC_OV_OF_MODE, ACC_OV_REG_MODE_MASK_I2C_ENABLE);
|
|
mdelay(ACC_I2C_ADDON_DETECT_DELAY_MS);
|
|
}
|
|
|
|
void acc_init_ov(struct acc_ov *ov, struct device *dev);
|
|
void acc_init_bm_ptr(struct acc_ov *ov, struct acc_core *cores,
|
|
const void *mem);
|
|
int acc_open(struct net_device *netdev);
|
|
int acc_close(struct net_device *netdev);
|
|
netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev);
|
|
int acc_get_berr_counter(const struct net_device *netdev,
|
|
struct can_berr_counter *bec);
|
|
int acc_set_mode(struct net_device *netdev, enum can_mode mode);
|
|
int acc_set_bittiming(struct net_device *netdev);
|
|
irqreturn_t acc_card_interrupt(struct acc_ov *ov, struct acc_core *cores);
|