Commit 85ef87ba authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-5.19-20220419' of...

Merge tag 'linux-can-next-for-5.19-20220419' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2022-04-19

this is a pull request of 17 patches for net-next/master.

The first 2 patches are by me and target the CAN driver
infrastructure. One patch renames a function in the rx_offload helper
the other one updates the CAN bitrate calculation to prefer small bit
rate pre-scalers over larger ones, which is encouraged by the CAN in
Automation.

Kris Bahnsen contributes a patch to fix the links to Technologic
Systems web resources in the sja1000 driver.

Christophe Leroy's patch prepares the mpc5xxx_can driver for upcoming
powerpc header cleanup.

Minghao Chi's patch converts the flexcan driver to use
pm_runtime_resume_and_get().

The next 2 patches target the Xilinx CAN driver. Lukas Bulwahn's patch
fixes an entry in the MAINTAINERS file. A patch by me marks the bit
timing constants as const.

Wolfram Sang's patch documents r8a77961 support on the
renesas,rcar-canfd bindings document.

The next 2 patches are by me and add support for the mcp251863 chip to
the mcp251xfd driver.

The last 7 patches are by Pavel Pisa, Martin Jerabek et al. and add
the ctucanfd driver for the CTU CAN FD IP Core.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c1f6f1e6 cfdb2f36
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/can/ctu,ctucanfd.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: CTU CAN FD Open-source IP Core Device Tree Bindings
description: |
Open-source CAN FD IP core developed at the Czech Technical University in Prague
The core sources and documentation on project page
[1] sources : https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core
[2] datasheet : https://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/doc/Datasheet.pdf
Integration in Xilinx Zynq SoC based system together with
OpenCores SJA1000 compatible controllers
[3] project : https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top
Martin Jerabek dimploma thesis with integration and testing
framework description
[4] PDF : https://dspace.cvut.cz/bitstream/handle/10467/80366/F3-DP-2019-Jerabek-Martin-Jerabek-thesis-2019-canfd.pdf
maintainers:
- Pavel Pisa <pisa@cmp.felk.cvut.cz>
- Ondrej Ille <ondrej.ille@gmail.com>
- Martin Jerabek <martin.jerabek01@gmail.com>
properties:
compatible:
oneOf:
- items:
- const: ctu,ctucanfd-2
- const: ctu,ctucanfd
- const: ctu,ctucanfd
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
description: |
phandle of reference clock (100 MHz is appropriate
for FPGA implementation on Zynq-7000 system).
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
additionalProperties: false
examples:
- |
ctu_can_fd_0: can@43c30000 {
compatible = "ctu,ctucanfd";
interrupts = <0 30 4>;
clocks = <&clkc 15>;
reg = <0x43c30000 0x10000>;
};
......@@ -5,8 +5,8 @@ $id: http://devicetree.org/schemas/net/can/microchip,mcp251xfd.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title:
Microchip MCP2517FD and MCP2518FD stand-alone CAN controller device tree
bindings
Microchip MCP2517FD, MCP2518FD and MCP251863 stand-alone CAN
controller device tree bindings
maintainers:
- Marc Kleine-Budde <mkl@pengutronix.de>
......@@ -17,13 +17,14 @@ allOf:
properties:
compatible:
oneOf:
- const: microchip,mcp2517fd
description: for MCP2517FD
- enum:
- microchip,mcp2517fd
- microchip,mcp2518fd
- microchip,mcp251xfd
- items:
- enum:
- microchip,mcp251863
- const: microchip,mcp2518fd
description: for MCP2518FD
- const: microchip,mcp251xfd
description: to autodetect chip variant
reg:
maxItems: 1
......
......@@ -23,6 +23,7 @@ properties:
- renesas,r8a774e1-canfd # RZ/G2H
- renesas,r8a7795-canfd # R-Car H3
- renesas,r8a7796-canfd # R-Car M3-W
- renesas,r8a77961-canfd # R-Car M3-W+
- renesas,r8a77965-canfd # R-Car M3-N
- renesas,r8a77970-canfd # R-Car V3M
- renesas,r8a77980-canfd # R-Car V3H
......
......@@ -283,6 +283,8 @@ patternProperties:
description: Shenzen Chuangsiqi Technology Co.,Ltd.
"^ctera,.*":
description: CTERA Networks Intl.
"^ctu,.*":
description: Czech Technical University in Prague
"^cubietech,.*":
description: Cubietech, Ltd.
"^cui,.*":
......
......@@ -5234,6 +5234,14 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
F: drivers/media/platform/sunxi/sun6i-csi/
CTU CAN FD DRIVER
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
M: Ondrej Ille <ondrej.ille@gmail.com>
L: linux-can@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml
F: drivers/net/can/ctucanfd/
CW1200 WLAN driver
M: Solomon Peachy <pizza@shaftnet.org>
S: Maintained
......@@ -21632,7 +21640,7 @@ M: Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>
R: Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
L: linux-can@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/can/xilinx_can.txt
F: Documentation/devicetree/bindings/net/can/xilinx,can.yaml
F: drivers/net/can/xilinx_can.c
XILINX GPIO DRIVER
......
......@@ -170,6 +170,7 @@ config PCH_CAN
source "drivers/net/can/c_can/Kconfig"
source "drivers/net/can/cc770/Kconfig"
source "drivers/net/can/ctucanfd/Kconfig"
source "drivers/net/can/ifi_canfd/Kconfig"
source "drivers/net/can/m_can/Kconfig"
source "drivers/net/can/mscan/Kconfig"
......
......@@ -16,6 +16,7 @@ obj-y += softing/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_CC770) += cc770/
obj-$(CONFIG_CAN_C_CAN) += c_can/
obj-$(CONFIG_CAN_CTUCANFD) += ctucanfd/
obj-$(CONFIG_CAN_FLEXCAN) += flexcan/
obj-$(CONFIG_CAN_GRCAN) += grcan.o
obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
......
config CAN_CTUCANFD
tristate "CTU CAN-FD IP core"
help
This driver adds support for the CTU CAN FD open-source IP core.
More documentation and core sources at project page
(https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core).
The core integration to Xilinx Zynq system as platform driver
is available (https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top).
Implementation on Intel FPGA-based PCI Express board is available
from project (https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd) and
on Intel SoC from project (https://gitlab.fel.cvut.cz/canbus/intel-soc-ctucanfd).
Guidepost CTU FEE CAN bus projects page https://canbus.pages.fel.cvut.cz/ .
config CAN_CTUCANFD_PCI
tristate "CTU CAN-FD IP core PCI/PCIe driver"
depends on CAN_CTUCANFD
depends on PCI
help
This driver adds PCI/PCIe support for CTU CAN-FD IP core.
The project providing FPGA design for Intel EP4CGX15 based DB4CGX15
PCIe board with PiKRON.com designed transceiver riser shield is available
at https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd .
config CAN_CTUCANFD_PLATFORM
tristate "CTU CAN-FD IP core platform (FPGA, SoC) driver"
depends on CAN_CTUCANFD
depends on OF || COMPILE_TEST
help
The core has been tested together with OpenCores SJA1000
modified to be CAN FD frames tolerant on MicroZed Zynq based
MZ_APO education kits designed by Petr Porazil from PiKRON.com
company. FPGA design https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top.
The kit description at the Computer Architectures course pages
https://cw.fel.cvut.cz/wiki/courses/b35apo/documentation/mz_apo/start .
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Makefile for the CTU CAN-FD IP module drivers
#
obj-$(CONFIG_CAN_CTUCANFD) := ctucanfd.o
ctucanfd-y := ctucanfd_base.o
obj-$(CONFIG_CAN_CTUCANFD_PCI) += ctucanfd_pci.o
obj-$(CONFIG_CAN_CTUCANFD_PLATFORM) += ctucanfd_platform.o
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*******************************************************************************
*
* CTU CAN FD IP Core
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
*
* Project advisors:
* Jiri Novak <jnovak@fel.cvut.cz>
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
*
* Department of Measurement (http://meas.fel.cvut.cz/)
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
* Czech Technical University (http://www.cvut.cz/)
******************************************************************************/
#ifndef __CTUCANFD__
#define __CTUCANFD__
#include <linux/netdevice.h>
#include <linux/can/dev.h>
#include <linux/list.h>
enum ctu_can_fd_can_registers;
struct ctucan_priv {
struct can_priv can; /* must be first member! */
void __iomem *mem_base;
u32 (*read_reg)(struct ctucan_priv *priv,
enum ctu_can_fd_can_registers reg);
void (*write_reg)(struct ctucan_priv *priv,
enum ctu_can_fd_can_registers reg, u32 val);
unsigned int txb_head;
unsigned int txb_tail;
u32 txb_prio;
unsigned int ntxbufs;
spinlock_t tx_lock; /* spinlock to serialize allocation and processing of TX buffers */
struct napi_struct napi;
struct device *dev;
struct clk *can_clk;
int irq_flags;
unsigned long drv_flags;
u32 rxfrm_first_word;
struct list_head peers_on_pdev;
};
/**
* ctucan_probe_common - Device type independent registration call
*
* This function does all the memory allocation and registration for the CAN
* device.
*
* @dev: Handle to the generic device structure
* @addr: Base address of CTU CAN FD core address
* @irq: Interrupt number
* @ntxbufs: Number of implemented Tx buffers
* @can_clk_rate: Clock rate, if 0 then clock are taken from device node
* @pm_enable_call: Whether pm_runtime_enable should be called
* @set_drvdata_fnc: Function to set network driver data for physical device
*
* Return: 0 on success and failure value on error
*/
int ctucan_probe_common(struct device *dev, void __iomem *addr,
int irq, unsigned int ntxbufs,
unsigned long can_clk_rate,
int pm_enable_call,
void (*set_drvdata_fnc)(struct device *dev,
struct net_device *ndev));
int ctucan_suspend(struct device *dev) __maybe_unused;
int ctucan_resume(struct device *dev) __maybe_unused;
#endif /*__CTUCANFD__*/
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*******************************************************************************
*
* CTU CAN FD IP Core
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
*
* Project advisors:
* Jiri Novak <jnovak@fel.cvut.cz>
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
*
* Department of Measurement (http://meas.fel.cvut.cz/)
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
* Czech Technical University (http://www.cvut.cz/)
******************************************************************************/
/* This file is autogenerated, DO NOT EDIT! */
#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__
#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__
#include <linux/bits.h>
/* CAN_Frame_format memory map */
enum ctu_can_fd_can_frame_format {
CTUCANFD_FRAME_FORMAT_W = 0x0,
CTUCANFD_IDENTIFIER_W = 0x4,
CTUCANFD_TIMESTAMP_L_W = 0x8,
CTUCANFD_TIMESTAMP_U_W = 0xc,
CTUCANFD_DATA_1_4_W = 0x10,
CTUCANFD_DATA_5_8_W = 0x14,
CTUCANFD_DATA_61_64_W = 0x4c,
};
/* CAN_FD_Frame_format memory region */
/* FRAME_FORMAT_W registers */
#define REG_FRAME_FORMAT_W_DLC GENMASK(3, 0)
#define REG_FRAME_FORMAT_W_RTR BIT(5)
#define REG_FRAME_FORMAT_W_IDE BIT(6)
#define REG_FRAME_FORMAT_W_FDF BIT(7)
#define REG_FRAME_FORMAT_W_BRS BIT(9)
#define REG_FRAME_FORMAT_W_ESI_RSV BIT(10)
#define REG_FRAME_FORMAT_W_RWCNT GENMASK(15, 11)
/* IDENTIFIER_W registers */
#define REG_IDENTIFIER_W_IDENTIFIER_EXT GENMASK(17, 0)
#define REG_IDENTIFIER_W_IDENTIFIER_BASE GENMASK(28, 18)
/* TIMESTAMP_L_W registers */
#define REG_TIMESTAMP_L_W_TIME_STAMP_L_W GENMASK(31, 0)
/* TIMESTAMP_U_W registers */
#define REG_TIMESTAMP_U_W_TIMESTAMP_U_W GENMASK(31, 0)
/* DATA_1_4_W registers */
#define REG_DATA_1_4_W_DATA_1 GENMASK(7, 0)
#define REG_DATA_1_4_W_DATA_2 GENMASK(15, 8)
#define REG_DATA_1_4_W_DATA_3 GENMASK(23, 16)
#define REG_DATA_1_4_W_DATA_4 GENMASK(31, 24)
/* DATA_5_8_W registers */
#define REG_DATA_5_8_W_DATA_5 GENMASK(7, 0)
#define REG_DATA_5_8_W_DATA_6 GENMASK(15, 8)
#define REG_DATA_5_8_W_DATA_7 GENMASK(23, 16)
#define REG_DATA_5_8_W_DATA_8 GENMASK(31, 24)
/* DATA_61_64_W registers */
#define REG_DATA_61_64_W_DATA_61 GENMASK(7, 0)
#define REG_DATA_61_64_W_DATA_62 GENMASK(15, 8)
#define REG_DATA_61_64_W_DATA_63 GENMASK(23, 16)
#define REG_DATA_61_64_W_DATA_64 GENMASK(31, 24)
#endif
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
*
* CTU CAN FD IP Core
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
* Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
*
* Project advisors:
* Jiri Novak <jnovak@fel.cvut.cz>
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
*
* Department of Measurement (http://meas.fel.cvut.cz/)
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
* Czech Technical University (http://www.cvut.cz/)
******************************************************************************/
#include <linux/module.h>
#include <linux/pci.h>
#include "ctucanfd.h"
#ifndef PCI_DEVICE_DATA
#define PCI_DEVICE_DATA(vend, dev, data) \
.vendor = PCI_VENDOR_ID_##vend, \
.device = PCI_DEVICE_ID_##vend##_##dev, \
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0, \
.driver_data = (kernel_ulong_t)(data)
#endif
#ifndef PCI_VENDOR_ID_TEDIA
#define PCI_VENDOR_ID_TEDIA 0x1760
#endif
#ifndef PCI_DEVICE_ID_TEDIA_CTUCAN_VER21
#define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
#endif
#define CTUCAN_BAR0_CTUCAN_ID 0x0000
#define CTUCAN_BAR0_CRA_BASE 0x4000
#define CYCLONE_IV_CRA_A2P_IE (0x0050)
#define CTUCAN_WITHOUT_CTUCAN_ID 0
#define CTUCAN_WITH_CTUCAN_ID 1
static bool use_msi = true;
module_param(use_msi, bool, 0444);
MODULE_PARM_DESC(use_msi, "PCIe implementation use MSI interrupts. Default: 1 (yes)");
static bool pci_use_second = true;
module_param(pci_use_second, bool, 0444);
MODULE_PARM_DESC(pci_use_second, "Use the second CAN core on PCIe card. Default: 1 (yes)");
struct ctucan_pci_board_data {
void __iomem *bar0_base;
void __iomem *cra_base;
void __iomem *bar1_base;
struct list_head ndev_list_head;
int use_msi;
};
static struct ctucan_pci_board_data *ctucan_pci_get_bdata(struct pci_dev *pdev)
{
return (struct ctucan_pci_board_data *)pci_get_drvdata(pdev);
}
static void ctucan_pci_set_drvdata(struct device *dev,
struct net_device *ndev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
struct ctucan_priv *priv = netdev_priv(ndev);
struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
list_add(&priv->peers_on_pdev, &bdata->ndev_list_head);
priv->irq_flags = IRQF_SHARED;
}
/**
* ctucan_pci_probe - PCI registration call
* @pdev: Handle to the pci device structure
* @ent: Pointer to the entry from ctucan_pci_tbl
*
* This function does all the memory allocation and registration for the CAN
* device.
*
* Return: 0 on success and failure value on error
*/
static int ctucan_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
unsigned long driver_data = ent->driver_data;
struct ctucan_pci_board_data *bdata;
void __iomem *addr;
void __iomem *cra_addr;
void __iomem *bar0_base;
u32 cra_a2p_ie;
u32 ctucan_id = 0;
int ret;
unsigned int ntxbufs;
unsigned int num_cores = 1;
unsigned int core_i = 0;
int irq;
int msi_ok = 0;
ret = pci_enable_device(pdev);
if (ret) {
dev_err(dev, "pci_enable_device FAILED\n");
goto err;
}
ret = pci_request_regions(pdev, KBUILD_MODNAME);
if (ret) {
dev_err(dev, "pci_request_regions FAILED\n");
goto err_disable_device;
}
if (use_msi) {
ret = pci_enable_msi(pdev);
if (!ret) {
dev_info(dev, "MSI enabled\n");
pci_set_master(pdev);
msi_ok = 1;
}
}
dev_info(dev, "ctucan BAR0 0x%08llx 0x%08llx\n",
(long long)pci_resource_start(pdev, 0),
(long long)pci_resource_len(pdev, 0));
dev_info(dev, "ctucan BAR1 0x%08llx 0x%08llx\n",
(long long)pci_resource_start(pdev, 1),
(long long)pci_resource_len(pdev, 1));
addr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
if (!addr) {
dev_err(dev, "PCI BAR 1 cannot be mapped\n");
ret = -ENOMEM;
goto err_release_regions;
}
/* Cyclone IV PCI Express Control Registers Area */
bar0_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
if (!bar0_base) {
dev_err(dev, "PCI BAR 0 cannot be mapped\n");
ret = -EIO;
goto err_pci_iounmap_bar1;
}
if (driver_data == CTUCAN_WITHOUT_CTUCAN_ID) {
cra_addr = bar0_base;
num_cores = 2;
} else {
cra_addr = bar0_base + CTUCAN_BAR0_CRA_BASE;
ctucan_id = ioread32(bar0_base + CTUCAN_BAR0_CTUCAN_ID);
dev_info(dev, "ctucan_id 0x%08lx\n", (unsigned long)ctucan_id);
num_cores = ctucan_id & 0xf;
}
irq = pdev->irq;
ntxbufs = 4;
bdata = kzalloc(sizeof(*bdata), GFP_KERNEL);
if (!bdata) {
ret = -ENOMEM;
goto err_pci_iounmap_bar0;
}
INIT_LIST_HEAD(&bdata->ndev_list_head);
bdata->bar0_base = bar0_base;
bdata->cra_base = cra_addr;
bdata->bar1_base = addr;
bdata->use_msi = msi_ok;
pci_set_drvdata(pdev, bdata);
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
0, ctucan_pci_set_drvdata);
if (ret < 0)
goto err_free_board;
core_i++;
while (pci_use_second && (core_i < num_cores)) {
addr += 0x4000;
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
0, ctucan_pci_set_drvdata);
if (ret < 0) {
dev_info(dev, "CTU CAN FD core %d initialization failed\n",
core_i);
break;
}
core_i++;
}
/* enable interrupt in
* Avalon-MM to PCI Express Interrupt Enable Register
*/
cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
cra_a2p_ie |= 1;
iowrite32(cra_a2p_ie, cra_addr + CYCLONE_IV_CRA_A2P_IE);
cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
return 0;
err_free_board:
pci_set_drvdata(pdev, NULL);
kfree(bdata);
err_pci_iounmap_bar0:
pci_iounmap(pdev, cra_addr);
err_pci_iounmap_bar1:
pci_iounmap(pdev, addr);
err_release_regions:
if (msi_ok) {
pci_disable_msi(pdev);
pci_clear_master(pdev);
}
pci_release_regions(pdev);
err_disable_device:
pci_disable_device(pdev);
err:
return ret;
}
/**
* ctucan_pci_remove - Unregister the device after releasing the resources
* @pdev: Handle to the pci device structure
*
* This function frees all the resources allocated to the device.
* Return: 0 always
*/
static void ctucan_pci_remove(struct pci_dev *pdev)
{
struct net_device *ndev;
struct ctucan_priv *priv = NULL;
struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
dev_dbg(&pdev->dev, "ctucan_remove");
if (!bdata) {
dev_err(&pdev->dev, "%s: no list of devices\n", __func__);
return;
}
/* disable interrupt in
* Avalon-MM to PCI Express Interrupt Enable Register
*/
if (bdata->cra_base)
iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE);
while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv,
peers_on_pdev)) != NULL) {
ndev = priv->can.dev;
unregister_candev(ndev);
netif_napi_del(&priv->napi);
list_del_init(&priv->peers_on_pdev);
free_candev(ndev);
}
pci_iounmap(pdev, bdata->bar1_base);
if (bdata->use_msi) {
pci_disable_msi(pdev);
pci_clear_master(pdev);
}
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_iounmap(pdev, bdata->bar0_base);
pci_set_drvdata(pdev, NULL);
kfree(bdata);
}
static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
static const struct pci_device_id ctucan_pci_tbl[] = {
{PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
CTUCAN_WITH_CTUCAN_ID)},
{},
};
static struct pci_driver ctucan_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = ctucan_pci_tbl,
.probe = ctucan_pci_probe,
.remove = ctucan_pci_remove,
.driver.pm = &ctucan_pci_pm_ops,
};
module_pci_driver(ctucan_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
MODULE_DESCRIPTION("CTU CAN FD for PCI bus");
// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
*
* CTU CAN FD IP Core
*
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
* Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
*
* Project advisors:
* Jiri Novak <jnovak@fel.cvut.cz>
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
*
* Department of Measurement (http://meas.fel.cvut.cz/)
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
* Czech Technical University (http://www.cvut.cz/)
******************************************************************************/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include "ctucanfd.h"
#define DRV_NAME "ctucanfd"
static void ctucan_platform_set_drvdata(struct device *dev,
struct net_device *ndev)
{
struct platform_device *pdev = container_of(dev, struct platform_device,
dev);
platform_set_drvdata(pdev, ndev);
}
/**
* ctucan_platform_probe - Platform registration call
* @pdev: Handle to the platform device structure
*
* This function does all the memory allocation and registration for the CAN
* device.
*
* Return: 0 on success and failure value on error
*/
static int ctucan_platform_probe(struct platform_device *pdev)
{
struct resource *res; /* IO mem resources */
struct device *dev = &pdev->dev;
void __iomem *addr;
int ret;
unsigned int ntxbufs;
int irq;
/* Get the virtual base address for the device */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr)) {
dev_err(dev, "Cannot remap address.\n");
ret = PTR_ERR(addr);
goto err;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "Cannot find interrupt.\n");
ret = irq;
goto err;
}
/* Number of tx bufs might be change in HW for future. If so,
* it will be passed as property via device tree
*/
ntxbufs = 4;
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 0,
1, ctucan_platform_set_drvdata);
if (ret < 0)
platform_set_drvdata(pdev, NULL);
err:
return ret;
}
/**
* ctucan_platform_remove - Unregister the device after releasing the resources
* @pdev: Handle to the platform device structure
*
* This function frees all the resources allocated to the device.
* Return: 0 always
*/
static int ctucan_platform_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ctucan_priv *priv = netdev_priv(ndev);
netdev_dbg(ndev, "ctucan_remove");
unregister_candev(ndev);
pm_runtime_disable(&pdev->dev);
netif_napi_del(&priv->napi);
free_candev(ndev);
return 0;
}
static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
/* Match table for OF platform binding */
static const struct of_device_id ctucan_of_match[] = {
{ .compatible = "ctu,ctucanfd-2", },
{ .compatible = "ctu,ctucanfd", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, ctucan_of_match);
static struct platform_driver ctucanfd_driver = {
.probe = ctucan_platform_probe,
.remove = ctucan_platform_remove,
.driver = {
.name = DRV_NAME,
.pm = &ctucan_platform_pm_ops,
.of_match_table = ctucan_of_match,
},
};
module_platform_driver(ctucanfd_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Martin Jerabek");
MODULE_DESCRIPTION("CTU CAN FD for platform");
......@@ -116,7 +116,7 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
&tseg1, &tseg2, &sample_point_error);
if (sample_point_error > best_sample_point_error)
if (sample_point_error >= best_sample_point_error)
continue;
best_sample_point_error = sample_point_error;
......
......@@ -221,7 +221,7 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
}
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
int can_rx_offload_queue_timestamp(struct can_rx_offload *offload,
struct sk_buff *skb, u32 timestamp)
{
struct can_rx_offload_cb *cb;
......@@ -240,7 +240,7 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
return 0;
}
EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
EXPORT_SYMBOL_GPL(can_rx_offload_queue_timestamp);
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
unsigned int idx, u32 timestamp,
......@@ -256,7 +256,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
if (!skb)
return 0;
err = can_rx_offload_queue_sorted(offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(offload, skb, timestamp);
if (err) {
stats->rx_errors++;
stats->tx_fifo_errors++;
......
......@@ -723,11 +723,9 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
const struct flexcan_priv *priv = netdev_priv(dev);
int err;
err = pm_runtime_get_sync(priv->dev);
if (err < 0) {
pm_runtime_put_noidle(priv->dev);
err = pm_runtime_resume_and_get(priv->dev);
if (err < 0)
return err;
}
err = __flexcan_get_berr_counter(dev, bec);
......@@ -845,7 +843,7 @@ static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
if (tx_errors)
dev->stats.tx_errors++;
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
if (err)
dev->stats.rx_fifo_errors++;
}
......@@ -892,7 +890,7 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
if (unlikely(new_state == CAN_STATE_BUS_OFF))
can_bus_off(dev);
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
if (err)
dev->stats.rx_fifo_errors++;
}
......@@ -1700,11 +1698,9 @@ static int flexcan_open(struct net_device *dev)
return -EINVAL;
}
err = pm_runtime_get_sync(priv->dev);
if (err < 0) {
pm_runtime_put_noidle(priv->dev);
err = pm_runtime_resume_and_get(priv->dev);
if (err < 0)
return err;
}
err = open_candev(dev);
if (err)
......
......@@ -464,7 +464,7 @@ static void m_can_receive_skb(struct m_can_classdev *cdev,
struct net_device_stats *stats = &cdev->net->stats;
int err;
err = can_rx_offload_queue_sorted(&cdev->offload, skb,
err = can_rx_offload_queue_timestamp(&cdev->offload, skb,
timestamp);
if (err)
stats->rx_fifo_errors++;
......
......@@ -14,6 +14,8 @@
#include <linux/platform_device.h>
#include <linux/netdevice.h>
#include <linux/can/dev.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include <linux/clk.h>
......
......@@ -107,7 +107,7 @@ config CAN_TSCAN1
depends on ISA
help
This driver is for Technologic Systems' TSCAN-1 PC104 boards.
http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
https://www.embeddedts.com/products/TS-CAN1
The driver supports multiple boards and automatically configures them:
PLD IO base addresses are read from jumpers JP1 and JP2,
IRQ numbers are read from jumpers JP4 and JP5,
......
......@@ -5,10 +5,9 @@
* Copyright 2010 Andre B. Oliveira
*/
/*
* References:
* - Getting started with TS-CAN1, Technologic Systems, Jun 2009
* http://www.embeddedarm.com/documentation/ts-can1-manual.pdf
/* References:
* - Getting started with TS-CAN1, Technologic Systems, Feb 2022
* https://docs.embeddedts.com/TS-CAN1
*/
#include <linux/init.h>
......
......@@ -37,6 +37,12 @@ static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp2518fd = {
.model = MCP251XFD_MODEL_MCP2518FD,
};
static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251863 = {
.quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX |
MCP251XFD_QUIRK_CRC_TX | MCP251XFD_QUIRK_ECC,
.model = MCP251XFD_MODEL_MCP251863,
};
/* Autodetect model, start with CRC enabled. */
static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251xfd = {
.quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX |
......@@ -75,6 +81,8 @@ static const char *__mcp251xfd_get_model_str(enum mcp251xfd_model model)
return "MCP2517FD";
case MCP251XFD_MODEL_MCP2518FD:
return "MCP2518FD";
case MCP251XFD_MODEL_MCP251863:
return "MCP251863";
case MCP251XFD_MODEL_MCP251XFD:
return "MCP251xFD";
}
......@@ -916,7 +924,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
if (err)
stats->rx_fifo_errors++;
......@@ -1021,7 +1029,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
return 0;
mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
if (err)
stats->rx_fifo_errors++;
......@@ -1094,7 +1102,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
cf->data[7] = bec.rxerr;
}
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
if (err)
stats->rx_fifo_errors++;
......@@ -1259,7 +1267,8 @@ mcp251xfd_handle_eccif_recover(struct mcp251xfd_priv *priv, u8 nr)
* - for mcp2518fd: offset not 0 or 1
*/
if (chip_tx_tail != tx_tail ||
!(offset == 0 || (offset == 1 && mcp251xfd_is_2518(priv)))) {
!(offset == 0 || (offset == 1 && (mcp251xfd_is_2518FD(priv) ||
mcp251xfd_is_251863(priv))))) {
netdev_err(priv->ndev,
"ECC Error information inconsistent (addr=0x%04x, nr=%d, tx_tail=0x%08x(%d), chip_tx_tail=%d, offset=%d).\n",
addr, nr, tx_ring->tail, tx_tail, chip_tx_tail,
......@@ -1697,7 +1706,7 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv)
else
devtype_data = &mcp251xfd_devtype_data_mcp2517fd;
if (!mcp251xfd_is_251X(priv) &&
if (!mcp251xfd_is_251XFD(priv) &&
priv->devtype_data.model != devtype_data->model) {
netdev_info(ndev,
"Detected %s, but firmware specifies a %s. Fixing up.\n",
......@@ -1929,6 +1938,9 @@ static const struct of_device_id mcp251xfd_of_match[] = {
}, {
.compatible = "microchip,mcp2518fd",
.data = &mcp251xfd_devtype_data_mcp2518fd,
}, {
.compatible = "microchip,mcp251863",
.data = &mcp251xfd_devtype_data_mcp251863,
}, {
.compatible = "microchip,mcp251xfd",
.data = &mcp251xfd_devtype_data_mcp251xfd,
......@@ -1945,6 +1957,9 @@ static const struct spi_device_id mcp251xfd_id_table[] = {
}, {
.name = "mcp2518fd",
.driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp2518fd,
}, {
.name = "mcp251863",
.driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251863,
}, {
.name = "mcp251xfd",
.driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251xfd,
......
......@@ -173,7 +173,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
}
mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
err = can_rx_offload_queue_sorted(&priv->offload, skb, hw_rx_obj->ts);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
if (err)
stats->rx_fifo_errors++;
......
......@@ -586,7 +586,8 @@ struct mcp251xfd_regs_status {
enum mcp251xfd_model {
MCP251XFD_MODEL_MCP2517FD = 0x2517,
MCP251XFD_MODEL_MCP2518FD = 0x2518,
MCP251XFD_MODEL_MCP251XFD = 0xffff, /* autodetect model */
MCP251XFD_MODEL_MCP251863 = 0x251863,
MCP251XFD_MODEL_MCP251XFD = 0xffffffff, /* autodetect model */
};
struct mcp251xfd_devtype_data {
......@@ -659,12 +660,13 @@ struct mcp251xfd_priv {
static inline bool \
mcp251xfd_is_##_model(const struct mcp251xfd_priv *priv) \
{ \
return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model##FD; \
return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model; \
}
MCP251XFD_IS(2517);
MCP251XFD_IS(2518);
MCP251XFD_IS(251X);
MCP251XFD_IS(2517FD);
MCP251XFD_IS(2518FD);
MCP251XFD_IS(251863);
MCP251XFD_IS(251XFD);
static inline bool mcp251xfd_is_fd_mode(const struct mcp251xfd_priv *priv)
{
......
......@@ -633,7 +633,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
timestamp = hecc_read(priv, HECC_CANLNT);
err = can_rx_offload_queue_sorted(&priv->offload, skb,
err = can_rx_offload_queue_timestamp(&priv->offload, skb,
timestamp);
if (err)
ndev->stats.rx_fifo_errors++;
......@@ -668,7 +668,7 @@ static void ti_hecc_change_state(struct net_device *ndev,
}
timestamp = hecc_read(priv, HECC_CANLNT);
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
if (err)
ndev->stats.rx_fifo_errors++;
}
......
......@@ -239,7 +239,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd = {
};
/* AXI CANFD Data Bittiming constants as per AXI CANFD 1.0 specs */
static struct can_bittiming_const xcan_data_bittiming_const_canfd = {
static const struct can_bittiming_const xcan_data_bittiming_const_canfd = {
.name = DRIVER_NAME,
.tseg1_min = 1,
.tseg1_max = 16,
......@@ -265,7 +265,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
};
/* AXI CANFD 2.0 Data Bittiming constants as per AXI CANFD 2.0 spec */
static struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
.name = DRIVER_NAME,
.tseg1_min = 1,
.tseg1_max = 32,
......
......@@ -42,7 +42,7 @@ int can_rx_offload_add_manual(struct net_device *dev,
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
u64 reg);
int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload);
int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
int can_rx_offload_queue_timestamp(struct can_rx_offload *offload,
struct sk_buff *skb, u32 timestamp);
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
unsigned int idx, u32 timestamp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment