Add support for esd CAN-USB/3 and CAN FD to esd_usb. Signed-off-by: Frank Jungclaus <frank.jungclaus@xxxxxx> --- drivers/net/can/usb/esd_usb.c | 282 ++++++++++++++++++++++++++++++---- 1 file changed, 249 insertions(+), 33 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index e24fa48b9b42..48cf5e88d216 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro + * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro * * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@xxxxxx> * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@xxxxxx> @@ -18,17 +18,19 @@ MODULE_AUTHOR("Matthias Fuchs <socketcan@xxxxxx>"); MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@xxxxxx>"); -MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces"); +MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces"); MODULE_LICENSE("GPL v2"); /* USB vendor and product ID */ #define USB_ESDGMBH_VENDOR_ID 0x0ab4 #define USB_CANUSB2_PRODUCT_ID 0x0010 #define USB_CANUSBM_PRODUCT_ID 0x0011 +#define USB_CANUSB3_PRODUCT_ID 0x0014 /* CAN controller clock frequencies */ #define ESD_USB2_CAN_CLOCK 60000000 #define ESD_USBM_CAN_CLOCK 36000000 +#define ESD_USB3_CAN_CLOCK 80000000 /* Maximum number of CAN nets */ #define ESD_USB_MAX_NETS 2 @@ -43,6 +45,9 @@ MODULE_LICENSE("GPL v2"); /* esd CAN message flags - dlc field */ #define ESD_DLC_RTR 0x10 +#define ESD_DLC_NO_BRS 0x10 +#define ESD_DLC_ESI 0x20 +#define ESD_DLC_FD 0x80 /* esd CAN message flags - id field */ #define ESD_EXTID 0x20000000 @@ -72,6 +77,28 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB2_BRP_INC 1 #define ESD_USB2_3_SAMPLES 0x00800000 +/* Bit timing CAN-USB/3 */ +#define ESD_USB3_TSEG1_MIN 1 +#define ESD_USB3_TSEG1_MAX 256 +#define ESD_USB3_TSEG2_MIN 1 +#define ESD_USB3_TSEG2_MAX 128 +#define ESD_USB3_SJW_MAX 128 +#define ESD_USB3_BRP_MIN 1 +#define ESD_USB3_BRP_MAX 1024 +#define ESD_USB3_BRP_INC 1 +/* Bit timing CAN-USB/3, data phase */ +#define ESD_USB3_DATA_TSEG1_MIN 1 +#define ESD_USB3_DATA_TSEG1_MAX 32 +#define ESD_USB3_DATA_TSEG2_MIN 1 +#define ESD_USB3_DATA_TSEG2_MAX 16 +#define ESD_USB3_DATA_SJW_MAX 8 +#define ESD_USB3_DATA_BRP_MIN 1 +#define ESD_USB3_DATA_BRP_MAX 32 +#define ESD_USB3_DATA_BRP_INC 1 + +/* Transmitter Delay Compensation */ +#define ESD_TDC_MODE_AUTO 0 + /* esd IDADD message */ #define ESD_ID_ENABLE 0x80 #define ESD_MAX_ID_SEGMENT 64 @@ -95,6 +122,21 @@ MODULE_LICENSE("GPL v2"); #define MAX_RX_URBS 4 #define MAX_TX_URBS 16 /* must be power of 2 */ +/* Modes for NTCAN_BAUDRATE_X */ +#define ESD_BAUDRATE_MODE_DISABLE 0 /* remove from bus */ +#define ESD_BAUDRATE_MODE_INDEX 1 /* ESD (CiA) bit rate idx */ +#define ESD_BAUDRATE_MODE_BTR_CTRL 2 /* BTR values (Controller)*/ +#define ESD_BAUDRATE_MODE_BTR_CANONICAL 3 /* BTR values (Canonical) */ +#define ESD_BAUDRATE_MODE_NUM 4 /* numerical bit rate */ +#define ESD_BAUDRATE_MODE_AUTOBAUD 5 /* autobaud */ + +/* Flags for NTCAN_BAUDRATE_X */ +#define ESD_BAUDRATE_FLAG_FD 0x0001 /* enable CAN FD Mode */ +#define ESD_BAUDRATE_FLAG_LOM 0x0002 /* enable Listen Only mode */ +#define ESD_BAUDRATE_FLAG_STM 0x0004 /* enable Self test mode */ +#define ESD_BAUDRATE_FLAG_TRS 0x0008 /* enable Triple Sampling */ +#define ESD_BAUDRATE_FLAG_TXP 0x0010 /* enable Transmit Pause */ + struct header_msg { u8 len; /* len is always the total message length in 32bit words */ u8 cmd; @@ -129,6 +171,7 @@ struct rx_msg { __le32 id; /* upper 3 bits contain flags */ union { u8 data[8]; + u8 data_fd[64]; struct { u8 status; /* CAN Controller Status */ u8 ecc; /* Error Capture Register */ @@ -144,8 +187,11 @@ struct tx_msg { u8 net; u8 dlc; u32 hnd; /* opaque handle, not used by device */ - __le32 id; /* upper 3 bits contain flags */ - u8 data[8]; + __le32 id; /* upper 3 bits contain flags */ + union { + u8 data[8]; + u8 data_fd[64]; + }; }; struct tx_done_msg { @@ -165,12 +211,37 @@ struct id_filter_msg { __le32 mask[ESD_MAX_ID_SEGMENT + 1]; }; +struct baudrate_x_cfg { + __le16 brp; /* bit rate pre-scaler */ + __le16 tseg1; /* TSEG1 register */ + __le16 tseg2; /* TSEG2 register */ + __le16 sjw; /* SJW register */ +}; + +struct tdc_cfg { + u8 tdc_mode; /* transmitter Delay Compensation mode */ + u8 ssp_offset; /* secondary Sample Point offset in mtq */ + s8 ssp_shift; /* secondary Sample Point shift in mtq */ + u8 tdc_filter; /* Transmitter Delay Compensation */ +}; + +struct baudrate_x { + __le16 mode; /* mode word */ + __le16 flags; /* control flags */ + struct tdc_cfg tdc; /* TDC configuration */ + struct baudrate_x_cfg arb; /* bit rate during arbitration phase */ + struct baudrate_x_cfg data; /* bit rate during data phase */ +}; + struct set_baudrate_msg { u8 len; u8 cmd; u8 net; u8 rsvd; - __le32 baud; + union { + __le32 baud; + struct baudrate_x baud_x; + }; }; /* Main message type used between library and application */ @@ -188,6 +259,7 @@ union __packed esd_usb_msg { static struct usb_device_id esd_usb_table[] = { {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, + {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)}, {} }; MODULE_DEVICE_TABLE(usb, esd_usb_table); @@ -326,11 +398,13 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, union esd_usb_msg *msg) { + bool is_canfd = msg->rx.dlc & ESD_DLC_FD ? true : false; struct net_device_stats *stats = &priv->netdev->stats; struct can_frame *cf; + struct canfd_frame *cfd; struct sk_buff *skb; - int i; u32 id; + u8 len; if (!netif_device_present(priv->netdev)) return; @@ -340,27 +414,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, if (id & ESD_EVENT) { esd_usb_rx_event(priv, msg); } else { - skb = alloc_can_skb(priv->netdev, &cf); + if (is_canfd) { + skb = alloc_canfd_skb(priv->netdev, &cfd); + } else { + skb = alloc_can_skb(priv->netdev, &cf); + cfd = (struct canfd_frame *)cf; + } + if (skb == NULL) { stats->rx_dropped++; return; } - cf->can_id = id & ESD_IDMASK; - can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, - priv->can.ctrlmode); - - if (id & ESD_EXTID) - cf->can_id |= CAN_EFF_FLAG; + cfd->can_id = id & ESD_IDMASK; - if (msg->rx.dlc & ESD_DLC_RTR) { - cf->can_id |= CAN_RTR_FLAG; + if (is_canfd) { + /* masking by 0x0F is already done within can_fd_dlc2len() */ + cfd->len = can_fd_dlc2len(msg->rx.dlc); + len = cfd->len; + if ((msg->rx.dlc & ESD_DLC_NO_BRS) == 0) + cfd->flags |= CANFD_BRS; + if (msg->rx.dlc & ESD_DLC_ESI) + cfd->flags |= CANFD_ESI; } else { - for (i = 0; i < cf->len; i++) - cf->data[i] = msg->rx.data[i]; - - stats->rx_bytes += cf->len; + can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, priv->can.ctrlmode); + len = cf->len; + if (msg->rx.dlc & ESD_DLC_RTR) { + cf->can_id |= CAN_RTR_FLAG; + len = 0; + } } + + if (id & ESD_EXTID) + cfd->can_id |= CAN_EFF_FLAG; + + memcpy(cfd->data, msg->rx.data_fd, len); + stats->rx_bytes += len; stats->rx_packets++; netif_rx(skb); @@ -735,7 +824,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, struct esd_usb *dev = priv->usb; struct esd_tx_urb_context *context = NULL; struct net_device_stats *stats = &netdev->stats; - struct can_frame *cf = (struct can_frame *)skb->data; + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; union esd_usb_msg *msg; struct urb *urb; u8 *buf; @@ -768,19 +857,28 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg->hdr.len = 3; /* minimal length */ msg->hdr.cmd = CMD_CAN_TX; msg->tx.net = priv->index; - msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); - msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); - if (cf->can_id & CAN_RTR_FLAG) - msg->tx.dlc |= ESD_DLC_RTR; + if (can_is_canfd_skb(skb)) { + msg->tx.dlc = can_fd_len2dlc(cfd->len); + msg->tx.dlc |= ESD_DLC_FD; + + if ((cfd->flags & CANFD_BRS) == 0) + msg->tx.dlc |= ESD_DLC_NO_BRS; + } else { + msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode); + + if (cfd->can_id & CAN_RTR_FLAG) + msg->tx.dlc |= ESD_DLC_RTR; + } - if (cf->can_id & CAN_EFF_FLAG) + msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK); + + if (cfd->can_id & CAN_EFF_FLAG) msg->tx.id |= cpu_to_le32(ESD_EXTID); - for (i = 0; i < cf->len; i++) - msg->tx.data[i] = cf->data[i]; + memcpy(msg->tx.data_fd, cfd->data, cfd->len); - msg->hdr.len += (cf->len + 3) >> 2; + msg->hdr.len += (cfd->len + 3) >> 2; for (i = 0; i < MAX_TX_URBS; i++) { if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { @@ -966,6 +1064,108 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) return err; } +static const struct can_bittiming_const esd_usb3_bittiming_const = { + .name = "esd_usb3", + .tseg1_min = ESD_USB3_TSEG1_MIN, + .tseg1_max = ESD_USB3_TSEG1_MAX, + .tseg2_min = ESD_USB3_TSEG2_MIN, + .tseg2_max = ESD_USB3_TSEG2_MAX, + .sjw_max = ESD_USB3_SJW_MAX, + .brp_min = ESD_USB3_BRP_MIN, + .brp_max = ESD_USB3_BRP_MAX, + .brp_inc = ESD_USB3_BRP_INC, +}; + +static const struct can_bittiming_const esd_usb3_data_bittiming_const = { + .name = "esd_usb3", + .tseg1_min = ESD_USB3_DATA_TSEG1_MIN, + .tseg1_max = ESD_USB3_DATA_TSEG1_MAX, + .tseg2_min = ESD_USB3_DATA_TSEG2_MIN, + .tseg2_max = ESD_USB3_DATA_TSEG2_MAX, + .sjw_max = ESD_USB3_DATA_SJW_MAX, + .brp_min = ESD_USB3_DATA_BRP_MIN, + .brp_max = ESD_USB3_DATA_BRP_MAX, + .brp_inc = ESD_USB3_DATA_BRP_INC, +}; + +static int esd_usb3_set_bittiming(struct net_device *netdev) +{ + struct esd_usb_net_priv *priv = netdev_priv(netdev); + struct can_bittiming *bt = &priv->can.bittiming; + struct can_bittiming *d_bt = &priv->can.data_bittiming; + union esd_usb_msg *msg; + int err; + u16 mode; + u16 flags = 0; + u16 brp, tseg1, tseg2, sjw; + u16 d_brp, d_tseg1, d_tseg2, d_sjw; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */ + mode = ESD_BAUDRATE_MODE_BTR_CANONICAL; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + flags |= ESD_BAUDRATE_FLAG_LOM; + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + flags |= ESD_BAUDRATE_FLAG_TRS; + + brp = bt->brp & (ESD_USB3_BRP_MAX - 1); + sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1); + tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1); + tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1); + + msg->setbaud.baud_x.arb.brp = cpu_to_le16(brp); + msg->setbaud.baud_x.arb.sjw = cpu_to_le16(sjw); + msg->setbaud.baud_x.arb.tseg1 = cpu_to_le16(tseg1); + msg->setbaud.baud_x.arb.tseg2 = cpu_to_le16(tseg2); + + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { + d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1); + d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1); + d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1); + d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1); + flags |= ESD_BAUDRATE_FLAG_FD; + } else { + d_brp = 0; + d_sjw = 0; + d_tseg1 = 0; + d_tseg2 = 0; + } + + msg->setbaud.baud_x.data.brp = cpu_to_le16(d_brp); + msg->setbaud.baud_x.data.sjw = cpu_to_le16(d_sjw); + msg->setbaud.baud_x.data.tseg1 = cpu_to_le16(d_tseg1); + msg->setbaud.baud_x.data.tseg2 = cpu_to_le16(d_tseg2); + msg->setbaud.baud_x.mode = cpu_to_le16(mode); + msg->setbaud.baud_x.flags = cpu_to_le16(flags); + msg->setbaud.baud_x.tdc.tdc_mode = ESD_TDC_MODE_AUTO; + msg->setbaud.baud_x.tdc.ssp_offset = 0; + msg->setbaud.baud_x.tdc.ssp_shift = 0; + msg->setbaud.baud_x.tdc.tdc_filter = 0; + + msg->hdr.len = 7; + msg->hdr.cmd = CMD_SETBAUD; + + msg->setbaud.net = priv->index; + msg->setbaud.rsvd = 0; + + netdev_info(netdev, + "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flg=%#x, arb: brp=%u, ts1=%u, ts2=%u, sjw=%u, data: dbrp=%u, dts1=%u, dts2=%u dsjw=%u\n", + priv->can.ctrlmode, priv->can.ctrlmode_supported, + priv->index, mode, flags, + brp, tseg1, tseg2, sjw, + d_brp, d_tseg1, d_tseg2, d_sjw); + + err = esd_usb_send_msg(priv->usb, msg); + + kfree(msg); + return err; +} + static int esd_usb_get_berr_counter(const struct net_device *netdev, struct can_berr_counter *bec) { @@ -1023,16 +1223,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) CAN_CTRLMODE_CC_LEN8_DLC | CAN_CTRLMODE_BERR_REPORTING; - if (le16_to_cpu(dev->udev->descriptor.idProduct) == - USB_CANUSBM_PRODUCT_ID) + switch (le16_to_cpu(dev->udev->descriptor.idProduct)) { + case USB_CANUSB3_PRODUCT_ID: + priv->can.clock.freq = ESD_USB3_CAN_CLOCK; + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; + priv->can.bittiming_const = &esd_usb3_bittiming_const; + priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const; + priv->can.do_set_bittiming = esd_usb3_set_bittiming; + priv->can.do_set_data_bittiming = esd_usb3_set_bittiming; + break; + + case USB_CANUSBM_PRODUCT_ID: priv->can.clock.freq = ESD_USBM_CAN_CLOCK; - else { + priv->can.bittiming_const = &esd_usb2_bittiming_const; + priv->can.do_set_bittiming = esd_usb2_set_bittiming; + break; + + case USB_CANUSB2_PRODUCT_ID: + default: priv->can.clock.freq = ESD_USB2_CAN_CLOCK; priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + priv->can.bittiming_const = &esd_usb2_bittiming_const; + priv->can.do_set_bittiming = esd_usb2_set_bittiming; + break; } - priv->can.bittiming_const = &esd_usb2_bittiming_const; - priv->can.do_set_bittiming = esd_usb2_set_bittiming; priv->can.do_set_mode = esd_usb_set_mode; priv->can.do_get_berr_counter = esd_usb_get_berr_counter; -- 2.25.1