This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

L138: SPI0 CS4 hanging during linux probe

Other Parts Discussed in Thread: DA8XX

Hi,

We have a system using the LogicPD SOM on our own baseboard running Linux (no dsp application at the moment, though we do plan to use the dsplink module in the future).  There are three NXP SC16IS762 SPI to dual UART chips (linux driver merged in sc16is7x2) on SPI0 CS2, CS3, CS4.  We have the system working with the 2.6.37 kernel (linux-03.21.00.04). Trying to bring the platform up using 3.3.0 kernel (Davinci-PSP-SDK-03.22.00.03 linux-03.22.00.03) the system hangs when probing the third chip (SPI0_SCS[4]).  I have traced this up to __spi_sync in spi.c, stuck waiting for wait_for_completion(&done), which never returns for this chip (but does return for SPI0 CS2, SPI0 CS3 and SPI1 CS0 [flash]).  When i replace this call with a wait_for_completion_timeout() call I can get through the boot process and ssh in, but accessing anything on SPI0 bus causes an eventual kernel panic.  It looks like CS4 is also stuck low once the device is probed, and it is a little tough to tell from the register prints I've added but something may be setting SPI0 to 5-wire mode, or at least forcing SPI_READY without modifying the spi devices .mode field.

I'm looking for any help into how to get this CS4 working reliably (as it did in 2.6.37 kernel)

The MII Bus (shares pins with SPI0) is disabled and the PHY is set to isolate before booting, the following are tweaks to the board-da850-evm.c file to fit our system:

static struct davinci_spi_platform_data da850evm_spi0_pdata = {

        .version        = SPI_VERSION_2,

        .num_chipselect = 6, /*2,*/ /* 1, */

        .intr_line      = 1,

};

 

static struct davinci_spi_platform_data da850evm_spi1_pdata = {

        .version        = SPI_VERSION_2,

        .num_chipselect = 3, /*2,*/ /* 1, */

        .intr_line      = 1,

};

static struct flash_platform_data da850evm_spiflash_data = {

        .name           = "m25p80",

        .parts          = da850evm_spiflash_part,

        .nr_parts       = ARRAY_SIZE(da850evm_spiflash_part),

        .type           = "m25p64",

};

 

static struct davinci_spi_config da850evm_spiflash_cfg = {

        .io_type        = SPI_IO_TYPE_DMA,

        .c2tdelay       = 8,

        .t2cdelay       = 8,

};

static struct sc16is7x2_platform_data da850evm_sc16is7x2_data = {

        .uartclk        = 14745600,

        .uart_base      = 0,

        .gpio_base      = 180,

        .label          = "eser",

        .names          = da850_sc16is7x2_names, /*"test",*/

};

 

static struct sc16is7x2_platform_data da850evm_sc16is7x2_data_2 = {

        .uartclk        = 14745600,

        .uart_base      = 2,

        .gpio_base      = 188,

        .label          = "eser",

        .names          = da850_sc16is7x2_names2, /*"first", */

};

 

static struct sc16is7x2_platform_data da850evm_sc16is7x2_data_3 = {

        .uartclk        = 14745600,

        .uart_base      = 4,

        .gpio_base      = 196,

        .label          = "eser",

        .names          = da850_sc16is7x2_names3, /*"first", */

};

 

static struct davinci_spi_config da850evm_sc16is7x2_cfg = {

        .io_type        = SPI_IO_TYPE_INTR,

        .c2tdelay       = 63,/*8,*/

        .t2cdelay       = 63, /*8,*/

};

static struct spi_board_info da850evm_spi_info[] = {

        [0] = {

                .modalias               = "m25p80",

                .platform_data          = &da850evm_spiflash_data,

                .controller_data        = &da850evm_spiflash_cfg,

                .mode                   = SPI_MODE_0,

                .max_speed_hz           = 30000000,

                .bus_num                = 1,

                .chip_select            = 0,

        },

        [1] = {

                .modalias               = "sc16is7x2",

                .platform_data          = &da850evm_sc16is7x2_data,

                .controller_data        = &da850evm_sc16is7x2_cfg,

                .mode                   = SPI_MODE_0,

                .max_speed_hz           = 14000000,

                .bus_num                = 0,

                .chip_select            = 2,

                .irq                    = 203,

        },

       

 

        [2] = {

                .modalias               = "sc16is7x2",

                .platform_data          = &da850evm_sc16is7x2_data_2,

                .controller_data        = &da850evm_sc16is7x2_cfg,

                .mode                   = SPI_MODE_0,

                .max_speed_hz           = 14000000,

                .bus_num                = 0, 

                .chip_select            = 3,

                .irq                    = 205,

        },

 

 

        [3] = {

                .modalias               = "sc16is7x2",

                .platform_data          = &da850evm_sc16is7x2_data_3,

                .controller_data        = &da850evm_sc16is7x2_cfg,

                .mode                   = SPI_MODE_0,

                .max_speed_hz           = 14000000,

                .bus_num                = 0,

                .chip_select            = 4, 

                .irq                    = 206,

        },

};

in da850_evm_init(void) function:

    ret = davinci_cfg_reg_list(da850_spi0_pins);    /* enable SPI0 in pinmux */

/*this function is added to devices-da8xx.c since the original da8xx_register_spi seems to be limited to a single bus/spi board info, also it ties length of board info array to max chip select numbers which is not correct*/

da8xx_register_spi_both_busses(da850evm_spi0_pdata.num_chipselect,da850evm_spi1_pdata.num_chipselect,da850evm_spi_info, ARRAY_SIZE(da850evm_spi_info));

I can provide more detailed trace information but I'm hoping someone else has managed to get the L138 and 3.3.x kernel working with both SPI busses and multiple chip selects.

 

Thanks,

Scott

 

  • Hi Scott,

    You may want to do a diff between the platform definition file that exists in the two PSP releases. If I remember correctly, the UART0 TXD and RXD pins were enabled in the default configuration of the EVM to enable the wireless connectivity demo and smart grid demos out of the box. UART0_TXD has a conflict with SPI0_CS4 so I would assume this might be the reason. If you have an emulator, you can confirm this quickly by connecting to the device after linux has booted, and looking for the PINMUX settings under View-> Register View to see if the pin is enabled as SPI0_CS4 or as UART0_TXD.

    Regards,

    Rahul

  • Hi Rahul,

    Thank you for taking the time to reply.  I had commented out the UART0 initialization since it would conflict with both SPI0 and MII and added debugging prints to the probing function that confirm the PINMUX3 is set to 0x11111111 (all set for SPI functionality) right before the system hangs.  We did modify the WL12xx defined enable and irq pins since they conflicted with our existing irq pins for the sc16is7x2s (the ones #defined at the top of board-da850-evm.c).  I'm copying in my modified da8xx_register_spi function below since I'd like feedback on how this is normally handled (registering both SPI busses with the original function in devices-da8xx seems to doubly-register the platform board information, and the number of chip selects setting does not seem correct when not using the lowest chip selects on the bus).

    Thanks for any other ideas you can think to try, I'm happy to add further debug code into the various parts of the kernel (but I do not have an emulator for doing deep inspection).  I also take it that there have not been any issues fixed with SPI0, DMA, or the other general underpinnings in the Linux code since 3.3.0 was released (no patches I should be applying, etc.)?

    Thanks again,

    Scott

     

    int  __init da8xx_register_spi_both_busses(int num_chipselect0, int num_chipselect1, struct spi_board_info *info,

                               unsigned len)

    {

          int ret;

    //One spi_board_info * per board

          ret = spi_register_board_info(info, len);

          if (ret)

                  pr_warning("%s: failed to register board info for spi busses0-1 :"

                             " %d\n", __func__, ret);

          pr_warning(" %s:post spi_register_board, len: %d\n  %d.%d:%X\n  %d.%d:%X\n  %d.%d:%X\n  %d.%d:%X\n",__func__,len,info[0].bus_num,info[0].chip_select,info[0].mode, info[1].bus_num,info[1].chip_select,info[1].mode, info[2].bus_num,info[2].chip_select,info[2].mode, info[3].bus_num,info[3].chip_select,info[3].mode);

    //Twp SPI busses need different pdata

          da8xx_spi_pdata[0].num_chipselect = num_chipselect0;

          da8xx_spi_pdata[1].num_chipselect = num_chipselect1; 

          if (cpu_is_davinci_da850()) {

                  da8xx_spi1_resources[0].start = DA850_SPI1_BASE;

                  da8xx_spi1_resources[0].end = DA850_SPI1_BASE + SZ_4K - 1;

          }

    //register bus 0

          ret=platform_device_register(&da8xx_spi_device[0]);

          if(ret)

                  pr_warning("%s: failed to register platform device for spi bus 0 :"

                      " %d\n", __func__, ret);

    //register bus 1

          ret=platform_device_register(&da8xx_spi_device[1]);

          if(ret)

                pr_warning("%s: failed to register platform device for spi bus 1 :"

                       " %d\n", __func__, ret);

    //This is a quick and sloppy return of only one of the two bus registrations...

     return ret;

    }