diff options
Diffstat (limited to 'drivers/net/can/ifi_canfd/ifi_canfd.c')
-rw-r--r-- | drivers/net/can/ifi_canfd/ifi_canfd.c | 198 |
1 files changed, 144 insertions, 54 deletions
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index a1bd54ffd31e..368bb0710d8f 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -34,6 +34,7 @@ #define IFI_CANFD_STCMD_LOOPBACK BIT(18) #define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) #define IFI_CANFD_STCMD_ENABLE_ISO BIT(25) +#define IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING BIT(26) #define IFI_CANFD_STCMD_NORMAL_MODE ((u32)BIT(31)) #define IFI_CANFD_RXSTCMD 0x4 @@ -51,7 +52,8 @@ #define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) #define IFI_CANFD_INTERRUPT 0xc -#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1)) +#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) +#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) #define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) #define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) #define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24) @@ -71,14 +73,18 @@ #define IFI_CANFD_TIME_TIMEB_OFF 0 #define IFI_CANFD_TIME_TIMEA_OFF 8 #define IFI_CANFD_TIME_PRESCALE_OFF 16 -#define IFI_CANFD_TIME_SJW_OFF_ISO 25 -#define IFI_CANFD_TIME_SJW_OFF_BOSCH 28 -#define IFI_CANFD_TIME_SET_SJW_BOSCH BIT(6) -#define IFI_CANFD_TIME_SET_TIMEB_BOSCH BIT(7) -#define IFI_CANFD_TIME_SET_PRESC_BOSCH BIT(14) -#define IFI_CANFD_TIME_SET_TIMEA_BOSCH BIT(15) +#define IFI_CANFD_TIME_SJW_OFF_7_9_8_8 25 +#define IFI_CANFD_TIME_SJW_OFF_4_12_6_6 28 +#define IFI_CANFD_TIME_SET_SJW_4_12_6_6 BIT(6) +#define IFI_CANFD_TIME_SET_TIMEB_4_12_6_6 BIT(7) +#define IFI_CANFD_TIME_SET_PRESC_4_12_6_6 BIT(14) +#define IFI_CANFD_TIME_SET_TIMEA_4_12_6_6 BIT(15) #define IFI_CANFD_TDELAY 0x1c +#define IFI_CANFD_TDELAY_DEFAULT 0xb +#define IFI_CANFD_TDELAY_MASK 0x3fff +#define IFI_CANFD_TDELAY_ABS BIT(14) +#define IFI_CANFD_TDELAY_EN BIT(15) #define IFI_CANFD_ERROR 0x20 #define IFI_CANFD_ERROR_TX_OFFSET 0 @@ -102,7 +108,26 @@ #define IFI_CANFD_RES1 0x40 -#define IFI_CANFD_RES2 0x44 +#define IFI_CANFD_ERROR_CTR 0x44 +#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC 0x21302899 +#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST BIT(0) +#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST BIT(1) +#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST BIT(2) +#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST BIT(3) +#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST BIT(4) +#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST BIT(5) +#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST BIT(6) +#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL BIT(8) +#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL BIT(9) +#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL BIT(10) +#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL BIT(11) +#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL BIT(12) +#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL BIT(13) +#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL BIT(14) +#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET 16 +#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK 0xff +#define IFI_CANFD_ERROR_CTR_ER_RESET BIT(30) +#define IFI_CANFD_ERROR_CTR_ER_ENABLE ((u32)BIT(31)) #define IFI_CANFD_PAR 0x48 @@ -196,6 +221,8 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable) if (enable) { enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY | IFI_CANFD_IRQMASK_RXFIFO_NEMPTY; + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER; } writel(IFI_CANFD_IRQMASK_SET_ERR | @@ -334,6 +361,68 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev) return 1; } +static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr) +{ + struct ifi_canfd_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST | + IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST | + IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST; + + if (!(errctr & errmask)) /* No error happened. */ + return 0; + + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + /* Propagate the error condition to the CAN stack. */ + skb = alloc_can_err_skb(ndev, &cf); + if (unlikely(!skb)) + return 0; + + /* Read the error counter register and check for new errors. */ + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + + if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) + cf->data[2] |= CAN_ERR_PROT_OVERLOAD; + + if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) + cf->data[3] = CAN_ERR_PROT_LOC_ACK; + + if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_BIT0; + + if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_BIT1; + + if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_STUFF; + + if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + + if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) + cf->data[2] |= CAN_ERR_PROT_FORM; + + /* Reset the error counter, ack the IRQ and re-enable the counter. */ + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); + writel(IFI_CANFD_INTERRUPT_ERROR_COUNTER, + priv->base + IFI_CANFD_INTERRUPT); + writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); + + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + netif_receive_skb(skb); + + return 1; +} + static int ifi_canfd_get_berr_counter(const struct net_device *ndev, struct can_berr_counter *bec) { @@ -469,6 +558,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD); + u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); /* Handle bus state changes */ if ((stcmd & stcmd_state_mask) || @@ -479,6 +569,10 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW) work_done += ifi_canfd_handle_lost_msg(ndev); + /* Handle lec errors on the bus */ + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + work_done += ifi_canfd_handle_lec_err(ndev, errctr); + /* Handle normal messages on RX */ if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY)) work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done); @@ -497,11 +591,13 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) struct ifi_canfd_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | - IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER; + IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | + IFI_CANFD_INTERRUPT_ERROR_WARNING | + IFI_CANFD_INTERRUPT_ERROR_COUNTER; const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; - const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ | - IFI_CANFD_INTERRUPT_ERROR_WARNING); + const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ | + IFI_CANFD_INTERRUPT_ERROR_WARNING)); u32 isr; isr = readl(priv->base + IFI_CANFD_INTERRUPT); @@ -513,44 +609,34 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) /* Clear all pending interrupts but ErrWarn */ writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT); - /* RX IRQ, start NAPI */ + /* RX IRQ or bus warning, start NAPI */ if (isr & rx_irq_mask) { ifi_canfd_irq_enable(ndev, 0); napi_schedule(&priv->napi); } /* TX IRQ */ - if (isr & tx_irq_mask) { + if (isr & IFI_CANFD_INTERRUPT_TXFIFO_REMOVE) { stats->tx_bytes += can_get_echo_skb(ndev, 0); stats->tx_packets++; can_led_event(ndev, CAN_LED_EVENT_TX); - netif_wake_queue(ndev); } + if (isr & tx_irq_mask) + netif_wake_queue(ndev); + return IRQ_HANDLED; } static const struct can_bittiming_const ifi_canfd_bittiming_const = { .name = KBUILD_MODNAME, .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ - .tseg1_max = 64, + .tseg1_max = 256, .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ - .tseg2_max = 64, - .sjw_max = 16, + .tseg2_max = 256, + .sjw_max = 128, .brp_min = 2, - .brp_max = 256, - .brp_inc = 1, -}; - -static const struct can_bittiming_const ifi_canfd_data_bittiming_const = { - .name = KBUILD_MODNAME, - .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ - .tseg1_max = 64, - .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ - .tseg2_max = 64, - .sjw_max = 16, - .brp_min = 2, - .brp_max = 256, + .brp_max = 512, .brp_inc = 1, }; @@ -559,20 +645,7 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev) struct ifi_canfd_priv *priv = netdev_priv(ndev); const struct can_bittiming *bt = &priv->can.bittiming; const struct can_bittiming *dbt = &priv->can.data_bittiming; - u16 brp, sjw, tseg1, tseg2; - u32 noniso_arg = 0; - u32 time_off; - - if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && - !(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) { - time_off = IFI_CANFD_TIME_SJW_OFF_ISO; - } else { - noniso_arg = IFI_CANFD_TIME_SET_TIMEB_BOSCH | - IFI_CANFD_TIME_SET_TIMEA_BOSCH | - IFI_CANFD_TIME_SET_PRESC_BOSCH | - IFI_CANFD_TIME_SET_SJW_BOSCH; - time_off = IFI_CANFD_TIME_SJW_OFF_BOSCH; - } + u16 brp, sjw, tseg1, tseg2, tdc; /* Configure bit timing */ brp = bt->brp - 2; @@ -582,8 +655,7 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev) writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | (brp << IFI_CANFD_TIME_PRESCALE_OFF) | - (sjw << time_off) | - noniso_arg, + (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), priv->base + IFI_CANFD_TIME); /* Configure data bit timing */ @@ -594,9 +666,13 @@ static void ifi_canfd_set_bittiming(struct net_device *ndev) writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | (brp << IFI_CANFD_TIME_PRESCALE_OFF) | - (sjw << time_off) | - noniso_arg, + (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), priv->base + IFI_CANFD_FTIME); + + /* Configure transmitter delay */ + tdc = (dbt->brp * (dbt->phase_seg1 + 1)) & IFI_CANFD_TDELAY_MASK; + writel(IFI_CANFD_TDELAY_EN | IFI_CANFD_TDELAY_ABS | tdc, + priv->base + IFI_CANFD_TDELAY); } static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id, @@ -640,7 +716,8 @@ static void ifi_canfd_start(struct net_device *ndev) /* Reset the IP */ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD); - writel(0, priv->base + IFI_CANFD_STCMD); + writel(IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING, + priv->base + IFI_CANFD_STCMD); ifi_canfd_set_bittiming(ndev); ifi_canfd_set_filters(ndev); @@ -659,7 +736,8 @@ static void ifi_canfd_start(struct net_device *ndev) writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ), priv->base + IFI_CANFD_INTERRUPT); - stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE; + stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE | + IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING; if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) stcmd |= IFI_CANFD_STCMD_BUSMONITOR; @@ -667,16 +745,23 @@ static void ifi_canfd_start(struct net_device *ndev) if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) stcmd |= IFI_CANFD_STCMD_LOOPBACK; - if (priv->can.ctrlmode & CAN_CTRLMODE_FD) + if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && + !(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) stcmd |= IFI_CANFD_STCMD_ENABLE_ISO; - if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO))) + if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD)) stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD; priv->can.state = CAN_STATE_ERROR_ACTIVE; ifi_canfd_irq_enable(ndev, 1); + /* Unlock, reset and enable the error counter. */ + writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC, + priv->base + IFI_CANFD_ERROR_CTR); + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); + writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); + /* Enable controller */ writel(stcmd, priv->base + IFI_CANFD_STCMD); } @@ -685,6 +770,10 @@ static void ifi_canfd_stop(struct net_device *ndev) { struct ifi_canfd_priv *priv = netdev_priv(ndev); + /* Reset and disable the error counter. */ + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); + writel(0, priv->base + IFI_CANFD_ERROR_CTR); + /* Reset the IP */ writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD); @@ -877,7 +966,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK); priv->can.bittiming_const = &ifi_canfd_bittiming_const; - priv->can.data_bittiming_const = &ifi_canfd_data_bittiming_const; + priv->can.data_bittiming_const = &ifi_canfd_bittiming_const; priv->can.do_set_mode = ifi_canfd_set_mode; priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter; @@ -888,7 +977,8 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD | - CAN_CTRLMODE_FD_NON_ISO; + CAN_CTRLMODE_FD_NON_ISO | + CAN_CTRLMODE_BERR_REPORTING; platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, dev); |