Merge pull request #278 from marckleinebudde/mcp251xfd-dump
mcp251xfd-dump: add tool to decode chip and driver state of mcp251xfdpull/283/head
commit
cafc4bf748
|
|
@ -20,6 +20,7 @@ GNUmakefile.in
|
|||
/config/m4/ltsugar.m4
|
||||
/config/m4/ltversion.m4
|
||||
/config/m4/lt~obsolete.m4
|
||||
/mcp251xfd/.dirstamp
|
||||
|
||||
/asc2log
|
||||
/bcmserver
|
||||
|
|
@ -47,6 +48,7 @@ GNUmakefile.in
|
|||
/j1939sr
|
||||
/log2asc
|
||||
/log2long
|
||||
/mcp251xfd-dump
|
||||
/slcan_attach
|
||||
/slcand
|
||||
/slcanpty
|
||||
|
|
|
|||
|
|
@ -65,6 +65,13 @@ set(PROGRAMS
|
|||
slcanpty
|
||||
)
|
||||
|
||||
add_executable(mcp251xfd-dump
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c
|
||||
mcp251xfd/mcp251xfd-dump.c
|
||||
mcp251xfd/mcp251xfd-main.c
|
||||
mcp251xfd/mcp251xfd-regmap.c
|
||||
)
|
||||
|
||||
if(NOT ANDROID)
|
||||
list(APPEND PROGRAMS ${PROGRAMS_J1939})
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ noinst_HEADERS = \
|
|||
include/linux/can/raw.h \
|
||||
include/linux/can/vxcan.h \
|
||||
include/linux/errqueue.h \
|
||||
include/linux/kernel.h \
|
||||
include/linux/net_tstamp.h \
|
||||
include/linux/netlink.h
|
||||
|
||||
|
|
@ -38,6 +39,15 @@ libcan_la_SOURCES = \
|
|||
libj1939_la_SOURCES = \
|
||||
libj1939.c
|
||||
|
||||
mcp251xfd_dump_SOURCES = \
|
||||
mcp251xfd/mcp251xfd-dev-coredump.c \
|
||||
mcp251xfd/mcp251xfd-dump-userspace.h \
|
||||
mcp251xfd/mcp251xfd-dump.c \
|
||||
mcp251xfd/mcp251xfd-dump.h \
|
||||
mcp251xfd/mcp251xfd-main.c \
|
||||
mcp251xfd/mcp251xfd-regmap.c \
|
||||
mcp251xfd/mcp251xfd.h
|
||||
|
||||
bin_PROGRAMS = \
|
||||
asc2log \
|
||||
bcmserver \
|
||||
|
|
@ -65,6 +75,7 @@ bin_PROGRAMS = \
|
|||
j1939sr \
|
||||
log2asc \
|
||||
log2long \
|
||||
mcp251xfd-dump \
|
||||
slcan_attach \
|
||||
slcand \
|
||||
slcanpty \
|
||||
|
|
@ -82,7 +93,9 @@ EXTRA_DIST = \
|
|||
README.md \
|
||||
autogen.sh \
|
||||
can-j1939-kickstart.md \
|
||||
can-j1939.md
|
||||
can-j1939.md \
|
||||
mcp251xfd/99-devcoredump.rules \
|
||||
mcp251xfd/devcoredump
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
configure \
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -96,6 +96,7 @@ PROGRAMS := \
|
|||
cansniffer \
|
||||
log2asc \
|
||||
log2long \
|
||||
mcp251xfd-dump \
|
||||
slcanpty
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
|
@ -142,3 +143,6 @@ j1939spy: j1939spy.o libj1939.o
|
|||
j1939sr: j1939sr.o libj1939.o
|
||||
testj1939: testj1939.o libj1939.o
|
||||
canbusload: canbusload.o canframelen.o
|
||||
|
||||
mcp251xfd-dump: mcp251xfd/mcp251xfd-dev-coredump.o mcp251xfd/mcp251xfd-dump.o mcp251xfd/mcp251xfd-main.o mcp251xfd/mcp251xfd-regmap.o
|
||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ CFLAGS="${CFLAGS} -Wall"
|
|||
AC_PROG_CC
|
||||
LT_INIT(win32-dll)
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2])
|
||||
AM_INIT_AUTOMAKE([foreign no-exeext dist-bzip2 subdir-objects])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _LINUX_KERNEL_H
|
||||
#define _LINUX_KERNEL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint32_t __le32;
|
||||
|
||||
struct mcp251xfd_mem;
|
||||
|
||||
struct regmap {
|
||||
struct mcp251xfd_mem *mem;
|
||||
};
|
||||
|
||||
#define pr_info(...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define pr_cont(...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define netdev_info(ndev, ...) fprintf(stdout, ## __VA_ARGS__)
|
||||
#define BUILD_BUG_ON(...)
|
||||
|
||||
#define BITS_PER_LONG (sizeof(long) * 8)
|
||||
|
||||
#define ____cacheline_aligned
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
int regmap_bulk_read(struct regmap *map, unsigned int reg,
|
||||
void *val, size_t val_count);
|
||||
|
||||
#define SZ_2K 0x00000800
|
||||
|
||||
#define __packed __attribute__((__packed__))
|
||||
|
||||
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
|
||||
|
||||
#define BIT(nr) (UL(1) << (nr))
|
||||
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#define _AC(X,Y) X
|
||||
#define _AT(T,X) X
|
||||
#else
|
||||
#define __AC(X,Y) (X##Y)
|
||||
#define _AC(X,Y) __AC(X,Y)
|
||||
#define _AT(T,X) ((T)(X))
|
||||
#endif
|
||||
|
||||
#define _UL(x) (_AC(x, UL))
|
||||
#define _ULL(x) (_AC(x, ULL))
|
||||
|
||||
#define UL(x) (_UL(x))
|
||||
#define ULL(x) (_ULL(x))
|
||||
|
||||
#define GENMASK(h, l) \
|
||||
(((~UL(0)) - (UL(1) << (l)) + 1) & \
|
||||
(~UL(0) >> (BITS_PER_LONG - 1 - (h))))
|
||||
|
||||
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
|
||||
|
||||
#define FIELD_PREP(_mask, _val) \
|
||||
({ \
|
||||
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
|
||||
})
|
||||
|
||||
#define FIELD_GET(_mask, _reg) \
|
||||
({ \
|
||||
(typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
|
||||
})
|
||||
|
||||
#define min_t(type, x, y) ({ \
|
||||
type __min1 = (x); \
|
||||
type __min2 = (y); \
|
||||
__min1 < __min2 ? __min1 : __min2; })
|
||||
|
||||
#define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
|
||||
|
||||
static const u8 dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
static inline u8 can_dlc2len(u8 can_dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
}
|
||||
|
||||
#endif /* _LINUX_KERNEL_H */
|
||||
|
|
@ -0,0 +1 @@
|
|||
ACTION=="add", SUBSYSTEM=="devcoredump", RUN+="/usr/sbin/devcoredump"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
timestamp=$(date +%+4Y%m%d-%H%M%S)
|
||||
filename=/var/log/devcoredump-${timestamp}.dump
|
||||
|
||||
cat /sys/${DEVPATH}/data > ${filename}
|
||||
echo 1 > /sys/${DEVPATH}/data
|
||||
|
||||
echo "devcoredump ${DEVPATH}" | logger
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020, 2021 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
#define pr_err(fmt, args...) fprintf(stderr, fmt, ##args)
|
||||
#define pr_no(fmt, args...) while (0) { fprintf(stdout, fmt, ##args); }
|
||||
|
||||
#ifdef DEBUG
|
||||
#define pr_debug(fmt, args...) pr_err(fmt, ##args)
|
||||
#else
|
||||
#define pr_debug(fmt, args...) pr_no(fmt, ##args)
|
||||
#endif
|
||||
|
||||
|
||||
struct mcp251xfd_dump_iter {
|
||||
const void *start;
|
||||
const struct mcp251xfd_dump_object_header *hdr;
|
||||
const void *object_start;
|
||||
const void *object_end;
|
||||
};
|
||||
|
||||
static __attribute__((__unused__)) const char *
|
||||
get_object_type_str(enum mcp251xfd_dump_object_type object_type)
|
||||
{
|
||||
switch (object_type) {
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
|
||||
return "reg";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
|
||||
return "tef";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
|
||||
return "rx";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
|
||||
return "tx";
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_END:
|
||||
return "end";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__((__unused__)) const char *
|
||||
get_ring_key_str(enum mcp251xfd_dump_object_ring_key key)
|
||||
{
|
||||
switch (key) {
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD:
|
||||
return "head";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL:
|
||||
return "tail";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE:
|
||||
return "base";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_NR:
|
||||
return "nr";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR:
|
||||
return "fifo-nr";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM:
|
||||
return "obj-num";
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE:
|
||||
return "obj-size";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_dev_coredump_read_reg(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_iter *iter,
|
||||
struct mcp251xfd_mem *mem)
|
||||
{
|
||||
const struct mcp251xfd_dump_object_reg *object;
|
||||
|
||||
for (object = iter->object_start;
|
||||
(void *)(object + 1) <= iter->object_end;
|
||||
object++) {
|
||||
uint32_t reg, val;
|
||||
|
||||
reg = le32toh(object->reg);
|
||||
val = le32toh(object->val);
|
||||
|
||||
pr_debug("%s: object=0x%04zx reg=0x%04x - val=0x%08x\n",
|
||||
__func__,
|
||||
(void *)object - iter->start,
|
||||
reg, val);
|
||||
|
||||
if (reg > ARRAY_SIZE(mem->buf))
|
||||
return -EINVAL;
|
||||
|
||||
*(uint32_t *)(mem->buf + reg) = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_dev_coredump_read_ring(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_iter *iter,
|
||||
struct mcp251xfd_ring *ring)
|
||||
{
|
||||
const struct mcp251xfd_dump_object_reg *object;
|
||||
|
||||
for (object = iter->object_start;
|
||||
(void *)(object + 1) <= iter->object_end;
|
||||
object++) {
|
||||
enum mcp251xfd_dump_object_ring_key key;
|
||||
uint32_t val;
|
||||
|
||||
key = le32toh(object->reg);
|
||||
val = le32toh(object->val);
|
||||
|
||||
pr_debug("%s: reg=0x%04zx key=0x%02x: %8s - val=0x%08x\n",
|
||||
__func__,
|
||||
(void *)object - iter->start,
|
||||
key, get_ring_key_str(key), val);
|
||||
|
||||
switch (key) {
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD:
|
||||
ring->head = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL:
|
||||
ring->tail = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_BASE:
|
||||
ring->base = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_NR:
|
||||
ring->nr = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR:
|
||||
ring->fifo_nr = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM:
|
||||
ring->obj_num = val;
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE:
|
||||
ring->obj_size = val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const void *dump, size_t dump_len)
|
||||
{
|
||||
struct mcp251xfd_dump_iter iter[] = {
|
||||
{
|
||||
.start = dump,
|
||||
.hdr = dump,
|
||||
},
|
||||
};
|
||||
|
||||
while ((void *)(iter->hdr + 1) <= iter->start + dump_len &&
|
||||
le32toh(iter->hdr->magic) == MCP251XFD_DUMP_MAGIC) {
|
||||
const struct mcp251xfd_dump_object_header *hdr = iter->hdr;
|
||||
enum mcp251xfd_dump_object_type object_type;
|
||||
size_t object_offset, object_len;
|
||||
int err;
|
||||
|
||||
object_type = le32toh(hdr->type);
|
||||
object_offset = le32toh(hdr->offset);
|
||||
object_len = le32toh(hdr->len);
|
||||
|
||||
if (object_offset + object_len > dump_len)
|
||||
return -EFAULT;
|
||||
|
||||
iter->object_start = iter->start + object_offset;
|
||||
iter->object_end = iter->object_start + object_len;
|
||||
|
||||
pr_debug("%s: hdr=0x%04zx type=0x%08x: %8s - offset=0x%04zx len=0x%04zx end=0x%04zx\n",
|
||||
__func__,
|
||||
(void *)iter->hdr - iter->start,
|
||||
object_type, get_object_type_str(object_type),
|
||||
object_offset, object_len, object_offset + object_len);
|
||||
|
||||
switch (object_type) {
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_REG:
|
||||
err = do_dev_coredump_read_reg(priv, iter, mem);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TEF:
|
||||
err = do_dev_coredump_read_ring(priv, iter, priv->tef);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_RX:
|
||||
err = do_dev_coredump_read_ring(priv, iter, priv->rx);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_TX:
|
||||
err = do_dev_coredump_read_ring(priv, iter, priv->tx);
|
||||
break;
|
||||
case MCP251XFD_DUMP_OBJECT_TYPE_END:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
iter->hdr++;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *dump_path)
|
||||
{
|
||||
struct stat statbuf;
|
||||
size_t dump_len;
|
||||
void *dump;
|
||||
int fd, err;
|
||||
|
||||
fd = open(dump_path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
err = fstat(fd, &statbuf);
|
||||
if (err < 0) {
|
||||
err = -errno;
|
||||
goto out_close;
|
||||
}
|
||||
dump_len = statbuf.st_size;
|
||||
|
||||
dump = mmap(NULL, dump_len, PROT_READ, MAP_SHARED, fd, 0x0);
|
||||
if (dump == MAP_FAILED) {
|
||||
err = -errno;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = do_dev_coredump_read(priv, mem, dump, dump_len);
|
||||
|
||||
munmap(dump, dump_len);
|
||||
out_close:
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Microchip MCP251xFD Family CAN controller debug tool
|
||||
*
|
||||
* Copyright (c) 2019, 2020 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_DUMP_USERSPACE_H
|
||||
#define _MCP251XFD_DUMP_USERSPACE_H
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump.h"
|
||||
|
||||
#define MCP251XFD_TX_FIFO 1
|
||||
#define MCP251XFD_RX_FIFO(x) (MCP251XFD_TX_FIFO + 1 + (x))
|
||||
|
||||
struct mcp251xfd_mem {
|
||||
char buf[0x1000];
|
||||
};
|
||||
|
||||
struct mcp251xfd_ring {
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
|
||||
u16 base;
|
||||
u8 nr;
|
||||
u8 fifo_nr;
|
||||
u8 obj_num;
|
||||
u8 obj_size;
|
||||
};
|
||||
|
||||
struct mcp251xfd_priv {
|
||||
struct regmap *map;
|
||||
|
||||
struct mcp251xfd_ring tef[1];
|
||||
struct mcp251xfd_ring tx[1];
|
||||
struct mcp251xfd_ring rx[1];
|
||||
|
||||
u8 rx_ring_num;
|
||||
};
|
||||
|
||||
static inline u8 mcp251xfd_get_ring_head(const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return ring->head & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
static inline u8 mcp251xfd_get_ring_tail(const struct mcp251xfd_ring *ring)
|
||||
{
|
||||
return ring->tail & (ring->obj_num - 1);
|
||||
}
|
||||
|
||||
void mcp251xfd_dump(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_dev_coredump_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path);
|
||||
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,863 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
struct mcp251xfd_dump_regs_fifo {
|
||||
u32 con;
|
||||
u32 sta;
|
||||
u32 ua;
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_regs_filter {
|
||||
u32 obj;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_regs {
|
||||
u32 con;
|
||||
u32 nbtcfg;
|
||||
u32 dbtcfg;
|
||||
u32 tdc;
|
||||
u32 tbc;
|
||||
u32 tscon;
|
||||
u32 vec;
|
||||
u32 intf;
|
||||
u32 rxif;
|
||||
u32 txif;
|
||||
u32 rxovif;
|
||||
u32 txatif;
|
||||
u32 txreq;
|
||||
u32 trec;
|
||||
u32 bdiag0;
|
||||
u32 bdiag1;
|
||||
union {
|
||||
struct {
|
||||
u32 tefcon;
|
||||
u32 tefsta;
|
||||
u32 tefua;
|
||||
};
|
||||
struct mcp251xfd_dump_regs_fifo tef;
|
||||
};
|
||||
u32 reserved0;
|
||||
union {
|
||||
struct {
|
||||
struct mcp251xfd_dump_regs_fifo txq;
|
||||
struct mcp251xfd_dump_regs_fifo tx_fifo;
|
||||
struct mcp251xfd_dump_regs_fifo rx_fifo;
|
||||
};
|
||||
struct mcp251xfd_dump_regs_fifo fifo[32];
|
||||
};
|
||||
u32 fltcon[8];
|
||||
struct mcp251xfd_dump_regs_filter filter[32];
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_ram {
|
||||
u8 ram[MCP251XFD_RAM_SIZE];
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_regs_mcp251xfd {
|
||||
u32 osc;
|
||||
u32 iocon;
|
||||
u32 crc;
|
||||
u32 ecccon;
|
||||
u32 eccstat;
|
||||
u32 devid;
|
||||
};
|
||||
|
||||
#define __dump_bit(val, prefix, bit, desc) \
|
||||
pr_info("%16s %s\t\t%s\n", __stringify(bit), \
|
||||
(val) & prefix##_##bit ? "x" : " ", desc)
|
||||
|
||||
#define __dump_mask(val, prefix, mask, fmt, desc) \
|
||||
pr_info("%16s = " fmt "\t\t%s\n", \
|
||||
__stringify(mask), \
|
||||
FIELD_GET(prefix##_##mask##_MASK, (val)), \
|
||||
desc)
|
||||
|
||||
static void mcp251xfd_dump_reg_con(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("CON: con(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_CON, TXBWS, "0x%02lx", "Transmit Bandwidth Sharing");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, ABAT, "Abort All Pending Transmissions");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, REQOP, "0x%02lx", "Request Operation Mode");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, OPMOD, "0x%02lx", "Operation Mode Status");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, TXQEN, "Enable Transmit Queue");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, STEF, "Store in Transmit Event FIFO");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, SERR2LOM, "Transition to Listen Only Mode on System Error");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, ESIGM, "Transmit ESI in Gateway Mode");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, RTXAT, "Restrict Retransmission Attempts");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, BRSDIS, "Bit Rate Switching Disable");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, BUSY, "CAN Module is Busy");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, WFT, "0x%02lx", "Selectable Wake-up Filter Time");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, WAKFIL, "Enable CAN Bus Line Wake-up Filter");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, PXEDIS, "Protocol Exception Event Detection Disabled");
|
||||
__dump_bit(val, MCP251XFD_REG_CON, ISOCRCEN, "Enable ISO CRC in CAN FD Frames");
|
||||
__dump_mask(val, MCP251XFD_REG_CON, DNCNT, "0x%02lx", "Device Net Filter Bit Number");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_nbtcfg(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("NBTCFG: nbtcfg(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, BRP, "%3lu", "Baud Rate Prescaler");
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, TSEG1, "%3lu", "Time Segment 1 (Propagation Segment + Phase Segment 1)");
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, TSEG2, "%3lu", "Time Segment 2 (Phase Segment 2)");
|
||||
__dump_mask(val, MCP251XFD_REG_NBTCFG, SJW, "%3lu", "Synchronization Jump Width");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_dbtcfg(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("DBTCFG: dbtcfg(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, BRP, "%3lu", "Baud Rate Prescaler");
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, TSEG1, "%3lu", "Time Segment 1 (Propagation Segment + Phase Segment 1)");
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, TSEG2, "%3lu", "Time Segment 2 (Phase Segment 2)");
|
||||
__dump_mask(val, MCP251XFD_REG_DBTCFG, SJW, "%3lu", "Synchronization Jump Width");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tdc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TDC: tdc(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_TDC, EDGFLTEN, "Enable Edge Filtering during Bus Integration state");
|
||||
__dump_bit(val, MCP251XFD_REG_TDC, SID11EN, "Enable 12-Bit SID in CAN FD Base Format Messages");
|
||||
__dump_mask(val, MCP251XFD_REG_TDC, TDCMOD, "0x%02lx", "Transmitter Delay Compensation Mode");
|
||||
__dump_mask(val, MCP251XFD_REG_TDC, TDCO, "0x%02lx", "Transmitter Delay Compensation Offset");
|
||||
__dump_mask(val, MCP251XFD_REG_TDC, TDCV, "0x%02lx", "Transmitter Delay Compensation Value");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tbc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TBC: tbc(0x%03x)=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_vec(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
u8 rx_code, tx_code, i_code;
|
||||
|
||||
pr_info("VEC: vec(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
rx_code = FIELD_GET(MCP251XFD_REG_VEC_RXCODE_MASK, val);
|
||||
tx_code = FIELD_GET(MCP251XFD_REG_VEC_TXCODE_MASK, val);
|
||||
i_code = FIELD_GET(MCP251XFD_REG_VEC_ICODE_MASK, val);
|
||||
|
||||
pr_info("\trxcode: ");
|
||||
if (rx_code == 0x40)
|
||||
pr_cont("No Interrupt");
|
||||
else if (rx_code < 0x20)
|
||||
pr_cont("FIFO %u", rx_code);
|
||||
else
|
||||
pr_cont("Reserved");
|
||||
pr_cont(" (0x%02x)\n", rx_code);
|
||||
|
||||
pr_info("\ttxcode: ");
|
||||
if (tx_code == 0x40)
|
||||
pr_cont("No Interrupt");
|
||||
else if (tx_code < 0x20)
|
||||
pr_cont("FIFO %u", tx_code);
|
||||
else
|
||||
pr_cont("Reserved");
|
||||
pr_cont(" (0x%02x)\n", tx_code);
|
||||
|
||||
pr_info("\ticode: ");
|
||||
if (i_code == 0x4a)
|
||||
pr_cont("Transmit Attempt Interrupt");
|
||||
else if (i_code == 0x49)
|
||||
pr_cont("Transmit Event FIFO Interrupt");
|
||||
else if (i_code == 0x48)
|
||||
pr_cont("Invalid Message Occurred");
|
||||
else if (i_code == 0x47)
|
||||
pr_cont("Operation Mode Changed");
|
||||
else if (i_code == 0x46)
|
||||
pr_cont("TBC Overflow");
|
||||
else if (i_code == 0x45)
|
||||
pr_cont("RX/TX MAB Overflow/Underflow");
|
||||
else if (i_code == 0x44)
|
||||
pr_cont("Address Error Interrupt");
|
||||
else if (i_code == 0x43)
|
||||
pr_cont("Receive FIFO Overflow Interrupt");
|
||||
else if (i_code == 0x42)
|
||||
pr_cont("Wake-up Interrupt");
|
||||
else if (i_code == 0x41)
|
||||
pr_cont("Error Interrupt");
|
||||
else if (i_code == 0x40)
|
||||
pr_cont("No Interrupt");
|
||||
else if (i_code < 0x20)
|
||||
pr_cont("FIFO %u", i_code);
|
||||
else
|
||||
pr_cont("Reserved");
|
||||
pr_cont(" (0x%02x)\n", i_code);
|
||||
}
|
||||
|
||||
#define __dump_int(val, bit, desc) \
|
||||
pr_info("\t" __stringify(bit) "\t%s\t%s\t%s\t%s\n", \
|
||||
(val) & MCP251XFD_REG_INT_##bit##E ? "x" : "", \
|
||||
(val) & MCP251XFD_REG_INT_##bit##F ? "x" : "", \
|
||||
FIELD_GET(MCP251XFD_REG_INT_IF_MASK, val) & \
|
||||
FIELD_GET(MCP251XFD_REG_INT_IE_MASK, val) & \
|
||||
MCP251XFD_REG_INT_##bit##F ? "x" : "", \
|
||||
desc)
|
||||
|
||||
static void mcp251xfd_dump_reg_intf(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("INT: intf(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
pr_info("\t\tIE\tIF\tIE & IF\n");
|
||||
__dump_int(val, IVMI, "Invalid Message Interrupt");
|
||||
__dump_int(val, WAKI, "Bus Wake Up Interrupt");
|
||||
__dump_int(val, CERRI, "CAN Bus Error Interrupt");
|
||||
__dump_int(val, SERRI, "System Error Interrupt");
|
||||
__dump_int(val, RXOVI, "Receive FIFO Overflow Interrupt");
|
||||
__dump_int(val, TXATI, "Transmit Attempt Interrupt");
|
||||
__dump_int(val, SPICRCI, "SPI CRC Error Interrupt");
|
||||
__dump_int(val, ECCI, "ECC Error Interrupt");
|
||||
__dump_int(val, TEFI, "Transmit Event FIFO Interrupt");
|
||||
__dump_int(val, MODI, "Mode Change Interrupt");
|
||||
__dump_int(val, TBCI, "Time Base Counter Interrupt");
|
||||
__dump_int(val, RXI, "Receive FIFO Interrupt");
|
||||
__dump_int(val, TXI, "Transmit FIFO Interrupt");
|
||||
}
|
||||
|
||||
#undef __dump_int
|
||||
|
||||
#define __create_dump_fifo_bitmask(fifo, name, description) \
|
||||
static void mcp251xfd_dump_reg_##fifo(const struct mcp251xfd_priv *priv, u32 val, u16 addr) \
|
||||
{ \
|
||||
int i; \
|
||||
\
|
||||
pr_info(__stringify(name) ": " __stringify(fifo) "(0x%03x)=0x%08x\n", addr, val); \
|
||||
pr_info(description ":\n"); \
|
||||
if (!val) { \
|
||||
pr_info("\t\t-none-\n"); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
pr_info("\t\t"); \
|
||||
for (i = 0; i < sizeof(val); i++) { \
|
||||
if (val & BIT(i)) \
|
||||
pr_cont("%d ", i); \
|
||||
} \
|
||||
\
|
||||
pr_cont("\n"); \
|
||||
}
|
||||
|
||||
__create_dump_fifo_bitmask(rxif, RXIF, "Receive FIFO Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(rxovif, RXOVIF, "Receive FIFO Overflow Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(txif, TXIF, "Transmit FIFO Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(txatif, TXATIF, "Transmit FIFO Attempt Interrupt Pending");
|
||||
__create_dump_fifo_bitmask(txreq, TXREQ, "Message Send Request");
|
||||
|
||||
#undef __create_dump_fifo_bitmask
|
||||
|
||||
static void mcp251xfd_dump_reg_trec(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TREC: trec(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, TXBO, "Transmitter in Bus Off State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, TXBP, "Transmitter in Error Passive State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, RXBP, "Receiver in Error Passive State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, TXWARN, "Transmitter in Error Warning State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, RXWARN, "Receiver in Error Warning State");
|
||||
__dump_bit(val, MCP251XFD_REG_TREC, EWARN, "Transmitter or Receiver is in Error Warning State");
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_TREC, TEC, "%3lu", "Transmit Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_TREC, REC, "%3lu", "Receive Error Counter");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_bdiag0(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("BDIAG0: bdiag0(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, DTERRCNT, "%3lu", "Data Bit Rate Transmit Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, DRERRCNT, "%3lu", "Data Bit Rate Receive Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, NTERRCNT, "%3lu", "Nominal Bit Rate Transmit Error Counter");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG0, NRERRCNT, "%3lu", "Nominal Bit Rate Receive Error Counter");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_bdiag1(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("BDIAG1: bdiag1(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DLCMM, "DLC Mismatch");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, ESI, "ESI flag of a received CAN FD message was set");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DCRCERR, "Data CRC Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DSTUFERR, "Data Bit Stuffing Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DFORMERR, "Data Format Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DBIT1ERR, "Data BIT1 Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, DBIT0ERR, "Data BIT0 Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, TXBOERR, "Device went to bus-off (and auto-recovered)");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NCRCERR, "CRC Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NSTUFERR, "Bit Stuffing Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NFORMERR, "Format Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NACKERR, "Transmitted message was not acknowledged");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NBIT1ERR, "Bit1 Error");
|
||||
__dump_bit(val, MCP251XFD_REG_BDIAG1, NBIT0ERR, "Bit0 Error");
|
||||
__dump_mask(val, MCP251XFD_REG_BDIAG1, EFMSGCNT, "%3lu", "Error Free Message Counter");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_osc(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("OSC: osc(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, SCLKRDY, "Synchronized SCLKDIV");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, OSCRDY, "Clock Ready");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, PLLRDY, "PLL Ready");
|
||||
__dump_mask(val, MCP251XFD_REG_OSC, CLKODIV, "0x%02lu", "Clock Output Divisor");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, SCLKDIV, "System Clock Divisor");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, LPMEN, "Low Power Mode (LPM) Enable (MCP2518FD only)");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, OSCDIS, "Clock (Oscillator) Disable");
|
||||
__dump_bit(val, MCP251XFD_REG_OSC, PLLEN, "PLL Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tefcon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TEFCON: tefcon(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_TEFCON, FSIZE, "%3lu", "FIFO Size");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, FRESET, "FIFO Reset");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, UINC, "Increment Tail");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFTSEN, "Transmit Event FIFO Time Stamp Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFOVIE, "Transmit Event FIFO Overflow Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFFIE, "Transmit Event FIFO Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFHIE, "Transmit Event FIFO Half Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFCON, TEFNEIE, "Transmit Event FIFO Not Empty Interrupt Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tefsta(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TEFSTA: tefsta(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFOVIF, "Transmit Event FIFO Overflow Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFFIF, "Transmit Event FIFO Full Interrupt Flag (0: not full)");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFHIF, "Transmit Event FIFO Half Full Interrupt Flag (0: < half full)");
|
||||
__dump_bit(val, MCP251XFD_REG_TEFSTA, TEFNEIF, "Transmit Event FIFO Not Empty Interrupt Flag (0: empty)");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_tefua(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("TEFUA: tefua(0x%03x)=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_fifocon(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("FIFOCON: fifocon(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, PLSIZE, "%3lu", "Payload Size");
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, FSIZE, "%3lu", "FIFO Size");
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, TXAT, "%3lu", "Retransmission Attempts");
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOCON, TXPRI, "%3lu", "Message Transmit Priority");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, FRESET, "FIFO Reset");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXREQ, "Message Send Request");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, UINC, "Increment Head/Tail");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXEN, "TX/RX FIFO Selection (0: RX, 1: TX)");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, RTREN, "Auto RTR Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, RXTSEN, "Received Message Time Stamp Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TXATIE, "Transmit Attempts Exhausted Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, RXOVIE, "Overflow Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFERFFIE, "Transmit/Receive FIFO Empty/Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFHRFHIE, "Transmit/Receive FIFO Half Empty/Half Full Interrupt Enable");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOCON, TFNRFNIE, "Transmit/Receive FIFO Not Full/Not Empty Interrupt Enable");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_fifosta(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("FIFOSTA: fifosta(0x%03x)=0x%08x\n", addr, val);
|
||||
|
||||
__dump_mask(val, MCP251XFD_REG_FIFOSTA, FIFOCI, "%3lu", "FIFO Message Index");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXABT, "Message Aborted Status (0: completed successfully, 1: aborted)");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXLARB, "Message Lost Arbitration Status");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXERR, "Error Detected During Transmission");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TXATIF, "Transmit Attempts Exhausted Interrupt Pending");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, RXOVIF, "Receive FIFO Overflow Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFERFFIF, "Transmit/Receive FIFO Empty/Full Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFHRFHIF, "Transmit/Receive FIFO Half Empty/Half Full Interrupt Flag");
|
||||
__dump_bit(val, MCP251XFD_REG_FIFOSTA, TFNRFNIF, "Transmit/Receive FIFO Not Full/Not Empty Interrupt Flag");
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_reg_fifoua(const struct mcp251xfd_priv *priv, u32 val, u16 addr)
|
||||
{
|
||||
pr_info("FIFOUA: fifoua(0x%03x)=0x%08x\n", addr, val);
|
||||
}
|
||||
|
||||
#define __dump_call(regs, val) \
|
||||
do { \
|
||||
mcp251xfd_dump_reg_##val(priv, (regs)->val, \
|
||||
(u16)(offsetof(typeof(*(regs)), val) + \
|
||||
(sizeof(*(regs)) == sizeof(struct mcp251xfd_dump_regs) ? \
|
||||
0 : MCP251XFD_REG_OSC))); \
|
||||
pr_info("\n"); \
|
||||
} while (0)
|
||||
|
||||
#define __dump_call_fifo(reg, val) \
|
||||
do { \
|
||||
mcp251xfd_dump_reg_##reg(priv, regs->val, (u16)offsetof(typeof(*regs), val)); \
|
||||
pr_info("\n"); \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_regs(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_regs_mcp251xfd *regs_mcp251xfd)
|
||||
{
|
||||
netdev_info(priv->ndev, "-------------------- register dump --------------------\n");
|
||||
__dump_call(regs, con);
|
||||
__dump_call(regs, nbtcfg);
|
||||
__dump_call(regs, dbtcfg);
|
||||
__dump_call(regs, tdc);
|
||||
__dump_call(regs, tbc);
|
||||
__dump_call(regs, vec);
|
||||
__dump_call(regs, intf);
|
||||
__dump_call(regs, rxif);
|
||||
__dump_call(regs, rxovif);
|
||||
__dump_call(regs, txif);
|
||||
__dump_call(regs, txatif);
|
||||
__dump_call(regs, txreq);
|
||||
__dump_call(regs, trec);
|
||||
__dump_call(regs, bdiag0);
|
||||
__dump_call(regs, bdiag1);
|
||||
__dump_call(regs_mcp251xfd, osc);
|
||||
pr_info("-------------------- TEF --------------------\n");
|
||||
__dump_call(regs, tefcon);
|
||||
__dump_call(regs, tefsta);
|
||||
__dump_call(regs, tefua);
|
||||
pr_info("-------------------- TX_FIFO --------------------\n");
|
||||
__dump_call_fifo(fifocon, fifo[MCP251XFD_TX_FIFO].con);
|
||||
__dump_call_fifo(fifosta, fifo[MCP251XFD_TX_FIFO].sta);
|
||||
__dump_call_fifo(fifoua, fifo[MCP251XFD_TX_FIFO].ua);
|
||||
pr_info(" -------------------- RX_FIFO --------------------\n");
|
||||
__dump_call_fifo(fifocon, fifo[MCP251XFD_RX_FIFO(0)].con);
|
||||
__dump_call_fifo(fifosta, fifo[MCP251XFD_RX_FIFO(0)].sta);
|
||||
__dump_call_fifo(fifoua, fifo[MCP251XFD_RX_FIFO(0)].ua);
|
||||
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
|
||||
}
|
||||
|
||||
#undef __dump_call
|
||||
#undef __dump_call_fifo
|
||||
|
||||
static u8 mcp251xfd_dump_get_fifo_size(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
|
||||
{
|
||||
u8 obj_size;
|
||||
|
||||
obj_size = FIELD_GET(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, fifo_con);
|
||||
switch (obj_size) {
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_8:
|
||||
return 8;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_12:
|
||||
return 12;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_16:
|
||||
return 16;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_20:
|
||||
return 20;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_24:
|
||||
return 24;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_32:
|
||||
return 32;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_48:
|
||||
return 48;
|
||||
case MCP251XFD_REG_FIFOCON_PLSIZE_64:
|
||||
return 64;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 mcp251xfd_dump_get_fifo_obj_num(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, u32 fifo_con)
|
||||
{
|
||||
u8 obj_num;
|
||||
|
||||
obj_num = FIELD_GET(MCP251XFD_REG_FIFOCON_FSIZE_MASK, fifo_con);
|
||||
|
||||
return obj_num + 1;
|
||||
}
|
||||
|
||||
static void mcp251xfd_dump_ram_fifo_obj_data(const struct mcp251xfd_priv *priv, const u8 *data, u8 dlc)
|
||||
{
|
||||
int i;
|
||||
u8 len;
|
||||
|
||||
len = can_dlc2len(get_canfd_dlc(dlc));
|
||||
|
||||
if (!len) {
|
||||
pr_info("%16s = -none-\n", "data");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if ((i % 8) == 0) {
|
||||
if (i == 0)
|
||||
pr_info("%16s = %02x", "data", data[i]);
|
||||
else
|
||||
pr_info(" %02x", data[i]);
|
||||
} else if ((i % 4) == 0) {
|
||||
pr_cont(" %02x", data[i]);
|
||||
} else if ((i % 8) == 7) {
|
||||
pr_cont(" %02x\n", data[i]);
|
||||
} else {
|
||||
pr_cont(" %02x", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (i % 8)
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
/* TEF */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tef.con);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tef_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return regs->tefua / sizeof(struct mcp251xfd_hw_tef_obj);
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tef_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
u8 n)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tef_obj) * n;
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tef_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tef_obj_rel_addr(priv, n) +
|
||||
MCP251XFD_RAM_START;
|
||||
}
|
||||
|
||||
/* TX */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_tx_obj_can) -
|
||||
sizeof_field(struct mcp251xfd_hw_tx_obj_can, data) +
|
||||
mcp251xfd_dump_get_fifo_size(priv, regs, regs->tx_fifo.con);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->tx_fifo.con);
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tx_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tef_obj_rel_addr(priv, mcp251xfd_dump_get_tef_obj_num(priv, regs)) +
|
||||
mcp251xfd_dump_get_tx_obj_size(priv, regs) * n;
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_tx_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs, u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, n) +
|
||||
MCP251XFD_RAM_START;
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return (regs->fifo[MCP251XFD_TX_FIFO].ua -
|
||||
mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, 0)) /
|
||||
mcp251xfd_dump_get_tx_obj_size(priv, regs);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_tx_head(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK,
|
||||
regs->fifo[MCP251XFD_TX_FIFO].sta);
|
||||
}
|
||||
|
||||
/* RX */
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_obj_size(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return sizeof(struct mcp251xfd_hw_rx_obj_can) -
|
||||
sizeof_field(struct mcp251xfd_hw_rx_obj_can, data) +
|
||||
mcp251xfd_dump_get_fifo_size(priv, regs, regs->rx_fifo.con);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_obj_num(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return mcp251xfd_dump_get_fifo_obj_num(priv, regs, regs->rx_fifo.con);
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_rx_obj_rel_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs, u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, mcp251xfd_dump_get_tx_obj_num(priv, regs)) +
|
||||
mcp251xfd_dump_get_rx_obj_size(priv, regs) * n;
|
||||
}
|
||||
|
||||
static u16
|
||||
mcp251xfd_dump_get_rx_obj_addr(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs, u8 n)
|
||||
{
|
||||
return mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, n) + MCP251XFD_RAM_START;
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_tail(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return (regs->fifo[MCP251XFD_RX_FIFO(0)].ua -
|
||||
mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, 0)) /
|
||||
mcp251xfd_dump_get_rx_obj_size(priv, regs);
|
||||
}
|
||||
|
||||
static u8
|
||||
mcp251xfd_dump_get_rx_head(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs)
|
||||
{
|
||||
return FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, regs->fifo[MCP251XFD_RX_FIFO(0)].sta);
|
||||
}
|
||||
|
||||
/* dump TEF */
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tef_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_ring *tef,
|
||||
const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
|
||||
u8 n)
|
||||
{
|
||||
pr_info("TEF Object: 0x%02x (0x%03x)%s%s%s%s%s\n",
|
||||
n, mcp251xfd_dump_get_tef_obj_addr(priv, n),
|
||||
mcp251xfd_get_ring_head(tef) == n ? " priv-HEAD" : "",
|
||||
mcp251xfd_dump_get_tef_tail(priv, regs) == n ? " chip-TAIL" : "",
|
||||
mcp251xfd_get_ring_tail(tef) == n ? " priv-TAIL" : "",
|
||||
(mcp251xfd_dump_get_tef_tail(priv, regs) == n ?
|
||||
((regs->tef.sta & MCP251XFD_REG_TEFSTA_TEFFIF) ? " chip-FIFO-full" :
|
||||
!(regs->tef.sta & MCP251XFD_REG_TEFSTA_TEFNEIF) ? " chip-FIFO-empty" : "") :
|
||||
("")),
|
||||
(mcp251xfd_get_ring_head(tef) == mcp251xfd_get_ring_tail(tef) &&
|
||||
mcp251xfd_get_ring_tail(tef) == n ?
|
||||
(priv->tef->head == priv->tef->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
|
||||
("")));
|
||||
pr_info("%16s = 0x%08x\n", "id", hw_tef_obj->id);
|
||||
pr_info("%16s = 0x%08x\n", "flags", hw_tef_obj->flags);
|
||||
pr_info("%16s = 0x%08x\n", "ts", hw_tef_obj->ts);
|
||||
__dump_mask(hw_tef_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ, "0x%06lx", "Sequence");
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tef_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram,
|
||||
const struct mcp251xfd_ring *tef)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("\nTEF Overview:\n");
|
||||
pr_info("%16s = 0x%02x 0x%08x\n", "head (p)",
|
||||
mcp251xfd_get_ring_head(tef),
|
||||
tef->head);
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
|
||||
mcp251xfd_dump_get_tef_tail(priv, regs),
|
||||
mcp251xfd_get_ring_tail(tef),
|
||||
tef->tail);
|
||||
pr_info("\n");
|
||||
|
||||
for (i = 0; i < mcp251xfd_dump_get_tef_obj_num(priv, regs); i++) {
|
||||
const struct mcp251xfd_hw_tef_obj *hw_tef_obj;
|
||||
u16 hw_tef_obj_rel_addr;
|
||||
|
||||
hw_tef_obj_rel_addr = mcp251xfd_dump_get_tef_obj_rel_addr(priv, i);
|
||||
|
||||
hw_tef_obj = (const struct mcp251xfd_hw_tef_obj *)&ram->ram[hw_tef_obj_rel_addr];
|
||||
mcp251xfd_dump_ram_tef_obj_one(priv, regs, tef, hw_tef_obj, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* dump TX */
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tx_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_ring *tx,
|
||||
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj,
|
||||
u8 n)
|
||||
{
|
||||
pr_info("TX Object: 0x%02x (0x%03x)%s%s%s%s%s%s\n",
|
||||
n, mcp251xfd_dump_get_tx_obj_addr(priv, regs, n),
|
||||
mcp251xfd_dump_get_tx_head(priv, regs) == n ? " chip-HEAD" : "",
|
||||
mcp251xfd_get_ring_head(tx) == n ? " priv-HEAD" : "",
|
||||
mcp251xfd_dump_get_tx_tail(priv, regs) == n ? " chip-TAIL" : "",
|
||||
mcp251xfd_get_ring_tail(tx) == n ? " priv-TAIL" : "",
|
||||
mcp251xfd_dump_get_tx_tail(priv, regs) == n ?
|
||||
(!(regs->tx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF) ? " chip-FIFO-full" :
|
||||
(regs->tx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFERFFIF) ? " chip-FIFO-empty" : "") :
|
||||
(""),
|
||||
(mcp251xfd_get_ring_head(tx) == mcp251xfd_get_ring_tail(tx) &&
|
||||
mcp251xfd_get_ring_tail(tx) == n ?
|
||||
(tx->head == tx->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
|
||||
("")));
|
||||
pr_info("%16s = 0x%08x\n", "id", hw_tx_obj->id);
|
||||
pr_info("%16s = 0x%08x\n", "flags", hw_tx_obj->flags);
|
||||
__dump_mask(hw_tx_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ_MCP2517FD, "0x%06lx", "Sequence (MCP2517)");
|
||||
__dump_mask(hw_tx_obj->flags, MCP251XFD_OBJ_FLAGS, SEQ_MCP2518FD, "0x%06lx", "Sequence (MCP2518)");
|
||||
mcp251xfd_dump_ram_fifo_obj_data(priv,
|
||||
hw_tx_obj->data,
|
||||
FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_tx_obj->flags));
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_tx_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram,
|
||||
const struct mcp251xfd_ring *tx)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("\nTX Overview:\n");
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/p)",
|
||||
mcp251xfd_dump_get_tx_head(priv, regs),
|
||||
mcp251xfd_get_ring_head(tx),
|
||||
tx->head);
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
|
||||
mcp251xfd_dump_get_tx_tail(priv, regs),
|
||||
mcp251xfd_get_ring_tail(tx),
|
||||
tx->tail);
|
||||
pr_info("\n");
|
||||
|
||||
for (i = 0; i < mcp251xfd_dump_get_tx_obj_num(priv, regs); i++) {
|
||||
const struct mcp251xfd_hw_tx_obj_canfd *hw_tx_obj;
|
||||
u16 hw_tx_obj_rel_addr;
|
||||
|
||||
hw_tx_obj_rel_addr = mcp251xfd_dump_get_tx_obj_rel_addr(priv, regs, i);
|
||||
|
||||
hw_tx_obj = (const struct mcp251xfd_hw_tx_obj_canfd *)&ram->ram[hw_tx_obj_rel_addr];
|
||||
mcp251xfd_dump_ram_tx_obj_one(priv, regs, tx, hw_tx_obj, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* dump RX */
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_rx_obj_one(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_ring *rx,
|
||||
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
|
||||
u8 n)
|
||||
{
|
||||
pr_info("RX Object: 0x%02x (0x%03x)%s%s%s%s%s%s\n",
|
||||
n, mcp251xfd_dump_get_rx_obj_addr(priv, regs, n),
|
||||
mcp251xfd_dump_get_rx_head(priv, regs) == n ? " chip-HEAD" : "",
|
||||
mcp251xfd_get_ring_head(rx) == n ? " priv-HEAD" : "",
|
||||
mcp251xfd_dump_get_rx_tail(priv, regs) == n ? " chip-TAIL" : "",
|
||||
mcp251xfd_get_ring_tail(rx) == n ? " priv-TAIL" : "",
|
||||
mcp251xfd_dump_get_rx_tail(priv, regs) == n ?
|
||||
((regs->rx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFERFFIF) ? " chip-FIFO-full" :
|
||||
!(regs->rx_fifo.sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF) ? " chip-FIFO-empty" : "") :
|
||||
(""),
|
||||
(mcp251xfd_get_ring_head(rx) == mcp251xfd_get_ring_tail(rx) &&
|
||||
mcp251xfd_get_ring_tail(rx) == n ?
|
||||
(priv->rx->head == priv->rx->tail ? " priv-FIFO-empty" : " priv-FIFO-full") :
|
||||
("")));
|
||||
pr_info("%16s = 0x%08x\n", "id", hw_rx_obj->id);
|
||||
pr_info("%16s = 0x%08x\n", "flags", hw_rx_obj->flags);
|
||||
pr_info("%16s = 0x%08x\n", "ts", hw_rx_obj->ts);
|
||||
mcp251xfd_dump_ram_fifo_obj_data(priv, hw_rx_obj->data, FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC, hw_rx_obj->flags));
|
||||
pr_info("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
mcp251xfd_dump_ram_rx_obj(const struct mcp251xfd_priv *priv,
|
||||
const struct mcp251xfd_dump_regs *regs,
|
||||
const struct mcp251xfd_dump_ram *ram,
|
||||
const struct mcp251xfd_ring *rx)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("\nRX Overview:\n");
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "head (c/p)",
|
||||
mcp251xfd_dump_get_rx_head(priv, regs),
|
||||
mcp251xfd_get_ring_head(rx), rx->head);
|
||||
pr_info("%16s = 0x%02x 0x%02x 0x%08x\n", "tail (c/p)",
|
||||
mcp251xfd_dump_get_rx_tail(priv, regs),
|
||||
mcp251xfd_get_ring_tail(rx), rx->tail);
|
||||
pr_info("\n");
|
||||
|
||||
for (i = 0; i < mcp251xfd_dump_get_rx_obj_num(priv, regs); i++) {
|
||||
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj;
|
||||
u16 hw_rx_obj_rel_addr;
|
||||
|
||||
hw_rx_obj_rel_addr = mcp251xfd_dump_get_rx_obj_rel_addr(priv, regs, i);
|
||||
hw_rx_obj = (const struct mcp251xfd_hw_rx_obj_canfd *)&ram->ram[hw_rx_obj_rel_addr];
|
||||
|
||||
mcp251xfd_dump_ram_rx_obj_one(priv, regs, rx, hw_rx_obj, i);
|
||||
}
|
||||
}
|
||||
|
||||
#undef __dump_mask
|
||||
#undef __dump_bit
|
||||
|
||||
static void mcp251xfd_dump_ram(const struct mcp251xfd_priv *priv, const struct mcp251xfd_dump_regs *regs, const struct mcp251xfd_dump_ram *ram)
|
||||
{
|
||||
netdev_info(priv->ndev, "----------------------- RAM dump ----------------------\n");
|
||||
mcp251xfd_dump_ram_tef_obj(priv, regs, ram, priv->tef);
|
||||
mcp251xfd_dump_ram_tx_obj(priv, regs, ram, priv->tx);
|
||||
mcp251xfd_dump_ram_rx_obj(priv, regs, ram, priv->rx);
|
||||
netdev_info(priv->ndev, "------------------------- end -------------------------\n");
|
||||
}
|
||||
|
||||
void mcp251xfd_dump(struct mcp251xfd_priv *priv)
|
||||
{
|
||||
struct mcp251xfd_dump_regs regs;
|
||||
struct mcp251xfd_dump_ram ram;
|
||||
struct mcp251xfd_dump_regs_mcp251xfd regs_mcp251xfd;
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct mcp251xfd_dump_regs) !=
|
||||
MCP251XFD_REG_FIFOUA(31) - MCP251XFD_REG_CON + 4);
|
||||
|
||||
err = regmap_bulk_read(priv->map, MCP251XFD_REG_CON,
|
||||
®s, sizeof(regs) / sizeof(u32));
|
||||
if (err)
|
||||
return;
|
||||
|
||||
err = regmap_bulk_read(priv->map, MCP251XFD_RAM_START,
|
||||
&ram, sizeof(ram) / sizeof(u32));
|
||||
if (err)
|
||||
return;
|
||||
|
||||
err = regmap_bulk_read(priv->map, MCP251XFD_REG_OSC,
|
||||
®s_mcp251xfd, sizeof(regs_mcp251xfd) / sizeof(u32));
|
||||
if (err)
|
||||
return;
|
||||
|
||||
mcp251xfd_dump_regs(priv, ®s, ®s_mcp251xfd);
|
||||
mcp251xfd_dump_ram(priv, ®s, &ram);
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
*
|
||||
* Copyright (c) 2019, 2020, 2021 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_DUMP_H
|
||||
#define _MCP251XFD_DUMP_H
|
||||
|
||||
#define MCP251XFD_DUMP_MAGIC 0x1825434d
|
||||
|
||||
enum mcp251xfd_dump_object_type {
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_REG,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_TEF,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_RX,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_TX,
|
||||
MCP251XFD_DUMP_OBJECT_TYPE_END = -1,
|
||||
};
|
||||
|
||||
enum mcp251xfd_dump_object_ring_key {
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
|
||||
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
|
||||
__MCP251XFD_DUMP_OBJECT_RING_KEY_MAX,
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_object_header {
|
||||
__le32 magic;
|
||||
__le32 type;
|
||||
__le32 offset;
|
||||
__le32 len;
|
||||
};
|
||||
|
||||
struct mcp251xfd_dump_object_reg {
|
||||
__le32 reg;
|
||||
__le32 val;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020, 2021 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s - decode chip and driver state of mcp251xfd.\n"
|
||||
"\n"
|
||||
"Usage: %s [options] <file>\n"
|
||||
"\n"
|
||||
" <file> path to dev coredump file\n"
|
||||
" ('/var/log/devcoredump-19700101-234200.dump')\n"
|
||||
" path to regmap register file\n"
|
||||
" ('/sys/kernel/debug/regmap/spi1.0-crc/registers')\n"
|
||||
" shortcut to regmap register file\n"
|
||||
" ('spi0.0')\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help this help\n"
|
||||
"\n",
|
||||
prg, prg);
|
||||
}
|
||||
|
||||
int regmap_bulk_read(struct regmap *map, unsigned int reg,
|
||||
void *val, size_t val_count)
|
||||
{
|
||||
memcpy(val, map->mem->buf + reg,
|
||||
val_count * sizeof(uint32_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct mcp251xfd_mem mem = { };
|
||||
struct regmap map = {
|
||||
.mem = &mem,
|
||||
};
|
||||
struct mcp251xfd_priv priv = {
|
||||
.map = &map,
|
||||
};
|
||||
const char *file_path;
|
||||
int opt, err;
|
||||
|
||||
struct option long_options[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "ei:pq::rvh", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
file_path = argv[optind];
|
||||
|
||||
if (!file_path) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
err = mcp251xfd_dev_coredump_read(&priv, &mem, file_path);
|
||||
if (err)
|
||||
err = mcp251xfd_regmap_read(&priv, &mem, file_path);
|
||||
if (err) {
|
||||
fprintf(stderr, "Unable to read file: '%s'\n", file_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mcp251xfd_dump(&priv);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Microchip MCP251xFD Family CAN controller debug tool
|
||||
//
|
||||
// Copyright (c) 2020 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-dump-userspace.h"
|
||||
|
||||
static int
|
||||
do_mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path)
|
||||
{
|
||||
FILE *reg_file;
|
||||
uint16_t reg;
|
||||
uint32_t val;
|
||||
|
||||
reg_file = fopen(file_path, "r");
|
||||
if (!reg_file)
|
||||
return -errno;
|
||||
|
||||
while (fscanf(reg_file, "%hx: %x\n", ®, &val) == 2) {
|
||||
if (reg >= ARRAY_SIZE(mem->buf))
|
||||
return -EINVAL;
|
||||
|
||||
*(uint32_t *)(mem->buf + reg) = val;
|
||||
}
|
||||
|
||||
fclose(reg_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp251xfd_regmap_read(struct mcp251xfd_priv *priv,
|
||||
struct mcp251xfd_mem *mem,
|
||||
const char *file_path)
|
||||
{
|
||||
char *tmp;
|
||||
int err;
|
||||
|
||||
err = do_mcp251xfd_regmap_read(priv, mem, file_path);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
/* maybe it's something like "spi0.0" */
|
||||
tmp = strchr(file_path, '/');
|
||||
if (tmp)
|
||||
return -ENOENT;
|
||||
|
||||
/* first try literally */
|
||||
err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s/registers", file_path);
|
||||
if (err == -1)
|
||||
return -errno;
|
||||
|
||||
err = do_mcp251xfd_regmap_read(priv, mem, tmp);
|
||||
free (tmp);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
/* then add "-crc" */
|
||||
err = asprintf(&tmp, "/sys/kernel/debug/regmap/%s-crc/registers", file_path);
|
||||
if (err == -1)
|
||||
return -errno;
|
||||
|
||||
err = do_mcp251xfd_regmap_read(priv, mem, tmp);
|
||||
free (tmp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -0,0 +1,389 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
*
|
||||
* Copyright (c) 2019, 2020 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
* Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_H
|
||||
#define _MCP251XFD_H
|
||||
|
||||
/* MPC251x registers */
|
||||
|
||||
/* CAN FD Controller Module SFR */
|
||||
#define MCP251XFD_REG_CON 0x00
|
||||
#define MCP251XFD_REG_CON_TXBWS_MASK GENMASK(31, 28)
|
||||
#define MCP251XFD_REG_CON_ABAT BIT(27)
|
||||
#define MCP251XFD_REG_CON_REQOP_MASK GENMASK(26, 24)
|
||||
#define MCP251XFD_REG_CON_MODE_MIXED 0
|
||||
#define MCP251XFD_REG_CON_MODE_SLEEP 1
|
||||
#define MCP251XFD_REG_CON_MODE_INT_LOOPBACK 2
|
||||
#define MCP251XFD_REG_CON_MODE_LISTENONLY 3
|
||||
#define MCP251XFD_REG_CON_MODE_CONFIG 4
|
||||
#define MCP251XFD_REG_CON_MODE_EXT_LOOPBACK 5
|
||||
#define MCP251XFD_REG_CON_MODE_CAN2_0 6
|
||||
#define MCP251XFD_REG_CON_MODE_RESTRICTED 7
|
||||
#define MCP251XFD_REG_CON_OPMOD_MASK GENMASK(23, 21)
|
||||
#define MCP251XFD_REG_CON_TXQEN BIT(20)
|
||||
#define MCP251XFD_REG_CON_STEF BIT(19)
|
||||
#define MCP251XFD_REG_CON_SERR2LOM BIT(18)
|
||||
#define MCP251XFD_REG_CON_ESIGM BIT(17)
|
||||
#define MCP251XFD_REG_CON_RTXAT BIT(16)
|
||||
#define MCP251XFD_REG_CON_BRSDIS BIT(12)
|
||||
#define MCP251XFD_REG_CON_BUSY BIT(11)
|
||||
#define MCP251XFD_REG_CON_WFT_MASK GENMASK(10, 9)
|
||||
#define MCP251XFD_REG_CON_WFT_T00FILTER 0x0
|
||||
#define MCP251XFD_REG_CON_WFT_T01FILTER 0x1
|
||||
#define MCP251XFD_REG_CON_WFT_T10FILTER 0x2
|
||||
#define MCP251XFD_REG_CON_WFT_T11FILTER 0x3
|
||||
#define MCP251XFD_REG_CON_WAKFIL BIT(8)
|
||||
#define MCP251XFD_REG_CON_PXEDIS BIT(6)
|
||||
#define MCP251XFD_REG_CON_ISOCRCEN BIT(5)
|
||||
#define MCP251XFD_REG_CON_DNCNT_MASK GENMASK(4, 0)
|
||||
|
||||
#define MCP251XFD_REG_NBTCFG 0x04
|
||||
#define MCP251XFD_REG_NBTCFG_BRP_MASK GENMASK(31, 24)
|
||||
#define MCP251XFD_REG_NBTCFG_TSEG1_MASK GENMASK(23, 16)
|
||||
#define MCP251XFD_REG_NBTCFG_TSEG2_MASK GENMASK(14, 8)
|
||||
#define MCP251XFD_REG_NBTCFG_SJW_MASK GENMASK(6, 0)
|
||||
|
||||
#define MCP251XFD_REG_DBTCFG 0x08
|
||||
#define MCP251XFD_REG_DBTCFG_BRP_MASK GENMASK(31, 24)
|
||||
#define MCP251XFD_REG_DBTCFG_TSEG1_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_DBTCFG_TSEG2_MASK GENMASK(11, 8)
|
||||
#define MCP251XFD_REG_DBTCFG_SJW_MASK GENMASK(3, 0)
|
||||
|
||||
#define MCP251XFD_REG_TDC 0x0c
|
||||
#define MCP251XFD_REG_TDC_EDGFLTEN BIT(25)
|
||||
#define MCP251XFD_REG_TDC_SID11EN BIT(24)
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_MASK GENMASK(17, 16)
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_AUTO 2
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_MANUAL 1
|
||||
#define MCP251XFD_REG_TDC_TDCMOD_DISABLED 0
|
||||
#define MCP251XFD_REG_TDC_TDCO_MASK GENMASK(14, 8)
|
||||
#define MCP251XFD_REG_TDC_TDCV_MASK GENMASK(5, 0)
|
||||
|
||||
#define MCP251XFD_REG_TBC 0x10
|
||||
|
||||
#define MCP251XFD_REG_TSCON 0x14
|
||||
#define MCP251XFD_REG_TSCON_TSRES BIT(18)
|
||||
#define MCP251XFD_REG_TSCON_TSEOF BIT(17)
|
||||
#define MCP251XFD_REG_TSCON_TBCEN BIT(16)
|
||||
#define MCP251XFD_REG_TSCON_TBCPRE_MASK GENMASK(9, 0)
|
||||
|
||||
#define MCP251XFD_REG_VEC 0x18
|
||||
#define MCP251XFD_REG_VEC_RXCODE_MASK GENMASK(30, 24)
|
||||
#define MCP251XFD_REG_VEC_TXCODE_MASK GENMASK(22, 16)
|
||||
#define MCP251XFD_REG_VEC_FILHIT_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_VEC_ICODE_MASK GENMASK(6, 0)
|
||||
|
||||
#define MCP251XFD_REG_INT 0x1c
|
||||
#define MCP251XFD_REG_INT_IF_MASK GENMASK(15, 0)
|
||||
#define MCP251XFD_REG_INT_IE_MASK GENMASK(31, 16)
|
||||
#define MCP251XFD_REG_INT_IVMIE BIT(31)
|
||||
#define MCP251XFD_REG_INT_WAKIE BIT(30)
|
||||
#define MCP251XFD_REG_INT_CERRIE BIT(29)
|
||||
#define MCP251XFD_REG_INT_SERRIE BIT(28)
|
||||
#define MCP251XFD_REG_INT_RXOVIE BIT(27)
|
||||
#define MCP251XFD_REG_INT_TXATIE BIT(26)
|
||||
#define MCP251XFD_REG_INT_SPICRCIE BIT(25)
|
||||
#define MCP251XFD_REG_INT_ECCIE BIT(24)
|
||||
#define MCP251XFD_REG_INT_TEFIE BIT(20)
|
||||
#define MCP251XFD_REG_INT_MODIE BIT(19)
|
||||
#define MCP251XFD_REG_INT_TBCIE BIT(18)
|
||||
#define MCP251XFD_REG_INT_RXIE BIT(17)
|
||||
#define MCP251XFD_REG_INT_TXIE BIT(16)
|
||||
#define MCP251XFD_REG_INT_IVMIF BIT(15)
|
||||
#define MCP251XFD_REG_INT_WAKIF BIT(14)
|
||||
#define MCP251XFD_REG_INT_CERRIF BIT(13)
|
||||
#define MCP251XFD_REG_INT_SERRIF BIT(12)
|
||||
#define MCP251XFD_REG_INT_RXOVIF BIT(11)
|
||||
#define MCP251XFD_REG_INT_TXATIF BIT(10)
|
||||
#define MCP251XFD_REG_INT_SPICRCIF BIT(9)
|
||||
#define MCP251XFD_REG_INT_ECCIF BIT(8)
|
||||
#define MCP251XFD_REG_INT_TEFIF BIT(4)
|
||||
#define MCP251XFD_REG_INT_MODIF BIT(3)
|
||||
#define MCP251XFD_REG_INT_TBCIF BIT(2)
|
||||
#define MCP251XFD_REG_INT_RXIF BIT(1)
|
||||
#define MCP251XFD_REG_INT_TXIF BIT(0)
|
||||
/* These IRQ flags must be cleared by SW in the CAN_INT register */
|
||||
#define MCP251XFD_REG_INT_IF_CLEARABLE_MASK \
|
||||
(MCP251XFD_REG_INT_IVMIF | MCP251XFD_REG_INT_WAKIF | \
|
||||
MCP251XFD_REG_INT_CERRIF | MCP251XFD_REG_INT_SERRIF | \
|
||||
MCP251XFD_REG_INT_MODIF)
|
||||
|
||||
#define MCP251XFD_REG_RXIF 0x20
|
||||
#define MCP251XFD_REG_TXIF 0x24
|
||||
#define MCP251XFD_REG_RXOVIF 0x28
|
||||
#define MCP251XFD_REG_TXATIF 0x2c
|
||||
#define MCP251XFD_REG_TXREQ 0x30
|
||||
|
||||
#define MCP251XFD_REG_TREC 0x34
|
||||
#define MCP251XFD_REG_TREC_TXBO BIT(21)
|
||||
#define MCP251XFD_REG_TREC_TXBP BIT(20)
|
||||
#define MCP251XFD_REG_TREC_RXBP BIT(19)
|
||||
#define MCP251XFD_REG_TREC_TXWARN BIT(18)
|
||||
#define MCP251XFD_REG_TREC_RXWARN BIT(17)
|
||||
#define MCP251XFD_REG_TREC_EWARN BIT(16)
|
||||
#define MCP251XFD_REG_TREC_TEC_MASK GENMASK(15, 8)
|
||||
#define MCP251XFD_REG_TREC_REC_MASK GENMASK(7, 0)
|
||||
|
||||
#define MCP251XFD_REG_BDIAG0 0x38
|
||||
#define MCP251XFD_REG_BDIAG0_DTERRCNT_MASK GENMASK(31, 24)
|
||||
#define MCP251XFD_REG_BDIAG0_DRERRCNT_MASK GENMASK(23, 16)
|
||||
#define MCP251XFD_REG_BDIAG0_NTERRCNT_MASK GENMASK(15, 8)
|
||||
#define MCP251XFD_REG_BDIAG0_NRERRCNT_MASK GENMASK(7, 0)
|
||||
|
||||
#define MCP251XFD_REG_BDIAG1 0x3c
|
||||
#define MCP251XFD_REG_BDIAG1_DLCMM BIT(31)
|
||||
#define MCP251XFD_REG_BDIAG1_ESI BIT(30)
|
||||
#define MCP251XFD_REG_BDIAG1_DCRCERR BIT(29)
|
||||
#define MCP251XFD_REG_BDIAG1_DSTUFERR BIT(28)
|
||||
#define MCP251XFD_REG_BDIAG1_DFORMERR BIT(27)
|
||||
#define MCP251XFD_REG_BDIAG1_DBIT1ERR BIT(25)
|
||||
#define MCP251XFD_REG_BDIAG1_DBIT0ERR BIT(24)
|
||||
#define MCP251XFD_REG_BDIAG1_TXBOERR BIT(23)
|
||||
#define MCP251XFD_REG_BDIAG1_NCRCERR BIT(21)
|
||||
#define MCP251XFD_REG_BDIAG1_NSTUFERR BIT(20)
|
||||
#define MCP251XFD_REG_BDIAG1_NFORMERR BIT(19)
|
||||
#define MCP251XFD_REG_BDIAG1_NACKERR BIT(18)
|
||||
#define MCP251XFD_REG_BDIAG1_NBIT1ERR BIT(17)
|
||||
#define MCP251XFD_REG_BDIAG1_NBIT0ERR BIT(16)
|
||||
#define MCP251XFD_REG_BDIAG1_BERR_MASK \
|
||||
(MCP251XFD_REG_BDIAG1_DLCMM | MCP251XFD_REG_BDIAG1_ESI | \
|
||||
MCP251XFD_REG_BDIAG1_DCRCERR | MCP251XFD_REG_BDIAG1_DSTUFERR | \
|
||||
MCP251XFD_REG_BDIAG1_DFORMERR | MCP251XFD_REG_BDIAG1_DBIT1ERR | \
|
||||
MCP251XFD_REG_BDIAG1_DBIT0ERR | MCP251XFD_REG_BDIAG1_TXBOERR | \
|
||||
MCP251XFD_REG_BDIAG1_NCRCERR | MCP251XFD_REG_BDIAG1_NSTUFERR | \
|
||||
MCP251XFD_REG_BDIAG1_NFORMERR | MCP251XFD_REG_BDIAG1_NACKERR | \
|
||||
MCP251XFD_REG_BDIAG1_NBIT1ERR | MCP251XFD_REG_BDIAG1_NBIT0ERR)
|
||||
#define MCP251XFD_REG_BDIAG1_EFMSGCNT_MASK GENMASK(15, 0)
|
||||
|
||||
#define MCP251XFD_REG_TEFCON 0x40
|
||||
#define MCP251XFD_REG_TEFCON_FSIZE_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_TEFCON_FRESET BIT(10)
|
||||
#define MCP251XFD_REG_TEFCON_UINC BIT(8)
|
||||
#define MCP251XFD_REG_TEFCON_TEFTSEN BIT(5)
|
||||
#define MCP251XFD_REG_TEFCON_TEFOVIE BIT(3)
|
||||
#define MCP251XFD_REG_TEFCON_TEFFIE BIT(2)
|
||||
#define MCP251XFD_REG_TEFCON_TEFHIE BIT(1)
|
||||
#define MCP251XFD_REG_TEFCON_TEFNEIE BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TEFSTA 0x44
|
||||
#define MCP251XFD_REG_TEFSTA_TEFOVIF BIT(3)
|
||||
#define MCP251XFD_REG_TEFSTA_TEFFIF BIT(2)
|
||||
#define MCP251XFD_REG_TEFSTA_TEFHIF BIT(1)
|
||||
#define MCP251XFD_REG_TEFSTA_TEFNEIF BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TEFUA 0x48
|
||||
|
||||
#define MCP251XFD_REG_TXQCON 0x50
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_MASK GENMASK(31, 29)
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_8 0
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_12 1
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_16 2
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_20 3
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_24 4
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_32 5
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_48 6
|
||||
#define MCP251XFD_REG_TXQCON_PLSIZE_64 7
|
||||
#define MCP251XFD_REG_TXQCON_FSIZE_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_UNLIMITED 3
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_THREE_SHOT 1
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_ONE_SHOT 0
|
||||
#define MCP251XFD_REG_TXQCON_TXAT_MASK GENMASK(22, 21)
|
||||
#define MCP251XFD_REG_TXQCON_TXPRI_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_TXQCON_FRESET BIT(10)
|
||||
#define MCP251XFD_REG_TXQCON_TXREQ BIT(9)
|
||||
#define MCP251XFD_REG_TXQCON_UINC BIT(8)
|
||||
#define MCP251XFD_REG_TXQCON_TXEN BIT(7)
|
||||
#define MCP251XFD_REG_TXQCON_TXATIE BIT(4)
|
||||
#define MCP251XFD_REG_TXQCON_TXQEIE BIT(2)
|
||||
#define MCP251XFD_REG_TXQCON_TXQNIE BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TXQSTA 0x54
|
||||
#define MCP251XFD_REG_TXQSTA_TXQCI_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_TXQSTA_TXABT BIT(7)
|
||||
#define MCP251XFD_REG_TXQSTA_TXLARB BIT(6)
|
||||
#define MCP251XFD_REG_TXQSTA_TXERR BIT(5)
|
||||
#define MCP251XFD_REG_TXQSTA_TXATIF BIT(4)
|
||||
#define MCP251XFD_REG_TXQSTA_TXQEIF BIT(2)
|
||||
#define MCP251XFD_REG_TXQSTA_TXQNIF BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_TXQUA 0x58
|
||||
|
||||
#define MCP251XFD_REG_FIFOCON(x) (0x50 + 0xc * (x))
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_MASK GENMASK(31, 29)
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_8 0
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_12 1
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_16 2
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_20 3
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_24 4
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_32 5
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_48 6
|
||||
#define MCP251XFD_REG_FIFOCON_PLSIZE_64 7
|
||||
#define MCP251XFD_REG_FIFOCON_FSIZE_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_MASK GENMASK(22, 21)
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_ONE_SHOT 0
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_THREE_SHOT 1
|
||||
#define MCP251XFD_REG_FIFOCON_TXAT_UNLIMITED 3
|
||||
#define MCP251XFD_REG_FIFOCON_TXPRI_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_FIFOCON_FRESET BIT(10)
|
||||
#define MCP251XFD_REG_FIFOCON_TXREQ BIT(9)
|
||||
#define MCP251XFD_REG_FIFOCON_UINC BIT(8)
|
||||
#define MCP251XFD_REG_FIFOCON_TXEN BIT(7)
|
||||
#define MCP251XFD_REG_FIFOCON_RTREN BIT(6)
|
||||
#define MCP251XFD_REG_FIFOCON_RXTSEN BIT(5)
|
||||
#define MCP251XFD_REG_FIFOCON_TXATIE BIT(4)
|
||||
#define MCP251XFD_REG_FIFOCON_RXOVIE BIT(3)
|
||||
#define MCP251XFD_REG_FIFOCON_TFERFFIE BIT(2)
|
||||
#define MCP251XFD_REG_FIFOCON_TFHRFHIE BIT(1)
|
||||
#define MCP251XFD_REG_FIFOCON_TFNRFNIE BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_FIFOSTA(x) (0x54 + 0xc * (x))
|
||||
#define MCP251XFD_REG_FIFOSTA_FIFOCI_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXABT BIT(7)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXLARB BIT(6)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXERR BIT(5)
|
||||
#define MCP251XFD_REG_FIFOSTA_TXATIF BIT(4)
|
||||
#define MCP251XFD_REG_FIFOSTA_RXOVIF BIT(3)
|
||||
#define MCP251XFD_REG_FIFOSTA_TFERFFIF BIT(2)
|
||||
#define MCP251XFD_REG_FIFOSTA_TFHRFHIF BIT(1)
|
||||
#define MCP251XFD_REG_FIFOSTA_TFNRFNIF BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_FIFOUA(x) (0x58 + 0xc * (x))
|
||||
|
||||
#define MCP251XFD_REG_FLTCON(x) (0x1d0 + 0x4 * (x))
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN3 BIT(31)
|
||||
#define MCP251XFD_REG_FLTCON_F3BP_MASK GENMASK(28, 24)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN2 BIT(23)
|
||||
#define MCP251XFD_REG_FLTCON_F2BP_MASK GENMASK(20, 16)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN1 BIT(15)
|
||||
#define MCP251XFD_REG_FLTCON_F1BP_MASK GENMASK(12, 8)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN0 BIT(7)
|
||||
#define MCP251XFD_REG_FLTCON_F0BP_MASK GENMASK(4, 0)
|
||||
#define MCP251XFD_REG_FLTCON_FLTEN(x) (BIT(7) << 8 * ((x) & 0x3))
|
||||
#define MCP251XFD_REG_FLTCON_FLT_MASK(x) (GENMASK(7, 0) << (8 * ((x) & 0x3)))
|
||||
#define MCP251XFD_REG_FLTCON_FBP(x, fifo) ((fifo) << 8 * ((x) & 0x3))
|
||||
|
||||
#define MCP251XFD_REG_FLTOBJ(x) (0x1f0 + 0x8 * (x))
|
||||
#define MCP251XFD_REG_FLTOBJ_EXIDE BIT(30)
|
||||
#define MCP251XFD_REG_FLTOBJ_SID11 BIT(29)
|
||||
#define MCP251XFD_REG_FLTOBJ_EID_MASK GENMASK(28, 11)
|
||||
#define MCP251XFD_REG_FLTOBJ_SID_MASK GENMASK(10, 0)
|
||||
|
||||
#define MCP251XFD_REG_FLTMASK(x) (0x1f4 + 0x8 * (x))
|
||||
#define MCP251XFD_REG_MASK_MIDE BIT(30)
|
||||
#define MCP251XFD_REG_MASK_MSID11 BIT(29)
|
||||
#define MCP251XFD_REG_MASK_MEID_MASK GENMASK(28, 11)
|
||||
#define MCP251XFD_REG_MASK_MSID_MASK GENMASK(10, 0)
|
||||
|
||||
/* RAM */
|
||||
#define MCP251XFD_RAM_START 0x400
|
||||
#define MCP251XFD_RAM_SIZE SZ_2K
|
||||
|
||||
/* Message Object */
|
||||
#define MCP251XFD_OBJ_ID_SID11 BIT(29)
|
||||
#define MCP251XFD_OBJ_ID_EID_MASK GENMASK(28, 11)
|
||||
#define MCP251XFD_OBJ_ID_SID_MASK GENMASK(10, 0)
|
||||
#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK GENMASK(31, 9)
|
||||
#define MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK GENMASK(15, 9)
|
||||
#define MCP251XFD_OBJ_FLAGS_SEQ_MASK MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK
|
||||
#define MCP251XFD_OBJ_FLAGS_ESI BIT(8)
|
||||
#define MCP251XFD_OBJ_FLAGS_FDF BIT(7)
|
||||
#define MCP251XFD_OBJ_FLAGS_BRS BIT(6)
|
||||
#define MCP251XFD_OBJ_FLAGS_RTR BIT(5)
|
||||
#define MCP251XFD_OBJ_FLAGS_IDE BIT(4)
|
||||
#define MCP251XFD_OBJ_FLAGS_DLC GENMASK(3, 0)
|
||||
|
||||
#define MCP251XFD_REG_FRAME_EFF_SID_MASK GENMASK(28, 18)
|
||||
#define MCP251XFD_REG_FRAME_EFF_EID_MASK GENMASK(17, 0)
|
||||
|
||||
/* MCP2517/18FD SFR */
|
||||
#define MCP251XFD_REG_OSC 0xe00
|
||||
#define MCP251XFD_REG_OSC_SCLKRDY BIT(12)
|
||||
#define MCP251XFD_REG_OSC_OSCRDY BIT(10)
|
||||
#define MCP251XFD_REG_OSC_PLLRDY BIT(8)
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_10 3
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_4 2
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_2 1
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_1 0
|
||||
#define MCP251XFD_REG_OSC_CLKODIV_MASK GENMASK(6, 5)
|
||||
#define MCP251XFD_REG_OSC_SCLKDIV BIT(4)
|
||||
#define MCP251XFD_REG_OSC_LPMEN BIT(3) /* MCP2518FD only */
|
||||
#define MCP251XFD_REG_OSC_OSCDIS BIT(2)
|
||||
#define MCP251XFD_REG_OSC_PLLEN BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_IOCON 0xe04
|
||||
#define MCP251XFD_REG_IOCON_INTOD BIT(30)
|
||||
#define MCP251XFD_REG_IOCON_SOF BIT(29)
|
||||
#define MCP251XFD_REG_IOCON_TXCANOD BIT(28)
|
||||
#define MCP251XFD_REG_IOCON_PM1 BIT(25)
|
||||
#define MCP251XFD_REG_IOCON_PM0 BIT(24)
|
||||
#define MCP251XFD_REG_IOCON_GPIO1 BIT(17)
|
||||
#define MCP251XFD_REG_IOCON_GPIO0 BIT(16)
|
||||
#define MCP251XFD_REG_IOCON_LAT1 BIT(9)
|
||||
#define MCP251XFD_REG_IOCON_LAT0 BIT(8)
|
||||
#define MCP251XFD_REG_IOCON_XSTBYEN BIT(6)
|
||||
#define MCP251XFD_REG_IOCON_TRIS1 BIT(1)
|
||||
#define MCP251XFD_REG_IOCON_TRIS0 BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_CRC 0xe08
|
||||
#define MCP251XFD_REG_CRC_FERRIE BIT(25)
|
||||
#define MCP251XFD_REG_CRC_CRCERRIE BIT(24)
|
||||
#define MCP251XFD_REG_CRC_FERRIF BIT(17)
|
||||
#define MCP251XFD_REG_CRC_CRCERRIF BIT(16)
|
||||
#define MCP251XFD_REG_CRC_IF_MASK GENMASK(17, 16)
|
||||
#define MCP251XFD_REG_CRC_MASK GENMASK(15, 0)
|
||||
|
||||
#define MCP251XFD_REG_ECCCON 0xe0c
|
||||
#define MCP251XFD_REG_ECCCON_PARITY_MASK GENMASK(14, 8)
|
||||
#define MCP251XFD_REG_ECCCON_DEDIE BIT(2)
|
||||
#define MCP251XFD_REG_ECCCON_SECIE BIT(1)
|
||||
#define MCP251XFD_REG_ECCCON_ECCEN BIT(0)
|
||||
|
||||
#define MCP251XFD_REG_ECCSTAT 0xe10
|
||||
#define MCP251XFD_REG_ECCSTAT_ERRADDR_MASK GENMASK(27, 16)
|
||||
#define MCP251XFD_REG_ECCSTAT_IF_MASK GENMASK(2, 1)
|
||||
#define MCP251XFD_REG_ECCSTAT_DEDIF BIT(2)
|
||||
#define MCP251XFD_REG_ECCSTAT_SECIF BIT(1)
|
||||
|
||||
#define MCP251XFD_REG_DEVID 0xe14 /* MCP2518FD only */
|
||||
#define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4)
|
||||
#define MCP251XFD_REG_DEVID_REV_MASK GENMASK(3, 0)
|
||||
|
||||
struct mcp251xfd_hw_tef_obj {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u32 ts;
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_tx_obj_can {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u8 data[sizeof_field(struct can_frame, data)];
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_tx_obj_canfd {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u8 data[sizeof_field(struct canfd_frame, data)];
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_rx_obj_can {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u32 ts;
|
||||
u8 data[sizeof_field(struct can_frame, data)];
|
||||
};
|
||||
|
||||
struct mcp251xfd_hw_rx_obj_canfd {
|
||||
u32 id;
|
||||
u32 flags;
|
||||
u32 ts;
|
||||
u8 data[sizeof_field(struct canfd_frame, data)];
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue