diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt index bfc0c433654f4e094143bf371a2f10cef6611d8e..bc77477c6878ac6af373f51b92cfb8a31371d826 100644 --- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -24,6 +24,14 @@ Optional properties: if this property is present then controller is assumed to be big endian. +- fsl,stop-mode: register bits of stop mode control, the format is + <&gpr req_gpr req_bit ack_gpr ack_bit>. + gpr is the phandle to general purpose register node. + req_gpr is the gpr register offset of CAN stop request. + req_bit is the bit offset of CAN stop request. + ack_gpr is the gpr register offset of CAN stop acknowledge. + ack_bit is the bit offset of CAN stop acknowledge. + Example: can@1c000 { diff --git a/Documentation/devicetree/bindings/net/can/xilinx_can.txt b/Documentation/devicetree/bindings/net/can/xilinx_can.txt index 060e2d46bad961d870467f6e86482a1714b58e45..100cc40b8510e4061f678483f74b3e1a2bd0b6c1 100644 --- a/Documentation/devicetree/bindings/net/can/xilinx_can.txt +++ b/Documentation/devicetree/bindings/net/can/xilinx_can.txt @@ -6,6 +6,7 @@ Required properties: - "xlnx,zynq-can-1.0" for Zynq CAN controllers - "xlnx,axi-can-1.00.a" for Axi CAN controllers - "xlnx,canfd-1.0" for CAN FD controllers + - "xlnx,canfd-2.0" for CAN FD 2.0 controllers - reg : Physical base address and size of the controller registers map. - interrupts : Property with a value describing the interrupt diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 7cdd0cead693dc5d78565f5fd988c6c25c7a2740..e0f0ad7a550aa8e159fe36e01a4f05d48ad6be3c 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -96,7 +96,7 @@ config CAN_AT91 config CAN_FLEXCAN tristate "Support for Freescale FLEXCAN based chips" - depends on ARM || PPC + depends on OF && HAS_IOMEM ---help--- Say Y here if you want to support for Freescale FlexCAN. diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 75ce11395ee8196f0dc3ed8b1368e591047d5edd..0f36eafe3ac16d5ba55432608acfd12eee0dd8e0 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -19,11 +19,13 @@ #include #include #include +#include #include #include #include #include #include +#include #define DRV_NAME "flexcan" @@ -131,16 +133,15 @@ (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE) #define FLEXCAN_ESR_ALL_INT \ (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \ - FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT) + FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \ + FLEXCAN_ESR_WAK_INT) /* FLEXCAN interrupt flag register (IFLAG) bits */ /* Errata ERR005829 step7: Reserve first valid MB */ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 -#define FLEXCAN_TX_MB 63 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) -#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST (FLEXCAN_TX_MB - 1) -#define FLEXCAN_IFLAG_MB(x) BIT(x & 0x1f) +#define FLEXCAN_IFLAG_MB(x) BIT((x) & 0x1f) #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5) @@ -189,12 +190,13 @@ #define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */ #define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */ #define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) /* default to BE register access */ +#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) /* Setup stop mode to support wakeup */ /* Structure of the message buffer */ struct flexcan_mb { u32 can_ctrl; u32 can_id; - u32 data[2]; + u32 data[]; }; /* Structure of the hardware registers */ @@ -223,7 +225,7 @@ struct flexcan_regs { u32 rxfgmask; /* 0x48 */ u32 rxfir; /* 0x4c */ u32 _reserved3[12]; /* 0x50 */ - struct flexcan_mb mb[64]; /* 0x80 */ + u8 mb[2][512]; /* 0x80 */ /* FIFO-mode: * MB * 0x080...0x08f 0 RX message buffer @@ -253,12 +255,24 @@ struct flexcan_devtype_data { u32 quirks; /* quirks needed for different IP cores */ }; +struct flexcan_stop_mode { + struct regmap *gpr; + u8 req_gpr; + u8 req_bit; + u8 ack_gpr; + u8 ack_bit; +}; + struct flexcan_priv { struct can_priv can; struct can_rx_offload offload; struct flexcan_regs __iomem *regs; + struct flexcan_mb __iomem *tx_mb; struct flexcan_mb __iomem *tx_mb_reserved; + u8 tx_mb_idx; + u8 mb_count; + u8 mb_size; u32 reg_ctrl_default; u32 reg_imask1_default; u32 reg_imask2_default; @@ -267,6 +281,7 @@ struct flexcan_priv { struct clk *clk_per; const struct flexcan_devtype_data *devtype_data; struct regulator *reg_xceiver; + struct flexcan_stop_mode stm; /* Read and Write APIs */ u32 (*read)(void __iomem *addr); @@ -290,7 +305,8 @@ static const struct flexcan_devtype_data fsl_imx28_devtype_data = { static const struct flexcan_devtype_data fsl_imx6q_devtype_data = { .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | - FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE, + FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | + FLEXCAN_QUIRK_SETUP_STOP_MODE, }; static const struct flexcan_devtype_data fsl_vf610_devtype_data = { @@ -350,6 +366,68 @@ static inline void flexcan_write_le(u32 val, void __iomem *addr) iowrite32(val, addr); } +static struct flexcan_mb __iomem *flexcan_get_mb(const struct flexcan_priv *priv, + u8 mb_index) +{ + u8 bank_size; + bool bank; + + if (WARN_ON(mb_index >= priv->mb_count)) + return NULL; + + bank_size = sizeof(priv->regs->mb[0]) / priv->mb_size; + + bank = mb_index >= bank_size; + if (bank) + mb_index -= bank_size; + + return (struct flexcan_mb __iomem *) + (&priv->regs->mb[bank][priv->mb_size * mb_index]); +} + +static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable) +{ + struct flexcan_regs __iomem *regs = priv->regs; + u32 reg_mcr; + + reg_mcr = priv->read(®s->mcr); + + if (enable) + reg_mcr |= FLEXCAN_MCR_WAK_MSK; + else + reg_mcr &= ~FLEXCAN_MCR_WAK_MSK; + + priv->write(reg_mcr, ®s->mcr); +} + +static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->regs; + u32 reg_mcr; + + reg_mcr = priv->read(®s->mcr); + reg_mcr |= FLEXCAN_MCR_SLF_WAK; + priv->write(reg_mcr, ®s->mcr); + + /* enable stop request */ + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, + 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); +} + +static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->regs; + u32 reg_mcr; + + /* remove stop request */ + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, + 1 << priv->stm.req_bit, 0); + + reg_mcr = priv->read(®s->mcr); + reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; + priv->write(reg_mcr, ®s->mcr); +} + static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; @@ -512,11 +590,11 @@ static int flexcan_get_berr_counter(const struct net_device *dev, static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) { const struct flexcan_priv *priv = netdev_priv(dev); - struct flexcan_regs __iomem *regs = priv->regs; struct can_frame *cf = (struct can_frame *)skb->data; u32 can_id; u32 data; u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16); + int i; if (can_dropped_invalid_skb(dev, skb)) return NETDEV_TX_OK; @@ -533,27 +611,23 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de if (cf->can_id & CAN_RTR_FLAG) ctrl |= FLEXCAN_MB_CNT_RTR; - if (cf->can_dlc > 0) { - data = be32_to_cpup((__be32 *)&cf->data[0]); - priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[0]); - } - if (cf->can_dlc > 4) { - data = be32_to_cpup((__be32 *)&cf->data[4]); - priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[1]); + for (i = 0; i < cf->can_dlc; i += sizeof(u32)) { + data = be32_to_cpup((__be32 *)&cf->data[i]); + priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]); } can_put_echo_skb(skb, dev, 0); - priv->write(can_id, ®s->mb[FLEXCAN_TX_MB].can_id); - priv->write(ctrl, ®s->mb[FLEXCAN_TX_MB].can_ctrl); + priv->write(can_id, &priv->tx_mb->can_id); + priv->write(ctrl, &priv->tx_mb->can_ctrl); /* Errata ERR005829 step8: * Write twice INACTIVE(0x8) code to first MB. */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, - &priv->tx_mb_reserved->can_ctrl); + &priv->tx_mb_reserved->can_ctrl); priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, - &priv->tx_mb_reserved->can_ctrl); + &priv->tx_mb_reserved->can_ctrl); return NETDEV_TX_OK; } @@ -672,8 +746,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, { struct flexcan_priv *priv = rx_offload_to_priv(offload); struct flexcan_regs __iomem *regs = priv->regs; - struct flexcan_mb __iomem *mb = ®s->mb[n]; + struct flexcan_mb __iomem *mb; u32 reg_ctrl, reg_id, reg_iflag1; + int i; + + mb = flexcan_get_mb(priv, n); if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { u32 code; @@ -714,8 +791,10 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, cf->can_id |= CAN_RTR_FLAG; cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf); - *(__be32 *)(cf->data + 0) = cpu_to_be32(priv->read(&mb->data[0])); - *(__be32 *)(cf->data + 4) = cpu_to_be32(priv->read(&mb->data[1])); + for (i = 0; i < cf->can_dlc; i += sizeof(u32)) { + __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)])); + *(__be32 *)(cf->data + i) = data; + } /* mark as read */ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { @@ -744,7 +823,7 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) u32 iflag1, iflag2; iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default & - ~FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB); + ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx); iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default; return (u64)iflag2 << 32 | iflag1; @@ -794,8 +873,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) reg_iflag2 = priv->read(®s->iflag2); /* transmission complete interrupt */ - if (reg_iflag2 & FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB)) { - u32 reg_ctrl = priv->read(®s->mb[FLEXCAN_TX_MB].can_ctrl); + if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) { + u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl); handled = IRQ_HANDLED; stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload, @@ -805,8 +884,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* after sending a RTR frame MB is in RX mode */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->mb[FLEXCAN_TX_MB].can_ctrl); - priv->write(FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB), ®s->iflag2); + &priv->tx_mb->can_ctrl); + priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), ®s->iflag2); netif_wake_queue(dev); } @@ -821,7 +900,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* state change interrupt or broken error state quirk fix is enabled */ if ((reg_esr & FLEXCAN_ESR_ERR_STATE) || (priv->devtype_data->quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE | - FLEXCAN_QUIRK_BROKEN_PERR_STATE))) + FLEXCAN_QUIRK_BROKEN_PERR_STATE))) flexcan_irq_state(dev, reg_esr); /* bus error IRQ - handle if bus error reporting is activated */ @@ -919,6 +998,7 @@ static int flexcan_chip_start(struct net_device *dev) struct flexcan_regs __iomem *regs = priv->regs; u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; int err, i; + struct flexcan_mb __iomem *mb; /* enable module */ err = flexcan_chip_enable(priv); @@ -935,11 +1015,9 @@ static int flexcan_chip_start(struct net_device *dev) /* MCR * * enable freeze - * enable fifo * halt now * only supervisor access * enable warning int - * disable local echo * enable individual RX masking * choose format C * set max mailbox number @@ -947,14 +1025,37 @@ static int flexcan_chip_start(struct net_device *dev) reg_mcr = priv->read(®s->mcr); reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV | - FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_IRMQ | - FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_MB); + FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ | FLEXCAN_MCR_IDAM_C | + FLEXCAN_MCR_MAXMB(priv->tx_mb_idx); + /* MCR + * + * FIFO: + * - disable for timestamp mode + * - enable for FIFO mode + */ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) reg_mcr &= ~FLEXCAN_MCR_FEN; else reg_mcr |= FLEXCAN_MCR_FEN; + /* MCR + * + * NOTE: In loopback mode, the CAN_MCR[SRXDIS] cannot be + * asserted because this will impede the self reception + * of a transmitted message. This is not documented in + * earlier versions of flexcan block guide. + * + * Self Reception: + * - enable Self Reception for loopback mode + * (by clearing "Self Reception Disable" bit) + * - disable for normal operation + */ + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) + reg_mcr &= ~FLEXCAN_MCR_SRX_DIS; + else + reg_mcr |= FLEXCAN_MCR_SRX_DIS; + netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); priv->write(reg_mcr, ®s->mcr); @@ -999,14 +1100,16 @@ static int flexcan_chip_start(struct net_device *dev) if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) { + mb = flexcan_get_mb(priv, i); priv->write(FLEXCAN_MB_CODE_RX_EMPTY, - ®s->mb[i].can_ctrl); + &mb->can_ctrl); } } else { /* clear and invalidate unused mailboxes first */ - for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= ARRAY_SIZE(regs->mb); i++) { + for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= priv->mb_count; i++) { + mb = flexcan_get_mb(priv, i); priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, - ®s->mb[i].can_ctrl); + &mb->can_ctrl); } } @@ -1016,7 +1119,7 @@ static int flexcan_chip_start(struct net_device *dev) /* mark TX mailbox as INACTIVE */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, - ®s->mb[FLEXCAN_TX_MB].can_ctrl); + &priv->tx_mb->can_ctrl); /* acceptance mask/acceptance code (accept everything) */ priv->write(0x0, ®s->rxgmask); @@ -1027,7 +1130,7 @@ static int flexcan_chip_start(struct net_device *dev) priv->write(0x0, ®s->rxfgmask); /* clear acceptance filters */ - for (i = 0; i < ARRAY_SIZE(regs->mb); i++) + for (i = 0; i < priv->mb_count; i++) priv->write(0, ®s->rximr[i]); /* On Vybrid, disable memory error detection interrupts @@ -1128,10 +1231,49 @@ static int flexcan_open(struct net_device *dev) if (err) goto out_close; + priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; + priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) + + (sizeof(priv->regs->mb[1]) / priv->mb_size); + + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) + priv->tx_mb_reserved = + flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP); + else + priv->tx_mb_reserved = + flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO); + priv->tx_mb_idx = priv->mb_count - 1; + priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); + + priv->reg_imask1_default = 0; + priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); + + priv->offload.mailbox_read = flexcan_mailbox_read; + + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { + u64 imask; + + priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST; + priv->offload.mb_last = priv->mb_count - 2; + + imask = GENMASK_ULL(priv->offload.mb_last, + priv->offload.mb_first); + priv->reg_imask1_default |= imask; + priv->reg_imask2_default |= imask >> 32; + + err = can_rx_offload_add_timestamp(dev, &priv->offload); + } else { + priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | + FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; + err = can_rx_offload_add_fifo(dev, &priv->offload, + FLEXCAN_NAPI_WEIGHT); + } + if (err) + goto out_free_irq; + /* start chip and queuing */ err = flexcan_chip_start(dev); if (err) - goto out_free_irq; + goto out_offload_del; can_led_event(dev, CAN_LED_EVENT_OPEN); @@ -1140,6 +1282,8 @@ static int flexcan_open(struct net_device *dev) return 0; + out_offload_del: + can_rx_offload_del(&priv->offload); out_free_irq: free_irq(dev->irq, dev); out_close: @@ -1160,6 +1304,7 @@ static int flexcan_close(struct net_device *dev) can_rx_offload_disable(&priv->offload); flexcan_chip_stop(dev); + can_rx_offload_del(&priv->offload); free_irq(dev->irq, dev); clk_disable_unprepare(priv->clk_per); clk_disable_unprepare(priv->clk_ipg); @@ -1260,6 +1405,59 @@ static void unregister_flexcandev(struct net_device *dev) unregister_candev(dev); } +static int flexcan_setup_stop_mode(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + struct device_node *gpr_np; + struct flexcan_priv *priv; + phandle phandle; + u32 out_val[5]; + int ret; + + if (!np) + return -EINVAL; + + /* stop mode property format is: + * <&gpr req_gpr req_bit ack_gpr ack_bit>. + */ + ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val, + ARRAY_SIZE(out_val)); + if (ret) { + dev_dbg(&pdev->dev, "no stop-mode property\n"); + return ret; + } + phandle = *out_val; + + gpr_np = of_find_node_by_phandle(phandle); + if (!gpr_np) { + dev_dbg(&pdev->dev, "could not find gpr node by phandle\n"); + return PTR_ERR(gpr_np); + } + + priv = netdev_priv(dev); + priv->stm.gpr = syscon_node_to_regmap(gpr_np); + of_node_put(gpr_np); + if (IS_ERR(priv->stm.gpr)) { + dev_dbg(&pdev->dev, "could not find gpr regmap\n"); + return PTR_ERR(priv->stm.gpr); + } + + priv->stm.req_gpr = out_val[1]; + priv->stm.req_bit = out_val[2]; + priv->stm.ack_gpr = out_val[3]; + priv->stm.ack_bit = out_val[4]; + + dev_dbg(&pdev->dev, + "gpr %s req_gpr=0x02%x req_bit=%u ack_gpr=0x02%x ack_bit=%u\n", + gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit, + priv->stm.ack_gpr, priv->stm.ack_bit); + + device_set_wakeup_capable(&pdev->dev, true); + + return 0; +} + static const struct of_device_id flexcan_of_match[] = { { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, @@ -1371,35 +1569,6 @@ static int flexcan_probe(struct platform_device *pdev) priv->devtype_data = devtype_data; priv->reg_xceiver = reg_xceiver; - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) - priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP]; - else - priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO]; - - priv->reg_imask1_default = 0; - priv->reg_imask2_default = FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB); - - priv->offload.mailbox_read = flexcan_mailbox_read; - - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { - u64 imask; - - priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST; - priv->offload.mb_last = FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST; - - imask = GENMASK_ULL(priv->offload.mb_last, priv->offload.mb_first); - priv->reg_imask1_default |= imask; - priv->reg_imask2_default |= imask >> 32; - - err = can_rx_offload_add_timestamp(dev, &priv->offload); - } else { - priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | - FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; - err = can_rx_offload_add_fifo(dev, &priv->offload, FLEXCAN_NAPI_WEIGHT); - } - if (err) - goto failed_offload; - err = register_flexcandev(dev); if (err) { dev_err(&pdev->dev, "registering netdev failed\n"); @@ -1408,12 +1577,17 @@ static int flexcan_probe(struct platform_device *pdev) devm_can_led_init(dev); + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) { + err = flexcan_setup_stop_mode(pdev); + if (err) + dev_dbg(&pdev->dev, "failed to setup stop-mode\n"); + } + dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", priv->regs, dev->irq); return 0; - failed_offload: failed_register: free_candev(dev); return err; @@ -1422,10 +1596,8 @@ static int flexcan_probe(struct platform_device *pdev) static int flexcan_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); - struct flexcan_priv *priv = netdev_priv(dev); unregister_flexcandev(dev); - can_rx_offload_del(&priv->offload); free_candev(dev); return 0; @@ -1438,9 +1610,17 @@ static int __maybe_unused flexcan_suspend(struct device *device) int err; if (netif_running(dev)) { - err = flexcan_chip_disable(priv); - if (err) - return err; + /* if wakeup is enabled, enter stop mode + * else enter disabled mode. + */ + if (device_may_wakeup(device)) { + enable_irq_wake(dev->irq); + flexcan_enter_stop_mode(priv); + } else { + err = flexcan_chip_disable(priv); + if (err) + return err; + } netif_stop_queue(dev); netif_device_detach(dev); } @@ -1459,14 +1639,45 @@ static int __maybe_unused flexcan_resume(struct device *device) if (netif_running(dev)) { netif_device_attach(dev); netif_start_queue(dev); - err = flexcan_chip_enable(priv); - if (err) - return err; + if (device_may_wakeup(device)) { + disable_irq_wake(dev->irq); + } else { + err = flexcan_chip_enable(priv); + if (err) + return err; + } } return 0; } -static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume); +static int __maybe_unused flexcan_noirq_suspend(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + struct flexcan_priv *priv = netdev_priv(dev); + + if (netif_running(dev) && device_may_wakeup(device)) + flexcan_enable_wakeup_irq(priv, true); + + return 0; +} + +static int __maybe_unused flexcan_noirq_resume(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + struct flexcan_priv *priv = netdev_priv(dev); + + if (netif_running(dev) && device_may_wakeup(device)) { + flexcan_enable_wakeup_irq(priv, false); + flexcan_exit_stop_mode(priv); + } + + return 0; +} + +static const struct dev_pm_ops flexcan_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(flexcan_suspend, flexcan_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(flexcan_noirq_suspend, flexcan_noirq_resume) +}; static struct platform_driver flexcan_driver = { .driver = { diff --git a/drivers/net/can/rcar/Kconfig b/drivers/net/can/rcar/Kconfig index 7b03a3a37db7e1158ea8e27671f306f8cd878904..bd5a8fcd83e18589511fbe9685801f0fc7d623e7 100644 --- a/drivers/net/can/rcar/Kconfig +++ b/drivers/net/can/rcar/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config CAN_RCAR tristate "Renesas R-Car CAN controller" depends on ARCH_RENESAS || ARM diff --git a/drivers/net/can/rcar/Makefile b/drivers/net/can/rcar/Makefile index 08de36a4cfccdc18a58cf560017b1dee7343f0b3..c9185b0c04a8bdf537465c748363a380dcc046af 100644 --- a/drivers/net/can/rcar/Makefile +++ b/drivers/net/can/rcar/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Makefile for the Renesas R-Car CAN & CAN FD controller drivers # diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index 771a4608373978c31b7011a45cf5659f543820c1..13e66297b65f1f8b5ff28ad6576828f57ef6a607 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* Renesas R-Car CAN device driver * * Copyright (C) 2013 Cogent Embedded, Inc. * Copyright (C) 2013 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ #include diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 602c19e23f052ed50bd691408bc9644bf5049cb5..05410008aa6b6ee2ac1a6a957c2b0b838f9ee2fc 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* Renesas R-Car CAN FD device driver * * Copyright (C) 2015 Renesas Electronics Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. */ /* The R-Car CAN FD controller can operate in either one of the below two modes diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index 1e65cb6c25912c6a2c55f5eb964e3e14230c9060..f6dc89927ece5c40a6aaf2dd48f3462b32b77088 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -88,6 +88,7 @@ config CAN_PLX_PCI - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/) - IXXAT Automation PC-I 04/PCI card (http://www.ixxat.com/) - Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card (http://www.connecttech.com) + - ASEM CAN raw - 2 isolated CAN channels (www.asem.it) config CAN_TSCAN1 tristate "TS-CAN1 PC104 boards" diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index f8ff25c8ee2e46122083de6f45816648f60c0370..9bcdefea138a94ba48050484afbe5fe15495db28 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -46,7 +46,8 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " "esd CAN-PCIe/2000, " "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), " "IXXAT PC-I 04/PCI, " - "ELCUS CAN-200-PCI") + "ELCUS CAN-200-PCI, " + "ASEM DUAL CAN-RAW") MODULE_LICENSE("GPL v2"); #define PLX_PCI_MAX_CHAN 2 @@ -70,7 +71,9 @@ struct plx_pci_card { */ #define PLX_LINT1_EN 0x1 /* Local interrupt 1 enable */ +#define PLX_LINT1_POL (1 << 1) /* Local interrupt 1 polarity */ #define PLX_LINT2_EN (1 << 3) /* Local interrupt 2 enable */ +#define PLX_LINT2_POL (1 << 4) /* Local interrupt 2 polarity */ #define PLX_PCI_INT_EN (1 << 6) /* PCI Interrupt Enable */ #define PLX_PCI_RESET (1 << 30) /* PCI Adapter Software Reset */ @@ -92,6 +95,9 @@ struct plx_pci_card { */ #define PLX_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) +/* OCR setting for ASEM Dual CAN raw */ +#define ASEM_PCI_OCR 0xfe + /* * In the CDR register, you should set CBP to 1. * You will probably also want to set the clock divider value to 7 @@ -145,10 +151,20 @@ struct plx_pci_card { #define MOXA_PCI_VENDOR_ID 0x1393 #define MOXA_PCI_DEVICE_ID 0x0100 +#define ASEM_RAW_CAN_VENDOR_ID 0x10b5 +#define ASEM_RAW_CAN_DEVICE_ID 0x9030 +#define ASEM_RAW_CAN_SUB_VENDOR_ID 0x3000 +#define ASEM_RAW_CAN_SUB_DEVICE_ID 0x1001 +#define ASEM_RAW_CAN_SUB_DEVICE_ID_BIS 0x1002 +#define ASEM_RAW_CAN_RST_REGISTER 0x54 +#define ASEM_RAW_CAN_RST_MASK_CAN1 0x20 +#define ASEM_RAW_CAN_RST_MASK_CAN2 0x04 + static void plx_pci_reset_common(struct pci_dev *pdev); static void plx9056_pci_reset_common(struct pci_dev *pdev); static void plx_pci_reset_marathon_pci(struct pci_dev *pdev); static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev); +static void plx_pci_reset_asem_dual_can_raw(struct pci_dev *pdev); struct plx_pci_channel_map { u32 bar; @@ -269,6 +285,14 @@ static struct plx_pci_card_info plx_pci_card_info_moxa = { /* based on PLX9052 */ }; +static struct plx_pci_card_info plx_pci_card_info_asem_dual_can = { + "ASEM Dual CAN raw PCI", 2, + PLX_PCI_CAN_CLOCK, ASEM_PCI_OCR, PLX_PCI_CDR, + {0, 0x00, 0x00}, { {2, 0x00, 0x00}, {4, 0x00, 0x00} }, + &plx_pci_reset_asem_dual_can_raw + /* based on PLX9030 */ +}; + static const struct pci_device_id plx_pci_tbl[] = { { /* Adlink PCI-7841/cPCI-7841 */ @@ -375,6 +399,20 @@ static const struct pci_device_id plx_pci_tbl[] = { 0, 0, (kernel_ulong_t)&plx_pci_card_info_moxa }, + { + /* ASEM Dual CAN raw */ + ASEM_RAW_CAN_VENDOR_ID, ASEM_RAW_CAN_DEVICE_ID, + ASEM_RAW_CAN_SUB_VENDOR_ID, ASEM_RAW_CAN_SUB_DEVICE_ID, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_asem_dual_can + }, + { + /* ASEM Dual CAN raw -new model */ + ASEM_RAW_CAN_VENDOR_ID, ASEM_RAW_CAN_DEVICE_ID, + ASEM_RAW_CAN_SUB_VENDOR_ID, ASEM_RAW_CAN_SUB_DEVICE_ID_BIS, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_asem_dual_can + }, { 0,} }; MODULE_DEVICE_TABLE(pci, plx_pci_tbl); @@ -524,6 +562,31 @@ static void plx_pci_reset_marathon_pcie(struct pci_dev *pdev) } } +/* Special reset function for ASEM Dual CAN raw card */ +static void plx_pci_reset_asem_dual_can_raw(struct pci_dev *pdev) +{ + void __iomem *bar0_addr; + u8 tmpval; + + plx_pci_reset_common(pdev); + + bar0_addr = pci_iomap(pdev, 0, 0); + if (!bar0_addr) { + dev_err(&pdev->dev, "Failed to remap reset space 0 (BAR0)\n"); + return; + } + + /* reset the two SJA1000 chips */ + tmpval = ioread8(bar0_addr + ASEM_RAW_CAN_RST_REGISTER); + tmpval &= ~(ASEM_RAW_CAN_RST_MASK_CAN1 | ASEM_RAW_CAN_RST_MASK_CAN2); + iowrite8(tmpval, bar0_addr + ASEM_RAW_CAN_RST_REGISTER); + usleep_range(300, 400); + tmpval |= ASEM_RAW_CAN_RST_MASK_CAN1 | ASEM_RAW_CAN_RST_MASK_CAN2; + iowrite8(tmpval, bar0_addr + ASEM_RAW_CAN_RST_REGISTER); + usleep_range(300, 400); + pci_iounmap(pdev, bar0_addr); +} + static void plx_pci_del_card(struct pci_dev *pdev) { struct plx_pci_card *card = pci_get_drvdata(pdev); diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c index f3d5bda012a107e430bca91bd09dd1d15be1bbf2..04aac3bb54efe0c07d24f299c68d0ba4ebe55422 100644 --- a/drivers/net/can/usb/ucan.c +++ b/drivers/net/can/usb/ucan.c @@ -715,7 +715,7 @@ static void ucan_read_bulk_callback(struct urb *urb) up->in_ep_size, urb->transfer_buffer, urb->transfer_dma); - netdev_dbg(up->netdev, "not resumbmitting urb; status: %d\n", + netdev_dbg(up->netdev, "not resubmitting urb; status: %d\n", urb->status); return; default: diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 045f0845e665e42a0d588cef735d2230c60a7b13..97d0933d9bd9b20d6ee9b0f81c7b5ecdeb3ad051 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -63,6 +63,7 @@ enum xcan_reg { XCAN_FSR_OFFSET = 0x00E8, /* RX FIFO Status */ XCAN_TXMSG_BASE_OFFSET = 0x0100, /* TX Message Space */ XCAN_RXMSG_BASE_OFFSET = 0x1100, /* RX Message Space */ + XCAN_RXMSG_2_BASE_OFFSET = 0x2100, /* RX Message Space */ }; #define XCAN_FRAME_ID_OFFSET(frame_base) ((frame_base) + 0x00) @@ -75,6 +76,8 @@ enum xcan_reg { XCAN_CANFD_FRAME_SIZE * (n)) #define XCAN_RXMSG_FRAME_OFFSET(n) (XCAN_RXMSG_BASE_OFFSET + \ XCAN_CANFD_FRAME_SIZE * (n)) +#define XCAN_RXMSG_2_FRAME_OFFSET(n) (XCAN_RXMSG_2_BASE_OFFSET + \ + XCAN_CANFD_FRAME_SIZE * (n)) /* the single TX mailbox used by this driver on CAN FD HW */ #define XCAN_TX_MAILBOX_IDX 0 @@ -152,6 +155,7 @@ enum xcan_reg { * instead of the regular FIFO at 0x50 */ #define XCAN_FLAG_RX_FIFO_MULTI 0x0010 +#define XCAN_FLAG_CANFD_2 0x0020 struct xcan_devtype_data { unsigned int flags; @@ -221,6 +225,18 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd = { .brp_inc = 1, }; +static const struct can_bittiming_const xcan_bittiming_const_canfd2 = { + .name = DRIVER_NAME, + .tseg1_min = 1, + .tseg1_max = 256, + .tseg2_min = 1, + .tseg2_max = 128, + .sjw_max = 128, + .brp_min = 1, + .brp_max = 256, + .brp_inc = 1, +}; + /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -612,7 +628,7 @@ static int xcan_start_xmit_mailbox(struct sk_buff *skb, struct net_device *ndev) * * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY when the tx queue is full */ -static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct xcan_priv *priv = netdev_priv(ndev); int ret; @@ -973,7 +989,10 @@ static int xcan_rx_fifo_get_next_frame(struct xcan_priv *priv) if (!(fsr & XCAN_FSR_FL_MASK)) return -ENOENT; - offset = XCAN_RXMSG_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK); + if (priv->devtype.flags & XCAN_FLAG_CANFD_2) + offset = XCAN_RXMSG_2_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK); + else + offset = XCAN_RXMSG_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK); } else { /* check if RX FIFO is empty */ @@ -1430,11 +1449,24 @@ static const struct xcan_devtype_data xcan_canfd_data = { .bus_clk_name = "s_axi_aclk", }; +static const struct xcan_devtype_data xcan_canfd2_data = { + .flags = XCAN_FLAG_EXT_FILTERS | + XCAN_FLAG_RXMNF | + XCAN_FLAG_TX_MAILBOXES | + XCAN_FLAG_CANFD_2 | + XCAN_FLAG_RX_FIFO_MULTI, + .bittiming_const = &xcan_bittiming_const_canfd2, + .btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD, + .btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD, + .bus_clk_name = "s_axi_aclk", +}; + /* Match table for OF platform binding */ static const struct of_device_id xcan_of_match[] = { { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, { .compatible = "xlnx,axi-can-1.00.a", .data = &xcan_axi_data }, { .compatible = "xlnx,canfd-1.0", .data = &xcan_canfd_data }, + { .compatible = "xlnx,canfd-2.0", .data = &xcan_canfd2_data }, { /* end of list */ }, }; MODULE_DEVICE_TABLE(of, xcan_of_match);