Commit c08e2401 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde

Merge patch series "can: bxcan: add support for single peripheral configuration"

Dario Binacchi <dario.binacchi@amarulasolutions.com> says:

The series adds support for managing bxCAN controllers in single peripheral
configuration.
Unlike stm32f4 SOCs, where bxCAN controllers are only in dual peripheral
configuration, stm32f7 SOCs contain three CAN peripherals, CAN1 and CAN2
in dual peripheral configuration and CAN3 in single peripheral
configuration:
- Dual CAN peripheral configuration:
 * CAN1: Primary bxCAN for managing the communication between a secondary
   bxCAN and the 512-byte SRAM memory.
 * CAN2: Secondary bxCAN with no direct access to the SRAM memory.
   This means that the two bxCAN cells share the 512-byte SRAM memory and
   CAN2 can't be used without enabling CAN1.
- Single CAN peripheral configuration:
 * CAN3: Primary bxCAN with dedicated Memory Access Controller unit and
   512-byte SRAM memory.

The driver has been tested on the stm32f769i-discovery board with a
kernel version 5.19.0-rc2 in loopback + silent mode:

| ip link set can[0-2] type can bitrate 125000 loopback on listen-only on
| ip link set up can[0-2]
| candump can[0-2] -L &
| cansend can[0-2] 300#AC.AB.AD.AE.75.49.AD.D1

Changes in v2:
- s/fiter/filter/ in the commit message
- Replace struct bxcan_mb::primary with struct bxcan_mb::cfg.
- Move after the patch "can: bxcan: add support for single peripheral configuration".
- Add node gcan3.
- Rename gcan as gcan1.
- Add property "st,can-secondary" to can2 node.
- Drop patch "dt-bindings: mfd: stm32f7: add binding definition for CAN3"
  because it has been accepted.
- Add patch "ARM: dts: stm32f429: put can2 in secondary mode".
- Add patch "dt-bindings: net: can: add "st,can-secondary" property".

v1: https://lore.kernel.org/all/20230423172528.1398158-1-dario.binacchi@amarulasolutions.com

Link: https://lore.kernel.org/all/20230427204540.3126234-1-dario.binacchi@amarulasolutions.comSigned-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 4920bded 0920ccdf
......@@ -21,11 +21,22 @@ properties:
st,can-primary:
description:
Primary and secondary mode of the bxCAN peripheral is only relevant
if the chip has two CAN peripherals. In that case they share some
of the required logic.
Primary mode of the bxCAN peripheral is only relevant if the chip has
two CAN peripherals in dual CAN configuration. In that case they share
some of the required logic.
Not to be used if the peripheral is in single CAN configuration.
To avoid misunderstandings, it should be noted that ST documentation
uses the terms master/slave instead of primary/secondary.
uses the terms master instead of primary.
type: boolean
st,can-secondary:
description:
Secondary mode of the bxCAN peripheral is only relevant if the chip
has two CAN peripherals in dual CAN configuration. In that case they
share some of the required logic.
Not to be used if the peripheral is in single CAN configuration.
To avoid misunderstandings, it should be noted that ST documentation
uses the terms slave instead of secondary.
type: boolean
reg:
......
......@@ -387,6 +387,7 @@ can2: can@40006800 {
interrupt-names = "tx", "rx0", "rx1", "sce";
resets = <&rcc STM32F4_APB1_RESET(CAN2)>;
clocks = <&rcc 0 STM32F4_APB1_CLOCK(CAN2)>;
st,can-secondary;
st,gcan = <&gcan>;
status = "disabled";
};
......
......@@ -283,6 +283,88 @@ pins2 {
slew-rate = <2>;
};
};
can1_pins_a: can1-0 {
pins1 {
pinmux = <STM32_PINMUX('A', 12, AF9)>; /* CAN1_TX */
};
pins2 {
pinmux = <STM32_PINMUX('A', 11, AF9)>; /* CAN1_RX */
bias-pull-up;
};
};
can1_pins_b: can1-1 {
pins1 {
pinmux = <STM32_PINMUX('B', 9, AF9)>; /* CAN1_TX */
};
pins2 {
pinmux = <STM32_PINMUX('B', 8, AF9)>; /* CAN1_RX */
bias-pull-up;
};
};
can1_pins_c: can1-2 {
pins1 {
pinmux = <STM32_PINMUX('D', 1, AF9)>; /* CAN1_TX */
};
pins2 {
pinmux = <STM32_PINMUX('D', 0, AF9)>; /* CAN1_RX */
bias-pull-up;
};
};
can1_pins_d: can1-3 {
pins1 {
pinmux = <STM32_PINMUX('H', 13, AF9)>; /* CAN1_TX */
};
pins2 {
pinmux = <STM32_PINMUX('H', 14, AF9)>; /* CAN1_RX */
bias-pull-up;
};
};
can2_pins_a: can2-0 {
pins1 {
pinmux = <STM32_PINMUX('B', 6, AF9)>; /* CAN2_TX */
};
pins2 {
pinmux = <STM32_PINMUX('B', 5, AF9)>; /* CAN2_RX */
bias-pull-up;
};
};
can2_pins_b: can2-1 {
pins1 {
pinmux = <STM32_PINMUX('B', 13, AF9)>; /* CAN2_TX */
};
pins2 {
pinmux = <STM32_PINMUX('B', 12, AF9)>; /* CAN2_RX */
bias-pull-up;
};
};
can3_pins_a: can3-0 {
pins1 {
pinmux = <STM32_PINMUX('A', 15, AF11)>; /* CAN3_TX */
};
pins2 {
pinmux = <STM32_PINMUX('A', 8, AF11)>; /* CAN3_RX */
bias-pull-up;
};
};
can3_pins_b: can3-1 {
pins1 {
pinmux = <STM32_PINMUX('B', 4, AF11)>; /* CAN3_TX */
};
pins2 {
pinmux = <STM32_PINMUX('B', 3, AF11)>; /* CAN3_RX */
bias-pull-up;
};
};
};
};
};
......@@ -257,6 +257,23 @@ rtc: rtc@40002800 {
status = "disabled";
};
can3: can@40003400 {
compatible = "st,stm32f4-bxcan";
reg = <0x40003400 0x200>;
interrupts = <104>, <105>, <106>, <107>;
interrupt-names = "tx", "rx0", "rx1", "sce";
resets = <&rcc STM32F7_APB1_RESET(CAN3)>;
clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN3)>;
st,gcan = <&gcan3>;
status = "disabled";
};
gcan3: gcan@40003600 {
compatible = "st,stm32f4-gcan", "syscon";
reg = <0x40003600 0x200>;
clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN3)>;
};
usart2: serial@40004400 {
compatible = "st,stm32f7-uart";
reg = <0x40004400 0x400>;
......@@ -337,6 +354,36 @@ i2c4: i2c@40006000 {
status = "disabled";
};
can1: can@40006400 {
compatible = "st,stm32f4-bxcan";
reg = <0x40006400 0x200>;
interrupts = <19>, <20>, <21>, <22>;
interrupt-names = "tx", "rx0", "rx1", "sce";
resets = <&rcc STM32F7_APB1_RESET(CAN1)>;
clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN1)>;
st,can-primary;
st,gcan = <&gcan1>;
status = "disabled";
};
gcan1: gcan@40006600 {
compatible = "st,stm32f4-gcan", "syscon";
reg = <0x40006600 0x200>;
clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN1)>;
};
can2: can@40006800 {
compatible = "st,stm32f4-bxcan";
reg = <0x40006800 0x200>;
interrupts = <63>, <64>, <65>, <66>;
interrupt-names = "tx", "rx0", "rx1", "sce";
resets = <&rcc STM32F7_APB1_RESET(CAN2)>;
clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN2)>;
st,can-secondary;
st,gcan = <&gcan1>;
status = "disabled";
};
cec: cec@40006c00 {
compatible = "st,stm32-cec";
reg = <0x40006C00 0x400>;
......
......@@ -118,7 +118,7 @@
#define BXCAN_FiR1_REG(b) (0x40 + (b) * 8)
#define BXCAN_FiR2_REG(b) (0x44 + (b) * 8)
#define BXCAN_FILTER_ID(primary) (primary ? 0 : 14)
#define BXCAN_FILTER_ID(cfg) ((cfg) == BXCAN_CFG_DUAL_SECONDARY ? 14 : 0)
/* Filter primary register (FMR) bits */
#define BXCAN_FMR_CANSB_MASK GENMASK(13, 8)
......@@ -135,6 +135,12 @@ enum bxcan_lec_code {
BXCAN_LEC_UNUSED
};
enum bxcan_cfg {
BXCAN_CFG_SINGLE = 0,
BXCAN_CFG_DUAL_PRIMARY,
BXCAN_CFG_DUAL_SECONDARY
};
/* Structure of the message buffer */
struct bxcan_mb {
u32 id; /* can identifier */
......@@ -167,7 +173,7 @@ struct bxcan_priv {
struct regmap *gcan;
int tx_irq;
int sce_irq;
bool primary;
enum bxcan_cfg cfg;
struct clk *clk;
spinlock_t rmw_lock; /* lock for read-modify-write operations */
unsigned int tx_head;
......@@ -202,17 +208,17 @@ static inline void bxcan_rmw(struct bxcan_priv *priv, void __iomem *addr,
spin_unlock_irqrestore(&priv->rmw_lock, flags);
}
static void bxcan_disable_filters(struct bxcan_priv *priv, bool primary)
static void bxcan_disable_filters(struct bxcan_priv *priv, enum bxcan_cfg cfg)
{
unsigned int fid = BXCAN_FILTER_ID(primary);
unsigned int fid = BXCAN_FILTER_ID(cfg);
u32 fmask = BIT(fid);
regmap_update_bits(priv->gcan, BXCAN_FA1R_REG, fmask, 0);
}
static void bxcan_enable_filters(struct bxcan_priv *priv, bool primary)
static void bxcan_enable_filters(struct bxcan_priv *priv, enum bxcan_cfg cfg)
{
unsigned int fid = BXCAN_FILTER_ID(primary);
unsigned int fid = BXCAN_FILTER_ID(cfg);
u32 fmask = BIT(fid);
/* Filter settings:
......@@ -680,7 +686,7 @@ static int bxcan_chip_start(struct net_device *ndev)
BXCAN_BTR_BRP_MASK | BXCAN_BTR_TS1_MASK | BXCAN_BTR_TS2_MASK |
BXCAN_BTR_SJW_MASK, set);
bxcan_enable_filters(priv, priv->primary);
bxcan_enable_filters(priv, priv->cfg);
/* Clear all internal status */
priv->tx_head = 0;
......@@ -806,7 +812,7 @@ static void bxcan_chip_stop(struct net_device *ndev)
BXCAN_IER_EPVIE | BXCAN_IER_EWGIE | BXCAN_IER_FOVIE1 |
BXCAN_IER_FFIE1 | BXCAN_IER_FMPIE1 | BXCAN_IER_FOVIE0 |
BXCAN_IER_FFIE0 | BXCAN_IER_FMPIE0 | BXCAN_IER_TMEIE, 0);
bxcan_disable_filters(priv, priv->primary);
bxcan_disable_filters(priv, priv->cfg);
bxcan_enter_sleep_mode(priv);
priv->can.state = CAN_STATE_STOPPED;
}
......@@ -931,7 +937,7 @@ static int bxcan_probe(struct platform_device *pdev)
struct clk *clk = NULL;
void __iomem *regs;
struct regmap *gcan;
bool primary;
enum bxcan_cfg cfg;
int err, rx_irq, tx_irq, sce_irq;
regs = devm_platform_ioremap_resource(pdev, 0);
......@@ -946,7 +952,13 @@ static int bxcan_probe(struct platform_device *pdev)
return PTR_ERR(gcan);
}
primary = of_property_read_bool(np, "st,can-primary");
if (of_property_read_bool(np, "st,can-primary"))
cfg = BXCAN_CFG_DUAL_PRIMARY;
else if (of_property_read_bool(np, "st,can-secondary"))
cfg = BXCAN_CFG_DUAL_SECONDARY;
else
cfg = BXCAN_CFG_SINGLE;
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) {
dev_err(dev, "failed to get clock\n");
......@@ -992,7 +1004,7 @@ static int bxcan_probe(struct platform_device *pdev)
priv->clk = clk;
priv->tx_irq = tx_irq;
priv->sce_irq = sce_irq;
priv->primary = primary;
priv->cfg = cfg;
priv->can.clock.freq = clk_get_rate(clk);
spin_lock_init(&priv->rmw_lock);
priv->tx_head = 0;
......
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