Guide to Enabling MCP251x (MCP2515) on the TX1 (SPI CAN)

Edit: TX2 version located here: Guide to Enabling MCP251x (MCP2515) on the TX2 (SPI CAN)
Edit: Updates for r28.1!nabling-mcp251x-mcp2515-on-the-tx2-spi-can/77911

The mcp251x.c driver is now configured entirely from the device tree, no more clunky board file!

I made some example dtsi gists with everything you need (in the DTB) to probe an MCP2515 on J21 and J23 Expansion Header. Thanks to annerjb for figuring out J21.

You would need to customize it for your own SPI and interrupt pin.

Old Guide for r24.2:

Looks like Nvidia has integrated CAN into the TX2, but the rest of us have to do it the old fashioned way. Here’s a quick guide on how to get an MCP2515 working with the TX1 development board.

Special Note: The TX1’s SPI logic level is 1.8V, the MCP2515 runs on 3.3V and expects a logic level of 0.9*VDD (~2.97V) to latch. Thus you’ll need a level shifter between the TX1 and the MCP2515 to bridge the gap if you’re using the Display Expansion connector (SPI0 and SPI2). It is possible that J21 SPI1 can be set to 3.3V by setting the jumper on J24, but I haven’t tested that.

Kernel Configuration

In order for the MCP2515 to work the kernel needs to have both SPI and the MCP251x drivers enabled. First step is becoming familiar with the process for building the kernel. Ridgerun has an excellent guide on the subject here: Compiling Tegra X1/X2 source code - RidgeRun Developer Connection

Run through that guide until you get to Build Kernel step 5:

make tegra21_defconfig
make menuconfig

The configurations that need to be set are the following:

  • CONFIG_SPI_SPIDEV=y
  • CONFIG_CAN_DEV=y
  • CONFIG_CAN_MCP251X=y

For menuconfig that means this:

Device Drivers --->
    <*> SPI support --->
        <*> User mode SPI device driver support
<*> Networking support --->
    <*> CAN bus subsystem support --->
        CAN Device Drivers --->
            <*> Microchip MCP251x SPI CAN controllers

Once the kernel is configured we need to update the dtsi and edit the TX1 board file so it knows where to find our MCP2515.

Device Tree
Next step, which may not be necessary for using the MCP2515, but is useful for debugging, is to enable spidev in the device tree. This allows you to manipulate the SPI port using tools such as the SPIDEV kernel module or the py-spidev python package (GitHub - doceme/py-spidev).

The TX1 loads a device tree blob (dtb) on boot which contains configuration information such as clock speeds, register settings, and pin defaults. To find out what file your board uses you can check dmesg.

ubuntu@tegra-ubuntu:~$ dmesg | grep .dts
[    0.000000] DTS File Name: arch/arm64/boot/dts/tegra210-jetson-tx1-p2597-2180-a01-devkit.dts

Now navigate your kernel_source folder. And take a look at that dts file.

cd $DEVDIR/64_TX1/Linux_for_Tegra_64_tx1/sources/kernel_source/
vim arch/arm64/boot/dts/tegra210-jetson-tx1-p2597-2180-a01-devkit.dts

After the copyright information you’ll see an include line. Insert your own include with the SPI configuration below that one. If you’re using my dtsi it would look like this:

/*
 * arch/arm64/boot/dts/tegra210-jetson-tx1-p2597-2180-a01-devkit.dts
 *
 * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#include "tegra210-jetson-cv-base-p2597-2180-a00.dts"
<b>#include "tegra210-daxc02.dtsi"</b>

Don’t forget to actually put that file (or a link to the file) in the folder so it can be included.

If you want to modify the device tree in place (on the TX1) you can find instructions at the following link: Jetson/TX1 SPI - eLinux.org

GPIO and SFIO
Selecting which GPIO to use (and figuring out which ones are available) can be tricky. In this section I’ll talk about GPIO and SFIO, pin mappings, and walk through enabling access to the SPI port on the J21 header.

The majority of pins on the TX1, and most embedded devices for that matter, can be configured to either source or sink current. They are aptly called “General Purpose Input Output” or GPIO. Sometimes these pins are connected to specialized internal circuitry for purposes such as analog to digital conversion, generating waveforms, or handling protocols such as UART, SPI, or I2C. When a pin has circuitry like that it is called a “Specific Function Input Output” or SFIO. The device tree is responsible for telling the TX1 how every single one of those pins is to be configured. Either as an output (source current), an input (sink current), or SFIO.

To start figuring out the TX1 GPIO system you’ll want to jump over to the download center and grab “Jetson TX1 Module Pinmux” (http://developer.nvidia.com/embedded/dlc/jetson-tx1-module-pinmux). This spreadsheet was created as a customer reference showing how the TX1 pins are configured. It even has scripts to allow you to generate a new gpio defaults dtsi, but I prefer to do everything in my own dtsi file. Mux is shorthand for “multiplexor” which is the device that handles selecting which internal circuitry a pin is connected to.

Column A shows the pin names and columns G-K show the GPIO and SFIO mappings. If we scroll down to the SPI section we can see that the SPI1 bus, which is connected to the J21 header, can be multiplxed to either GPIO PC1-4, or SPI. We can also see on column AN that GPIO is selected by default. Thus to use the port as SPI we need to configure those pins to be SFIO instead of GPIO.

“GPIO3_PC.00” probably doesn’t mean much to you. Luckily there is a mapping buried in the kernel source.

cd $DEVDIR/64_TX1/Linux_for_Tegra_64_tx1/sources/kernel_source/
less arch/arm/mach-tegra/gpio-names.h

With the gpio-names file we can cross reference the GPIO names with the actual pin numbers.

#define TEGRA_GPIO_PC0          16
#define TEGRA_GPIO_PC1          17
#define TEGRA_GPIO_PC2          18
#define TEGRA_GPIO_PC3          19
#define TEGRA_GPIO_PC4          20

Once we have that information, switching the pins to sfio is as easy as calling “gpio-to-sfio” in gpio defaults like in my example dtsi.

gpio@6000d000 {
    /* Needed for J21 Header SPI1 */
    gpio_default: default {
        gpio-input = <170 174 185>; // Set PV2, PV6, and PX1 to input
        gpio-to-sfio = <16 17 18 19 20>; // J21 Header SPI1
    };
};

This sets three pins, 170, 174, and 185 to inputs, and converts 5 pins, 16-20, to SFIO.

Choosing an interrupt GPIO

Now that we have these two documents we can choose pins for our MCP2515 interrupts. Lets say we want to stick with the J21 header. If we take a look at the header pinout (NVIDIA Jetson TX1 J21 Header Pinout - JetsonHacks) we can see that several pins are helpfully already labeled as GPIO. Most of these have some other label such as GPIO9_MOTION_INT, but these are just suggestions. A GPIO is a GPIO, you can use it for whatever you would like.

Say we wanted to use J21 pin 31 (GPIO9_MOTION_INT) as our interrupt pin. Pull up the Pinmux spreadsheet and search for GPIO9. You should find something like “GPIO9/MOTION_INT” in column A. Scrolling over to column G shows that it is mapped to “GPIO3_PX.02”

Now check /arch/arm/mach-tegra/gpio-names.h for the pin number.

cd $DEVDIR/64_TX1/Linux_for_Tegra_64_tx1/sources/kernel_source/
cat arch/arm/mach-tegra/gpio-names | grep PX2

Using that number (in this case 186) you can set that gpio to an input in the dtsi and use it for your interrupt in the board-file, below. Note that gpio-names.h is compiled into the kernel. So for the board file you can use the define in place of the pin number. Ex: TEGRA_GPIO_PX2

Board File
The version of the MCP251x driver included in the kernel does not use the device tree for its configuration. Thus the TX1’s board file needs to be modified to add the driver’s private data structs.

This board file compiled into the TX1 kernel is located here:

kernel_source/arch/arm64/mach-tegra/board-t210ref.c

First define the MCP2515 private data structures and init function. You may need to make the following changes to my definitions:

  • Change the irq to whichever GPIO pin you are using
  • Switch the oscillator_frequency to match the crystal you have connected to the mcp2515
  • Change the bus_num to the SPI port you are using, see my dtsi file for mapping
#ifdef CONFIG_CAN_MCP251X
    #include <linux/can/platform/mcp251x.h>
    #define CAN_GPIO_IRQ_MCP251x_SPI TEGRA_GPIO_PV6

    static struct mcp251x_platform_data mcp251x_info = {
           <b>.oscillator_frequency = 16 * 1000 * 1000,</b> /* Oscillator connected to the MCP2515 crystal */
           .board_specific_setup = NULL, /* We don't have a board specific setup */
           .power_enable         = NULL, /* We don't want any power enable function */
           .transceiver_enable   = NULL, /* We don't want any transceiver enable function */
    };

    struct spi_board_info mcp251x_spi_board[1] = {
           {
                   .modalias = "mcp2515", /* (or mcp2510) used chip controller */
                   .platform_data = &mcp251x_info, /* reference to the mcp251x_platform_data mcp251x_info */
                   .max_speed_hz  = 2 * 1000 * 1000, /* max speed of the used chip */
                   .chip_select   = 0, /* the spi cs usage*/
                   <b>.bus_num = 1,</b> // SPI0
                   .mode = SPI_MODE_0,
           },
    };

    static int __init mcp251x_init(void)
    {
           mcp251x_spi_board[0].irq = gpio_to_irq(CAN_GPIO_IRQ_MCP251x_SPI); // #define CAN_GPIO_IRQ_MCP251x_SPI TEGRA_GPIO_PK2
           spi_register_board_info(mcp251x_spi_board, ARRAY_SIZE(mcp251x_spi_board));
           pr_info("mcp251x_init\n");
           return 0;
    }

#endif

Next add the init function to t210ref_late_init;

static void __init tegra_t210ref_late_init(void)
{
	struct board_info board_info;
	tegra_get_board_info(&board_info);
	pr_info("board_info: id:sku:fab:major:minor = 0x%04x:0x%04x:0x%02x:0x%02x:0x%02x\n",
		board_info.board_id, board_info.sku,
		board_info.fab, board_info.major_revision,
		board_info.minor_revision);

	t210ref_usb_init();
	tegra_io_dpd_init();
#ifdef CONFIG_PM_SLEEP
	/* FIXME: Assumed all t210ref platforms have sdhci DT support */
	t210ref_suspend_init();
#endif
	tegra21_emc_init();
	isomgr_init();

[b]#ifdef CONFIG_CAN_MCP251X
	mcp251x_init();
#endif[/b]

	/* put PEX pads into DPD mode to save additional power */
	t210ref_camera_init();
}

Once you have those changes made go ahead and finish the Riderun guide (step 6+) and finish compiling and flashing the kernel.

Bringing up the Interface
The MCP2515 should appear as a can0 interface under ifconfig -a

To bring it up use the following commands (change bitrate to whatever your bus is)

sudo ip link set can0 type can bitrate 500000
sudo ifconfig can0 up

board-t210ref.c (13.7 KB)
tegra210-daxc03.dtsi.txt (2.97 KB)

Atrer,

Great post this really is the best explanation I found. There is one area that is incomplete/needs clarifying.
You included a dtsi file (which is a device tree include file) but you never explain which DTS file in the kernel /arch/arm64/boot/dts/ folder did you modify to / include your dtsi

The link that you provided to the external elinux.org wiki does not go about this either.

Also quick question you used for SPI0 interrupt TEGRA_GPIO_PV6 where can I find this on the Jetson Documentation where it’s mapped to the physical port?

Thanks

Good point, I’ll add that info once I get to work. In the meantime you can tell what dts file your board is loading by looking near the top of dmesg.

Try

dmesg | grep .dts

Or just look at the whole thing with

dmesg | less

I’ll go through how to figure out GPIO too.

Thanks for the feedback!

Ok i will take a look tonight to see which dts is my jetson tx1 loading and add the #include of your dtsi at the beginning.

Do you have what J21 pin is the TEGRA_GPIO_PV6 pin mapped too? I assume you do since you got it working.

Added sections on GPIO and how to select an interrupt pin with an example for the J21 connector!

As for your specific question that’s GPIO7/TOUCH_RST on the Display Expansion connector.

This is a great explanation!

Atrer,
Thanks I still haven’t been able to get it to work.
I am seeing this excessively on the dmesg.

Any idea why?
I tried attaching a logic analyzer and don’t seem to be showing activity on the SPI.

let me know what could be useful to assist me in debugging this?

I’m assuming you’re trying to use SPI1 from J21.

First, sanity check. Have you have selected 3.3V on J24 using the jumper?

Second, careful which bus_num you select in your spi_board_info. It looks like your MCP2515 might be looking on spi1.0 which is actually SPI2 on the expansion connector (yeah, I know, it’s super confusing). Which one did you select? You’ll want bus_num=0.

/*
 * J21 Header SPI1 == bus_num 0
 * Expansion SPI0 == bus_num 3
 * Expansion SPI2 == bus_num 1
 */

Thanks the bus_num definetly helped move forward. I can now see traffic on the SPI with the logic analyzer.
Voltage was set to 3.3v thought I am still having issues.

This is on my .dtsi

gpio-input = <170 174 185 186>;

This is on my board-t210ref.c

#define CAN_GPIO_IRQ_MCP251x_SPI TEGRA_GPIO_PX2

As you can see there is traffic reaching the MCP2515 but the enable lines seem to be behaving odly.
My CS pin is connected to the SPI1_CS0# on the J21 the logic capture includes both

.chip_select   = 0, /* the spi cs usage*/

Let me know if you spot anything obvious. I will add more debugging info in about 12 hours.

Your DTSI and board file seem to have been cut off. Might be good to attach the full thing so I can look at it. Scroll over the icons in the upper right corner of your post and you’ll see a paperclip for attach.

Your Saleae is showing CS1 getting toggled appropriately, what happens if you just switch your MCP to that pin? Does it probe?

I tried it on both CS1 and CS0 but I will give it another try tonight.
I purposely put snippets of both. But I will also attach the full file tonight.

Here are attached the DTSI and .c file for the board.

I moved the CS1 pin and same outcome. Here it’s a capture from the 5v side of the TTL that converts from 3.3 to 5v (so it definitely is reaching the MCP)

Dmesg:

EDIT: added a logic data capture (this is just linux booting)
and my kernel .config in case i am missing something.
board-t210ref.c (13.9 KB)
putty.log (88 KB)
.config.txt (116 KB)

tegra210-daxc03.dtsi (2).txt (2.97 KB)

mcp2515 jetsontx1.zip (338 KB)

Looks like it might actually be fighting something else.

Here’s the driver source:
http://lxr.free-electrons.com/source/drivers/net/can/mcp251x.c?v=3.13#L649

You’re failing in hardware_probe because the chip isn’t responding correctly.

649 static int mcp251x_hw_probe(struct spi_device *spi)
650 {
651         int st1, st2;
652 
653         mcp251x_hw_reset(spi);
654 
655         /*
656          * Please note that these are "magic values" based on after
657          * reset defaults taken from data sheet which allows us to see
658          * if we really have a chip on the bus (we avoid common all
659          * zeroes or all ones situations)
660          */
661         st1 = mcp251x_read_reg(spi, CANSTAT) & 0xEE;
662         st2 = mcp251x_read_reg(spi, CANCTRL) & 0x17;
663 
664         dev_dbg(&spi->dev, "CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);
665 
666         /* Check for power up default values */
667         return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
668 }

However this first block is correct
“0xC0” is the reset instruction
“0x03” is read
“0x0E” is the CANSTAT register
“0x80” from MISO is the correct reply

Since you got a valid reply that tells me that you’re probably talking to the MCP2515 correctly.

Then stuff gets weird…
“0xC3” binary 0b11000011 is not a command valid for the MCP2515. The next thing that we should see would be a 0x03, 0x0F sequence to try and read CANCTRL.

What I’d try is comment out the mcp init in your board file and see if there is any traffic on the SPI bus without the MCP trying to probe. If there is, then that might be your problem. If nothing strange is going on, try using SPIDEV to communicate with the MCP2515 manually.

Fun fact, there’s no need to re-flash between kernel changes. You can recompile the kernel (make zImage) and then just copy Image and zImage over to /boot/ on the TX1. Then reboot. Makes kernel updates like that super quick. First time you do it there will be an ownership/permission issue, so you’ll need to transfer them to a directory you own and copy them over manually. But once “ubuntu” owns them you can send them straight to boot.

scp arch/arm64/boot/Image [name]@[ip-address]:/boot/
scp arch/arm64/boot/zImage [name]@[ip-address]:/boot/
scp arch/arm64/boot/dts/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb [name]@[ip-address]:/boot/

No luck I am starting the process from scracth. I was able to verify using SPI dev the integrity of the miso to mosi communication. Which tag did you check out the one on the ridgerun page? (tegra-l4t-r24.2)

I am closer than ever.
I was connecting on the J21 header a few pins on the wrong spot -_-.
You where right there was extra traffic because it was the I2C pin directly below CS1

I am now using CS0 (for real). But the kernel is now throwing a probe failed error.

I went thru the kernel code but I have no Idea why would the alloc of the can device fail and it didn’t seem to clearly explain possible reasons.

Here is a capture of the traffic I tried it with two different MCP2515 boards and they both had the same issue.

Lastly here are the mcp settings:


mcpworking.zip (1.23 KB)

Thanks Arter for the great explaination.

I am facing some issues while following the mentioned implementation procedure.

  1. There was no device “/dev/spidev0.0”.
ubuntu@tegra-ubuntu:~$ dmesg | grep .dts
[    0.000000] DTS File Name: arch/arm64/boot/dts/tegra210-jetson-tx1-p2597-2180-a01-devkit.dts
ubuntu@tegra-ubuntu:~$ dmesg | grep spi
[    0.000000] Lowering qspi maximum rate from 163200000 to 116600000
[    0.359612] PMC: IO pad spi voltage is 1800000
[    0.377726] PMC: IO pad spi-hv voltage is 1800000
[    1.569932] tegra210-pmc-iopower pmc-iopower.29: Rail iopower-spi is having fixed voltage 1800000
[    1.578770] tegra210-pmc-iopower pmc-iopower.29: Rail iopower-spi-hv is having fixed voltage 1800000
[    3.482162] spi-tegra114 7000d400.spi: Static pin configuration used
[    3.490534] spi_master spi0: cannot find modalias for /spi@7000d400/prod-settings
[    3.500013] spi-tegra114 7000d400.spi: chipselect 0 already in use
[    3.508015] spi_master spi0: spi_device register error /spi@7000d400/spidev0_0
[    3.517640] spi-tegra114 7000d600.spi: Static pin configuration used
[    3.526147] spi_master spi1: cannot find modalias for /spi@7000d600/prod-settings
[    3.536097] spi-tegra114 7000da00.spi: Static pin configuration used
[    3.544723] spi_master spi3: cannot find modalias for /spi@7000da00/prod-settings
[    3.587620] mcp251x spi0.0: Probe failed
[    3.593789] mcp251x spi0.0: probe failed
ubuntu@tegra-ubuntu:~$ ls /dev/spi*
/dev/spidev0.1  /dev/spidev1.0  /dev/spidev3.0
ubuntu@tegra-ubuntu:~$ dmesg | grep mcp
[    0.723090] mcp251x_init
[    3.594974] mcp251x spi0.0: Probe failed
[    3.601139] mcp251x spi0.0: probe failed

Dts: arch/arm64/boot/dts/tegra210-jetson-tx1-p2597-2180-a01-devkit.dts

#include "tegra210-jetson-cv-base-p2597-2180-a00.dts"
#include "tegra210-daxc03.dtsi"

arch/arm64/mach-tegra/board-t210ref.c

#ifdef CONFIG_CAN_MCP251X
#include <linux/can/platform/mcp251x.h>
#define CAN_GPIO_IRQ_MCP251x_B TEGRA_GPIO_PX2

static struct mcp251x_platform_data mcp251x_info = {
       .oscillator_frequency = 16 * 1000 * 1000, /* Oscillator connected to the MCP2515 crystal */
       .board_specific_setup = NULL, /* We don't have a board specific setup */
       .power_enable         = NULL, /* We don't want any power enable function */
       .transceiver_enable   = NULL, /* We don't want any transceiver enable function */
};

struct spi_board_info mcp251x_spi_board_b[1] = {
       {
               .modalias = "mcp2515", /* (or mcp2510) used chip controller */
               .platform_data = &mcp251x_info, /* reference to the mcp251x_platform_data mcp251x_info */
               .max_speed_hz  = 2 * 1000 * 1000, /* max speed of the used chip */
               .chip_select   = 0, /* the spi cs usage*/
               .bus_num = 0, // SPI0
               .mode = SPI_MODE_0,
       },
};

static int __init mcp251x_init(void)
{
       mcp251x_spi_board_b->irq = gpio_to_irq(CAN_GPIO_IRQ_MCP251x_B);
       spi_register_board_info(mcp251x_spi_board_b, ARRAY_SIZE(mcp251x_spi_board_b));

       pr_info("mcp251x_init\n");
      return 0;
}

#endif

late_init function

static void __init tegra_t210ref_late_init(void)
{
        struct board_info board_info;
        tegra_get_board_info(&board_info);
        pr_info("board_info: id:sku:fab:major:minor = 0x%04x:0x%04x:0x%02x:0x%02x:0x%02x\n",
                board_info.board_id, board_info.sku,
                board_info.fab, board_info.major_revision,
                board_info.minor_revision);

        t210ref_usb_init();
        tegra_io_dpd_init();
#ifdef CONFIG_PM_SLEEP
        /* FIXME: Assumed all t210ref platforms have sdhci DT support */
        t210ref_suspend_init();
#endif
        tegra21_emc_init();
        isomgr_init();

#ifdef CONFIG_CAN_MCP251X
        mcp251x_init();
#endif

        /* put PEX pads into DPD mode to save additional power */
        t210ref_camera_init();
}

Can somebody help to point what could be the probable reason for this issue?

I think both of you are using the wrong bus number.

annerjb, if you’re connecting the MCP2515 to J21 then you should be using SPI1.0, not SPI0.0

bani_j, same thing a bus_num of 0 is actually SPI1 on the J21 header, which did show up in your devices.

/*
 * J21 Header SPI1 == bus_num 0
 * Expansion SPI0 == bus_num 3
 * Expansion SPI2 == bus_num 1
 */

@Atrer i want to use the spi bus on J21 header and is referenced in .dts at spi@7000d400.

as mentioned in the link http://elinux.org/Jetson/TX1_SPI. I am able to see traffic (using Oscilloscope) and also successfully able to test loopback test by connecting the MOSI and MISO pins at J21 through jumper (spidev0.0)

spi@7000d400 {
    	status = "okay";
    	
    	spidev0_0 {
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			compatible = "linux,spidev", "spidev";
			status = "okay";
			reg = <0x0>;
			spi-max-frequency = <20000000>;
			nvidia,enable-hw-based-cs;
			nvidia,cs-setup-clk-count = <0x1e>;
			nvidia,cs-hold-clk-count = <0x1e>;
			nvidia,rx-clk-tap-delay = <0x1f>;
			nvidia,tx-clk-tap-delay = <0x0>;
	    };
	    
	    spidev0_1 {
			#address-cells = <0x1>;
			#size-cells = <0x0>;
			compatible = "linux,spidev", "spidev";
			status = "okay";
			reg = <0x1>;
			spi-max-frequency = <20000000>;
			nvidia,enable-hw-based-cs;
			nvidia,cs-setup-clk-count = <0x1e>;
			nvidia,cs-hold-clk-count = <0x1e>;
			nvidia,rx-clk-tap-delay = <0x1f>;
			nvidia,tx-clk-tap-delay = <0x0>;
	    };
    };

.
Note: Till this point I didn’t have made any changes to “board-t210ref.c”.

But as soon as I make the changes “arch/arm64/mach-tegra/board-t210ref.c” and replaces the kernel image on the board “/boot/” directory and reboots the board, I cannot see the corresponding spi device in the /dev hierarchy.

i.e if i configure “bus_num = 0” in board-t210ref.c I cannot find /dev/spidev0.0

ubuntu@tegra-ubuntu:~$ dmesg | grep spi
[    0.000000] Lowering qspi maximum rate from 163200000 to 116600000
[    0.359612] PMC: IO pad spi voltage is 1800000
[    0.377726] PMC: IO pad spi-hv voltage is 1800000
[    1.569932] tegra210-pmc-iopower pmc-iopower.29: Rail iopower-spi is having fixed voltage 1800000
[    1.578770] tegra210-pmc-iopower pmc-iopower.29: Rail iopower-spi-hv is having fixed voltage 1800000
[    3.482162] spi-tegra114 7000d400.spi: Static pin configuration used
[    3.490534] spi_master spi0: cannot find modalias for /spi@7000d400/prod-settings
[    3.500013] spi-tegra114 7000d400.spi: chipselect 0 already in use
[    3.508015] spi_master spi0: spi_device register error /spi@7000d400/spidev0_0
[    3.517640] spi-tegra114 7000d600.spi: Static pin configuration used
[    3.526147] spi_master spi1: cannot find modalias for /spi@7000d600/prod-settings
[    3.536097] spi-tegra114 7000da00.spi: Static pin configuration used
[    3.544723] spi_master spi3: cannot find modalias for /spi@7000da00/prod-settings
[    3.587620] mcp251x spi0.0: Probe failed
[    3.593789] mcp251x spi0.0: probe failed
ubuntu@tegra-ubuntu:~$ ls /dev/spi*
/dev/spidev0.1  /dev/spidev1.0  /dev/spidev3.0
ubuntu@tegra-ubuntu:~$ dmesg | grep mcp

and if I configure “bus_num = 1” in board-t210ref.c I cannot find /dev/spidev1.0

ubuntu@tegra-ubuntu:~$ dmesg | grep spi
[    0.000000] Lowering qspi maximum rate from 163200000 to 116600000
[    0.359516] PMC: IO pad spi voltage is 1800000
[    0.377630] PMC: IO pad spi-hv voltage is 1800000
[    1.569807] tegra210-pmc-iopower pmc-iopower.29: Rail iopower-spi is having fixed voltage 1800000
[    1.578649] tegra210-pmc-iopower pmc-iopower.29: Rail iopower-spi-hv is having fixed voltage 1800000
[    3.490060] spi-tegra114 7000d400.spi: Static pin configuration used
[    3.498398] spi_master spi0: cannot find modalias for /spi@7000d400/prod-settings
[    3.508452] spi-tegra114 7000d600.spi: Static pin configuration used
[    3.516894] spi_master spi1: cannot find modalias for /spi@7000d600/prod-settings
[    3.526465] spi-tegra114 7000d600.spi: chipselect 0 already in use
[    3.534586] spi_master spi1: spi_device register error /spi@7000d600/spidev1_0
[    3.544000] spi-tegra114 7000da00.spi: Static pin configuration used
[    3.552621] spi_master spi3: cannot find modalias for /spi@7000da00/prod-settings
[    4.593781] mcp251x spi1.0: MCP251x didn't enter in conf mode after reset
[    4.603104] mcp251x spi1.0: Probe failed
[    4.609358] mcp251x spi1.0: probe failed
ubuntu@tegra-ubuntu:~$ dmesg | grep mcp
[    0.722929] mcp251x_init
[    4.593781] mcp251x spi1.0: MCP251x didn't enter in conf mode after reset
[    4.603104] mcp251x spi1.0: Probe failed
[    4.609358] mcp251x spi1.0: probe failed
ubuntu@tegra-ubuntu:~$ ls /dev/spidev*
/dev/spidev0.0  /dev/spidev0.1  /dev/spidev3.0

It seems that I am trying to configure the same bus twice.

Something which you may want to be aware of is that an initrd image is used. Updates may require being placed there as well (see the INITRD entry in extlinux.conf and the “/boot/initrd” file).

An example of exploring and modifying initrd:
[url]https://devtalk.nvidia.com/default/topic/1011027/jetson-tk1/jetson-tx1-initrd/post/5157554/#5157554[/url]

@linuxdev @Atrer

Since Release 28.1.There are no hard-code in arch/arm64/mach-tegra.Where do you place the platform code and board info code?

I have to move hard-code to device tree

/{
	spi@7000d600{
	status = "okay";
		can0@0{
			status = "okay";
			compatible = "nvidia,mcp2515";
			reg = <1>;
			gpio-controller;
			spi-max-frequency = <10000000>;
			oscillator-frequency = <8000000>;
			
		};
	};
	gpio@6000d000{
		gpio_default:default{
			gpio-to-sfio=<16 17 18 19 20>;
		};
	};
};

But the driver probe failed

[    2.953632] [mcp2515]entering mcp251x_can_probe
[    2.959918] node:0xffd31fe0
[    2.964419] read fre successfully,fre:8000000
[    2.970590] ret:0,line:1139
[    2.975098] [mcp2515]entering mcp251x_hw_probe
[    2.981298] [mcp2515]entering mcp251x_hw_reset
[    2.987475] [mcp2515]entering mcp251x_gpio_reset
[    3.525622] random: nonblocking pool is initialized
[    4.006488] DEVICE_NAME spi1.1: MCP251x didn't enter in conf mode after reset
[    4.015570] DEVICE_NAME spi1.1: Probe failed:1143
[    4.022041] [mcp2515]error probe:1164
[    4.027428] [mcp2515]error rx buf:1168
[    4.032841] [mcp2515] error tx buf:1172
[    4.038307] [mcp2515]error alloc:1178
[    4.043550] DEVICE_NAME spi1.1: probe failed:1183
[    4.049826] [mcp2515]err out:1185

I cat signal from SPI pins with logic analyzer.The SPI pins(CS1 MISO MOSI SCLK) have nothing wave.

Could you help me?Thanks