Module: xenomai-3 Branch: master Commit: 02bc0b1bc778e6262933ab8377298c3b6d7781ee URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=02bc0b1bc778e6262933ab8377298c3b6d7781ee
Author: Philippe Gerum <r...@xenomai.org> Date: Tue Sep 8 20:42:47 2015 +0200 drivers/can: merge assorted CAN fixes from 2.6.x commit a7b94fc631816e64988f32247edc788e7c70efd1 Author: Matthew Lindner <mlind...@daifukuwebb.com> Date: Mon Oct 20 17:24:45 2014 -0400 drivers/can: Properly initialize bittime commit 7fcc04ce4bca162bc3367c4f04b8bd96edc02ca9 Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org> Date: Wed Jan 29 12:57:24 2014 +0100 drivers/flexcan: avoid unaligned access commit 34c5ec7a704115cd84530ee36c540b981f1fef4e Author: Henri Roosen <henriroo...@gmail.com> Date: Tue May 28 13:14:09 2013 +0200 Fix rtcan_flexcan for mx6 for OpenFirmware platforms The default rx fifo global mask register, newly introduced in mx6q, is 0xffffffff and the reset value in Message buffers(can be reused as the memory of rx fifo filter table) is none zero, it will wrongly cause the can to be unable to recevie packets due to filter. We need to clear it to make sure to receive all packets. Signed-off-by: Henri Roosen <henriroo...@gmail.com> Acked-by: Wolfgang Grandegger <w...@grandegger.com> commit e7fb1d155969a6cf3194e1a7b5257e5375b328f0 Author: Henri Roosen <henriroo...@gmail.com> Date: Tue May 28 13:14:09 2013 +0200 make rtcan_flexcan driver compatible with non OpenFirmware platforms This also fixes the rx fifo global mask for mx6: The default rx fifo global mask register, newly introduced in mx6q, is 0xffffffff and the reset value in Message buffers(can be reused as the memory of rx fifo filter table) is none zero, it will wrongly cause the can to be unable to recevie packets due to filter. We need to clear it to make sure to receive all packets. Signed-off-by: Henri Roosen <henriroo...@gmail.com> Acked-by: Wolfgang Grandegger <w...@grandegger.com> --- kernel/drivers/can/rtcan_flexcan.c | 141 +++++++++++++++++++++++++----------- kernel/drivers/can/rtcan_raw.c | 39 ++++------ kernel/drivers/can/rtcan_raw_dev.c | 1 + 3 files changed, 113 insertions(+), 68 deletions(-) diff --git a/kernel/drivers/can/rtcan_flexcan.c b/kernel/drivers/can/rtcan_flexcan.c index 1290118..adfbef8 100644 --- a/kernel/drivers/can/rtcan_flexcan.c +++ b/kernel/drivers/can/rtcan_flexcan.c @@ -30,9 +30,11 @@ #include <linux/module.h> #include <linux/version.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pinctrl/consumer.h> #include <linux/regulator/consumer.h> +#include <asm/unaligned.h> #include <rtdm/driver.h> @@ -42,20 +44,15 @@ #include "rtcan_raw.h" #include "rtcan_internal.h" -/* - * Due to a bug in most Flexcan cores, the bus error interrupt needs - * to be enabled. Otherwise we don't get any bus warning or passive - * interrupts. This is not necessay for the i.MX28, for example and - * this modules parameter allows to overcome this limitation. - */ -static int berr_int = 1; -module_param(berr_int, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(berr_int, - "Bus error interrupt [1 (enabled)]. Can be disabled for i.MX28."); - #define DEV_NAME "rtcan%d" #define DRV_NAME "flexcan" +enum flexcan_ip_version { + FLEXCAN_VER_3_0_0, + FLEXCAN_VER_3_0_4, + FLEXCAN_VER_10_0_12, +}; + /* 8 for RX fifo and 2 error handling */ #define FLEXCAN_NAPI_WEIGHT (8 + 2) @@ -160,6 +157,23 @@ MODULE_PARM_DESC(berr_int, #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) +/* + * FLEXCAN hardware feature flags + * + * Below is some version info we got: + * SOC Version IP-Version Glitch- [TR]WRN_INT + * Filter? connected? + * MX25 FlexCAN2 03.00.00.00 no no + * MX28 FlexCAN2 03.00.04.00 yes yes + * MX35 FlexCAN2 03.00.00.00 no no + * MX53 FlexCAN2 03.00.00.00 yes no + * MX6s FlexCAN3 10.00.12.00 yes yes + * + * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. + */ +#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */ +#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */ + /* Structure of the message buffer */ struct flexcan_mb { u32 can_ctrl; @@ -182,10 +196,20 @@ struct flexcan_regs { u32 imask1; /* 0x28 */ u32 iflag2; /* 0x2c */ u32 iflag1; /* 0x30 */ - u32 _reserved2[19]; + u32 crl2; /* 0x34 */ + u32 esr2; /* 0x38 */ + u32 _reserved2[2]; + u32 crcr; /* 0x44 */ + u32 rxfgmask; /* 0x48 */ + u32 rxfir; /* 0x4c */ + u32 _reserved3[12]; struct flexcan_mb cantxfg[64]; }; +struct flexcan_devtype_data { + u32 features; /* hardware controller features */ +}; + struct flexcan_priv { struct rtcan_device *dev; @@ -194,10 +218,21 @@ struct flexcan_priv { u32 reg_esr; u32 reg_ctrl_default; + struct can_bittime bit_time; + const struct flexcan_devtype_data *devtype_data; struct regulator *reg_xceiver; struct clk *clk_ipg; struct clk *clk_per; - struct can_bittime bit_time; +}; + +static struct flexcan_devtype_data fsl_p1010_devtype_data = { + .features = FLEXCAN_HAS_BROKEN_ERR_STATE, +}; + +static struct flexcan_devtype_data fsl_imx28_devtype_data; + +static struct flexcan_devtype_data fsl_imx6q_devtype_data = { + .features = FLEXCAN_HAS_V10_FEATURES, }; static char *flexcan_ctrl_name = "FLEXCAN"; @@ -457,11 +492,9 @@ static void flexcan_rx_interrupt(struct rtcan_device *dev, cf->can_id |= CAN_RTR_FLAG; skb->rb_frame_size = EMPTY_RB_FRAME_SIZE; } else { - skb->rb_frame_size = EMPTY_RB_FRAME_SIZE + cf->can_dlc ; - *(__be32 *)(cf->data + 0) = - cpu_to_be32(flexcan_read(&mb->data[0])); - *(__be32 *)(cf->data + 4) = - cpu_to_be32(flexcan_read(&mb->data[1])); + skb->rb_frame_size = EMPTY_RB_FRAME_SIZE + cf->can_dlc; + put_unaligned_be32(flexcan_read(&mb->data[0]), cf->data + 0); + put_unaligned_be32(flexcan_read(&mb->data[1]), cf->data + 4); } /* Store the interface index */ @@ -707,19 +740,17 @@ static int flexcan_chip_start(struct rtcan_device *dev) * enable tx and rx warning interrupt * enable bus off interrupt * (== FLEXCAN_CTRL_ERR_STATE) - * - * _note_: by default we enable the "error interrupt" - * (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any - * warning or bus passive interrupts on most Flexcan cores. - * The Flexcan on the i.MX28 does not have this bug and it - * can be disabled if no bus error reporting is necessary - * by setting the module parameter "berr_int" to 0. */ reg_ctrl = flexcan_read(®s->ctrl); reg_ctrl &= ~FLEXCAN_CTRL_TSYN; reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF | FLEXCAN_CTRL_ERR_STATE; - if (berr_int) + /* + * enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK), + * on most Flexcan cores, too. Otherwise we don't get + * any error warning or passive interrupts. + */ + if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE) reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; /* save for later use */ @@ -743,6 +774,9 @@ static int flexcan_chip_start(struct rtcan_device *dev) flexcan_write(0x0, ®s->rx14mask); flexcan_write(0x0, ®s->rx15mask); + if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) + flexcan_write(0x0, ®s->rxfgmask); + flexcan_transceiver_switch(priv, 1); /* synchronize with the can bus */ @@ -819,7 +853,7 @@ static int flexcan_mode_start(struct rtcan_device *dev, rtdm_lockctx_t *lock_ctx) { struct flexcan_priv *priv = rtcan_priv(dev); - int err; + int err = 0; switch (dev->state) { @@ -879,25 +913,19 @@ out: int flexcan_set_mode(struct rtcan_device *dev, can_mode_t mode, rtdm_lockctx_t *lock_ctx) { - int err = 0; - switch (mode) { case CAN_MODE_STOP: - err = flexcan_mode_stop(dev, lock_ctx); - break; + return flexcan_mode_stop(dev, lock_ctx); case CAN_MODE_START: - err = flexcan_mode_start(dev, lock_ctx); - break; + return flexcan_mode_start(dev, lock_ctx); - case CAN_MODE_SLEEP: default: - err = -EOPNOTSUPP; break; } - return err; + return -EOPNOTSUPP; } static int register_flexcandev(struct rtcan_device *dev) @@ -961,8 +989,17 @@ static void put_clocks(struct flexcan_priv *priv) clk_put(priv->clk_ipg); } +static struct of_device_id flexcan_of_match[] = { + { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, + { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, + { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, + { /* sentinel */ }, +}; + static int flexcan_probe(struct platform_device *pdev) { + const struct flexcan_devtype_data *devtype_data; + const struct of_device_id *of_id = NULL; struct flexcan_priv *priv; struct rtcan_device *dev; resource_size_t mem_size; @@ -976,9 +1013,22 @@ static int flexcan_probe(struct platform_device *pdev) if (IS_ERR(pinctrl)) return PTR_ERR(pinctrl); - if (pdev->dev.of_node) + if (pdev->dev.of_node) { of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clock_freq); + of_id = of_match_device(flexcan_of_match, &pdev->dev); + } + + if (of_id) + devtype_data = of_id->data; + else + devtype_data = (typeof(devtype_data)) + platform_get_device_id(pdev)->driver_data; + + if (devtype_data == NULL) { + dev_err(&pdev->dev, "no feature set defined"); + return -ENODEV; + } dev = rtcan_dev_alloc(sizeof(struct flexcan_priv), 0); if (dev == NULL) @@ -1024,6 +1074,7 @@ static int flexcan_probe(struct platform_device *pdev) priv->base = base; priv->irq = irq; priv->dev = dev; + priv->devtype_data = devtype_data; priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); if (IS_ERR(priv->reg_xceiver)) priv->reg_xceiver = NULL; @@ -1086,20 +1137,24 @@ static int flexcan_remove(struct platform_device *pdev) return 0; } -static struct of_device_id flexcan_of_match[] = { - { - .compatible = "fsl,p1010-flexcan", - }, - {}, +static struct platform_device_id flexcan_id_table[] = { + { .name = "imx25-flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, + { .name = "imx28-flexcan", .driver_data = (kernel_ulong_t)&fsl_imx28_devtype_data, }, + { .name = "imx35-flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, + { .name = "imx53-flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, + { .name = "imx6q-flexcan", .driver_data = (kernel_ulong_t)&fsl_imx6q_devtype_data, }, + { .name = "flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, + { /* sentinel */ }, }; static struct platform_driver flexcan_driver = { .driver = { /* For legacy platform support */ - .name = "flexcan", + .name = DRV_NAME, .owner = THIS_MODULE, .of_match_table = flexcan_of_match, }, + .id_table = flexcan_id_table, .probe = flexcan_probe, .remove = flexcan_remove, }; diff --git a/kernel/drivers/can/rtcan_raw.c b/kernel/drivers/can/rtcan_raw.c index 135ca4d..20e554c 100644 --- a/kernel/drivers/can/rtcan_raw.c +++ b/kernel/drivers/can/rtcan_raw.c @@ -513,24 +513,18 @@ int rtcan_raw_ioctl(struct rtdm_fd *fd, } -#define MEMCPY_FROM_RING_BUF(to, len) \ - \ - if (unlikely((recv_buf_index + len) > RTCAN_RXBUF_SIZE)) { \ - /* Wrap around end of buffer */ \ - \ - first_part_size = RTCAN_RXBUF_SIZE - recv_buf_index; \ - \ - memcpy(to, &recv_buf[recv_buf_index], first_part_size); \ - memcpy((void *)to + first_part_size, recv_buf, \ - len - first_part_size); \ - \ - } else \ - \ - memcpy(to, &recv_buf[recv_buf_index], len); \ - \ - \ - recv_buf_index = (recv_buf_index + len) & (RTCAN_RXBUF_SIZE - 1); - +#define MEMCPY_FROM_RING_BUF(to, len) \ +do { \ + if (unlikely((recv_buf_index + len) > RTCAN_RXBUF_SIZE)) { \ + /* Wrap around end of buffer */ \ + first_part_size = RTCAN_RXBUF_SIZE - recv_buf_index; \ + memcpy(to, &recv_buf[recv_buf_index], first_part_size); \ + memcpy((void *)to + first_part_size, recv_buf, \ + len - first_part_size); \ + } else \ + memcpy(to, &recv_buf[recv_buf_index], len); \ + recv_buf_index = (recv_buf_index + len) & (RTCAN_RXBUF_SIZE - 1); \ +} while (0) ssize_t rtcan_raw_recvmsg(struct rtdm_fd *fd, struct msghdr *msg, int flags) @@ -670,19 +664,14 @@ ssize_t rtcan_raw_recvmsg(struct rtdm_fd *fd, /* If frame is an RTR or one with no payload it's not necessary * to copy the data bytes. */ - if (!(frame.can_id & CAN_RTR_FLAG) && payload_size) { + if (!(frame.can_id & CAN_RTR_FLAG) && payload_size) /* Copy data bytes */ MEMCPY_FROM_RING_BUF(frame.data, payload_size); - } - /* Is a timestamp available and is the caller actually interested? */ - if (msg->msg_controllen && (can_dlc & RTCAN_HAS_TIMESTAMP)) { + if (msg->msg_controllen && (can_dlc & RTCAN_HAS_TIMESTAMP)) /* Copy timestamp */ MEMCPY_FROM_RING_BUF(×tamp, RTCAN_TIMESTAMP_SIZE); - } - - /* Message completely read from the socket's ring buffer. Now check if * caller is just peeking. */ diff --git a/kernel/drivers/can/rtcan_raw_dev.c b/kernel/drivers/can/rtcan_raw_dev.c index 1da6261..0f4f52f 100644 --- a/kernel/drivers/can/rtcan_raw_dev.c +++ b/kernel/drivers/can/rtcan_raw_dev.c @@ -219,6 +219,7 @@ static int rtcan_calc_bit_time(struct rtcan_device *dev, bt->phase_seg1 = tseg1 - bt->prop_seg; bt->phase_seg2 = tseg2; bt->sjw = 1; + bt->sam = 0; bt->brp = best_brp; /* real bit-rate */ _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://xenomai.org/mailman/listinfo/xenomai-git