On 4/19/19 7:14 AM, kernel@xxxxxxxxxxxxxxxx wrote: > From: Martin Sperl <kernel@xxxxxxxxxxxxxxxx> > > Add un-optimized Can2.0 and CanFD support. > > CAN-Transmission and Optimizations and are separate patches > > On a Rasperry pi 3 it is already able to process Can2.0 Frames > with DLC=0 on a CAN bus with 1MHz. without losing any packets > on the SPI side. Packets still get lost inside the network stack. > > Signed-off-by: Martin Sperl <kernel@xxxxxxxxxxxxxxxx> [..] > diff --git a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c > index f98b02ff057b..eabd7ca50645 100644 > --- a/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c > +++ b/drivers/net/can/spi/mcp25xxfd/mcp25xxfd_can.c > @@ -38,23 +38,162 @@ > * for timestamping of RX frames as well as for TEF entries. > */ > > -/* Implementation notes: > - * > - * Right now we only use the CAN controller block to put us into deep sleep > - * this means that the oscillator clock is turned off. > - * So this is the only thing that we implement here right now > - */ > - > +#include <linux/can/core.h> > +#include <linux/can/dev.h> > #include <linux/device.h> > +#include <linux/interrupt.h> > #include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/regulator/consumer.h> > #include <linux/spi/spi.h> > > +#include "mcp25xxfd_base.h" > +#include "mcp25xxfd_can_debugfs.h" > +#include "mcp25xxfd_can_fifo.h" > +#include "mcp25xxfd_can_int.h" > +#include "mcp25xxfd_can_priv.h" > #include "mcp25xxfd_clock.h" > #include "mcp25xxfd_cmd.h" > +#include "mcp25xxfd_int.h" > #include "mcp25xxfd_priv.h" > #include "mcp25xxfd_regs.h" > > -static int mcp25xxfd_can_get_mode(struct mcp25xxfd_priv *priv, u32 *reg) > +#include <uapi/linux/can/netlink.h> > + > +/* module parameters */ > +unsigned int bw_sharing_log2bits; > +module_param(bw_sharing_log2bits, uint, 0664); > +MODULE_PARM_DESC(bw_sharing_log2bits, > + "Delay between 2 transmissions in number of arbitration bit times\n"); > +bool enable_edge_filter; > +module_param(enable_edge_filter, bool, 0664); > +MODULE_PARM_DESC(enable_edge_filter, > + "Enable ISO11898-1:2015 edge_filtering"); > +unsigned int tdc_mode = 2; > +module_param(tdc_mode, uint, 0664); > +MODULE_PARM_DESC(tdc_mode, > + "Transmitter Delay Mode - 0 = disabled, 1 = fixed, 2 = auto\n"); > +unsigned int tdc_value; > +module_param(tdc_value, uint, 0664); > +MODULE_PARM_DESC(tdc_value, > + "Transmission Delay Value - range: [0:63] SCLK"); > +int tdc_offset = 64; /* outside of range to use computed values */ > +module_param(tdc_offset, int, 0664); > +MODULE_PARM_DESC(tdc_offset, > + "Transmission Delay offset - range: [-64:63] SCLK"); > + > +/* everything related to bit timing */ > +static > +const struct can_bittiming_const mcp25xxfd_can_nominal_bittiming_const = { > + .name = DEVICE_NAME, > + .tseg1_min = 2, > + .tseg1_max = BIT(MCP25XXFD_CAN_NBTCFG_TSEG1_BITS), > + .tseg2_min = 1, > + .tseg2_max = BIT(MCP25XXFD_CAN_NBTCFG_TSEG2_BITS), > + .sjw_max = BIT(MCP25XXFD_CAN_NBTCFG_SJW_BITS), > + .brp_min = 1, > + .brp_max = BIT(MCP25XXFD_CAN_NBTCFG_BRP_BITS), > + .brp_inc = 1, > +}; > + > +static > +const struct can_bittiming_const mcp25xxfd_can_data_bittiming_const = { > + .name = DEVICE_NAME, > + .tseg1_min = 1, > + .tseg1_max = BIT(MCP25XXFD_CAN_DBTCFG_TSEG1_BITS), > + .tseg2_min = 1, > + .tseg2_max = BIT(MCP25XXFD_CAN_DBTCFG_TSEG2_BITS), > + .sjw_max = BIT(MCP25XXFD_CAN_DBTCFG_SJW_BITS), > + .brp_min = 1, > + .brp_max = BIT(MCP25XXFD_CAN_DBTCFG_BRP_BITS), > + .brp_inc = 1, > +}; > + > +static int mcp25xxfd_can_do_set_nominal_bittiming(struct net_device *net) > +{ > + struct mcp25xxfd_can_priv *cpriv = netdev_priv(net); > + struct can_bittiming *bt = &cpriv->can.bittiming; > + > + int sjw = bt->sjw; > + int pseg2 = bt->phase_seg2; > + int pseg1 = bt->phase_seg1; > + int propseg = bt->prop_seg; > + int brp = bt->brp; > + > + int tseg1 = propseg + pseg1; > + int tseg2 = pseg2; > + > + /* calculate nominal bit timing */ > + cpriv->regs.nbtcfg = ((sjw - 1) << MCP25XXFD_CAN_NBTCFG_SJW_SHIFT) | > + ((tseg2 - 1) << MCP25XXFD_CAN_NBTCFG_TSEG2_SHIFT) | > + ((tseg1 - 1) << MCP25XXFD_CAN_NBTCFG_TSEG1_SHIFT) | > + ((brp - 1) << MCP25XXFD_CAN_NBTCFG_BRP_SHIFT); > + > + return mcp25xxfd_cmd_write(cpriv->priv->spi, MCP25XXFD_CAN_NBTCFG, > + cpriv->regs.nbtcfg); > +} > + > +static int mcp25xxfd_can_do_set_data_bittiming(struct net_device *net) > +{ > + struct mcp25xxfd_can_priv *cpriv = netdev_priv(net); > + struct mcp25xxfd_priv *priv = cpriv->priv; > + struct can_bittiming *bt = &cpriv->can.data_bittiming; > + struct spi_device *spi = priv->spi; > + > + int sjw = bt->sjw; > + int pseg2 = bt->phase_seg2; > + int pseg1 = bt->phase_seg1; > + int propseg = bt->prop_seg; > + int brp = bt->brp; > + > + int tseg1 = propseg + pseg1; > + int tseg2 = pseg2; > + > + int tdco; > + int ret; > + > + /* set up Transmitter delay compensation */ > + cpriv->regs.tdc = 0; > + /* configure TDC mode */ > + if (tdc_mode < 4) > + cpriv->regs.tdc = tdc_mode << MCP25XXFD_CAN_TDC_TDCMOD_SHIFT; > + else > + cpriv->regs.tdc = MCP25XXFD_CAN_TDC_TDCMOD_AUTO << > + MCP25XXFD_CAN_TDC_TDCMOD_SHIFT; > + > + /* configure TDC offsets */ > + if ((tdc_offset >= -64) && tdc_offset < 64) > + tdco = tdc_offset; > + else > + tdco = clamp_t(int, bt->brp * tseg1, -64, 63); > + cpriv->regs.tdc |= (tdco << MCP25XXFD_CAN_TDC_TDCO_SHIFT) & > + MCP25XXFD_CAN_TDC_TDCO_MASK; > + > + /* configure TDC value */ > + if (tdc_value < 64) > + cpriv->regs.tdc |= tdc_value << MCP25XXFD_CAN_TDC_TDCV_SHIFT; > + > + /* enable edge filtering */ > + if (enable_edge_filter) > + cpriv->regs.tdc |= MCP25XXFD_CAN_TDC_EDGFLTEN; > + > + /* set TDC */ > + ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_CAN_TDC, cpriv->regs.tdc); > + if (ret) > + return ret; > + > + /* calculate data bit timing */ > + cpriv->regs.dbtcfg = ((sjw - 1) << MCP25XXFD_CAN_DBTCFG_SJW_SHIFT) | > + ((tseg2 - 1) << MCP25XXFD_CAN_DBTCFG_TSEG2_SHIFT) | > + ((tseg1 - 1) << MCP25XXFD_CAN_DBTCFG_TSEG1_SHIFT) | > + ((brp - 1) << MCP25XXFD_CAN_DBTCFG_BRP_SHIFT); > + > + return mcp25xxfd_cmd_write(spi, MCP25XXFD_CAN_DBTCFG, > + cpriv->regs.dbtcfg); > +} > + > +int mcp25xxfd_can_get_mode(struct mcp25xxfd_priv *priv, u32 *reg) > { > int ret; > > @@ -66,11 +205,11 @@ static int mcp25xxfd_can_get_mode(struct mcp25xxfd_priv *priv, u32 *reg) > MCP25XXFD_CAN_CON_OPMOD_SHIFT; > } > > -static int mcp25xxfd_can_switch_mode(struct mcp25xxfd_priv *priv, > - u32 *reg, int mode) > +int mcp25xxfd_can_switch_mode_no_wait(struct mcp25xxfd_priv *priv, > + u32 *reg, int mode) > { > u32 dummy; > - int ret, i; > + int ret; > > /* get the current mode/register - if reg is NULL > * when the can controller is not setup yet > @@ -78,9 +217,11 @@ static int mcp25xxfd_can_switch_mode(struct mcp25xxfd_priv *priv, > * (this only happens during initialization phase) > */ > if (reg) { > - ret = mcp25xxfd_can_get_mode(priv, reg); > - if (ret < 0) > - return ret; > + if (!reg) { > + ret = mcp25xxfd_can_get_mode(priv, reg); > + if (ret < 0) > + return ret; > + } After this patch the function reads: > static int mcp25xxfd_can_switch_mode_no_wait(struct mcp25xxfd_priv *priv, > u32 *reg, int mode) > { > u32 dummy; > int ret; > > /* get the current mode/register - if reg is NULL > * when the can controller is not setup yet > * typically by calling mcp25xxfd_can_sleep_mode > * (this only happens during initialization phase) > */ > if (reg) { > if (!reg) { This looks wrong. > ret = mcp25xxfd_can_get_mode(priv, reg); > if (ret < 0) > return ret; > } > } else { > /* alternatively use dummy */ > dummy = 0; > reg = &dummy; > } > Marc -- Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Attachment:
signature.asc
Description: OpenPGP digital signature