diff options
Diffstat (limited to 'drivers/net/can/xilinx_can.c')
-rw-r--r-- | drivers/net/can/xilinx_can.c | 206 |
1 files changed, 118 insertions, 88 deletions
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 9bce846acfcc..204a7890dc9c 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -51,16 +51,15 @@ enum xcan_reg { XCAN_ISR_OFFSET = 0x1C, /* Interrupt status */ XCAN_IER_OFFSET = 0x20, /* Interrupt enable */ XCAN_ICR_OFFSET = 0x24, /* Interrupt clear */ - XCAN_TXFIFO_ID_OFFSET = 0x30,/* TX FIFO ID */ - XCAN_TXFIFO_DLC_OFFSET = 0x34, /* TX FIFO DLC */ - XCAN_TXFIFO_DW1_OFFSET = 0x38, /* TX FIFO Data Word 1 */ - XCAN_TXFIFO_DW2_OFFSET = 0x3C, /* TX FIFO Data Word 2 */ - XCAN_RXFIFO_ID_OFFSET = 0x50, /* RX FIFO ID */ - XCAN_RXFIFO_DLC_OFFSET = 0x54, /* RX FIFO DLC */ - XCAN_RXFIFO_DW1_OFFSET = 0x58, /* RX FIFO Data Word 1 */ - XCAN_RXFIFO_DW2_OFFSET = 0x5C, /* RX FIFO Data Word 2 */ + XCAN_TXFIFO_OFFSET = 0x30, /* TX FIFO base */ + XCAN_RXFIFO_OFFSET = 0x50, /* RX FIFO base */ }; +#define XCAN_FRAME_ID_OFFSET(frame_base) ((frame_base) + 0x00) +#define XCAN_FRAME_DLC_OFFSET(frame_base) ((frame_base) + 0x04) +#define XCAN_FRAME_DW1_OFFSET(frame_base) ((frame_base) + 0x08) +#define XCAN_FRAME_DW2_OFFSET(frame_base) ((frame_base) + 0x0C) + /* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */ #define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */ #define XCAN_SRR_RESET_MASK 0x00000001 /* Soft Reset the CAN core */ @@ -101,11 +100,6 @@ enum xcan_reg { #define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */ #define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */ -#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\ - XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \ - XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \ - XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK) - /* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */ #define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ #define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */ @@ -118,6 +112,15 @@ enum xcan_reg { #define XCAN_FRAME_MAX_DATA_LEN 8 #define XCAN_TIMEOUT (1 * HZ) +/* TX-FIFO-empty interrupt available */ +#define XCAN_FLAG_TXFEMP 0x0001 + +struct xcan_devtype_data { + unsigned int flags; + const struct can_bittiming_const *bittiming_const; + const char *bus_clk_name; +}; + /** * struct xcan_priv - This definition define CAN driver instance * @can: CAN private data structure. @@ -133,6 +136,7 @@ enum xcan_reg { * @irq_flags: For request_irq() * @bus_clk: Pointer to struct clk * @can_clk: Pointer to struct clk + * @devtype: Device type specific constants */ struct xcan_priv { struct can_priv can; @@ -149,6 +153,7 @@ struct xcan_priv { unsigned long irq_flags; struct clk *bus_clk; struct clk *can_clk; + struct xcan_devtype_data devtype; }; /* CAN Bittiming constants as per Xilinx CAN specs */ @@ -164,11 +169,6 @@ static const struct can_bittiming_const xcan_bittiming_const = { .brp_inc = 1, }; -#define XCAN_CAP_WATERMARK 0x0001 -struct xcan_devtype_data { - unsigned int caps; -}; - /** * xcan_write_reg_le - Write a value to the device register little endian * @priv: Driver private data structure @@ -329,7 +329,11 @@ static int xcan_chip_start(struct net_device *ndev) return err; /* Enable interrupts */ - priv->write_reg(priv, XCAN_IER_OFFSET, XCAN_INTR_ALL); + priv->write_reg(priv, XCAN_IER_OFFSET, + XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK | + XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | + XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | + XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK); /* Check whether it is loopback mode or normal mode */ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { @@ -390,33 +394,15 @@ static int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode) } /** - * xcan_start_xmit - Starts the transmission - * @skb: sk_buff pointer that contains data to be Txed - * @ndev: Pointer to net_device structure - * - * This function is invoked from upper layers to initiate transmission. This - * function uses the next available free txbuff and populates their fields to - * start the transmission. - * - * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY when the tx queue is full + * xcan_write_frame - Write a frame to HW + * @skb: sk_buff pointer that contains data to be Txed + * @frame_offset: Register offset to write the frame to */ -static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static void xcan_write_frame(struct xcan_priv *priv, struct sk_buff *skb, + int frame_offset) { - struct xcan_priv *priv = netdev_priv(ndev); - struct can_frame *cf = (struct can_frame *)skb->data; u32 id, dlc, data[2] = {0, 0}; - unsigned long flags; - - if (can_dropped_invalid_skb(ndev, skb)) - return NETDEV_TX_OK; - - /* Check if the TX buffer is full */ - if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) & - XCAN_SR_TXFLL_MASK)) { - netif_stop_queue(ndev); - netdev_err(ndev, "BUG!, TX FIFO full when queue awake!\n"); - return NETDEV_TX_BUSY; - } + struct can_frame *cf = (struct can_frame *)skb->data; /* Watch carefully on the bit sequence */ if (cf->can_id & CAN_EFF_FLAG) { @@ -452,23 +438,42 @@ static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (cf->can_dlc > 4) data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); + priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id); + /* If the CAN frame is RTR frame this write triggers transmission */ + priv->write_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_offset), dlc); + if (!(cf->can_id & CAN_RTR_FLAG)) { + priv->write_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_offset), + data[0]); + /* If the CAN frame is Standard/Extended frame this + * write triggers transmission + */ + priv->write_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_offset), + data[1]); + } +} + +/** + * xcan_start_xmit_fifo - Starts the transmission (FIFO mode) + * + * Return: 0 on success, -ENOSPC if FIFO is full. + */ +static int xcan_start_xmit_fifo(struct sk_buff *skb, struct net_device *ndev) +{ + struct xcan_priv *priv = netdev_priv(ndev); + unsigned long flags; + + /* Check if the TX buffer is full */ + if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) & + XCAN_SR_TXFLL_MASK)) + return -ENOSPC; + can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); spin_lock_irqsave(&priv->tx_lock, flags); priv->tx_head++; - /* Write the Frame to Xilinx CAN TX FIFO */ - priv->write_reg(priv, XCAN_TXFIFO_ID_OFFSET, id); - /* If the CAN frame is RTR frame this write triggers tranmission */ - priv->write_reg(priv, XCAN_TXFIFO_DLC_OFFSET, dlc); - if (!(cf->can_id & CAN_RTR_FLAG)) { - priv->write_reg(priv, XCAN_TXFIFO_DW1_OFFSET, data[0]); - /* If the CAN frame is Standard/Extended frame this - * write triggers tranmission - */ - priv->write_reg(priv, XCAN_TXFIFO_DW2_OFFSET, data[1]); - } + xcan_write_frame(priv, skb, XCAN_TXFIFO_OFFSET); /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ if (priv->tx_max > 1) @@ -480,6 +485,35 @@ static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) spin_unlock_irqrestore(&priv->tx_lock, flags); + return 0; +} + +/** + * xcan_start_xmit - Starts the transmission + * @skb: sk_buff pointer that contains data to be Txed + * @ndev: Pointer to net_device structure + * + * This function is invoked from upper layers to initiate transmission. This + * function uses the next available free txbuff and populates their fields to + * start the transmission. + * + * 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) +{ + int ret; + + if (can_dropped_invalid_skb(ndev, skb)) + return NETDEV_TX_OK; + + ret = xcan_start_xmit_fifo(skb, ndev); + + if (ret < 0) { + netdev_err(ndev, "BUG!, TX full when queue awake!\n"); + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + return NETDEV_TX_OK; } @@ -487,13 +521,14 @@ static netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) * xcan_rx - Is called from CAN isr to complete the received * frame processing * @ndev: Pointer to net_device structure + * @frame_base: Register offset to the frame to be read * * This function is invoked from the CAN isr(poll) to process the Rx frames. It * does minimal processing and invokes "netif_receive_skb" to complete further * processing. * Return: 1 on success and 0 on failure. */ -static int xcan_rx(struct net_device *ndev) +static int xcan_rx(struct net_device *ndev, int frame_base) { struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; @@ -508,9 +543,9 @@ static int xcan_rx(struct net_device *ndev) } /* Read a frame from Xilinx zynq CANPS */ - id_xcan = priv->read_reg(priv, XCAN_RXFIFO_ID_OFFSET); - dlc = priv->read_reg(priv, XCAN_RXFIFO_DLC_OFFSET) >> - XCAN_DLCR_DLC_SHIFT; + id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base)); + dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base)) >> + XCAN_DLCR_DLC_SHIFT; /* Change Xilinx CAN data length format to socketCAN data format */ cf->can_dlc = get_can_dlc(dlc); @@ -533,8 +568,8 @@ static int xcan_rx(struct net_device *ndev) } /* DW1/DW2 must always be read to remove message from RXFIFO */ - data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); - data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + data[0] = priv->read_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_base)); + data[1] = priv->read_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_base)); if (!(cf->can_id & CAN_RTR_FLAG)) { /* Change Xilinx CAN data format to socketCAN data format */ @@ -806,7 +841,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota) isr = priv->read_reg(priv, XCAN_ISR_OFFSET); while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) { - work_done += xcan_rx(ndev); + work_done += xcan_rx(ndev, XCAN_RXFIFO_OFFSET); priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK); isr = priv->read_reg(priv, XCAN_ISR_OFFSET); } @@ -1193,13 +1228,21 @@ static const struct dev_pm_ops xcan_dev_pm_ops = { }; static const struct xcan_devtype_data xcan_zynq_data = { - .caps = XCAN_CAP_WATERMARK, + .flags = XCAN_FLAG_TXFEMP, + .bittiming_const = &xcan_bittiming_const, + .bus_clk_name = "pclk", +}; + +static const struct xcan_devtype_data xcan_axi_data = { + .flags = 0, + .bittiming_const = &xcan_bittiming_const, + .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", }, + { .compatible = "xlnx,axi-can-1.00.a", .data = &xcan_axi_data }, { /* end of list */ }, }; MODULE_DEVICE_TABLE(of, xcan_of_match); @@ -1219,7 +1262,7 @@ static int xcan_probe(struct platform_device *pdev) struct net_device *ndev; struct xcan_priv *priv; const struct of_device_id *of_id; - int caps = 0; + const struct xcan_devtype_data *devtype = &xcan_axi_data; void __iomem *addr; int ret, rx_max, tx_max, tx_fifo_depth; @@ -1241,12 +1284,8 @@ static int xcan_probe(struct platform_device *pdev) goto err; of_id = of_match_device(xcan_of_match, &pdev->dev); - if (of_id) { - const struct xcan_devtype_data *devtype_data = of_id->data; - - if (devtype_data) - caps = devtype_data->caps; - } + if (of_id && of_id->data) + devtype = of_id->data; /* There is no way to directly figure out how many frames have been * sent when the TXOK interrupt is processed. If watermark programming @@ -1259,7 +1298,7 @@ static int xcan_probe(struct platform_device *pdev) * sent), which is not a sensible state - possibly TXFWMEMP is not * completely synchronized with the rest of the bits? */ - if (caps & XCAN_CAP_WATERMARK) + if (devtype->flags & XCAN_FLAG_TXFEMP) tx_max = min(tx_fifo_depth, 2); else tx_max = 1; @@ -1271,13 +1310,14 @@ static int xcan_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->dev = &pdev->dev; - priv->can.bittiming_const = &xcan_bittiming_const; + priv->can.bittiming_const = devtype->bittiming_const; priv->can.do_set_mode = xcan_do_set_mode; priv->can.do_get_berr_counter = xcan_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_BERR_REPORTING; priv->reg_base = addr; priv->tx_max = tx_max; + priv->devtype = *devtype; spin_lock_init(&priv->tx_lock); /* Get IRQ for the device */ @@ -1295,22 +1335,12 @@ static int xcan_probe(struct platform_device *pdev) ret = PTR_ERR(priv->can_clk); goto err_free; } - /* Check for type of CAN device */ - if (of_device_is_compatible(pdev->dev.of_node, - "xlnx,zynq-can-1.0")) { - priv->bus_clk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(priv->bus_clk)) { - dev_err(&pdev->dev, "bus clock not found\n"); - ret = PTR_ERR(priv->bus_clk); - goto err_free; - } - } else { - priv->bus_clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); - if (IS_ERR(priv->bus_clk)) { - dev_err(&pdev->dev, "bus clock not found\n"); - ret = PTR_ERR(priv->bus_clk); - goto err_free; - } + + priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); + if (IS_ERR(priv->bus_clk)) { + dev_err(&pdev->dev, "bus clock not found\n"); + ret = PTR_ERR(priv->bus_clk); + goto err_free; } priv->write_reg = xcan_write_reg_le; |