1618 lines
37 KiB
C
1618 lines
37 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
|
|
*
|
|
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
|
|
* Copyright (C) 2016, 2021, 2022 Marc Kleine-Budde <mkl@pengutronix.de>
|
|
*
|
|
* Derived from:
|
|
* can_baud.c - CAN baudrate calculation
|
|
* Code based on LinCAN sources and H8S2638 project
|
|
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
|
* Copyright 2005 Stanislav Marek
|
|
* email:pisa@cmp.felk.cvut.cz
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the version 2 of the GNU General Public License
|
|
* as published by the Free Software Foundation
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <libgen.h>
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "compat.h"
|
|
|
|
enum {
|
|
OPT_TQ = UCHAR_MAX + 1,
|
|
OPT_PROP_SEG,
|
|
OPT_PHASE_SEG1,
|
|
OPT_PHASE_SEG2,
|
|
OPT_SJW,
|
|
OPT_BRP,
|
|
OPT_TSEG1,
|
|
OPT_TSEG2,
|
|
OPT_ALG,
|
|
};
|
|
|
|
struct calc_bittiming_const {
|
|
const struct can_bittiming_const bittiming_const;
|
|
const struct can_bittiming_const data_bittiming_const;
|
|
|
|
const struct calc_ref_clk ref_clk[16];
|
|
|
|
void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
|
void (*printf_data_btr)(struct can_bittiming *bt, bool hdr);
|
|
};
|
|
|
|
struct alg {
|
|
union {
|
|
int (*calc_bittiming)(struct net_device *dev, struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc);
|
|
int (*calc_bittiming_const)(const struct net_device *dev, struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc);
|
|
int (*calc_bittiming_extack)(const struct net_device *dev, struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc, struct netlink_ext_ack *extack);
|
|
};
|
|
union {
|
|
int (*fixup_bittiming)(struct net_device *dev, struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc);
|
|
int (*fixup_bittiming_const)(const struct net_device *dev, struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc);
|
|
int (*fixup_bittiming_extack)(const struct net_device *dev, struct can_bittiming *bt,
|
|
const struct can_bittiming_const *btc,
|
|
struct netlink_ext_ack *extack);
|
|
|
|
};
|
|
const char *name;
|
|
};
|
|
|
|
struct calc_data {
|
|
const struct can_bittiming_const *bittiming_const;
|
|
const struct alg *alg;
|
|
void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
|
const char *name;
|
|
|
|
const struct calc_ref_clk *ref_clks;
|
|
const unsigned int *bitrates;
|
|
|
|
unsigned int sample_point;
|
|
|
|
const struct calc_ref_clk *opt_ref_clk;
|
|
const unsigned int *opt_bitrates;
|
|
const unsigned int *opt_data_bitrates;
|
|
const struct can_bittiming *opt_bt;
|
|
|
|
bool quiet;
|
|
bool verbose;
|
|
bool fd_mode;
|
|
};
|
|
|
|
static void print_usage(char *cmd)
|
|
{
|
|
printf("%s - calculate CAN bit timing parameters.\n", cmd);
|
|
printf("Usage: %s [options] [<CAN-contoller-name>]\n"
|
|
"Options:\n"
|
|
"\t-q don't print header line\n"
|
|
"\t-v verbose output, print bit timing const\n"
|
|
"\t-l list all support CAN controller names\n"
|
|
"\t-b <bitrate> arbitration bit-rate in bits/sec\n"
|
|
"\t-d <bitrate> data bit-rate in bits/sec\n"
|
|
"\t-s <samp_pt> sample-point in one-tenth of a percent\n"
|
|
"\t or 0 for CIA recommended sample points\n"
|
|
"\t-c <clock> real CAN system clock in Hz\n"
|
|
"\t--alg <alg> choose specified algorithm for bit-timing calculation\n"
|
|
"\n"
|
|
"Or supply low level bit timing parameters to decode them:\n"
|
|
"\n"
|
|
"\t--tq Time quantum in ns\n"
|
|
"\t--prop-seg Propagation segment in TQs\n"
|
|
"\t--phase-seg1 Phase buffer segment 1 in TQs\n"
|
|
"\t--phase-seg2 Phase buffer segment 2 in TQs\n"
|
|
"\t--sjw Synchronisation jump width in TQs\n"
|
|
"\t--brp Bit-rate prescaler\n"
|
|
"\t--tseg1 Time segment 1 = prop-seg + phase-seg1\n"
|
|
"\t--tseg2 Time segment 2 = phase_seg2\n",
|
|
cmd);
|
|
}
|
|
|
|
static void printf_btr_nop(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
}
|
|
|
|
#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20)
|
|
#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8)
|
|
#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4)
|
|
#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07)
|
|
|
|
static void printf_btr_rcar_can(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "CiBCR");
|
|
} else {
|
|
uint32_t bcr;
|
|
|
|
bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
|
|
RCAR_CAN_BCR_BPR(bt->brp - 1) |
|
|
RCAR_CAN_BCR_SJW(bt->sjw - 1) |
|
|
RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1);
|
|
|
|
printf("0x%08x", bcr << 8);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_mcp251x(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
uint8_t cnf1, cnf2, cnf3;
|
|
|
|
if (hdr) {
|
|
printf("CNF1 CNF2 CNF3");
|
|
} else {
|
|
cnf1 = ((bt->sjw - 1) << 6) | (bt->brp - 1);
|
|
cnf2 = 0x80 | ((bt->phase_seg1 - 1) << 3) | (bt->prop_seg - 1);
|
|
cnf3 = bt->phase_seg2 - 1;
|
|
printf("0x%02x 0x%02x 0x%02x", cnf1, cnf2, cnf3);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_mcp251xfd(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "NBTCFG");
|
|
} else {
|
|
uint32_t nbtcfg = ((bt->brp - 1) << 24) |
|
|
((bt->prop_seg + bt->phase_seg1 - 1) << 16) |
|
|
((bt->phase_seg2 - 1) << 8) |
|
|
(bt->sjw - 1);
|
|
printf("0x%08x", nbtcfg);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_bxcan(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "CAN_BTR");
|
|
} else {
|
|
uint32_t btr;
|
|
|
|
btr = (((bt->brp -1) & 0x3ff) << 0) |
|
|
(((bt->prop_seg + bt->phase_seg1 -1) & 0xf) << 16) |
|
|
(((bt->phase_seg2 -1) & 0x7) << 20) |
|
|
(((bt->sjw -1) & 0x3) << 24);
|
|
|
|
printf("0x%08x", btr);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_at91(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "CAN_BR");
|
|
} else {
|
|
uint32_t br = ((bt->phase_seg2 - 1) |
|
|
((bt->phase_seg1 - 1) << 4) |
|
|
((bt->prop_seg - 1) << 8) |
|
|
((bt->sjw - 1) << 12) |
|
|
((bt->brp - 1) << 16));
|
|
printf("0x%08x", br);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_c_can(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%13s", "BTR BRPEXT");
|
|
} else {
|
|
uint32_t btr;
|
|
uint32_t brpext;
|
|
|
|
btr = (((bt->brp -1) & 0x3f) << 0) |
|
|
(((bt->sjw -1) & 0x3) << 6) |
|
|
(((bt->prop_seg + bt->phase_seg1 -1) & 0xf) << 8) |
|
|
(((bt->phase_seg2 -1) & 0x7) << 12);
|
|
brpext = ((bt->brp -1) >> 6) & 0xf;
|
|
|
|
printf("0x%04x 0x%04x", btr, brpext);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_flexcan(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "CAN_CTRL");
|
|
} else {
|
|
uint32_t ctrl = (((bt->brp - 1) << 24) |
|
|
((bt->sjw - 1) << 22) |
|
|
((bt->phase_seg1 - 1) << 19) |
|
|
((bt->phase_seg2 - 1) << 16) |
|
|
((bt->prop_seg - 1) << 0));
|
|
|
|
printf("0x%08x", ctrl);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_mcan(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "NBTP");
|
|
} else {
|
|
uint32_t nbtp;
|
|
|
|
|
|
nbtp = (((bt->brp -1) & 0x1ff) << 16) |
|
|
(((bt->sjw -1) & 0x7f) << 25) |
|
|
(((bt->prop_seg + bt->phase_seg1 -1) & 0xff) << 8) |
|
|
(((bt->phase_seg2 -1) & 0x7f) << 0);
|
|
|
|
printf("0x%08x", nbtp);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
uint8_t btr0, btr1;
|
|
|
|
if (hdr) {
|
|
printf("%9s", "BTR0 BTR1");
|
|
} else {
|
|
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
|
|
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
|
|
(((bt->phase_seg2 - 1) & 0x7) << 4);
|
|
printf("0x%02x 0x%02x", btr0, btr1);
|
|
}
|
|
}
|
|
|
|
static void printf_btr_ti_hecc(struct can_bittiming *bt, bool hdr)
|
|
{
|
|
if (hdr) {
|
|
printf("%10s", "CANBTC");
|
|
} else {
|
|
uint32_t can_btc;
|
|
|
|
can_btc = (bt->phase_seg2 - 1) & 0x7;
|
|
can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1)
|
|
& 0xF) << 3;
|
|
can_btc |= ((bt->sjw - 1) & 0x3) << 8;
|
|
can_btc |= ((bt->brp - 1) & 0xFF) << 16;
|
|
|
|
printf("0x%08x", can_btc);
|
|
}
|
|
}
|
|
|
|
static const struct calc_bittiming_const can_calc_consts[] = {
|
|
{
|
|
.bittiming_const = {
|
|
.name = "rcar_can",
|
|
.tseg1_min = 4,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 65000000, },
|
|
},
|
|
.printf_btr = printf_btr_rcar_can,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "rcar_canfd",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 128,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 32,
|
|
.sjw_max = 32,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "rcar_canfd",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 8,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "rcar_canfd (CC)",
|
|
.tseg1_min = 4,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "rockchip_canfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 256,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 128,
|
|
.sjw_max = 128,
|
|
.brp_min = 2,
|
|
.brp_max = 256,
|
|
.brp_inc = 2,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "rockchip_canfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 32,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 16,
|
|
.sjw_max = 16,
|
|
.brp_min = 2,
|
|
.brp_max = 256,
|
|
.brp_inc = 2,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
{ .clk = 300000000, .name = "rock-3a" },
|
|
},
|
|
}, { /* -------- SPI -------- */
|
|
.bittiming_const = {
|
|
.name = "hi311x",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 24000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "mcp251x",
|
|
.tseg1_min = 3,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
/* The mcp251x uses half of the external OSC clock as the base clock */
|
|
{ .clk = 8000000 / 2, .name = "8 MHz OSC" },
|
|
{ .clk = 12000000 / 2, .name = "12 MHz OSC" },
|
|
{ .clk = 16000000 / 2, .name = "16 MHz OSC" },
|
|
{ .clk = 20000000 / 2, .name = "20 MHz OSC" },
|
|
},
|
|
.printf_btr = printf_btr_mcp251x,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "mcp251xfd",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 256,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 128,
|
|
.sjw_max = 128,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "mcp251xfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 32,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 16,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
.printf_btr = printf_btr_mcp251xfd,
|
|
}, { /* -------- USB -------- */
|
|
.bittiming_const = {
|
|
.name = "usb_8dev",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 32000000, },
|
|
}
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "ems_usb",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 8000000, },
|
|
},
|
|
}, {
|
|
|
|
#define ESD_USB2_TSEG1_MIN 1
|
|
#define ESD_USB2_TSEG1_MAX 16
|
|
#define ESD_USB2_TSEG2_MIN 1
|
|
#define ESD_USB2_TSEG2_MAX 8
|
|
#define ESD_USB2_SJW_MAX 4
|
|
#define ESD_USB2_BRP_MIN 1
|
|
#define ESD_USB2_BRP_MAX 1024
|
|
#define ESD_USB2_BRP_INC 1
|
|
|
|
#define ESD_USB2_CAN_CLOCK 60000000
|
|
#define ESD_USBM_CAN_CLOCK 36000000
|
|
|
|
.bittiming_const = {
|
|
.name = "esd_usb2",
|
|
.tseg1_min = ESD_USB2_TSEG1_MIN,
|
|
.tseg1_max = ESD_USB2_TSEG1_MAX,
|
|
.tseg2_min = ESD_USB2_TSEG2_MIN,
|
|
.tseg2_max = ESD_USB2_TSEG2_MAX,
|
|
.sjw_max = ESD_USB2_SJW_MAX,
|
|
.brp_min = ESD_USB2_BRP_MIN,
|
|
.brp_max = ESD_USB2_BRP_MAX,
|
|
.brp_inc = ESD_USB2_BRP_INC,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = ESD_USB2_CAN_CLOCK, .name = "CAN-USB/2", },
|
|
{ .clk = ESD_USBM_CAN_CLOCK, .name = "CAN-USB/Micro", },
|
|
},
|
|
}, { /* gs_usb */
|
|
.bittiming_const = {
|
|
.name = "bxcan", // stm32f072
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 48000000, },
|
|
},
|
|
.printf_btr = printf_btr_bxcan,
|
|
}, { /* gs_usb */
|
|
.bittiming_const = {
|
|
.name = "CANtact Pro", // LPC65616
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "CANtact Pro", // LPC65616
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 24000000, .name = "CANtact Pro (original)", },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
}, {
|
|
|
|
#define KVASER_USB_TSEG1_MIN 1
|
|
#define KVASER_USB_TSEG1_MAX 16
|
|
#define KVASER_USB_TSEG2_MIN 1
|
|
#define KVASER_USB_TSEG2_MAX 8
|
|
#define KVASER_USB_SJW_MAX 4
|
|
#define KVASER_USB_BRP_MIN 1
|
|
#define KVASER_USB_BRP_MAX 64
|
|
#define KVASER_USB_BRP_INC 1
|
|
|
|
.bittiming_const = {
|
|
.name = "kvaser_usb",
|
|
.tseg1_min = KVASER_USB_TSEG1_MIN,
|
|
.tseg1_max = KVASER_USB_TSEG1_MAX,
|
|
.tseg2_min = KVASER_USB_TSEG2_MIN,
|
|
.tseg2_max = KVASER_USB_TSEG2_MAX,
|
|
.sjw_max = KVASER_USB_SJW_MAX,
|
|
.brp_min = KVASER_USB_BRP_MIN,
|
|
.brp_max = KVASER_USB_BRP_MAX,
|
|
.brp_inc = KVASER_USB_BRP_INC,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 8000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "kvaser_usb_kcan",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 255,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 32,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 8192,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "kvaser_usb_kcan",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 255,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 32,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 8192,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 80000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "kvaser_usb_flex",
|
|
.tseg1_min = 4,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 24000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "pcan_usb_pro",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 56000000, },
|
|
},
|
|
}, {
|
|
|
|
#define PUCAN_TSLOW_BRP_BITS 10
|
|
#define PUCAN_TSLOW_TSGEG1_BITS 8
|
|
#define PUCAN_TSLOW_TSGEG2_BITS 7
|
|
#define PUCAN_TSLOW_SJW_BITS 7
|
|
|
|
#define PUCAN_TFAST_BRP_BITS 10
|
|
#define PUCAN_TFAST_TSGEG1_BITS 5
|
|
#define PUCAN_TFAST_TSGEG2_BITS 4
|
|
#define PUCAN_TFAST_SJW_BITS 4
|
|
|
|
.bittiming_const = {
|
|
.name = "pcan_usb_fd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = (1 << PUCAN_TSLOW_TSGEG1_BITS),
|
|
.tseg2_min = 1,
|
|
.tseg2_max = (1 << PUCAN_TSLOW_TSGEG2_BITS),
|
|
.sjw_max = (1 << PUCAN_TSLOW_SJW_BITS),
|
|
.brp_min = 1,
|
|
.brp_max = (1 << PUCAN_TSLOW_BRP_BITS),
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "pcan_usb_fd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = (1 << PUCAN_TFAST_TSGEG1_BITS),
|
|
.tseg2_min = 1,
|
|
.tseg2_max = (1 << PUCAN_TFAST_TSGEG2_BITS),
|
|
.sjw_max = (1 << PUCAN_TFAST_SJW_BITS),
|
|
.brp_min = 1,
|
|
.brp_max = (1 << PUCAN_TFAST_BRP_BITS),
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 80000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "softing",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 32,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 8000000, },
|
|
{ .clk = 16000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "at91",
|
|
.tseg1_min = 4,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 2,
|
|
.brp_max = 128,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 66000000, .name = "sama5d3", },
|
|
{ .clk = 99532800, .name = "ronetix PM9263", },
|
|
{ .clk = 100000000, },
|
|
},
|
|
.printf_btr = printf_btr_at91,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "cc770",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 8000000 },
|
|
}
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "c_can",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 24000000, },
|
|
},
|
|
.printf_btr = printf_btr_c_can,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "flexcan",
|
|
.tseg1_min = 4,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 24000000, .name = "mx28" },
|
|
{ .clk = 30000000, .name = "mx6" },
|
|
{ .clk = 49875000, },
|
|
{ .clk = 66000000, },
|
|
{ .clk = 66500000, .name = "mx25" },
|
|
{ .clk = 66666666, },
|
|
{ .clk = 83368421, .name = "vybrid" },
|
|
},
|
|
.printf_btr = printf_btr_flexcan,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "flexcan-fd",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 96,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 32,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "flexcan-fd",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 39,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
}, {
|
|
|
|
#define GRCAN_CONF_PS1_MIN 1
|
|
#define GRCAN_CONF_PS1_MAX 15
|
|
#define GRCAN_CONF_PS2_MIN 2
|
|
#define GRCAN_CONF_PS2_MAX 8
|
|
#define GRCAN_CONF_RSJ_MAX 4
|
|
#define GRCAN_CONF_SCALER_MIN 0
|
|
#define GRCAN_CONF_SCALER_MAX 255
|
|
#define GRCAN_CONF_SCALER_INC 1
|
|
|
|
.bittiming_const = {
|
|
.name = "grcan",
|
|
.tseg1_min = GRCAN_CONF_PS1_MIN + 1,
|
|
.tseg1_max = GRCAN_CONF_PS1_MAX + 1,
|
|
.tseg2_min = GRCAN_CONF_PS2_MIN,
|
|
.tseg2_max = GRCAN_CONF_PS2_MAX,
|
|
.sjw_max = GRCAN_CONF_RSJ_MAX,
|
|
.brp_min = GRCAN_CONF_SCALER_MIN + 1,
|
|
.brp_max = GRCAN_CONF_SCALER_MAX + 1,
|
|
.brp_inc = GRCAN_CONF_SCALER_INC,
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "ifi_canfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 256,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 256,
|
|
.sjw_max = 128,
|
|
.brp_min = 2,
|
|
.brp_max = 512,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "ifi_canfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 256,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 256,
|
|
.sjw_max = 128,
|
|
.brp_min = 2,
|
|
.brp_max = 512,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "janz-ican3",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 8000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "kvaser_pciefd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 512,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 32,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 8192,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "kvaser_pciefd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 512,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 32,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 8192,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "mscan",
|
|
.tseg1_min = 4,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 32000000, },
|
|
{ .clk = 33000000, },
|
|
{ .clk = 33300000, },
|
|
{ .clk = 33333333, },
|
|
{ .clk = 66660000, .name = "mpc5121", },
|
|
{ .clk = 66666666, .name = "mpc5121" },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "mcan-v3.0",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 64,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 16,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 1024,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "mcan-v3.0",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 32,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
.printf_btr = printf_btr_mcan,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "mcan-v3.1+",
|
|
.tseg1_min = 2,
|
|
.tseg1_max = 256,
|
|
.tseg2_min = 2,
|
|
.tseg2_max = 128,
|
|
.sjw_max = 128,
|
|
.brp_min = 1,
|
|
.brp_max = 512,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "mcan-v3.1+",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 32,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 16,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 32,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
{ .clk = 24000000, .name = "stm32mp1 - ck_hse" },
|
|
{ .clk = 24573875, .name = "stm32mp1 - pll3_q" },
|
|
{ .clk = 29700000, .name = "stm32mp1 - pll4_q" },
|
|
{ .clk = 48000000, .name = "stm32mp1 lxatac (new)" },
|
|
{ .clk = 60000000, .name = "stm32mp1 ecu02.5- pll4_r" },
|
|
{ .clk = 62500000, .name = "stm32mp1 lxatac (old) - pll4_r" },
|
|
{ .clk = 74250000, .name = "stm32mp1 - pll4_r" },
|
|
},
|
|
.printf_btr = printf_btr_mcan,
|
|
}, {
|
|
|
|
#define PUCAN_TSLOW_BRP_BITS 10
|
|
#define PUCAN_TSLOW_TSGEG1_BITS 8
|
|
#define PUCAN_TSLOW_TSGEG2_BITS 7
|
|
#define PUCAN_TSLOW_SJW_BITS 7
|
|
|
|
#define PUCAN_TFAST_BRP_BITS 10
|
|
#define PUCAN_TFAST_TSGEG1_BITS 5
|
|
#define PUCAN_TFAST_TSGEG2_BITS 4
|
|
#define PUCAN_TFAST_SJW_BITS 4
|
|
|
|
.bittiming_const = {
|
|
.name = "peak_canfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = (1 << PUCAN_TSLOW_TSGEG1_BITS),
|
|
.tseg2_min = 1,
|
|
.tseg2_max = (1 << PUCAN_TSLOW_TSGEG2_BITS),
|
|
.sjw_max = (1 << PUCAN_TSLOW_SJW_BITS),
|
|
.brp_min = 1,
|
|
.brp_max = (1 << PUCAN_TSLOW_BRP_BITS),
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "peak_canfd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = (1 << PUCAN_TFAST_TSGEG1_BITS),
|
|
.tseg2_min = 1,
|
|
.tseg2_max = (1 << PUCAN_TFAST_TSGEG2_BITS),
|
|
.sjw_max = (1 << PUCAN_TFAST_SJW_BITS),
|
|
.brp_min = 1,
|
|
.brp_max = (1 << PUCAN_TFAST_BRP_BITS),
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, },
|
|
{ .clk = 24000000, },
|
|
{ .clk = 30000000, },
|
|
{ .clk = 40000000, },
|
|
{ .clk = 60000000, },
|
|
{ .clk = 80000000, },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "sja1000",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 16000000 / 2, },
|
|
{ .clk = 24000000 / 2, .name = "f81601" },
|
|
},
|
|
.printf_btr = printf_btr_sja1000,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "sun4i_can",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 64,
|
|
.brp_inc = 1,
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "ti_hecc",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 13000000, },
|
|
},
|
|
.printf_btr = printf_btr_ti_hecc,
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "xilinx_can",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "xilinx_can_fd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 64,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 16,
|
|
.sjw_max = 16,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "xilinx_can_fd",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 8,
|
|
.brp_min = 1,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
},
|
|
}, {
|
|
.bittiming_const = {
|
|
.name = "xilinx_can_fd2",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 256,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 128,
|
|
.sjw_max = 128,
|
|
.brp_min = 2,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.data_bittiming_const = {
|
|
.name = "xilinx_can_fd2",
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 32,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 16,
|
|
.sjw_max = 16,
|
|
.brp_min = 2,
|
|
.brp_max = 256,
|
|
.brp_inc = 1,
|
|
},
|
|
.ref_clk = {
|
|
{ .clk = 20000000, .name = "CIA recommendation" },
|
|
{ .clk = 40000000, .name = "CIA recommendation" },
|
|
{ .clk = 79999999, .name = "Versal ACAP" },
|
|
{ .clk = 80000000, .name = "Versal ACAP" },
|
|
},
|
|
},
|
|
};
|
|
|
|
static const unsigned int common_bitrates[] = {
|
|
1000000,
|
|
800000,
|
|
666666,
|
|
500000,
|
|
250000,
|
|
125000,
|
|
100000,
|
|
83333,
|
|
50000,
|
|
33333,
|
|
20000,
|
|
10000,
|
|
0
|
|
};
|
|
|
|
static const unsigned int common_data_bitrates[] = {
|
|
12000000,
|
|
10000000,
|
|
8000000,
|
|
5000000,
|
|
4000000,
|
|
2000000,
|
|
1000000,
|
|
0
|
|
};
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
|
|
#define can_update_spt can_update_spt_v2_6_31
|
|
#define can_calc_bittiming can_calc_bittiming_v2_6_31
|
|
#define can_fixup_bittiming can_fixup_bittiming_v2_6_31
|
|
#include "can-calc-bit-timing-v2_6_31.c"
|
|
#undef can_update_spt
|
|
#undef can_calc_bittiming
|
|
#undef can_fixup_bittiming
|
|
|
|
#define can_update_spt can_update_spt_v3_18
|
|
#define can_calc_bittiming can_calc_bittiming_v3_18
|
|
#define can_fixup_bittiming can_fixup_bittiming_v3_18
|
|
#include "can-calc-bit-timing-v3_18.c"
|
|
#undef can_update_spt
|
|
#undef can_calc_bittiming
|
|
#undef can_fixup_bittiming
|
|
|
|
#define can_update_sample_point can_update_sample_point_v4_8
|
|
#define can_calc_bittiming can_calc_bittiming_v4_8
|
|
#define can_fixup_bittiming can_fixup_bittiming_v4_8
|
|
#include "can-calc-bit-timing-v4_8.c"
|
|
#undef can_update_sample_point
|
|
#undef can_calc_bittiming
|
|
#undef can_fixup_bittiming
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#define can_update_sample_point can_update_sample_point_v5_16
|
|
#define can_calc_bittiming can_calc_bittiming_v5_16
|
|
#define can_fixup_bittiming can_fixup_bittiming_v5_16
|
|
#include "can-calc-bit-timing-v5_16.c"
|
|
#undef can_update_sample_point
|
|
#undef can_calc_bittiming
|
|
#undef can_fixup_bittiming
|
|
|
|
#define can_update_sample_point can_update_sample_point_v5_19
|
|
#define can_calc_bittiming can_calc_bittiming_v5_19
|
|
#define can_fixup_bittiming can_fixup_bittiming_v5_19
|
|
#include "can-calc-bit-timing-v5_19.c"
|
|
#undef can_update_sample_point
|
|
#undef can_calc_bittiming
|
|
#undef can_fixup_bittiming
|
|
|
|
#define can_update_sample_point can_update_sample_point_v6_3
|
|
#define can_calc_bittiming can_calc_bittiming_v6_3
|
|
#define can_fixup_bittiming can_fixup_bittiming_v6_3
|
|
#include "can-calc-bit-timing-v6_3.c"
|
|
#undef can_update_sample_point
|
|
#undef can_calc_bittiming
|
|
#undef can_fixup_bittiming
|
|
|
|
static const struct alg alg_list[] = {
|
|
/* 1st will be default */
|
|
{
|
|
.calc_bittiming_extack = can_calc_bittiming_v6_3,
|
|
.fixup_bittiming_extack = can_fixup_bittiming_v6_3,
|
|
.name = "v6.3",
|
|
}, {
|
|
.calc_bittiming_const = can_calc_bittiming_v5_19,
|
|
.fixup_bittiming_const = can_fixup_bittiming_v5_19,
|
|
.name = "v5.19",
|
|
}, {
|
|
.calc_bittiming = can_calc_bittiming_v5_16,
|
|
.fixup_bittiming = can_fixup_bittiming_v5_16,
|
|
.name = "v5.16",
|
|
}, {
|
|
.calc_bittiming = can_calc_bittiming_v4_8,
|
|
.fixup_bittiming = can_fixup_bittiming_v4_8,
|
|
.name = "v4.8",
|
|
}, {
|
|
.calc_bittiming = can_calc_bittiming_v3_18,
|
|
.fixup_bittiming = can_fixup_bittiming_v3_18,
|
|
.name = "v3.18",
|
|
}, {
|
|
.calc_bittiming = can_calc_bittiming_v2_6_31,
|
|
.fixup_bittiming = can_fixup_bittiming_v2_6_31,
|
|
.name = "v2.6.31",
|
|
},
|
|
};
|
|
|
|
static __u32 get_cia_sample_point(__u32 bitrate)
|
|
{
|
|
__u32 sampl_pt;
|
|
|
|
if (bitrate > 800000)
|
|
sampl_pt = 750;
|
|
else if (bitrate > 500000)
|
|
sampl_pt = 800;
|
|
else
|
|
sampl_pt = 875;
|
|
|
|
return sampl_pt;
|
|
}
|
|
|
|
static void print_bittiming_one(const struct alg *alg,
|
|
const struct can_bittiming_const *bittiming_const,
|
|
const struct can_bittiming *ref_bt,
|
|
const struct calc_ref_clk *ref_clk,
|
|
unsigned int bitrate_nominal,
|
|
unsigned int sample_point_nominal,
|
|
void (*printf_btr)(struct can_bittiming *bt, bool hdr),
|
|
bool quiet,
|
|
bool verbose,
|
|
bool fd_mode)
|
|
{
|
|
struct net_device dev = {
|
|
.priv.clock.freq = ref_clk->clk,
|
|
};
|
|
struct can_bittiming bt = {
|
|
.bitrate = bitrate_nominal,
|
|
.sample_point = sample_point_nominal,
|
|
};
|
|
unsigned int bitrate_error, sample_point_error;
|
|
|
|
if (!quiet) {
|
|
printf("%sBit timing parameters for %s with %.6f MHz ref clock %s%s%susing algo '%s'\n",
|
|
fd_mode ? "Data " : "",
|
|
bittiming_const->name,
|
|
ref_clk->clk / 1000000.0,
|
|
ref_clk->name ? "(" : "",
|
|
ref_clk->name ? ref_clk->name : "",
|
|
ref_clk->name ? ") " : "",
|
|
alg->name);
|
|
if (verbose) {
|
|
printf(" _----+--------------=> TSeg1: %u … %4u\n"
|
|
" / / _---------=> TSeg2: %u … %4u\n"
|
|
" | | / _-----=> SJW: %u … %4u\n"
|
|
" | | | / _-=> BRP: %u … %4u (inc: %u)\n"
|
|
" | | | | /\n",
|
|
bittiming_const->tseg1_min, bittiming_const->tseg1_max,
|
|
bittiming_const->tseg2_min, bittiming_const->tseg2_max,
|
|
1, bittiming_const->sjw_max,
|
|
bittiming_const->brp_min, bittiming_const->brp_max, bittiming_const->brp_inc);
|
|
printf(" nominal | | | | | real Bitrt nom real SampP\n");
|
|
} else {
|
|
printf(" nominal real Bitrt nom real SampP\n");
|
|
}
|
|
printf(" Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ");
|
|
|
|
printf_btr(&bt, true);
|
|
printf("\n");
|
|
}
|
|
|
|
if (ref_bt) {
|
|
bt = *ref_bt;
|
|
|
|
if (alg->fixup_bittiming(&dev, &bt, bittiming_const)) {
|
|
printf("%8d ***parameters exceed controller's range***\n", bitrate_nominal);
|
|
return;
|
|
}
|
|
} else {
|
|
if (alg->calc_bittiming(&dev, &bt, bittiming_const)) {
|
|
printf("%8d ***bitrate not possible***\n", bitrate_nominal);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bitrate_error = abs(bitrate_nominal - bt.bitrate);
|
|
sample_point_error = abs(sample_point_nominal - bt.sample_point);
|
|
|
|
printf("%8d " /* Bitrate */
|
|
"%6d %3d %4d %4d " /* TQ[ns], PrS, PhS1, PhS2 */
|
|
"%3d %3d " /* SJW, BRP */
|
|
"%8d ", /* real Bitrate */
|
|
bitrate_nominal,
|
|
bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2,
|
|
bt.sjw, bt.brp,
|
|
bt.bitrate);
|
|
|
|
if (100.0 * bitrate_error / bitrate_nominal > 99.9)
|
|
printf("≥100%% ");
|
|
else
|
|
printf("%4.1f%% ", /* Bitrate Error */
|
|
100.0 * bitrate_error / bitrate_nominal);
|
|
|
|
printf("%4.1f%% %4.1f%% ", /* nom Sample Point, real Sample Point */
|
|
sample_point_nominal / 10.0,
|
|
bt.sample_point / 10.0);
|
|
|
|
if (100.0 * sample_point_error / sample_point_nominal > 99.9)
|
|
printf("≥100%% ");
|
|
else
|
|
printf("%4.1f%% ", /* Sample Point Error */
|
|
100.0 * sample_point_error / sample_point_nominal);
|
|
|
|
printf_btr(&bt, false);
|
|
printf("\n");
|
|
}
|
|
|
|
static void print_bittiming(const struct calc_data *data)
|
|
{
|
|
const struct calc_ref_clk *ref_clks = data->ref_clks;
|
|
|
|
if (!ref_clks->clk && !data->quiet)
|
|
printf("Skipping bit timing parameter calculation for %s, no ref clock defined\n\n",
|
|
data->bittiming_const->name);
|
|
|
|
while (ref_clks->clk) {
|
|
void (*printf_btr)(struct can_bittiming *bt, bool hdr);
|
|
unsigned int const *bitrates = data->bitrates;
|
|
bool quiet = data->quiet;
|
|
bool verbose = data->verbose;
|
|
|
|
if (data->printf_btr)
|
|
printf_btr = data->printf_btr;
|
|
else
|
|
printf_btr = printf_btr_nop;
|
|
|
|
while (*bitrates) {
|
|
unsigned int sample_point;
|
|
|
|
/* get nominal sample point */
|
|
if (data->sample_point)
|
|
sample_point = data->sample_point;
|
|
else
|
|
sample_point = get_cia_sample_point(*bitrates);
|
|
|
|
print_bittiming_one(data->alg,
|
|
data->bittiming_const,
|
|
data->opt_bt,
|
|
ref_clks,
|
|
*bitrates,
|
|
sample_point,
|
|
printf_btr,
|
|
quiet,
|
|
verbose,
|
|
data->fd_mode);
|
|
bitrates++;
|
|
quiet = true;
|
|
}
|
|
|
|
printf("\n");
|
|
ref_clks++;
|
|
}
|
|
}
|
|
|
|
static void do_list_calc_bittiming_list(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(alg_list); i++)
|
|
printf(" %s\n", alg_list[i].name);
|
|
}
|
|
|
|
static void do_list(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++)
|
|
printf("%s\n", can_calc_consts[i].bittiming_const.name);
|
|
}
|
|
|
|
static void do_calc(struct calc_data *data)
|
|
{
|
|
unsigned int i;
|
|
bool found = false;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
|
|
const struct calc_bittiming_const *btc;
|
|
|
|
btc = &can_calc_consts[i];
|
|
|
|
if (data->name &&
|
|
strcmp(data->name, btc->bittiming_const.name) &&
|
|
strcmp(data->name, btc->data_bittiming_const.name))
|
|
continue;
|
|
|
|
found = true;
|
|
|
|
if (btc->bittiming_const.name[0]) {
|
|
data->bittiming_const = &btc->bittiming_const;
|
|
data->printf_btr = btc->printf_btr;
|
|
|
|
if (data->opt_ref_clk)
|
|
data->ref_clks = data->opt_ref_clk;
|
|
else
|
|
data->ref_clks = btc->ref_clk;
|
|
|
|
if (data->opt_bitrates)
|
|
data->bitrates = data->opt_bitrates;
|
|
else
|
|
data->bitrates = common_bitrates;
|
|
|
|
data->fd_mode = false;
|
|
|
|
print_bittiming(data);
|
|
}
|
|
|
|
if (btc->data_bittiming_const.name[0]) {
|
|
data->bittiming_const = &btc->data_bittiming_const;
|
|
|
|
if (btc->printf_data_btr)
|
|
data->printf_btr = btc->printf_data_btr;
|
|
else
|
|
data->printf_btr = btc->printf_btr;
|
|
|
|
if (data->opt_ref_clk)
|
|
data->ref_clks = data->opt_ref_clk;
|
|
else
|
|
data->ref_clks = btc->ref_clk;
|
|
|
|
if (data->opt_data_bitrates)
|
|
data->bitrates = data->opt_data_bitrates;
|
|
else if (data->opt_bitrates)
|
|
data->bitrates = data->opt_bitrates;
|
|
else
|
|
data->bitrates = common_data_bitrates;
|
|
|
|
data->fd_mode = true;
|
|
|
|
print_bittiming(data);
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
printf("error: unknown CAN controller '%s', try one of these:\n\n", data->name);
|
|
do_list();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct calc_ref_clk opt_ref_clk[] = {
|
|
{ .name = "cmd-line" },
|
|
{ /* sentinel */ }
|
|
};
|
|
struct can_bittiming opt_bt[1] = { };
|
|
unsigned int opt_bitrate[] = {
|
|
0,
|
|
0 /* sentinel */
|
|
};
|
|
unsigned int opt_data_bitrate[] = {
|
|
0,
|
|
0 /* sentinel */
|
|
};
|
|
struct calc_data data[] = {
|
|
{
|
|
.alg = alg_list,
|
|
}
|
|
};
|
|
const char *opt_alg_name = NULL;
|
|
bool list = false;
|
|
int opt;
|
|
|
|
const struct option long_options[] = {
|
|
{ "tq", required_argument, 0, OPT_TQ, },
|
|
{ "prop-seg", required_argument, 0, OPT_PROP_SEG, },
|
|
{ "phase-seg1", required_argument, 0, OPT_PHASE_SEG1, },
|
|
{ "phase-seg2", required_argument, 0, OPT_PHASE_SEG2, },
|
|
{ "sjw", required_argument, 0, OPT_SJW, },
|
|
{ "brp", required_argument, 0, OPT_BRP, },
|
|
{ "tseg1", required_argument, 0, OPT_TSEG1, },
|
|
{ "tseg2", required_argument, 0, OPT_TSEG2, },
|
|
{ "alg", optional_argument, 0, OPT_ALG, },
|
|
{ 0, 0, 0, 0 },
|
|
};
|
|
|
|
while ((opt = getopt_long(argc, argv, "b:c:d:lqs:v?", long_options, NULL)) != -1) {
|
|
switch (opt) {
|
|
case 'b':
|
|
opt_bitrate[0] = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case 'c':
|
|
opt_ref_clk->clk = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case 'd':
|
|
opt_data_bitrate[0] = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case 'l':
|
|
list = true;
|
|
break;
|
|
|
|
case 'q':
|
|
data->quiet = true;
|
|
break;
|
|
|
|
case 's':
|
|
data->sample_point = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case 'v':
|
|
data->verbose = true;
|
|
break;
|
|
|
|
case OPT_TQ:
|
|
opt_bt->tq = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_PROP_SEG:
|
|
opt_bt->prop_seg = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_PHASE_SEG1:
|
|
opt_bt->phase_seg1 = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_PHASE_SEG2:
|
|
opt_bt->phase_seg2 = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_SJW:
|
|
opt_bt->sjw = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_BRP:
|
|
opt_bt->brp = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_TSEG1: {
|
|
__u32 tseg1;
|
|
|
|
tseg1 = strtoul(optarg, NULL, 10);
|
|
opt_bt->prop_seg = tseg1 / 2;
|
|
opt_bt->phase_seg1 = tseg1 - opt_bt->prop_seg;
|
|
break;
|
|
}
|
|
|
|
case OPT_TSEG2:
|
|
opt_bt->phase_seg2 = strtoul(optarg, NULL, 10);
|
|
break;
|
|
|
|
case OPT_ALG:
|
|
if (!optarg) {
|
|
printf("Supported CAN calc bit timing algorithms:\n\n");
|
|
do_list_calc_bittiming_list();
|
|
printf("\n");
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
opt_alg_name = optarg;
|
|
break;
|
|
|
|
default:
|
|
print_usage(basename(argv[0]));
|
|
exit(EXIT_FAILURE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (argc > optind + 1) {
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (argc == optind + 1)
|
|
data->name = argv[optind];
|
|
|
|
if (list) {
|
|
do_list();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
if (data->sample_point && (data->sample_point >= 1000 || data->sample_point < 100))
|
|
print_usage(argv[0]);
|
|
|
|
if (opt_alg_name) {
|
|
bool alg_found = false;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(alg_list); i++) {
|
|
if (!strcmp(opt_alg_name, alg_list[i].name)) {
|
|
data->alg = &alg_list[i];
|
|
alg_found = true;
|
|
}
|
|
}
|
|
|
|
if (!alg_found) {
|
|
printf("error: unknown CAN calc bit timing algorithm '%s', try one of these:\n\n", opt_alg_name);
|
|
do_list_calc_bittiming_list();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
if (opt_ref_clk->clk)
|
|
data->opt_ref_clk = opt_ref_clk;
|
|
if (opt_bitrate[0])
|
|
data->opt_bitrates = opt_bitrate;
|
|
if (opt_data_bitrate[0])
|
|
data->opt_data_bitrates = opt_data_bitrate;
|
|
if (opt_bt->prop_seg)
|
|
data->opt_bt = opt_bt;
|
|
|
|
do_calc(data);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|