We got it to work. We are going to test it thoroughly but it seems to be working fine for now.
We downloaded a 5.5.0 TorizonCore image (which is previous to the inclusion of the CONFIG_CAN_SJA1000=m and CONFIG_CAN_SJA1000_PLATFORM=m options), we download the SJA1000 kernel driver source code, modified as needed it and then added it to be compiled and included in our custom TorizonCore image. After a lot of trial and error and device tree tweaking we finally got it working.
As described in our previous post, for the driver, we only needed to modify a number in each of the sp_technologic_read_reg16 and sp_technologic_write_reg16 functions. We modified it so that in the second EIM access step instead of writing or reading to or from address reg_base + 2, it writes or reads to or from address reg_base + 4. Everything else is exactly the same as in the in-tree driver.
static u8 sp_technologic_read_reg16(const struct sja1000_priv *priv, int reg)
{
struct technologic_priv *tp = priv->priv;
unsigned long flags;
u8 val;
spin_lock_irqsave(&tp->io_lock, flags);
iowrite16(reg, priv->reg_base + 0);
val = ioread16(priv->reg_base + 4);
spin_unlock_irqrestore(&tp->io_lock, flags);
return val;
}
static void sp_technologic_write_reg16(const struct sja1000_priv *priv,
int reg, u8 val)
{
struct technologic_priv *tp = priv->priv;
unsigned long flags;
spin_lock_irqsave(&tp->io_lock, flags);
iowrite16(reg, priv->reg_base + 0);
iowrite16(val, priv->reg_base + 4);
spin_unlock_irqrestore(&tp->io_lock, flags);
}
The working weim device tree node is as follows:
&weim {
status = "okay";
/* weim memory map */
ranges = <0 0 0x08000000 0x08000000>;
/* SJA1000 CAN Controller on Colibri EIM_CS0 */
can3@0,0 {
compatible = "technologic,sja1000";
reg = <0 0x00000000 0x00000100>;
interrupt-parent = <&gpio3>;
interrupts = <27 0x2>;
nxp,external-clock-frequency = <24000000>;
nxp,tx-output-config = <0x06>; /* TX0 push-pull */
fsl,weim-cs-timing = <0x00810031 0x00001000 0x10040200
0x00000000 0x10FC01C0 0x00000000>;
status = "okay";
};
};
Register values for the fsl,weim-cs-timing property:
Expected signals timings are:
(We don’t use the ADV signal)
We also had to modify the pinctrl_weim_sram node to add the gpio interrupt line.
&pinctrl_weim_sram {
fsl,pins = <
MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1
MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1
/* Data */
MX6QDL_PAD_CSI0_DATA_EN__EIM_DATA00 0x1b0b0
MX6QDL_PAD_CSI0_VSYNC__EIM_DATA01 0x1b0b0
MX6QDL_PAD_CSI0_DAT4__EIM_DATA02 0x1b0b0
MX6QDL_PAD_CSI0_DAT5__EIM_DATA03 0x1b0b0
MX6QDL_PAD_CSI0_DAT6__EIM_DATA04 0x1b0b0
MX6QDL_PAD_CSI0_DAT7__EIM_DATA05 0x1b0b0
MX6QDL_PAD_CSI0_DAT8__EIM_DATA06 0x1b0b0
MX6QDL_PAD_CSI0_DAT9__EIM_DATA07 0x1b0b0
MX6QDL_PAD_CSI0_DAT12__EIM_DATA08 0x1b0b0
MX6QDL_PAD_CSI0_DAT13__EIM_DATA09 0x1b0b0
MX6QDL_PAD_CSI0_DAT14__EIM_DATA10 0x1b0b0
MX6QDL_PAD_CSI0_DAT15__EIM_DATA11 0x1b0b0
MX6QDL_PAD_CSI0_DAT16__EIM_DATA12 0x1b0b0
MX6QDL_PAD_CSI0_DAT17__EIM_DATA13 0x1b0b0
MX6QDL_PAD_CSI0_DAT18__EIM_DATA14 0x1b0b0
MX6QDL_PAD_CSI0_DAT19__EIM_DATA15 0x1b0b0
/* Address */
MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1
MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1
MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1
MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1
MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1
MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1
MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1
MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1
MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1
MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1
MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1
MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1
MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1
MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1
MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1
MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1
/* Interrupt */
MX6QDL_PAD_EIM_D27__GPIO3_IO27 0xb0b1
>;
};
The last test we did was replacing the TorizonCore v5.5.0 base image with a TorizonCore v5.7.0 development nightly build image (which includes CONFIG_CAN_SJA1000=m and CONFIG_CAN_SJA1000_PLATFORM=m options) for our custom image build. The custom image built successfully despite having both the in-tree SJA1000 driver and the external SJA1000 driver. We deployed the custom image to the target board and it seems like TorizonCore loaded the modified external driver instead of the in-tree driver, so CAN communications with the SJA1000 kept working.
torizon@colibri-imx6:~$ zcat /proc/config.gz | grep SJA
CONFIG_CAN_SJA1000=m
# CONFIG_CAN_SJA1000_ISA is not set
CONFIG_CAN_SJA1000_PLATFORM=m
torizon@colibri-imx6:~$ dmesg | grep sja
[ 11.372921] sja1000: loading out-of-tree module taints kernel.
[ 11.373804] sja1000 CAN netdevice driver
[ 11.392842] sja1000_platform 8000000.can3: sja1000_platform device registered (reg_base=(ptrval), irq=165)
[ 118.455981] sja1000_platform 8000000.can3 can0: setting BTR0=0x02 BTR1=0x1c
torizon@colibri-imx6:~$
Can we expect that out-tree driver will always be loaded instead of the in-tree driver? Or should we petition to remove the CONFIG_CAN_SJA1000_PLATFORM=m kernel option from TorizonCore build to avoid any future module conflicts?