diff --git a/can-calc-bit-timing.c b/can-calc-bit-timing.c index 82fdda8..dc2a62c 100644 --- a/can-calc-bit-timing.c +++ b/can-calc-bit-timing.c @@ -2,7 +2,7 @@ /* can-calc-bit-timing.c: Calculate CAN bit timing parameters * * Copyright (C) 2008 Wolfgang Grandegger - * Copyright (C) 2016, 2021 Marc Kleine-Budde + * Copyright (C) 2016, 2021, 2022 Marc Kleine-Budde * * Derived from: * can_baud.c - CAN baudrate calculation @@ -38,6 +38,7 @@ enum { OPT_BRP, OPT_TSEG1, OPT_TSEG2, + OPT_ALG, }; /* imported from kernel */ @@ -57,7 +58,7 @@ enum { __abs_choose_expr(x, char, \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(x), char), \ - (char)({ signed char __x = (x); __x<0?-__x:__x; }), \ + (char)({ signed char __x = (x); __x < 0 ? -__x:__x; }), \ ((void)0))))))) #define __abs_choose_expr(x, type, other) __builtin_choose_expr( \ @@ -93,13 +94,13 @@ enum { */ #define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) -# define do_div(n,base) ({ \ +#define do_div(n, base) ({ \ uint32_t __base = (base); \ uint32_t __rem; \ __rem = ((uint64_t)(n)) % __base; \ (n) = ((uint64_t)(n)) / __base; \ __rem; \ - }) +}) /* */ @@ -115,14 +116,7 @@ typedef __u32 u32; struct calc_ref_clk { __u32 clk; /* CAN system clock frequency in Hz */ - char *name; -}; - -struct calc_bittiming_const { - struct can_bittiming_const bittiming_const; - - const struct calc_ref_clk ref_clk[16]; - void (*printf_btr)(struct can_bittiming *bt, bool hdr); + const char *name; }; /* @@ -136,6 +130,41 @@ struct net_device { struct can_priv priv; }; +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]; + + const void (*printf_btr)(struct can_bittiming *bt, bool hdr); + const void (*printf_data_btr)(struct can_bittiming *bt, bool hdr); +}; + +struct can_calc_bittiming { + int (*alg)(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc); + const char *name; +}; + +struct calc_data { + const struct can_bittiming_const *bittiming_const; + const struct can_calc_bittiming *calc_bittiming; + const 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; +}; + static inline void *netdev_priv(const struct net_device *dev) { return (void *)&dev->priv; @@ -148,10 +177,12 @@ static void print_usage(char *cmd) "Options:\n" "\t-q don't print header line\n" "\t-l list all support CAN controller names\n" - "\t-b bit-rate in bits/sec\n" + "\t-b arbitration bit-rate in bits/sec\n" + "\t-d data bit-rate in bits/sec\n" "\t-s sample-point in one-tenth of a percent\n" "\t or 0 for CIA recommended sample points\n" "\t-c real CAN system clock in Hz\n" + "\t--alg choose specified algorithm for bit-timing calculation\n" "\n" "Or supply low level bit timing parameters to decode them:\n" "\n" @@ -165,91 +196,8 @@ static void print_usage(char *cmd) cmd); } -static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr) +static void printf_btr_nop(struct can_bittiming *bt, bool hdr) { - uint8_t btr0, btr1; - - if (hdr) { - printf("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_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_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_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("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_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); - } } #define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20) @@ -273,6 +221,33 @@ static void printf_btr_rcar_can(struct can_bittiming *bt, bool hdr) } } +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) { @@ -289,10 +264,24 @@ static void printf_btr_bxcan(struct can_bittiming *bt, bool hdr) } } +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("%s", " BTR BRPEXT"); + printf("%13s", "BTR BRPEXT"); } else { uint32_t btr; uint32_t brpext; @@ -307,6 +296,21 @@ static void printf_btr_c_can(struct can_bittiming *bt, bool hdr) } } +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) { @@ -324,82 +328,108 @@ static void printf_btr_mcan(struct can_bittiming *bt, bool hdr) } } -static struct calc_bittiming_const can_calc_consts[] = { +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 = "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 = 8000000, }, - }, - .printf_btr = printf_btr_sja1000, - }, { - .bittiming_const = { - .name = "mscan", + .name = "rcar_can", .tseg1_min = 4, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, - .brp_max = 64, + .brp_max = 1024, .brp_inc = 1, }, .ref_clk = { - { .clk = 32000000, }, - { .clk = 33000000, }, - { .clk = 33300000, }, - { .clk = 33333333, }, - { .clk = 66660000, .name = "mpc5121", }, - { .clk = 66666666, .name = "mpc5121" }, + { .clk = 65000000, }, }, + .printf_btr = printf_btr_rcar_can, }, { .bittiming_const = { - .name = "at91", - .tseg1_min = 4, - .tseg1_max = 16, + .name = "rcar_canfd", + .tseg1_min = 2, + .tseg1_max = 128, .tseg2_min = 2, - .tseg2_max = 8, - .sjw_max = 4, - .brp_min = 2, - .brp_max = 128, + .tseg2_max = 32, + .sjw_max = 32, + .brp_min = 1, + .brp_max = 1024, .brp_inc = 1, }, - .ref_clk = { - { .clk = 99532800, .name = "ronetix PM9263", }, - { .clk = 100000000, }, - }, - .printf_btr = printf_btr_at91, - }, { - .bittiming_const = { - .name = "flexcan", - .tseg1_min = 4, + .data_bittiming_const = { + .name = "rcar_canfd", + .tseg1_min = 2, .tseg1_max = 16, .tseg2_min = 2, .tseg2_max = 8, - .sjw_max = 4, + .sjw_max = 8, .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, }, - { .clk = 66666666, }, - { .clk = 83368421, .name = "vybrid" }, + { .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, + }, + }, { /* -------- 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, }, }, - .printf_btr = printf_btr_flexcan, }, { .bittiming_const = { .name = "mcp251x", @@ -431,33 +461,28 @@ static struct calc_bittiming_const can_calc_consts[] = { .brp_max = 256, .brp_inc = 1, }, - .ref_clk = { - { .clk = 20000000, }, - { .clk = 40000000, }, - }, - .printf_btr = printf_btr_mcp251xfd, - }, { - .bittiming_const = { - .name = "ti_hecc", + .data_bittiming_const = { + .name = "mcp251xfd", .tseg1_min = 1, - .tseg1_max = 16, + .tseg1_max = 32, .tseg2_min = 1, - .tseg2_max = 8, - .sjw_max = 4, + .tseg2_max = 16, + .sjw_max = 16, .brp_min = 1, .brp_max = 256, .brp_inc = 1, }, .ref_clk = { - { .clk = 13000000, }, + { .clk = 20000000, .name = "CIA recommendation"}, + { .clk = 40000000, .name = "CIA recommendation"}, }, - .printf_btr = printf_btr_ti_hecc, - }, { + .printf_btr = printf_btr_mcp251xfd, + }, { /* -------- USB -------- */ .bittiming_const = { - .name = "rcar_can", - .tseg1_min = 4, + .name = "usb_8dev", + .tseg1_min = 1, .tseg1_max = 16, - .tseg2_min = 2, + .tseg2_min = 1, .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, @@ -465,12 +490,55 @@ static struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 65000000, }, - }, - .printf_btr = printf_btr_rcar_can, + { .clk = 32000000, }, + } }, { .bittiming_const = { - .name = "bxcan", + .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, @@ -484,6 +552,199 @@ static struct calc_bittiming_const can_calc_consts[] = { { .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 = 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", @@ -500,6 +761,194 @@ static struct calc_bittiming_const can_calc_consts[] = { { .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+", @@ -512,14 +961,183 @@ static struct calc_bittiming_const can_calc_consts[] = { .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 = 40000000, }, + { .clk = 20000000, .name = "CIA recommendation"}, + { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 24000000, .name = "stm32mp1 - ck_hse" }, + { .clk = 24573875, .name = "stm32mp1 - pll3_1" }, + { .clk = 74250000, .name = "stm32mp1 - pll4_r" }, + { .clk = 29700000, .name = "stm32mp1 - pll4_q" }, }, .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"}, + }, }, }; -static long common_bitrates[] = { +static const unsigned int common_bitrates[] = { 1000000, 800000, 500000, @@ -529,6 +1147,18 @@ static long common_bitrates[] = { 50000, 20000, 10000, + 0 +}; + +static const unsigned int common_data_bitrates[] = { + 12000000, + 10000000, + 8000000, + 5000000, + 4000000, + 2000000, + 1000000, + 0 }; #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ @@ -547,6 +1177,144 @@ static long common_bitrates[] = { * registers of the CAN controller. You can find more information * in the header file linux/can/netlink.h. */ + +/* + * imported from v3.18-rc1~52^2~248^2~1 + * + * b25a437206ed can: dev: remove unused variable from can_calc_bittiming() function + */ +#undef can_calc_bittiming +#undef can_update_spt +#define can_calc_bittiming can_calc_bittiming_v3_18 +#define can_update_spt can_update_spt_v3_18 + +static int can_update_spt(const struct can_bittiming_const *btc, + int sampl_pt, int tseg, int *tseg1, int *tseg2) +{ + *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000; + if (*tseg2 < btc->tseg2_min) + *tseg2 = btc->tseg2_min; + if (*tseg2 > btc->tseg2_max) + *tseg2 = btc->tseg2_max; + *tseg1 = tseg - *tseg2; + if (*tseg1 > btc->tseg1_max) { + *tseg1 = btc->tseg1_max; + *tseg2 = tseg - *tseg1; + } + return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); +} + +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + struct can_priv *priv = netdev_priv(dev); + long best_error = 1000000000, error = 0; + int best_tseg = 0, best_brp = 0, brp = 0; + int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0; + int spt_error = 1000, spt = 0, sampl_pt; + long rate; + u64 v64; + + /* Use CIA recommended sample points */ + if (bt->sample_point) { + sampl_pt = bt->sample_point; + } else { + if (bt->bitrate > 800000) + sampl_pt = 750; + else if (bt->bitrate > 500000) + sampl_pt = 800; + else + sampl_pt = 875; + } + + /* tseg even = round down, odd = round up */ + for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1; + tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) { + tsegall = 1 + tseg / 2; + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; + /* chose brp step which is possible in system */ + brp = (brp / btc->brp_inc) * btc->brp_inc; + if ((brp < btc->brp_min) || (brp > btc->brp_max)) + continue; + rate = priv->clock.freq / (brp * tsegall); + error = bt->bitrate - rate; + /* tseg brp biterror */ + if (error < 0) + error = -error; + if (error > best_error) + continue; + best_error = error; + if (error == 0) { + spt = can_update_spt(btc, sampl_pt, tseg / 2, + &tseg1, &tseg2); + error = sampl_pt - spt; + if (error < 0) + error = -error; + if (error > spt_error) + continue; + spt_error = error; + } + best_tseg = tseg / 2; + best_brp = brp; + if (error == 0) + break; + } + + if (best_error) { + /* Error in one-tenth of a percent */ + error = (best_error * 1000) / bt->bitrate; + if (error > CAN_CALC_MAX_ERROR) { + netdev_err(dev, + "bitrate error %ld.%ld%% too high\n", + error / 10, error % 10); + return -EDOM; + } else { + netdev_warn(dev, "bitrate error %ld.%ld%%\n", + error / 10, error % 10); + } + } + + /* real sample point */ + bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg, + &tseg1, &tseg2); + + v64 = (u64)best_brp * 1000000000UL; + do_div(v64, priv->clock.freq); + bt->tq = (u32)v64; + bt->prop_seg = tseg1 / 2; + bt->phase_seg1 = tseg1 - bt->prop_seg; + bt->phase_seg2 = tseg2; + + /* check for sjw user settings */ + if (!bt->sjw || !btc->sjw_max) + bt->sjw = 1; + else { + /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */ + if (bt->sjw > btc->sjw_max) + bt->sjw = btc->sjw_max; + /* bt->sjw must not be higher than tseg2 */ + if (tseg2 < bt->sjw) + bt->sjw = tseg2; + } + + bt->brp = best_brp; + /* real bit-rate */ + bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1)); + + return 0; +} + +/* + * imported from v4.8-rc1~140^2~304^2~11 + * + * 7da29f97d6c8 can: dev: can-calc-bit-timing(): better sample point calculation + */ +#undef can_update_spt +#undef can_calc_bittiming +#define can_update_spt can_update_spt_v4_8 +#define can_calc_bittiming can_calc_bittiming_v4_8 + static int can_update_spt(const struct can_bittiming_const *btc, unsigned int spt_nominal, unsigned int tseg, unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, @@ -691,6 +1459,20 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, return 0; } +#undef can_calc_bittiming +#undef can_update_spt + +static const struct can_calc_bittiming calc_bittiming_list[] = { + /* 1st will be default */ + { + .alg = can_calc_bittiming_v4_8, + .name = "v4.8", + }, { + .alg = can_calc_bittiming_v3_18, + .name = "v3.18", + }, +}; + static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, const struct can_bittiming_const *btc) { @@ -745,88 +1527,137 @@ static __u32 get_cia_sample_point(__u32 bitrate) return sampl_pt; } -static void print_bit_timing(const struct calc_bittiming_const *btc, - const struct can_bittiming *ref_bt, - const struct calc_ref_clk *ref_clk, - unsigned int bitrate_nominal, - unsigned int spt_nominal, - bool quiet) +static void print_bittiming_one(const struct can_calc_bittiming *calc_bittiming, + 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) { struct net_device dev = { .priv.clock.freq = ref_clk->clk, }; struct can_bittiming bt = { .bitrate = bitrate_nominal, - .sample_point = spt_nominal, + .sample_point = sample_point_nominal, }; - long rate_error, spt_error; + unsigned int bitrate_error, sample_point_error; if (!quiet) { - printf("Bit timing parameters for %s%s%s%s with %.6f MHz ref clock\n" - "nominal real Bitrt nom real SampP\n" - "Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ", - btc->bittiming_const.name, - ref_clk->name ? " (" : "", + printf("Bit timing parameters for %s with %.6f MHz ref clock %s%s%susing algo '%s'\n" + " nominal real Bitrt nom real SampP\n" + " Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ", + bittiming_const->name, + ref_clk->clk / 1000000.0, + ref_clk->name ? "(" : "", ref_clk->name ? ref_clk->name : "", - ref_clk->name ? ")" : "", - ref_clk->clk / 1000000.0); + ref_clk->name ? ") " : "", + calc_bittiming->name); - if (btc->printf_btr) - btc->printf_btr(&bt, true); + printf_btr(&bt, true); printf("\n"); } if (ref_bt) { bt = *ref_bt; - if (can_fixup_bittiming(&dev, &bt, &btc->bittiming_const)) { - printf("%7d ***parameters exceed controller's range***\n", bitrate_nominal); + if (can_fixup_bittiming(&dev, &bt, bittiming_const)) { + printf("%8d ***parameters exceed controller's range***\n", bitrate_nominal); return; } } else { - if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) { - printf("%7d ***bitrate not possible***\n", bitrate_nominal); + if (calc_bittiming->alg(&dev, &bt, bittiming_const)) { + printf("%8d ***bitrate not possible***\n", bitrate_nominal); return; } } - /* get nominal sample point */ - if (!spt_nominal) - spt_nominal = get_cia_sample_point(bitrate_nominal); + bitrate_error = abs(bitrate_nominal - bt.bitrate); + sample_point_error = abs(sample_point_nominal - bt.sample_point); - rate_error = abs(bitrate_nominal - bt.bitrate); - spt_error = abs(spt_nominal - bt.sample_point); - - printf("%7d " /* Bitrate */ + printf("%8d " /* Bitrate */ "%6d %3d %4d %4d " /* TQ[ns], PrS, PhS1, PhS2 */ "%3d %3d " /* SJW, BRP */ - "%7d ", /* real Bitrate */ + "%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 * rate_error / bitrate_nominal > 99.9) - printf("≥100%% "); + if (100.0 * bitrate_error / bitrate_nominal > 99.9) + printf("≥100%% "); else - printf("%4.1f%% ", - 100.0 * rate_error / bitrate_nominal); + printf("%4.1f%% ", /* Bitrate Error */ + 100.0 * bitrate_error / bitrate_nominal); - printf("%4.1f%% %4.1f%% ", /* nom SampP, real SampP */ - spt_nominal / 10.0, + printf("%4.1f%% %4.1f%% ", /* nom Sample Point, real Sample Point */ + sample_point_nominal / 10.0, bt.sample_point / 10.0); - if (100.0 * spt_error / spt_nominal > 99.9) - printf("≥100%% "); + if (100.0 * sample_point_error / sample_point_nominal > 99.9) + printf("≥100%% "); else - printf("%4.1f%% ", /* SampP Error */ - 100.0 * spt_error / spt_nominal); + printf("%4.1f%% ", /* Sample Point Error */ + 100.0 * sample_point_error / sample_point_nominal); - if (btc->printf_btr) - btc->printf_btr(&bt, false); + 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; + + 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->calc_bittiming, + data->bittiming_const, + data->opt_bt, + ref_clks, + *bitrates, + sample_point, + printf_btr, + quiet); + bitrates++; + quiet = true; + } + + printf("\n"); + ref_clks++; + } +} + +static void do_list_calc_bittiming_list(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(calc_bittiming_list); i++) + printf(" %s\n", calc_bittiming_list[i].name); +} + static void do_list(void) { unsigned int i; @@ -835,51 +1666,66 @@ static void do_list(void) printf("%s\n", can_calc_consts[i].bittiming_const.name); } -static void do_calc(const char *name, - const struct can_bittiming *opt_ref_bt, - __u32 bitrate_nominal, unsigned int spt_nominal, - struct calc_ref_clk *opt_ref_clk, bool quiet) +static void do_calc(struct calc_data *data) { - const struct calc_bittiming_const *btc; - const struct calc_ref_clk *ref_clk; - unsigned int i, j, k; + unsigned int i; bool found = false; for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) { - if (name && - strcmp(can_calc_consts[i].bittiming_const.name, name) != 0) + 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; - btc = &can_calc_consts[i]; - for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) { - if (opt_ref_clk) - ref_clk = opt_ref_clk; + 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 - ref_clk = &btc->ref_clk[j]; + data->ref_clks = btc->ref_clk; - if (!ref_clk->clk) - break; + if (data->opt_bitrates) + data->bitrates = data->opt_bitrates; + else + data->bitrates = common_bitrates; - if (bitrate_nominal) { - print_bit_timing(btc, opt_ref_bt, ref_clk, bitrate_nominal, - spt_nominal, quiet); - } else { - for (k = 0; k < ARRAY_SIZE(common_bitrates); k++) - print_bit_timing(btc, opt_ref_bt, ref_clk, - common_bitrates[k], - spt_nominal, k); - } - printf("\n"); + print_bittiming(data); + } - if (opt_ref_clk) - break; + 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; + + print_bittiming(data); } } if (!found) { - printf("error: unknown CAN controller '%s', try one of these:\n\n", name); + printf("error: unknown CAN controller '%s', try one of these:\n\n", data->name); do_list(); exit(EXIT_FAILURE); } @@ -887,18 +1733,30 @@ static void do_calc(const char *name, int main(int argc, char *argv[]) { - __u32 bitrate_nominal = 0; - unsigned int spt_nominal = 0; - struct calc_ref_clk opt_ref_clk = { - .name = "cmd-line", + struct calc_ref_clk opt_ref_clk[] = { + { .name = "cmd-line" }, + { /* sentinel */ } }; - struct can_bittiming bt = { 0 }; - bool quiet = false, list = false; - const char *name = NULL; + 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[] = { + { + .calc_bittiming = calc_bittiming_list, + } + }; + const char *opt_alg_name = NULL; + bool list = false; int opt; const struct option long_options[] = { - { "tq", required_argument, 0, OPT_TQ, }, + { "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, }, @@ -906,17 +1764,22 @@ int main(int argc, char *argv[]) { "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:lqs:?", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "b:c:d:lqs:?", long_options, NULL)) != -1) { switch (opt) { case 'b': - bitrate_nominal = atoi(optarg); + opt_bitrate[0] = strtoul(optarg, NULL, 10); break; case 'c': - opt_ref_clk.clk = strtoul(optarg, NULL, 10); + opt_ref_clk->clk = strtoul(optarg, NULL, 10); + break; + + case 'd': + opt_data_bitrate[0] = strtoul(optarg, NULL, 10); break; case 'l': @@ -924,11 +1787,11 @@ int main(int argc, char *argv[]) break; case 'q': - quiet = true; + data->quiet = true; break; case 's': - spt_nominal = strtoul(optarg, NULL, 10); + data->sample_point = strtoul(optarg, NULL, 10); break; case '?': @@ -937,40 +1800,50 @@ int main(int argc, char *argv[]) break; case OPT_TQ: - bt.tq = strtoul(optarg, NULL, 10); + opt_bt->tq = strtoul(optarg, NULL, 10); break; case OPT_PROP_SEG: - bt.prop_seg = strtoul(optarg, NULL, 10); + opt_bt->prop_seg = strtoul(optarg, NULL, 10); break; case OPT_PHASE_SEG1: - bt.phase_seg1 = strtoul(optarg, NULL, 10); + opt_bt->phase_seg1 = strtoul(optarg, NULL, 10); break; case OPT_PHASE_SEG2: - bt.phase_seg2 = strtoul(optarg, NULL, 10); + opt_bt->phase_seg2 = strtoul(optarg, NULL, 10); break; case OPT_SJW: - bt.sjw = strtoul(optarg, NULL, 10); + opt_bt->sjw = strtoul(optarg, NULL, 10); break; case OPT_BRP: - bt.brp = strtoul(optarg, NULL, 10); + opt_bt->brp = strtoul(optarg, NULL, 10); break; case OPT_TSEG1: { __u32 tseg1; tseg1 = strtoul(optarg, NULL, 10); - bt.prop_seg = tseg1 / 2; - bt.phase_seg1 = tseg1 - bt.prop_seg; + opt_bt->prop_seg = tseg1 / 2; + opt_bt->phase_seg1 = tseg1 - opt_bt->prop_seg; break; } case OPT_TSEG2: - bt.phase_seg2 = strtoul(optarg, NULL, 10); + 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: @@ -986,23 +1859,44 @@ int main(int argc, char *argv[]) } if (argc == optind + 1) - name = argv[optind]; + data->name = argv[optind]; if (list) { do_list(); exit(EXIT_SUCCESS); } - if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100)) { + if (data->sample_point && (data->sample_point >= 1000 || data->sample_point < 100)) print_usage(argv[0]); - exit(EXIT_FAILURE); + + if (opt_alg_name) { + bool alg_found = false; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(calc_bittiming_list); i++) { + if (!strcmp(opt_alg_name, calc_bittiming_list[i].name)) { + data->calc_bittiming = &calc_bittiming_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); + } } - do_calc(name, - bt.prop_seg ? &bt: NULL, - bitrate_nominal, spt_nominal, - opt_ref_clk.clk ? &opt_ref_clk : NULL, - quiet); + 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); }