diff --git a/.gitignore b/.gitignore index 568f070..1faf977 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ GNUmakefile.in /config/m4/ltsugar.m4 /config/m4/ltversion.m4 /config/m4/lt~obsolete.m4 +/calc-bit-timing/.dirstamp /mcp251xfd/.dirstamp /asc2log diff --git a/CMakeLists.txt b/CMakeLists.txt index fea4171..c317188 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,10 @@ set(PROGRAMS slcanpty ) +add_executable(can-calc-bit-timing + calc-bit-timing/can-calc-bit-timing.c +) + add_executable(mcp251xfd-dump mcp251xfd/mcp251xfd-dev-coredump.c mcp251xfd/mcp251xfd-dump.c diff --git a/GNUmakefile.am b/GNUmakefile.am index 02c37ab..8ce78e2 100644 --- a/GNUmakefile.am +++ b/GNUmakefile.am @@ -5,6 +5,8 @@ AM_CPPFLAGS = \ -I$(top_builddir)/include \ $(linux_CFLAGS) +EXTRA_DIST = + # link every app against libcan, it's static so it wouldn't hurt LDADD = \ libcan.la @@ -39,6 +41,16 @@ libcan_la_SOURCES = \ libj1939_la_SOURCES = \ libj1939.c +can_calc_bit_timing_SOURCES = \ + calc-bit-timing/can-calc-bit-timing.c + +EXTRA_DIST += \ + calc-bit-timing/can-calc-bit-timing-v2_6_31.c \ + calc-bit-timing/can-calc-bit-timing-v3_18.c \ + calc-bit-timing/can-calc-bit-timing-v4_8.c \ + calc-bit-timing/can-calc-bit-timing-v5_16.c \ + calc-bit-timing/can-calc-bit-timing-v5_19.c + mcp251xfd_dump_SOURCES = \ mcp251xfd/mcp251xfd-dev-coredump.c \ mcp251xfd/mcp251xfd-dump-userspace.h \ @@ -87,7 +99,7 @@ j1939spy_LDADD = libj1939.la j1939sr_LDADD = libj1939.la testj1939_LDADD = libj1939.la -EXTRA_DIST = \ +EXTRA_DIST += \ .travis.yml \ Android.mk \ README.md \ diff --git a/Makefile b/Makefile index fb52643..970a4cb 100644 --- a/Makefile +++ b/Makefile @@ -142,5 +142,8 @@ 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 +can-calc-bit-timing: calc-bit-timing/can-calc-bit-timing.o + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +mcp251xfd-dump: mcp251xfd/mcp251xfd-dev-coredump.o mcp251xfd/mcp251xfd-dump.o mcp251xfd/mcp251xfd-main.o mcp251xfd/mcp251xfd-regmap.o $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ diff --git a/calc-bit-timing/can-calc-bit-timing-v2_6_31.c b/calc-bit-timing/can-calc-bit-timing-v2_6_31.c new file mode 100644 index 0000000..3020aa1 --- /dev/null +++ b/calc-bit-timing/can-calc-bit-timing-v2_6_31.c @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * imported from v2.6.31-rc1~330^2~376 + * + * 39549eef3587 can: CAN Network device driver and Netlink interface + * + * cherry-picked for easier integration: + * 61463a30f652 can: make function can_get_bittiming static + * aabdfd6adb80 can: replace the dev_dbg/info/err/... with the new netdev_xxx macros + * 08da7da41ea4 can: provide a separate bittiming_const parameter to bittiming functions + * b25a437206ed can: dev: remove unused variable from can_calc_bittiming() function +*/ + +/* + * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * 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 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Bit-timing calculation derived from: + * + * 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 + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +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; + bt->sjw = 1; + bt->brp = best_brp; + /* real bit-rate */ + bt->bitrate = priv->clock.freq / (bt->brp * (tseg1 + tseg2 + 1)); + + return 0; +} + +/* + * Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + struct can_priv *priv = netdev_priv(dev); + int tseg1, alltseg; + u64 brp64; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} diff --git a/calc-bit-timing/can-calc-bit-timing-v3_18.c b/calc-bit-timing/can-calc-bit-timing-v3_18.c new file mode 100644 index 0000000..14ac8ea --- /dev/null +++ b/calc-bit-timing/can-calc-bit-timing-v3_18.c @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * imported from v3.18-rc1~52^2~248^2~1 + * + */ + +/* + * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * 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 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/* + * Bit-timing calculation derived from: + * + * 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 + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +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; +} + +/* + * Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + struct can_priv *priv = netdev_priv(dev); + int tseg1, alltseg; + u64 brp64; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} diff --git a/calc-bit-timing/can-calc-bit-timing-v4_8.c b/calc-bit-timing/can-calc-bit-timing-v4_8.c new file mode 100644 index 0000000..7b0dad7 --- /dev/null +++ b/calc-bit-timing/can-calc-bit-timing-v4_8.c @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * imported from v4.8-rc1~140^2~304^2~11 + * + */ + +/* + * Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + * + * 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 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/* + * Bit-timing calculation derived from: + * + * 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 + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +static int can_update_sample_point(const struct can_bittiming_const *btc, + unsigned int sample_point_nominal, unsigned int tseg, + unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, + unsigned int *sample_point_error_ptr) +{ + unsigned int sample_point_error, best_sample_point_error = UINT_MAX; + unsigned int sample_point, best_sample_point = 0; + unsigned int tseg1, tseg2; + int i; + + for (i = 0; i <= 1; i++) { + tseg2 = tseg + CAN_CALC_SYNC_SEG - (sample_point_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i; + tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); + tseg1 = tseg - tseg2; + if (tseg1 > btc->tseg1_max) { + tseg1 = btc->tseg1_max; + tseg2 = tseg - tseg1; + } + + sample_point = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG); + sample_point_error = abs(sample_point_nominal - sample_point); + + if ((sample_point <= sample_point_nominal) && (sample_point_error < best_sample_point_error)) { + best_sample_point = sample_point; + best_sample_point_error = sample_point_error; + *tseg1_ptr = tseg1; + *tseg2_ptr = tseg2; + } + } + + if (sample_point_error_ptr) + *sample_point_error_ptr = best_sample_point_error; + + return best_sample_point; +} + +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); + unsigned int bitrate; /* current bitrate */ + unsigned int bitrate_error; /* difference between current and nominal value */ + unsigned int best_bitrate_error = UINT_MAX; + unsigned int sample_point_error; /* difference between current and nominal value */ + unsigned int best_sample_point_error = UINT_MAX; + unsigned int sample_point_nominal; /* nominal sample point */ + unsigned int best_tseg = 0; /* current best value for tseg */ + unsigned int best_brp = 0; /* current best value for brp */ + unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; + u64 v64; + + /* Use CiA recommended sample points */ + if (bt->sample_point) { + sample_point_nominal = bt->sample_point; + } else { + if (bt->bitrate > 800000) + sample_point_nominal = 750; + else if (bt->bitrate > 500000) + sample_point_nominal = 800; + else + sample_point_nominal = 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 = CAN_CALC_SYNC_SEG + tseg / 2; + + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; + + /* choose 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; + + bitrate = priv->clock.freq / (brp * tsegall); + bitrate_error = abs(bt->bitrate - bitrate); + + /* tseg brp biterror */ + if (bitrate_error > best_bitrate_error) + continue; + + /* reset sample point error if we have a better bitrate */ + if (bitrate_error < best_bitrate_error) + best_sample_point_error = UINT_MAX; + + can_update_sample_point(btc, sample_point_nominal, tseg / 2, &tseg1, &tseg2, &sample_point_error); + if (sample_point_error > best_sample_point_error) + continue; + + best_sample_point_error = sample_point_error; + best_bitrate_error = bitrate_error; + best_tseg = tseg / 2; + best_brp = brp; + + if (bitrate_error == 0 && sample_point_error == 0) + break; + } + + if (best_bitrate_error) { + /* Error in one-tenth of a percent */ + v64 = (u64)best_bitrate_error * 1000; + do_div(v64, bt->bitrate); + bitrate_error = (u32)v64; + if (bitrate_error > CAN_CALC_MAX_ERROR) { + netdev_err(dev, + "bitrate error %d.%d%% too high\n", + bitrate_error / 10, bitrate_error % 10); + return -EDOM; + } + netdev_warn(dev, "bitrate error %d.%d%%\n", + bitrate_error / 10, bitrate_error % 10); + } + + /* real sample point */ + bt->sample_point = can_update_sample_point(btc, sample_point_nominal, best_tseg, + &tseg1, &tseg2, NULL); + + v64 = (u64)best_brp * 1000 * 1000 * 1000; + 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 bitrate */ + bt->bitrate = priv->clock.freq / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2)); + + return 0; +} + +/* + * Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + struct can_priv *priv = netdev_priv(dev); + int tseg1, alltseg; + u64 brp64; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} diff --git a/calc-bit-timing/can-calc-bit-timing-v5_16.c b/calc-bit-timing/can-calc-bit-timing-v5_16.c new file mode 100644 index 0000000..aecfdbd --- /dev/null +++ b/calc-bit-timing/can-calc-bit-timing-v5_16.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * imported from v5.16-rc1~159^2~104^2~13 + * + */ + +/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + */ + +/* Bit-timing calculation derived from: + * + * 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 + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +static int +can_update_sample_point(const struct can_bittiming_const *btc, + unsigned int sample_point_nominal, unsigned int tseg, + unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, + unsigned int *sample_point_error_ptr) +{ + unsigned int sample_point_error, best_sample_point_error = UINT_MAX; + unsigned int sample_point, best_sample_point = 0; + unsigned int tseg1, tseg2; + int i; + + for (i = 0; i <= 1; i++) { + tseg2 = tseg + CAN_SYNC_SEG - + (sample_point_nominal * (tseg + CAN_SYNC_SEG)) / + 1000 - i; + tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); + tseg1 = tseg - tseg2; + if (tseg1 > btc->tseg1_max) { + tseg1 = btc->tseg1_max; + tseg2 = tseg - tseg1; + } + + sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) / + (tseg + CAN_SYNC_SEG); + sample_point_error = abs(sample_point_nominal - sample_point); + + if (sample_point <= sample_point_nominal && + sample_point_error < best_sample_point_error) { + best_sample_point = sample_point; + best_sample_point_error = sample_point_error; + *tseg1_ptr = tseg1; + *tseg2_ptr = tseg2; + } + } + + if (sample_point_error_ptr) + *sample_point_error_ptr = best_sample_point_error; + + return best_sample_point; +} + +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); + unsigned int bitrate; /* current bitrate */ + unsigned int bitrate_error; /* difference between current and nominal value */ + unsigned int best_bitrate_error = UINT_MAX; + unsigned int sample_point_error; /* difference between current and nominal value */ + unsigned int best_sample_point_error = UINT_MAX; + unsigned int sample_point_nominal; /* nominal sample point */ + unsigned int best_tseg = 0; /* current best value for tseg */ + unsigned int best_brp = 0; /* current best value for brp */ + unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; + u64 v64; + + /* Use CiA recommended sample points */ + if (bt->sample_point) { + sample_point_nominal = bt->sample_point; + } else { + if (bt->bitrate > 800 * CAN_KBPS) + sample_point_nominal = 750; + else if (bt->bitrate > 500 * CAN_KBPS) + sample_point_nominal = 800; + else + sample_point_nominal = 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 = CAN_SYNC_SEG + tseg / 2; + + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; + + /* choose 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; + + bitrate = priv->clock.freq / (brp * tsegall); + bitrate_error = abs(bt->bitrate - bitrate); + + /* tseg brp biterror */ + if (bitrate_error > best_bitrate_error) + continue; + + /* reset sample point error if we have a better bitrate */ + if (bitrate_error < best_bitrate_error) + best_sample_point_error = UINT_MAX; + + can_update_sample_point(btc, sample_point_nominal, tseg / 2, + &tseg1, &tseg2, &sample_point_error); + if (sample_point_error > best_sample_point_error) + continue; + + best_sample_point_error = sample_point_error; + best_bitrate_error = bitrate_error; + best_tseg = tseg / 2; + best_brp = brp; + + if (bitrate_error == 0 && sample_point_error == 0) + break; + } + + if (best_bitrate_error) { + /* Error in one-tenth of a percent */ + v64 = (u64)best_bitrate_error * 1000; + do_div(v64, bt->bitrate); + bitrate_error = (u32)v64; + if (bitrate_error > CAN_CALC_MAX_ERROR) { + netdev_err(dev, + "bitrate error %d.%d%% too high\n", + bitrate_error / 10, bitrate_error % 10); + return -EDOM; + } + netdev_warn(dev, "bitrate error %d.%d%%\n", + bitrate_error / 10, bitrate_error % 10); + } + + /* real sample point */ + bt->sample_point = can_update_sample_point(btc, sample_point_nominal, + best_tseg, &tseg1, &tseg2, + NULL); + + v64 = (u64)best_brp * 1000 * 1000 * 1000; + 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 bitrate */ + bt->bitrate = priv->clock.freq / + (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2)); + + return 0; +} + +/* Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + struct can_priv *priv = netdev_priv(dev); + unsigned int tseg1, alltseg; + u64 brp64; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} diff --git a/calc-bit-timing/can-calc-bit-timing-v5_19.c b/calc-bit-timing/can-calc-bit-timing-v5_19.c new file mode 100644 index 0000000..a1b8821 --- /dev/null +++ b/calc-bit-timing/can-calc-bit-timing-v5_19.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * imported from v5.19-rc1~159^2~286^2~15 + * + */ + +/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2006 Andrey Volkov, Varma Electronics + * Copyright (C) 2008-2009 Wolfgang Grandegger + */ + +/* Bit-timing calculation derived from: + * + * 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 + * + * Calculates proper bit-timing parameters for a specified bit-rate + * and sample-point, which can then be used to set the bit-timing + * registers of the CAN controller. You can find more information + * in the header file linux/can/netlink.h. + */ +static int +can_update_sample_point(const struct can_bittiming_const *btc, + const unsigned int sample_point_nominal, const unsigned int tseg, + unsigned int *tseg1_ptr, unsigned int *tseg2_ptr, + unsigned int *sample_point_error_ptr) +{ + unsigned int sample_point_error, best_sample_point_error = UINT_MAX; + unsigned int sample_point, best_sample_point = 0; + unsigned int tseg1, tseg2; + int i; + + for (i = 0; i <= 1; i++) { + tseg2 = tseg + CAN_SYNC_SEG - + (sample_point_nominal * (tseg + CAN_SYNC_SEG)) / + 1000 - i; + tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); + tseg1 = tseg - tseg2; + if (tseg1 > btc->tseg1_max) { + tseg1 = btc->tseg1_max; + tseg2 = tseg - tseg1; + } + + sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) / + (tseg + CAN_SYNC_SEG); + sample_point_error = abs(sample_point_nominal - sample_point); + + if (sample_point <= sample_point_nominal && + sample_point_error < best_sample_point_error) { + best_sample_point = sample_point; + best_sample_point_error = sample_point_error; + *tseg1_ptr = tseg1; + *tseg2_ptr = tseg2; + } + } + + if (sample_point_error_ptr) + *sample_point_error_ptr = best_sample_point_error; + + return best_sample_point; +} + +int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + struct can_priv *priv = netdev_priv(dev); + unsigned int bitrate; /* current bitrate */ + unsigned int bitrate_error; /* difference between current and nominal value */ + unsigned int best_bitrate_error = UINT_MAX; + unsigned int sample_point_error; /* difference between current and nominal value */ + unsigned int best_sample_point_error = UINT_MAX; + unsigned int sample_point_nominal; /* nominal sample point */ + unsigned int best_tseg = 0; /* current best value for tseg */ + unsigned int best_brp = 0; /* current best value for brp */ + unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; + u64 v64; + + /* Use CiA recommended sample points */ + if (bt->sample_point) { + sample_point_nominal = bt->sample_point; + } else { + if (bt->bitrate > 800 * KILO /* BPS */) + sample_point_nominal = 750; + else if (bt->bitrate > 500 * KILO /* BPS */) + sample_point_nominal = 800; + else + sample_point_nominal = 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 = CAN_SYNC_SEG + tseg / 2; + + /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ + brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; + + /* choose 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; + + bitrate = priv->clock.freq / (brp * tsegall); + bitrate_error = abs(bt->bitrate - bitrate); + + /* tseg brp biterror */ + if (bitrate_error > best_bitrate_error) + continue; + + /* reset sample point error if we have a better bitrate */ + if (bitrate_error < best_bitrate_error) + best_sample_point_error = UINT_MAX; + + can_update_sample_point(btc, sample_point_nominal, tseg / 2, + &tseg1, &tseg2, &sample_point_error); + if (sample_point_error >= best_sample_point_error) + continue; + + best_sample_point_error = sample_point_error; + best_bitrate_error = bitrate_error; + best_tseg = tseg / 2; + best_brp = brp; + + if (bitrate_error == 0 && sample_point_error == 0) + break; + } + + if (best_bitrate_error) { + /* Error in one-tenth of a percent */ + v64 = (u64)best_bitrate_error * 1000; + do_div(v64, bt->bitrate); + bitrate_error = (u32)v64; + if (bitrate_error > CAN_CALC_MAX_ERROR) { + netdev_err(dev, + "bitrate error %d.%d%% too high\n", + bitrate_error / 10, bitrate_error % 10); + return -EDOM; + } + netdev_warn(dev, "bitrate error %d.%d%%\n", + bitrate_error / 10, bitrate_error % 10); + } + + /* real sample point */ + bt->sample_point = can_update_sample_point(btc, sample_point_nominal, + best_tseg, &tseg1, &tseg2, + NULL); + + v64 = (u64)best_brp * 1000 * 1000 * 1000; + 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 bitrate */ + bt->bitrate = priv->clock.freq / + (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2)); + + return 0; +} + +/* Checks the validity of the specified bit-timing parameters prop_seg, + * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate + * prescaler value brp. You can find more information in the header + * file linux/can/netlink.h. + */ +static int can_fixup_bittiming(const struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) +{ + const struct can_priv *priv = netdev_priv(dev); + unsigned int tseg1, alltseg; + u64 brp64; + + tseg1 = bt->prop_seg + bt->phase_seg1; + if (!bt->sjw) + bt->sjw = 1; + if (bt->sjw > btc->sjw_max || + tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || + bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) + return -ERANGE; + + brp64 = (u64)priv->clock.freq * (u64)bt->tq; + if (btc->brp_inc > 1) + do_div(brp64, btc->brp_inc); + brp64 += 500000000UL - 1; + do_div(brp64, 1000000000UL); /* the practicable BRP */ + if (btc->brp_inc > 1) + brp64 *= btc->brp_inc; + bt->brp = (u32)brp64; + + if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) + return -EINVAL; + + alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; + bt->bitrate = priv->clock.freq / (bt->brp * alltseg); + bt->sample_point = ((tseg1 + 1) * 1000) / alltseg; + + return 0; +} diff --git a/can-calc-bit-timing.c b/calc-bit-timing/can-calc-bit-timing.c similarity index 74% rename from can-calc-bit-timing.c rename to calc-bit-timing/can-calc-bit-timing.c index dc2a62c..787a50f 100644 --- a/can-calc-bit-timing.c +++ b/calc-bit-timing/can-calc-bit-timing.c @@ -140,15 +140,25 @@ struct calc_bittiming_const { 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); +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); + }; + 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); + }; const char *name; }; struct calc_data { const struct can_bittiming_const *bittiming_const; - const struct can_calc_bittiming *calc_bittiming; + const struct alg *alg; const void (*printf_btr)(struct can_bittiming *bt, bool hdr); const char *name; @@ -163,6 +173,7 @@ struct calc_data { const struct can_bittiming *opt_bt; bool quiet; + bool fd_mode; }; static inline void *netdev_priv(const struct net_device *dev) @@ -400,8 +411,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, }, { .bittiming_const = { @@ -445,6 +456,7 @@ static const struct calc_bittiming_const can_calc_consts[] = { .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" }, }, @@ -473,8 +485,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, .printf_btr = printf_btr_mcp251xfd, }, { /* -------- USB -------- */ @@ -577,7 +589,7 @@ static const struct calc_bittiming_const can_calc_consts[] = { }, .ref_clk = { { .clk = 24000000, .name = "CANtact Pro (original)", }, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 40000000, .name = "CIA recommendation" }, }, }, { @@ -778,7 +790,7 @@ static const struct calc_bittiming_const can_calc_consts[] = { { .clk = 30000000, .name = "mx6" }, { .clk = 49875000, }, { .clk = 66000000, }, - { .clk = 66500000, .name = "mx25"}, + { .clk = 66500000, .name = "mx25" }, { .clk = 66666666, }, { .clk = 83368421, .name = "vybrid" }, }, @@ -807,8 +819,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, }, { @@ -856,8 +868,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, }, { .bittiming_const = { @@ -898,8 +910,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, }, { .bittiming_const = { @@ -945,8 +957,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, .printf_btr = printf_btr_mcan, }, { @@ -973,12 +985,15 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .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 = 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, }, { @@ -1104,8 +1119,8 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, }, }, { .bittiming_const = { @@ -1131,8 +1146,10 @@ static const struct calc_bittiming_const can_calc_consts[] = { .brp_inc = 1, }, .ref_clk = { - { .clk = 20000000, .name = "CIA recommendation"}, - { .clk = 40000000, .name = "CIA recommendation"}, + { .clk = 20000000, .name = "CIA recommendation" }, + { .clk = 40000000, .name = "CIA recommendation" }, + { .clk = 79999999, .name = "Versal ACAP" }, + { .clk = 80000000, .name = "Versal ACAP" }, }, }, }; @@ -1140,11 +1157,14 @@ static const struct calc_bittiming_const can_calc_consts[] = { static const unsigned int common_bitrates[] = { 1000000, 800000, + 666666, 500000, 250000, 125000, 100000, + 83333, 50000, + 33333, 20000, 10000, 0 @@ -1163,356 +1183,75 @@ static const unsigned int common_data_bitrates[] = { #define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */ #define CAN_CALC_SYNC_SEG 1 +#define CAN_SYNC_SEG 1 +#define CAN_KBPS 1000 +#define KILO 1000UL -/* - * Bit-timing calculation derived from: - * - * 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 - * - * Calculates proper bit-timing parameters for a specified bit-rate - * and sample-point, which can then be used to set the bit-timing - * 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 +#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 -#define can_calc_bittiming can_calc_bittiming_v3_18 +#undef can_calc_bittiming +#undef can_fixup_bittiming + #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 - */ +#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 -#define can_update_spt can_update_spt_v4_8 +#undef can_fixup_bittiming + +#define can_update_sample_point can_update_sample_point_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, - unsigned int *spt_error_ptr) -{ - unsigned int spt_error, best_spt_error = UINT_MAX; - unsigned int spt, best_spt = 0; - unsigned int tseg1, tseg2; - int i; - - for (i = 0; i <= 1; i++) { - tseg2 = tseg + CAN_CALC_SYNC_SEG - (spt_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i; - tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max); - tseg1 = tseg - tseg2; - if (tseg1 > btc->tseg1_max) { - tseg1 = btc->tseg1_max; - tseg2 = tseg - tseg1; - } - - spt = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG); - spt_error = abs(spt_nominal - spt); - - if ((spt <= spt_nominal) && (spt_error < best_spt_error)) { - best_spt = spt; - best_spt_error = spt_error; - *tseg1_ptr = tseg1; - *tseg2_ptr = tseg2; - } - } - - if (spt_error_ptr) - *spt_error_ptr = best_spt_error; - - return best_spt; -} - -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); - unsigned int rate; /* current bitrate */ - unsigned int rate_error; /* difference between current and nominal value */ - unsigned int best_rate_error = UINT_MAX; - unsigned int spt_error; /* difference between current and nominal value */ - unsigned int best_spt_error = UINT_MAX; - unsigned int spt_nominal; /* nominal sample point */ - unsigned int best_tseg = 0; /* current best value for tseg */ - unsigned int best_brp = 0; /* current best value for brp */ - unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0; - u64 v64; - - /* Use CiA recommended sample points */ - if (bt->sample_point) { - spt_nominal = bt->sample_point; - } else { - if (bt->bitrate > 800000) - spt_nominal = 750; - else if (bt->bitrate > 500000) - spt_nominal = 800; - else - spt_nominal = 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 = CAN_CALC_SYNC_SEG + tseg / 2; - - /* Compute all possible tseg choices (tseg=tseg1+tseg2) */ - brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2; - - /* choose 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); - rate_error = abs(bt->bitrate - rate); - - /* tseg brp biterror */ - if (rate_error > best_rate_error) - continue; - - /* reset sample point error if we have a better bitrate */ - if (rate_error < best_rate_error) - best_spt_error = UINT_MAX; - - can_update_spt(btc, spt_nominal, tseg / 2, &tseg1, &tseg2, &spt_error); - if (spt_error > best_spt_error) - continue; - - best_spt_error = spt_error; - best_rate_error = rate_error; - best_tseg = tseg / 2; - best_brp = brp; - - if (rate_error == 0 && spt_error == 0) - break; - } - - if (best_rate_error) { - /* Error in one-tenth of a percent */ - rate_error = (best_rate_error * 1000) / bt->bitrate; - if (rate_error > CAN_CALC_MAX_ERROR) { - netdev_err(dev, - "bitrate error %ld.%ld%% too high\n", - rate_error / 10, rate_error % 10); - return -EDOM; - } - netdev_warn(dev, "bitrate error %ld.%ld%%\n", - rate_error / 10, rate_error % 10); - } - - /* real sample point */ - bt->sample_point = can_update_spt(btc, spt_nominal, best_tseg, - &tseg1, &tseg2, NULL); - - v64 = (u64)best_brp * 1000 * 1000 * 1000; - 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 * (CAN_CALC_SYNC_SEG + tseg1 + tseg2)); - - return 0; -} - +#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_update_spt +#undef can_fixup_bittiming -static const struct can_calc_bittiming calc_bittiming_list[] = { +#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 + +static const struct alg alg_list[] = { /* 1st will be default */ { - .alg = can_calc_bittiming_v4_8, + .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", }, { - .alg = can_calc_bittiming_v3_18, + .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 int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, - const struct can_bittiming_const *btc) -{ - struct can_priv *priv = netdev_priv(dev); - unsigned int tseg1, alltseg; - u64 brp64, v64; - - tseg1 = bt->prop_seg + bt->phase_seg1; - if (!bt->sjw) - bt->sjw = 1; - if (bt->sjw > btc->sjw_max || - tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max || - bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max) - return -ERANGE; - - if (!bt->brp) { - brp64 = (u64)priv->clock.freq * (u64)bt->tq; - if (btc->brp_inc > 1) - do_div(brp64, btc->brp_inc); - brp64 += 500000000UL - 1; - do_div(brp64, 1000000000UL); /* the practicable BRP */ - if (btc->brp_inc > 1) - brp64 *= btc->brp_inc; - bt->brp = brp64; - } - - v64 = bt->brp * 1000 * 1000 * 1000; - do_div(v64, priv->clock.freq); - bt->tq = v64; - - if (bt->brp < btc->brp_min || bt->brp > btc->brp_max) - return -EINVAL; - - alltseg = CAN_CALC_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2; - bt->bitrate = priv->clock.freq / (bt->brp * alltseg); - bt->sample_point = ((CAN_CALC_SYNC_SEG + tseg1) * 1000) / alltseg; - - return 0; -} - static __u32 get_cia_sample_point(__u32 bitrate) { __u32 sampl_pt; @@ -1527,14 +1266,15 @@ static __u32 get_cia_sample_point(__u32 bitrate) return sampl_pt; } -static void print_bittiming_one(const struct can_calc_bittiming *calc_bittiming, +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 quiet, + bool fd_mode) { struct net_device dev = { .priv.clock.freq = ref_clk->clk, @@ -1546,15 +1286,16 @@ static void print_bittiming_one(const struct can_calc_bittiming *calc_bittiming, unsigned int bitrate_error, sample_point_error; if (!quiet) { - printf("Bit timing parameters for %s with %.6f MHz ref clock %s%s%susing algo '%s'\n" + printf("%sBit 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 ", + fd_mode ? "Data " : "", bittiming_const->name, ref_clk->clk / 1000000.0, ref_clk->name ? "(" : "", ref_clk->name ? ref_clk->name : "", ref_clk->name ? ") " : "", - calc_bittiming->name); + alg->name); printf_btr(&bt, true); printf("\n"); @@ -1563,12 +1304,12 @@ static void print_bittiming_one(const struct can_calc_bittiming *calc_bittiming, if (ref_bt) { bt = *ref_bt; - if (can_fixup_bittiming(&dev, &bt, bittiming_const)) { + if (alg->fixup_bittiming(&dev, &bt, bittiming_const)) { printf("%8d ***parameters exceed controller's range***\n", bitrate_nominal); return; } } else { - if (calc_bittiming->alg(&dev, &bt, bittiming_const)) { + if (alg->calc_bittiming(&dev, &bt, bittiming_const)) { printf("%8d ***bitrate not possible***\n", bitrate_nominal); return; } @@ -1633,14 +1374,15 @@ static void print_bittiming(const struct calc_data *data) else sample_point = get_cia_sample_point(*bitrates); - print_bittiming_one(data->calc_bittiming, + print_bittiming_one(data->alg, data->bittiming_const, data->opt_bt, ref_clks, *bitrates, sample_point, printf_btr, - quiet); + quiet, + data->fd_mode); bitrates++; quiet = true; } @@ -1654,8 +1396,8 @@ 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); + for (i = 0; i < ARRAY_SIZE(alg_list); i++) + printf(" %s\n", alg_list[i].name); } static void do_list(void) @@ -1697,6 +1439,8 @@ static void do_calc(struct calc_data *data) else data->bitrates = common_bitrates; + data->fd_mode = false; + print_bittiming(data); } @@ -1720,6 +1464,8 @@ static void do_calc(struct calc_data *data) else data->bitrates = common_data_bitrates; + data->fd_mode = true; + print_bittiming(data); } } @@ -1748,7 +1494,7 @@ int main(int argc, char *argv[]) }; struct calc_data data[] = { { - .calc_bittiming = calc_bittiming_list, + .alg = alg_list, } }; const char *opt_alg_name = NULL; @@ -1873,9 +1619,9 @@ int main(int argc, char *argv[]) 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]; + 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; } }